init elas atelier
This commit is contained in:
+124
-120
@@ -2,7 +2,9 @@
|
||||
import '../styles/global.css';
|
||||
import 'katex/dist/katex.min.css';
|
||||
import 'highlight.js/styles/atom-one-dark.css';
|
||||
import '@fontsource-variable/inter';
|
||||
import '@fontsource-variable/fraunces';
|
||||
import '@fontsource-variable/eb-garamond';
|
||||
import '@fontsource/caveat';
|
||||
import '@fontsource-variable/jetbrains-mono';
|
||||
import ThemeSwitcher from '../components/react/ThemeSwitcher';
|
||||
import Search from '../components/react/Search';
|
||||
@@ -23,136 +25,138 @@ const API_URL = process.env.PUBLIC_API_URL || 'http://backend:3000';
|
||||
const isAdmin = Astro.cookies.get('admin_session')?.value === '1';
|
||||
|
||||
let siteConfig = {
|
||||
title: "Narlblog",
|
||||
subtitle: "A clean, modern blog",
|
||||
footer: "Built with Rust & Astro",
|
||||
favicon: "/favicon.svg",
|
||||
theme: "mocha",
|
||||
custom_css: ""
|
||||
title: "Ela's Atelier",
|
||||
subtitle: "Works on paper, canvas, and elsewhere",
|
||||
footer: "Hand-arranged with care",
|
||||
favicon: "/favicon.svg",
|
||||
theme: "salon",
|
||||
custom_css: ""
|
||||
};
|
||||
|
||||
try {
|
||||
const res = await fetch(`${API_URL}/api/config`);
|
||||
if (res.ok) {
|
||||
siteConfig = await res.json();
|
||||
}
|
||||
const res = await fetch(`${API_URL}/api/config`);
|
||||
if (res.ok) {
|
||||
siteConfig = await res.json();
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch config:", e);
|
||||
console.error("Failed to fetch config:", e);
|
||||
}
|
||||
|
||||
const fullTitle = `${title} | ${siteConfig.title}`;
|
||||
const fullTitle = `${title} · ${siteConfig.title}`;
|
||||
const year = new Date().getFullYear();
|
||||
---
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<link rel="icon" href={siteConfig.favicon} />
|
||||
<meta name="generator" content={Astro.generator} />
|
||||
<title>{fullTitle}</title>
|
||||
{description && <meta name="description" content={description} />}
|
||||
<meta property="og:title" content={fullTitle} />
|
||||
{description && <meta property="og:description" content={description} />}
|
||||
<meta property="og:type" content={type} />
|
||||
<meta property="og:site_name" content={siteConfig.title} />
|
||||
<meta property="og:url" content={Astro.url.href} />
|
||||
{image && <meta property="og:image" content={image} />}
|
||||
<meta name="twitter:card" content={image ? 'summary_large_image' : 'summary'} />
|
||||
<meta name="twitter:title" content={fullTitle} />
|
||||
{description && <meta name="twitter:description" content={description} />}
|
||||
{image && <meta name="twitter:image" content={image} />}
|
||||
<link rel="alternate" type="application/rss+xml" title={siteConfig.title} href="/feed.xml" />
|
||||
{siteConfig.custom_css && <style set:html={siteConfig.custom_css} />}
|
||||
<script is:inline define:vars={{ defaultTheme: siteConfig.theme }}>
|
||||
const savedTheme = localStorage.getItem('user-theme') || defaultTheme;
|
||||
document.documentElement.classList.add(savedTheme);
|
||||
</script>
|
||||
<slot name="head" />
|
||||
</head>
|
||||
<body class="bg-bg text-text selection:bg-surface2 selection:text-text">
|
||||
<!-- Static Mesh Gradient Background -->
|
||||
<div class="fixed inset-0 z-[-1] overflow-hidden bg-bg pointer-events-none">
|
||||
<div class="absolute top-[-10%] left-[-10%] w-[55%] h-[45%] rounded-full bg-mauve/10 blur-[110px] opacity-60"></div>
|
||||
<div class="absolute bottom-[-10%] right-[-10%] w-[55%] h-[55%] rounded-full bg-blue/10 blur-[110px] opacity-50"></div>
|
||||
<div class="absolute top-[30%] right-[10%] w-[35%] h-[35%] rounded-full bg-teal/8 blur-[90px] opacity-40"></div>
|
||||
</div>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<link rel="icon" href={siteConfig.favicon} />
|
||||
<meta name="generator" content={Astro.generator} />
|
||||
<title>{fullTitle}</title>
|
||||
{description && <meta name="description" content={description} />}
|
||||
<meta property="og:title" content={fullTitle} />
|
||||
{description && <meta property="og:description" content={description} />}
|
||||
<meta property="og:type" content={type} />
|
||||
<meta property="og:site_name" content={siteConfig.title} />
|
||||
<meta property="og:url" content={Astro.url.href} />
|
||||
{image && <meta property="og:image" content={image} />}
|
||||
<meta name="twitter:card" content={image ? 'summary_large_image' : 'summary'} />
|
||||
<meta name="twitter:title" content={fullTitle} />
|
||||
{description && <meta name="twitter:description" content={description} />}
|
||||
{image && <meta name="twitter:image" content={image} />}
|
||||
<link rel="alternate" type="application/rss+xml" title={siteConfig.title} href="/feed.xml" />
|
||||
{siteConfig.custom_css && <style set:html={siteConfig.custom_css} />}
|
||||
<script is:inline define:vars={{ defaultTheme: siteConfig.theme }}>
|
||||
const savedTheme = localStorage.getItem('user-theme') || defaultTheme || 'salon';
|
||||
document.documentElement.classList.add(savedTheme);
|
||||
</script>
|
||||
<slot name="head" />
|
||||
</head>
|
||||
<body class="text-text">
|
||||
<div class="salon-atmosphere" aria-hidden="true"></div>
|
||||
|
||||
<nav class="max-w-6xl mx-auto px-4 md:px-6 py-4 md:py-8">
|
||||
<header class="glass px-4 py-3 md:px-6 md:py-4 flex flex-col md:flex-row items-center justify-between gap-4">
|
||||
<div class="w-full md:w-auto text-center md:text-left">
|
||||
{isAdmin ? (
|
||||
<EditableText
|
||||
client:load
|
||||
initial={siteConfig.title}
|
||||
fieldKey="title"
|
||||
isAdmin
|
||||
ariaLabel="site title"
|
||||
className="text-xl md:text-2xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-mauve to-blue inline-block"
|
||||
/>
|
||||
) : (
|
||||
<a href="/" class="text-xl md:text-2xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-mauve to-blue block">
|
||||
{siteConfig.title}
|
||||
</a>
|
||||
)}
|
||||
{isAdmin ? (
|
||||
<div class="text-[8px] md:text-[10px] text-subtext0 uppercase tracking-widest">
|
||||
<EditableText
|
||||
client:load
|
||||
initial={siteConfig.subtitle}
|
||||
fieldKey="subtitle"
|
||||
isAdmin
|
||||
ariaLabel="site subtitle"
|
||||
className="inline"
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<p class="text-[8px] md:text-[10px] text-subtext0 uppercase tracking-widest">{siteConfig.subtitle}</p>
|
||||
)}
|
||||
</div>
|
||||
<div class="flex gap-2 md:gap-3 items-center text-sm md:text-base w-full md:w-auto justify-center md:justify-end">
|
||||
<Search client:load />
|
||||
{isAdmin && (
|
||||
<div class="flex items-center gap-1 pl-2 ml-1 border-l border-surface1/60">
|
||||
<a
|
||||
href="/"
|
||||
class="inline-flex items-center gap-1.5 text-xs uppercase tracking-wider px-2.5 py-1 rounded-full bg-mauve/15 text-mauve border border-mauve/30 hover:bg-mauve/25 transition-colors"
|
||||
title="Signed in as admin"
|
||||
>
|
||||
<span class="w-1.5 h-1.5 rounded-full bg-mauve animate-pulse"></span>
|
||||
Admin
|
||||
</a>
|
||||
<LogoutButton client:load />
|
||||
</div>
|
||||
)}
|
||||
<ThemeSwitcher client:only="react" defaultTheme={siteConfig.theme} />
|
||||
</div>
|
||||
</header>
|
||||
</nav>
|
||||
<header class="border-b border-[var(--surface2)]/60 relative z-10">
|
||||
<div class="max-w-6xl mx-auto px-6 md:px-10 py-5 md:py-7 flex flex-col md:flex-row md:items-end gap-4 md:gap-6">
|
||||
<a href="/" class="nameplate group" aria-label="Home">
|
||||
{isAdmin ? (
|
||||
<EditableText
|
||||
client:load
|
||||
initial={siteConfig.title}
|
||||
fieldKey="title"
|
||||
isAdmin
|
||||
ariaLabel="site title"
|
||||
className="nameplate-title"
|
||||
/>
|
||||
) : (
|
||||
<span class="nameplate-title group-hover:text-[var(--mauve)] transition-colors">{siteConfig.title}</span>
|
||||
)}
|
||||
{isAdmin ? (
|
||||
<EditableText
|
||||
client:load
|
||||
initial={siteConfig.subtitle}
|
||||
fieldKey="subtitle"
|
||||
isAdmin
|
||||
ariaLabel="site subtitle"
|
||||
className="nameplate-subtitle"
|
||||
/>
|
||||
) : (
|
||||
<span class="nameplate-subtitle">{siteConfig.subtitle}</span>
|
||||
)}
|
||||
</a>
|
||||
|
||||
<main class={`mx-auto px-4 md:px-6 py-4 md:py-8 ${wide ? 'max-w-[95vw]' : 'max-w-6xl'}`}>
|
||||
<slot />
|
||||
</main>
|
||||
<div class="flex-1 hidden md:flex items-end justify-center pb-1">
|
||||
<span class="font-display italic text-[var(--subtext0)] text-sm tracking-wider">— exhibition est. {year} —</span>
|
||||
</div>
|
||||
|
||||
<footer class="max-w-6xl mx-auto px-4 md:px-6 py-8 md:py-12 text-center text-xs md:text-sm text-subtext1 border-t border-white/5 mt-8 md:mt-12">
|
||||
<p class="mb-2">
|
||||
{isAdmin ? (
|
||||
<EditableText
|
||||
client:load
|
||||
initial={siteConfig.footer}
|
||||
fieldKey="footer"
|
||||
isAdmin
|
||||
ariaLabel="footer text"
|
||||
className="inline"
|
||||
/>
|
||||
) : siteConfig.footer}
|
||||
</p>
|
||||
<div class="text-xs text-subtext0 mb-2">
|
||||
<a href="/feed.xml" class="hover:text-mauve transition-colors">RSS</a>
|
||||
</div>
|
||||
<div class="text-subtext0 opacity-50">
|
||||
© {new Date().getFullYear()} {siteConfig.title}
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
<div class="flex flex-wrap items-center gap-3 justify-start md:justify-end">
|
||||
<Search client:load />
|
||||
{isAdmin && (
|
||||
<div class="flex items-center gap-1 pl-3 ml-1 border-l border-[var(--surface2)]/60">
|
||||
<a
|
||||
href="/admin"
|
||||
class="chip chip-accent uppercase"
|
||||
title="Signed in as curator"
|
||||
>
|
||||
<span class="w-1.5 h-1.5 rounded-full bg-[var(--rosewater)] animate-pulse"></span>
|
||||
Curator
|
||||
</a>
|
||||
<LogoutButton client:load />
|
||||
</div>
|
||||
)}
|
||||
<ThemeSwitcher client:only="react" defaultTheme={siteConfig.theme} />
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class={`mx-auto px-6 md:px-10 py-10 md:py-16 relative z-10 ${wide ? 'max-w-[95vw]' : 'max-w-6xl'}`}>
|
||||
<slot />
|
||||
</main>
|
||||
|
||||
<footer class="max-w-6xl mx-auto px-6 md:px-10 py-12 md:py-16 text-center border-t border-[var(--surface2)]/40 mt-12 relative z-10">
|
||||
<div class="section-rule mb-6">
|
||||
<span class="ornament">✦</span>
|
||||
<span class="font-display italic text-[var(--subtext0)] text-sm">end of catalogue</span>
|
||||
<span class="ornament">✦</span>
|
||||
</div>
|
||||
<p class="font-display italic text-base text-[var(--subtext1)] mb-2">
|
||||
{isAdmin ? (
|
||||
<EditableText
|
||||
client:load
|
||||
initial={siteConfig.footer}
|
||||
fieldKey="footer"
|
||||
isAdmin
|
||||
ariaLabel="footer text"
|
||||
className="inline"
|
||||
/>
|
||||
) : siteConfig.footer}
|
||||
</p>
|
||||
<div class="text-xs text-[var(--subtext0)] tracking-[0.2em] uppercase mb-3">
|
||||
<a href="/feed.xml" class="hover:text-[var(--mauve)] transition-colors">RSS Feed</a>
|
||||
</div>
|
||||
<div class="text-[var(--overlay0)] text-xs italic">
|
||||
© {year} · {siteConfig.title}
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user