194 lines
4.3 KiB
Svelte

<!-- @format -->
<script lang="ts">
export let activeSection: string | null = "entries";
export let onSelect: (id: string) => void = () => {};
type NavItem = {
id: string;
label: string;
icon: string;
};
const workspaceItems: NavItem[] = [
{ id: "entries", label: "Entries", icon: "menu_book" },
{ id: "calendar", label: "Calendar", icon: "calendar_month" },
{ id: "fragments", label: "Fragments", icon: "auto_stories" },
{ id: "todos", label: "To-Do List", icon: "checklist" },
{ id: "lists", label: "Lists", icon: "lists" },
];
function selectItem(id: string) {
onSelect(id);
}
</script>
<aside class="navbar" aria-label="Primary navigation">
<div class="navbar-header">
<img src="svelte.svg" alt="Journal logo" />
</div>
<nav class="nav-groups" aria-label="Journal sections">
<div class="nav-group">
{#each workspaceItems as item}
<button
type="button"
class="nav-button"
class:is-active={activeSection === item.id}
on:click={() => selectItem(item.id)}
aria-label={item.label}
>
<span class="material-symbols-outlined">{item.icon}</span>
<span class="nav-tooltip" role="tooltip">{item.label}</span>
</button>
{/each}
</div>
</nav>
<button
type="button"
class="settings-chip"
class:is-active={activeSection === "settings"}
aria-label="Settings"
on:click={() => selectItem("settings")}
>
<span class="material-symbols-outlined">settings</span>
<span class="nav-tooltip" role="tooltip">Settings</span>
</button>
</aside>
<style>
.navbar {
position: relative;
z-index: 20;
display: flex;
flex-direction: column;
align-items: center;
gap: 14px;
padding: 14px 10px;
background: linear-gradient(
180deg,
var(--surface-2) 0%,
var(--bg-navbar) 100%
);
border-right: 1px solid var(--border-soft);
}
.navbar-header img {
width: 34px;
height: 34px;
object-fit: cover;
border-radius: 9px;
border: 1px solid var(--border-strong);
display: block;
}
.nav-groups {
width: 100%;
display: flex;
flex-direction: column;
gap: 10px;
}
.nav-group {
display: flex;
flex-direction: column;
gap: 4px;
align-items: center;
}
.nav-button,
.settings-chip {
position: relative;
width: 44px;
height: 44px;
display: grid;
place-items: center;
border-radius: 10px;
color: var(--text-dim);
border: 1px solid transparent;
cursor: pointer;
transition:
background-color 0.14s ease,
color 0.14s ease,
border-color 0.14s ease;
}
.nav-button .material-symbols-outlined {
font-size: 1.18rem;
}
.settings-chip .material-symbols-outlined {
font-size: 1.18rem;
}
.nav-tooltip {
position: absolute;
left: calc(100% + 12px);
top: 50%;
transform: translateY(-50%) translateX(-4px);
opacity: 0;
pointer-events: none;
white-space: nowrap;
padding: 4px 9px;
border-radius: 6px;
font-size: 0.76rem;
font-weight: 500;
color: var(--text-primary);
background: var(--surface-1);
border: 1px solid var(--border-strong);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.35);
transition:
opacity 0.12s ease,
transform 0.12s ease;
}
.nav-button:hover,
.nav-button:focus-visible,
.settings-chip:hover,
.settings-chip:focus-visible {
color: var(--text-primary);
background: var(--bg-hover);
border-color: var(--border-soft);
}
.nav-button:hover .nav-tooltip,
.nav-button:focus-visible .nav-tooltip,
.settings-chip:hover .nav-tooltip,
.settings-chip:focus-visible .nav-tooltip {
opacity: 1;
transform: translateY(-50%) translateX(0);
}
.nav-button.is-active {
color: var(--text-primary);
background: var(--bg-active);
border-color: var(--border-strong);
}
.nav-button.is-active .material-symbols-outlined {
color: var(--accent);
}
.settings-chip {
margin-top: auto;
}
.settings-chip.is-active {
color: var(--text-primary);
background: var(--bg-active);
border-color: var(--border-strong);
}
.settings-chip.is-active .material-symbols-outlined {
color: var(--accent);
}
@media (max-width: 980px) {
.nav-button,
.settings-chip {
width: 40px;
height: 40px;
}
}
</style>