Address review comments: extract JS and SVGs to files, drop custom fonts
- public/capture.js: Alpine.js captureApp() extracted from capture.rb
- public/icons/{camera,folder,image,check}.svg: icon SVGs extracted from capture.rb
- lib/views/capture.rb: inline JS and SVG methods replaced with icon() helper
  that reads from public/icons/ at render time; Google Fonts links removed
- lib/views/layout.rb: Google Fonts preconnect and stylesheet links removed
- public/app.css: --font-ui and --font-mono now use system font stacks only
change
commit 48f3a660f8823487781723a6166a6f3737ae3551
author Alpha Chen <alpha@kejadlen.dev>
date
parent fb9fe632
diff --git a/lib/views/capture.rb b/lib/views/capture.rb
index 37b997e..40e9be6 100644
--- a/lib/views/capture.rb
+++ b/lib/views/capture.rb
@@ -5,42 +5,7 @@ require_relative "layout"
 module Domus
   module Views
     class Capture < Phlex::HTML
-      ALPINE_JS = <<~JS
-        function captureApp() {
-          return {
-            state: 'capture',
-            preview: null,
-            dragging: false,
-
-            handleFile(file) {
-              if (!file) return;
-              this.preview = file.type.startsWith('image/') ? URL.createObjectURL(file) : null;
-              this.state = 'saved';
-            },
-
-            onFileInput(e) {
-              this.handleFile(e.target.files[0]);
-            },
-
-            onDrop(e) {
-              this.dragging = false;
-              const file = e.dataTransfer?.files[0];
-              if (file) {
-                this.$refs.fileInput.files = e.dataTransfer.files;
-                this.handleFile(file);
-              }
-            },
-
-            reset() {
-              if (this.preview) URL.revokeObjectURL(this.preview);
-              this.state = 'capture';
-              this.preview = null;
-              this.$refs.fileInput.value = '';
-              this.$refs.cameraInput.value = '';
-            }
-          }
-        }
-      JS
+      ICONS_DIR = File.expand_path("../../public/icons", __dir__)
 
       def view_template
         doctype
@@ -49,14 +14,11 @@ module Domus
             meta(charset: "utf-8")
             meta(name: "viewport", content: "width=device-width, initial-scale=1")
             title { "Domus - Add document" }
-            link(rel: "preconnect", href: "https://fonts.googleapis.com")
-            link(rel: "preconnect", href: "https://fonts.gstatic.com", crossorigin: true)
-            link(rel: "stylesheet", href: "https://fonts.googleapis.com/css2?family=Hanken+Grotesk:wght@400;500;550;600;650;700&family=JetBrains+Mono:wght@400;500&display=swap")
             link(rel: "stylesheet", href: "/app.css")
+            script(defer: true, src: "/capture.js")
             script(defer: true, src: "https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js")
           end
           body do
-            script { raw safe(ALPINE_JS) }
             render_page
           end
         end
@@ -119,7 +81,7 @@ module Domus
                   class: "btn btn-primary",
                   "@click": "$refs.cameraInput.click()"
                 ) do
-                  camera_icon
+                  icon("camera")
                   plain "Take a photo"
                 end
 
@@ -128,7 +90,7 @@ module Domus
                   class: "btn",
                   "@click": "$refs.fileInput.click()"
                 ) do
-                  folder_icon
+                  icon("folder")
                   plain "Browse files"
                 end
               end
@@ -153,7 +115,7 @@ module Domus
                   class: "preview-placeholder",
                   "x-show": "!preview"
                 ) do
-                  image_icon
+                  icon("image")
                   plain "captured file"
                 end
               end
@@ -161,7 +123,7 @@ module Domus
               div(class: "save-form") do
                 div(class: "btn-row") do
                   button(type: "submit", class: "btn btn-primary") do
