feat: 100% width sidebar on mobile
This commit is contained in:
parent
c3f377c635
commit
52c94d22ad
@ -168,8 +168,24 @@
|
||||
}
|
||||
|
||||
/* Sidebar */
|
||||
@media (max-width: 768px) {
|
||||
.sidebar {
|
||||
@apply w-full max-w-full;
|
||||
}
|
||||
|
||||
body.sidebar-open {
|
||||
@apply overflow-hidden;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.sidebar {
|
||||
@apply w-64;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
@apply fixed flex h-full w-64 flex-col overflow-hidden border-r border-[var(--light-foreground)] bg-[var(--light-foreground)] transition-all duration-300;
|
||||
@apply fixed flex h-full flex-col overflow-hidden border-r border-[var(--light-foreground)] bg-[var(--light-foreground)] transition-all duration-300;
|
||||
}
|
||||
|
||||
.dark .sidebar {
|
||||
@ -453,6 +469,18 @@
|
||||
}
|
||||
|
||||
/* Main layout */
|
||||
.main-layout-container {
|
||||
@apply flex h-screen bg-[var(--light-background)];
|
||||
}
|
||||
|
||||
.dark .main-layout-container {
|
||||
@apply bg-[var(--dark-background)];
|
||||
}
|
||||
|
||||
.main-error-popup {
|
||||
@apply fixed top-4 right-4 z-50 max-w-md;
|
||||
}
|
||||
|
||||
.main-header {
|
||||
@apply flex items-center justify-between bg-[var(--light-foreground)] p-4 shadow-sm;
|
||||
}
|
||||
|
@ -19,11 +19,11 @@
|
||||
export let isLoading = false
|
||||
|
||||
// State
|
||||
let sidebarOpen = true
|
||||
let sidebarOpen = false
|
||||
let showSettings = false
|
||||
let isEditing = false
|
||||
|
||||
onMount(async () => {
|
||||
onMount(async (): Promise<any> => {
|
||||
isLoading = true
|
||||
|
||||
try {
|
||||
@ -44,6 +44,22 @@
|
||||
} finally {
|
||||
isLoading = false
|
||||
}
|
||||
|
||||
// Default to sidebar closed on mobile
|
||||
const handleResize = () => {
|
||||
if (window.innerWidth < 768 && sidebarOpen) {
|
||||
sidebarOpen = false
|
||||
}
|
||||
}
|
||||
|
||||
handleResize()
|
||||
|
||||
// Keep listening to browser's resize events
|
||||
window.addEventListener("resize", handleResize)
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("resize", handleResize)
|
||||
}
|
||||
})
|
||||
|
||||
const loadNotes = async () => {
|
||||
@ -59,6 +75,10 @@
|
||||
sidebarOpen = !sidebarOpen
|
||||
}
|
||||
|
||||
const closeSidebar = () => {
|
||||
sidebarOpen = false
|
||||
}
|
||||
|
||||
const toggleSettings = () => {
|
||||
showSettings = !showSettings
|
||||
}
|
||||
@ -81,9 +101,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add caching (!!!)
|
||||
|
||||
const selectNote = async (noteId: string) => {
|
||||
// TODO: check from cache props first before requesting from API
|
||||
|
||||
console.log(`loading ${noteId}`)
|
||||
const note = await apiClient.getFullNote(noteId)
|
||||
|
||||
@ -116,10 +136,10 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex h-screen bg-[var(--light-background)]">
|
||||
<div class="main-layout-container">
|
||||
<!-- Error notification -->
|
||||
{#if $cError}
|
||||
<div class="fixed right-4 top-4 z-50 max-w-md">
|
||||
<div class="main-error-popup">
|
||||
<div class="error">
|
||||
{$cError}
|
||||
<button class="ml-2 text-red-700" on:click={() => cError.set(null)}> × </button>
|
||||
@ -127,22 +147,23 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Sidebar -->
|
||||
<!-- Sidebar (2-way binding prop allows changing the same var. in either component) -->
|
||||
<Sidebar
|
||||
{sidebarOpen}
|
||||
bind:sidebarOpen
|
||||
notes={$availableNotes || []}
|
||||
currentNote={$currentFullNote}
|
||||
{toggleSettings}
|
||||
{logout}
|
||||
{createNewNote}
|
||||
{selectNote}
|
||||
on:close={closeSidebar}
|
||||
/>
|
||||
|
||||
<!-- Main content -->
|
||||
<div
|
||||
class="flex flex-1 flex-col overflow-hidden transition-all duration-300"
|
||||
class:ml-64={sidebarOpen}
|
||||
class:ml-0={!sidebarOpen}
|
||||
class:md:-ml-64={!sidebarOpen}
|
||||
class:md:ml-0={sidebarOpen}
|
||||
>
|
||||
<!-- Top navbar -->
|
||||
<header class="main-header">
|
||||
|
@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { NoteMetadata, FullNote } from "$lib/client"
|
||||
import Close from "$lib/icons/Close.svelte"
|
||||
import CreateNew from "$lib/icons/CreateNew.svelte"
|
||||
import Logout from "$lib/icons/Logout.svelte"
|
||||
import Search from "$lib/icons/Search.svelte"
|
||||
@ -14,6 +15,8 @@
|
||||
export let createNewNote: () => Promise<void>
|
||||
export let selectNote: (noteId: string) => Promise<void>
|
||||
|
||||
// TODO: add caching props -> e.g. `export const previousNotes: FullNote[]`
|
||||
|
||||
const formatDate = (dateString: string | Date): string => {
|
||||
if (!dateString) {
|
||||
return ""
|
||||
@ -30,6 +33,10 @@
|
||||
})
|
||||
}
|
||||
|
||||
const closeSidebar = () => {
|
||||
sidebarOpen = false
|
||||
}
|
||||
|
||||
const handleNoteKeydown = (event: KeyboardEvent, noteID: string) => {
|
||||
if (event.key === "Enter" || event.key === " ") {
|
||||
event.preventDefault() // Prevent page scroll on space
|
||||
@ -47,7 +54,13 @@
|
||||
<!-- TODO: make the sidebar take up whole screen width on mobile -->
|
||||
<!-- TODO: add admin modal (opens a view similar to the settings modal) button to the bottom (if the user is an admin) -->
|
||||
|
||||
<aside class="sidebar" class:translate-x-0={sidebarOpen} class:translate-x-[-100%]={!sidebarOpen}>
|
||||
<aside
|
||||
class="sidebar z-10"
|
||||
class:translate-x-0={sidebarOpen}
|
||||
class:translate-x-[-100%]={!sidebarOpen}
|
||||
class:fixed={true}
|
||||
class:md:relative={true}
|
||||
>
|
||||
<!-- Sidebar header -->
|
||||
<div class="sidebar-header">
|
||||
<div class="flex items-center justify-between">
|
||||
@ -64,6 +77,17 @@
|
||||
<input type="text" placeholder="Search" bind:value={searchQuery} class="search-bar" />
|
||||
<Search />
|
||||
</div>
|
||||
|
||||
<!-- Close button visible only on mobile -->
|
||||
<div class="relative pl-4">
|
||||
<button
|
||||
on:click={closeSidebar}
|
||||
class="btn-secondary rounded-full p-2 md:hidden"
|
||||
aria-label="Close sidebar"
|
||||
>
|
||||
<Close />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -98,6 +122,12 @@
|
||||
<!-- Sidebar footer -->
|
||||
<div class="sidebar-footer">
|
||||
<div class="flex justify-between">
|
||||
<button on:click={logout} class="btn-secondary rounded-full p-2" aria-label="Logout">
|
||||
<Logout />
|
||||
</button>
|
||||
|
||||
<!-- It's better for UX that the logout button isn't on the right side -->
|
||||
|
||||
<button
|
||||
on:click={toggleSettings}
|
||||
class="btn-secondary rounded-full p-2"
|
||||
@ -105,10 +135,6 @@
|
||||
>
|
||||
<Settings />
|
||||
</button>
|
||||
|
||||
<button on:click={logout} class="btn-secondary rounded-full p-2" aria-label="Logout">
|
||||
<Logout />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
Loading…
x
Reference in New Issue
Block a user