perf: self-host fonts and add /admin route
Self-hosted fonts: - Download all 10 typefaces (35 font files, 728KB) from Google Fonts - Create @font-face declarations in assets/css/fonts.css - Remove Google Fonts external dependency from layouts - Privacy improvement (no Google tracking) - Performance improvement (no DNS lookup to fonts.googleapis.com) - GDPR compliant (no third-party requests) Admin access: - Add /admin route that redirects to /admin/theme (requires auth) - Remove Admin link from footer (too visible for visitors) - Shop owners can bookmark or type /admin directly Layout improvements: - Create shop_root.html.heex as minimal root for shop pages - Shop pages no longer show admin nav bar Other: - Update .gitignore to exclude digested static files - Add PageSpeed 100% task to ROADMAP.md - Fix test to check /users/settings instead of shop homepage Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -102,6 +102,9 @@
|
||||
/* Make LiveView wrapper divs transparent for layout */
|
||||
[data-phx-session], [data-phx-teleported-src] { display: contents }
|
||||
|
||||
/* Self-hosted fonts - all font-face declarations */
|
||||
@import "./fonts.css";
|
||||
|
||||
/* Theme CSS - Layer 1: Primitives (fixed CSS variables) */
|
||||
@import "./theme-primitives.css";
|
||||
|
||||
|
||||
269
assets/css/fonts.css
Normal file
269
assets/css/fonts.css
Normal file
@@ -0,0 +1,269 @@
|
||||
/* Self-hosted Google Fonts
|
||||
* All fonts loaded locally for privacy and performance.
|
||||
* Browsers only download fonts actually used on the page.
|
||||
*/
|
||||
|
||||
/* Inter - Clean, Modern, Impulse presets (body) */
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
font-display: swap;
|
||||
src: url('/fonts/inter-v20-latin-300.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url('/fonts/inter-v20-latin-regular.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url('/fonts/inter-v20-latin-500.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url('/fonts/inter-v20-latin-600.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url('/fonts/inter-v20-latin-700.woff2') format('woff2');
|
||||
}
|
||||
|
||||
/* Manrope - Clean preset (heading) */
|
||||
@font-face {
|
||||
font-family: 'Manrope';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url('/fonts/manrope-v20-latin-regular.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Manrope';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url('/fonts/manrope-v20-latin-500.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Manrope';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url('/fonts/manrope-v20-latin-600.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Manrope';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url('/fonts/manrope-v20-latin-700.woff2') format('woff2');
|
||||
}
|
||||
|
||||
/* Work Sans - Friendly preset (body) */
|
||||
@font-face {
|
||||
font-family: 'Work Sans';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
font-display: swap;
|
||||
src: url('/fonts/work-sans-v24-latin-300.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Work Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url('/fonts/work-sans-v24-latin-regular.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Work Sans';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url('/fonts/work-sans-v24-latin-500.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Work Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url('/fonts/work-sans-v24-latin-600.woff2') format('woff2');
|
||||
}
|
||||
|
||||
/* DM Sans - Minimal preset (heading) */
|
||||
@font-face {
|
||||
font-family: 'DM Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url('/fonts/dm-sans-v17-latin-regular.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'DM Sans';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url('/fonts/dm-sans-v17-latin-500.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'DM Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url('/fonts/dm-sans-v17-latin-600.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'DM Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url('/fonts/dm-sans-v17-latin-700.woff2') format('woff2');
|
||||
}
|
||||
|
||||
/* Raleway - Editorial, Impulse presets (body/heading) */
|
||||
@font-face {
|
||||
font-family: 'Raleway';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
font-display: swap;
|
||||
src: url('/fonts/raleway-v37-latin-300.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Raleway';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url('/fonts/raleway-v37-latin-regular.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Raleway';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url('/fonts/raleway-v37-latin-500.woff2') format('woff2');
|
||||
}
|
||||
|
||||
/* Space Grotesk - Modern preset (heading) */
|
||||
@font-face {
|
||||
font-family: 'Space Grotesk';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url('/fonts/space-grotesk-v22-latin-regular.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Space Grotesk';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url('/fonts/space-grotesk-v22-latin-500.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Space Grotesk';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url('/fonts/space-grotesk-v22-latin-600.woff2') format('woff2');
|
||||
}
|
||||
|
||||
/* Playfair Display - Editorial preset (heading) */
|
||||
@font-face {
|
||||
font-family: 'Playfair Display';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url('/fonts/playfair-display-v40-latin-regular.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Playfair Display';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url('/fonts/playfair-display-v40-latin-500.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Playfair Display';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url('/fonts/playfair-display-v40-latin-700.woff2') format('woff2');
|
||||
}
|
||||
|
||||
/* Cormorant Garamond - Classic preset (heading) */
|
||||
@font-face {
|
||||
font-family: 'Cormorant Garamond';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url('/fonts/cormorant-garamond-v21-latin-regular.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Cormorant Garamond';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url('/fonts/cormorant-garamond-v21-latin-500.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Cormorant Garamond';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url('/fonts/cormorant-garamond-v21-latin-600.woff2') format('woff2');
|
||||
}
|
||||
|
||||
/* Source Serif 4 - Classic, Minimal presets (body) */
|
||||
@font-face {
|
||||
font-family: 'Source Serif 4';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url('/fonts/source-serif-4-v14-latin-regular.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Source Serif 4';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url('/fonts/source-serif-4-v14-latin-600.woff2') format('woff2');
|
||||
}
|
||||
|
||||
/* Fraunces - Friendly preset (heading) */
|
||||
@font-face {
|
||||
font-family: 'Fraunces';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url('/fonts/fraunces-v38-latin-regular.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Fraunces';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url('/fonts/fraunces-v38-latin-500.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Fraunces';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url('/fonts/fraunces-v38-latin-600.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Fraunces';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url('/fonts/fraunces-v38-latin-700.woff2') format('woff2');
|
||||
}
|
||||
Reference in New Issue
Block a user