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
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>