this repo has no description

cmd/blog: copy static assets from appview during build

Signed-off-by: Anirudh Oppiliappan <anirudh@tangled.org>

anirudh.fi 91dcca51 7f4e49b2

verified
+47 -9
+2
.gitignore
··· 22 22 genjwks.out 23 23 /nix/vm-data 24 24 blog/build/ 25 + build/ 26 + .wrangler/
+4 -4
.tangled/workflows/deploy-blog.yml
··· 16 16 mkdir -p appview/pages/static 17 17 touch appview/pages/static/x 18 18 19 - - name: build blog cmd 20 - command: | 21 - go build -o blog.out ./cmd/blog 22 - 23 19 - name: generate css 24 20 command: | 25 21 tailwindcss -i input.css -o appview/pages/static/tw.css 22 + 23 + - name: build blog cmd 24 + command: | 25 + go build -o blog.out ./cmd/blog 26 26 27 27 - name: build static site 28 28 command: |
+3
appview/pages/funcmap.go
··· 521 521 } 522 522 523 523 secret := p.avatar.SharedSecret 524 + if secret == "" { 525 + return "" 526 + } 524 527 h := hmac.New(sha256.New, []byte(secret)) 525 528 h.Write([]byte(did)) 526 529 signature := hex.EncodeToString(h.Sum(nil))
+4 -1
blog/templates/index.html
··· 37 37 <h2 class="font-bold text-gray-900 dark:text-white text-base leading-snug mb-1 group-hover:underline">{{ .Meta.Title }}</h2> 38 38 <p class="text-sm text-gray-500 dark:text-gray-400 line-clamp-2 flex-1">{{ .Meta.Subtitle }}</p> 39 39 <div class="flex items-center mt-4"> 40 + {{ $hasAvatar := false }}{{ range .Meta.Authors }}{{ if tinyAvatar .Handle }}{{ $hasAvatar = true }}{{ end }}{{ end }} 41 + {{ if $hasAvatar }} 40 42 <div class="inline-flex items-center -space-x-2"> 41 43 {{ range .Meta.Authors }} 42 - <img src="{{ tinyAvatar .Handle }}" class="size-6 rounded-full border border-gray-300 dark:border-gray-700" alt="{{ .Name }}" title="{{ .Name }}" /> 44 + {{ $av := tinyAvatar .Handle }}{{ if $av }}<img src="{{ $av }}" class="size-6 rounded-full border border-gray-300 dark:border-gray-700" alt="{{ .Name }}" title="{{ .Name }}" />{{ end }} 43 45 {{ end }} 44 46 </div> 47 + {{ end }} 45 48 </div> 46 49 </div> 47 50 </a>
+4 -1
blog/templates/post.html
··· 45 45 <p class="italic mt-1 mb-3 text-lg text-gray-600 dark:text-gray-400">{{ .Post.Meta.Subtitle }}</p> 46 46 47 47 <div class="flex items-center gap-3 not-prose"> 48 + {{ $hasAvatar := false }}{{ range $authors }}{{ if tinyAvatar .Handle }}{{ $hasAvatar = true }}{{ end }}{{ end }} 49 + {{ if $hasAvatar }} 48 50 <div class="inline-flex items-center -space-x-2"> 49 51 {{ range $authors }} 50 - <img src="{{ tinyAvatar .Handle }}" class="size-7 rounded-full border border-gray-300 dark:border-gray-700" alt="{{ .Handle }}" title="{{ .Handle }}" /> 52 + {{ $av := tinyAvatar .Handle }}{{ if $av }}<img src="{{ $av }}" class="size-7 rounded-full border border-gray-300 dark:border-gray-700" alt="{{ .Handle }}" title="{{ .Handle }}" />{{ end }} 51 53 {{ end }} 52 54 </div> 55 + {{ end }} 53 56 <div class="flex items-center gap-1 text-sm text-gray-700 dark:text-gray-300"> 54 57 {{ range $i, $a := $authors }} 55 58 {{ if gt $i 0 }}<span class="text-gray-400">&amp;</span>{{ end }}
+30 -3
cmd/blog/main.go
··· 4 4 "context" 5 5 "fmt" 6 6 "io" 7 + "io/fs" 7 8 "log/slog" 8 9 "net/http" 9 10 "os" ··· 84 85 return fmt.Errorf("rendering index: %w", err) 85 86 } 86 87 87 - // posts — each at build/<slug>/index.html directly (no /blog/ prefix) 88 88 for _, post := range posts { 89 - post := post 90 89 postDir := filepath.Join(outDir, post.Meta.Slug) 91 90 if err := os.MkdirAll(postDir, 0755); err != nil { 92 91 return err ··· 98 97 } 99 98 } 100 99 101 - // atom feed — at build/feed.xml 100 + // atom feed 102 101 baseURL := "https://blog.tangled.org" 103 102 atom, err := blog.AtomFeed(posts, baseURL) 104 103 if err != nil { ··· 108 107 return fmt.Errorf("writing feed: %w", err) 109 108 } 110 109 110 + // copy embedded static assets into build/static/ so Cloudflare Pages 111 + // can serve them from the same origin as the built HTML 112 + staticSrc, err := fs.Sub(pages.Files, "static") 113 + if err != nil { 114 + return fmt.Errorf("accessing embedded static dir: %w", err) 115 + } 116 + if err := copyFS(staticSrc, filepath.Join(outDir, "static")); err != nil { 117 + return fmt.Errorf("copying static assets: %w", err) 118 + } 119 + 111 120 logger.Info("build complete", "dir", outDir) 112 121 return nil 122 + } 123 + 124 + // copyFS copies all files from src into destDir, preserving directory structure. 125 + func copyFS(src fs.FS, destDir string) error { 126 + return fs.WalkDir(src, ".", func(path string, d fs.DirEntry, err error) error { 127 + if err != nil { 128 + return err 129 + } 130 + dest := filepath.Join(destDir, path) 131 + if d.IsDir() { 132 + return os.MkdirAll(dest, 0755) 133 + } 134 + data, err := fs.ReadFile(src, path) 135 + if err != nil { 136 + return err 137 + } 138 + return os.WriteFile(dest, data, 0644) 139 + }) 113 140 } 114 141 115 142 func runServe(ctx context.Context, logger *slog.Logger, addr string) error {