all repos — weimar @ 3d9ddf2add48689bb513ed4f59a427849dfe0805

Unnamed repository; edit this file 'description' to name the repository.

web/src/routes/+layout.svelte (view raw)

  1<script lang="ts">
  2	import { onMount } from 'svelte';
  3	import { logout, getMe, getConfig, type CurrentUser, type SiteConfig } from '$lib/api';
  4	import Avatar from '$lib/Avatar.svelte';
  5
  6	let { children } = $props();
  7
  8	let user = $state<CurrentUser | null>(null);
  9	let checking = $state(true);
 10	let siteConfig = $state<SiteConfig | null>(null);
 11
 12	onMount(() => {
 13		getConfig()
 14			.then((c) => { siteConfig = c; document.title = c.site_title; })
 15			.catch(() => {});
 16		getMe()
 17			.then((u) => { user = u; })
 18			.catch(() => {})
 19			.finally(() => { checking = false; });
 20	});
 21
 22	async function handleLogout() {
 23		await logout();
 24		user = null;
 25		window.location.href = '/login';
 26	}
 27</script>
 28
 29<nav>
 30	<div class="nav-brand">
 31		<a href="/" class="nav-logo">
 32			{#if siteConfig?.logo_url}
 33				<img src={siteConfig.logo_url} alt={siteConfig.site_title} class="nav-logo-img" />
 34			{:else}
 35				{siteConfig?.site_title ?? 'weimar'}
 36			{/if}
 37		</a>
 38		<span class="nav-divider"></span>
 39	</div>
 40	<div class="nav-links">
 41		<a href="/browse">BROWSE</a>
 42		<a href="/upload">UPLOAD</a>
 43		{#if !checking}
 44			{#if user}
 45				<a href="/settings" class="nav-avatar-link">
 46					<Avatar src={user.avatar_url} username={user.username} size={28} />
 47				</a>
 48				<button class="link logout" onclick={handleLogout}>LOGOUT</button>
 49			{:else}
 50				<a href="/login">LOGIN</a>
 51			{/if}
 52		{/if}
 53	</div>
 54</nav>
 55
 56<div class="main">
 57	{@render children()}
 58</div>
 59
 60<style>
 61	:global(*) {
 62		margin: 0;
 63		padding: 0;
 64		box-sizing: border-box;
 65	}
 66
 67	:global(body) {
 68		font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
 69		background: #f5f5f5;
 70		color: #1a1a1a;
 71		-webkit-font-smoothing: antialiased;
 72	}
 73
 74	:global(h1) {
 75		font-family: 'Oswald', sans-serif;
 76		font-weight: 700;
 77		font-size: 2.5rem;
 78		text-transform: uppercase;
 79		letter-spacing: 0.03em;
 80		line-height: 1.1;
 81		color: #1a1a1a;
 82	}
 83
 84	:global(h2) {
 85		font-family: 'Oswald', sans-serif;
 86		font-weight: 600;
 87		font-size: 1.5rem;
 88		text-transform: uppercase;
 89		letter-spacing: 0.05em;
 90	}
 91
 92	:global(a) {
 93		color: #c62828;
 94		text-decoration: none;
 95		font-weight: 600;
 96	}
 97
 98	:global(a:hover) {
 99		text-decoration: underline;
100	}
101
102	nav {
103		display: flex;
104		align-items: center;
105		justify-content: space-between;
106		padding: 0 1.5rem;
107		height: 3.5rem;
108		background: #1a1a1a;
109		border-bottom: 3px solid #c62828;
110	}
111
112	.nav-brand {
113		display: flex;
114		align-items: center;
115		gap: 1rem;
116	}
117
118	.nav-logo {
119		font-family: 'Oswald', sans-serif;
120		font-weight: 700;
121		font-size: 1.4rem;
122		letter-spacing: 0.15em;
123		color: #fff;
124		text-decoration: none;
125	}
126	.nav-logo:hover {
127		text-decoration: none;
128		color: #ef5350;
129	}
130	.nav-logo-img {
131		display: block;
132		height: 1.8rem;
133		width: auto;
134	}
135
136	.nav-divider {
137		display: block;
138		width: 1px;
139		height: 1.6rem;
140		background: rgba(255,255,255,0.2);
141	}
142
143	.nav-links {
144		display: flex;
145		align-items: center;
146		gap: 0;
147		height: 100%;
148	}
149
150	.nav-links a, .logout {
151		display: flex;
152		align-items: center;
153		height: 100%;
154		padding: 0 1.25rem;
155		font-family: 'Oswald', sans-serif;
156		font-weight: 500;
157		font-size: 0.85rem;
158		letter-spacing: 0.12em;
159		color: rgba(255,255,255,0.8);
160		text-decoration: none;
161		text-transform: uppercase;
162		transition: background 0.15s, color 0.15s;
163		position: relative;
164	}
165
166	.nav-links a:hover, .logout:hover {
167		background: #c62828;
168		color: #fff;
169		text-decoration: none;
170	}
171
172	.nav-links a::after {
173		content: '';
174		position: absolute;
175		bottom: 0;
176		left: 0;
177		right: 0;
178		height: 0;
179		background: #c62828;
180		transition: height 0.15s;
181	}
182
183	.nav-links a:hover::after {
184		height: 3px;
185	}
186
187	.nav-avatar-link {
188		padding: 0 0.75rem !important;
189	}
190	.nav-avatar-link::after {
191		display: none !important;
192	}
193	.nav-avatar-link:hover {
194		background: none !important;
195	}
196
197	.logout {
198		background: none;
199		border: none;
200		cursor: pointer;
201		font-size: 0.85rem;
202	}
203
204	.main {
205		max-width: 1400px;
206		margin: 0 auto;
207		padding: 1.5rem;
208	}
209</style>