-                    check_icon
+                    icon("check")
                     plain "Save document"
                   end
                   button(
@@ -176,39 +138,8 @@ module Domus
         end
       end
 
-      def camera_icon
-        raw safe(<<~SVG)
-          <svg class="icon" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
-            <path d="M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z"/>
-            <circle cx="12" cy="13" r="3"/>
-          </svg>
-        SVG
-      end
-
-      def folder_icon
-        raw safe(<<~SVG)
-          <svg class="icon" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
-            <path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/>
-          </svg>
-        SVG
-      end
-
-      def image_icon
-        raw safe(<<~SVG)
-          <svg class="icon" xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
-            <rect x="3" y="3" width="18" height="18" rx="2" ry="2"/>
-            <circle cx="8.5" cy="8.5" r="1.5"/>
-            <polyline points="21 15 16 10 5 21"/>
-          </svg>
-        SVG
-      end
-
-      def check_icon
-        raw safe(<<~SVG)
-          <svg class="icon" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
-            <polyline points="20 6 9 17 4 12"/>
-          </svg>
-        SVG
+      def icon(name)
+        raw safe(File.read(File.join(ICONS_DIR, "#{name}.svg")))
       end
     end
   end
diff --git a/lib/views/layout.rb b/lib/views/layout.rb
index 8160698..b773a4b 100644
--- a/lib/views/layout.rb
+++ b/lib/views/layout.rb
@@ -18,9 +18,6 @@ module Domus
             meta(charset: "utf-8")
             meta(name: "viewport", content: "width=device-width, initial-scale=1")
             title { @title }
-            link(rel: "preconnect", href: "https://fonts.googleapis.com")
-            link(rel: "preconnect", href: "https://fonts.gstatic.com", crossorigin: true)
-            link(rel: "stylesheet", href: "https://fonts.googleapis.com/css2?family=Hanken+Grotesk:wght@400;500;550;600;650;700&family=JetBrains+Mono:wght@400;500&display=swap")
             link(rel: "stylesheet", href: "/app.css")
             script(defer: true, src: "https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js")
           end
diff --git a/public/app.css b/public/app.css
index e886773..bbd6830 100644
--- a/public/app.css
+++ b/public/app.css
@@ -32,8 +32,8 @@
   --accent-ink: oklch(0.42 0.17 290);
   --accent-soft:oklch(0.96 0.03 290);
   --radius:     10px;
-  --font-ui:    "Hanken Grotesk", system-ui, -apple-system, sans-serif;
-  --font-mono:  "JetBrains Mono", ui-monospace, "SF Mono", monospace;
+  --font-ui:    system-ui, -apple-system, sans-serif;
+  --font-mono:  ui-monospace, "SF Mono", monospace;
 }
 
 *, *::before, *::after { box-sizing: border-box; }
diff --git a/public/capture.js b/public/capture.js
new file mode 100644
index 0000000..7495180
--- /dev/null
+++ b/public/capture.js
@@ -0,0 +1,34 @@
+function captureApp() {
+  return {
+    state: 'capture',
+    preview: null,
+    dragging: false,
+
+    handleFile(file) {
+      if (!file) return;
+      this.preview = file.type.startsWith('image/') ? URL.createObjectURL(file) : null;
+      this.state = 'saved';
+    },
+
+    onFileInput(e) {
+      this.handleFile(e.target.files[0]);
+    },
+
+    onDrop(e) {
+      this.dragging = false;
+      const file = e.dataTransfer?.files[0];
+      if (file) {
+        this.$refs.fileInput.files = e.dataTransfer.files;
+        this.handleFile(file);
+      }
+    },
+
+    reset() {
+      if (this.preview) URL.revokeObjectURL(this.preview);
+      this.state = 'capture';
+      this.preview = null;
+      this.$refs.fileInput.value = '';
+      this.$refs.cameraInput.value = '';
+    }
+  }
+}
diff --git a/public/icons/camera.svg b/public/icons/camera.svg
new file mode 100644
index 0000000..8a2a485
--- /dev/null
+++ b/public/icons/camera.svg
@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
+  <path d="M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z"/>
+  <circle cx="12" cy="13" r="3"/>
+</svg>
diff --git a/public/icons/check.svg b/public/icons/check.svg
new file mode 100644
index 0000000..a829f52
--- /dev/null
+++ b/public/icons/check.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
+  <polyline points="20 6 9 17 4 12"/>
+</svg>
diff --git a/public/icons/folder.svg b/public/icons/folder.svg
new file mode 100644
index 0000000..640282c
--- /dev/null
+++ b/public/icons/folder.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
+  <path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/>
+</svg>
diff --git a/public/icons/image.svg b/public/icons/image.svg
new file mode 100644
index 0000000..41aa4a7
--- /dev/null
+++ b/public/icons/image.svg
@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
+  <rect x="3" y="3" width="18" height="18" rx="2" ry="2"/>
+  <circle cx="8.5" cy="8.5" r="1.5"/>
+  <polyline points="21 15 16 10 5 21"/>
+</svg>