Browse Source

Menus

master
Nuša Pukšič 7 months ago committed by buttercat1791
parent
commit
06fb80f73b
  1. 10
      deno.lock
  2. 13
      package-lock.json
  3. 1
      package.json
  4. 45
      src/app.css
  5. 1
      src/lib/a/index.ts
  6. 2
      src/lib/a/nav/AFooter.svelte
  7. 85
      src/lib/a/nav/ANavbar.svelte
  8. 41
      src/lib/a/nav/AUserDropdown.svelte
  9. 15
      src/lib/a/nav/nav-types.ts
  10. 2
      src/lib/a/primitives/APagination.svelte
  11. 10
      src/lib/a/primitives/ASwitch.svelte
  12. 4
      src/lib/a/reader/ATechToggle.svelte
  13. 194
      src/lib/components/util/Profile.svelte
  14. 41
      src/lib/nav/site-nav.ts
  15. 2
      src/routes/+layout.svelte
  16. 3
      src/routes/profile/+page.svelte
  17. 10
      src/routes/profile/my-notes/+page.svelte

10
deno.lock

@ -32,6 +32,7 @@ @@ -32,6 +32,7 @@
"npm:flowbite-svelte-icons@2.1": "2.1.1_svelte@5.38.2__acorn@8.15.0_tailwind-merge@3.3.1",
"npm:flowbite-svelte@0.48": "0.48.6_svelte@5.38.2__acorn@8.15.0",
"npm:flowbite-svelte@1.11": "1.11.8_svelte@5.38.2__acorn@8.15.0_tailwindcss@4.1.12_tailwind-merge@3.3.1",
"npm:flowbite-typography@^1.0.5": "1.0.5",
"npm:flowbite@2": "2.5.2",
"npm:flowbite@~2.5.2": "2.5.2",
"npm:he@1.2": "1.2.0",
@ -2104,6 +2105,14 @@ @@ -2104,6 +2105,14 @@
"tailwindcss"
]
},
"flowbite-typography@1.0.5": {
"integrity": "sha512-IqTwOYgGZkXTK/5ngx3A9oQwgOqnRyUKUfIiB+w6xDmiD8z3cKDIgYfFpHIMKbLVfg+QmJIPqEEPrGZbAwVT6g==",
"dependencies": [
"lodash.castarray",
"lodash.isplainobject",
"lodash.merge"
]
},
"flowbite@2.5.2": {
"integrity": "sha512-kwFD3n8/YW4EG8GlY3Od9IoKND97kitO+/ejISHSqpn3vw2i5K/+ZI8Jm2V+KC4fGdnfi0XZ+TzYqQb4Q1LshA==",
"dependencies": [
@ -3581,6 +3590,7 @@ @@ -3581,6 +3590,7 @@
"npm:eslint-plugin-svelte@^3.11.0",
"npm:flowbite-svelte-icons@2.1",
"npm:flowbite-svelte@1.11",
"npm:flowbite-typography@^1.0.5",
"npm:flowbite@~2.5.2",
"npm:he@1.2",
"npm:highlight.js@^11.11.1",

13
package-lock.json generated

@ -45,6 +45,7 @@ @@ -45,6 +45,7 @@
"flowbite": "~2.5.2",
"flowbite-svelte": "1.11.x",
"flowbite-svelte-icons": "2.1.x",
"flowbite-typography": "^1.0.5",
"playwright": "^1.50.1",
"postcss": "^8.5.6",
"postcss-load-config": "6.x",
@ -4325,6 +4326,18 @@ @@ -4325,6 +4326,18 @@
"postcss": "^8.5.1"
}
},
"node_modules/flowbite-typography": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/flowbite-typography/-/flowbite-typography-1.0.5.tgz",
"integrity": "sha512-IqTwOYgGZkXTK/5ngx3A9oQwgOqnRyUKUfIiB+w6xDmiD8z3cKDIgYfFpHIMKbLVfg+QmJIPqEEPrGZbAwVT6g==",
"dev": true,
"license": "MIT",
"dependencies": {
"lodash.castarray": "^4.4.0",
"lodash.isplainobject": "^4.0.6",
"lodash.merge": "^4.6.2"
}
},
"node_modules/fraction.js": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",

1
package.json

@ -54,6 +54,7 @@ @@ -54,6 +54,7 @@
"flowbite": "~2.5.2",
"flowbite-svelte": "1.11.x",
"flowbite-svelte-icons": "2.1.x",
"flowbite-typography": "^1.0.5",
"playwright": "^1.50.1",
"postcss": "^8.5.6",
"postcss-load-config": "6.x",

45
src/app.css

@ -14,6 +14,8 @@ @@ -14,6 +14,8 @@
@layer theme, base, components, utilities;
@plugin "flowbite/plugin";
@plugin "flowbite-typography";
@custom-variant dark (&:where(.dark, .dark *));
@theme {
@ -455,6 +457,11 @@ @@ -455,6 +457,11 @@
}
@layer components {
nav a {
text-decoration-line: none !important;
}
canvas.qr-code {
@apply block mx-auto my-4;
}
@ -490,19 +497,36 @@ @@ -490,19 +497,36 @@
scroll-behavior: smooth;
/* common heading base styles */
h1,h2,h3,h4,h5,h6 { @apply text-gray-900 dark:text-gray-100 pt-4; }
h1, h2, h3, h4, h5, h6 {
@apply text-gray-900 dark:text-gray-100 pt-4;
}
/* sizes/weights per level */
h1 { @apply text-4xl font-bold; }
h2 { @apply text-3xl font-bold; }
h3 { @apply text-2xl font-bold; }
h4 { @apply text-xl font-bold; }
h5 { @apply text-lg font-semibold; }
h6 { @apply text-base font-semibold; }
h1 {
@apply text-4xl font-bold;
}
div {
@apply flex flex-col space-y-4;
h2 {
@apply text-3xl font-bold;
}
h3 {
@apply text-2xl font-bold;
}
h4 {
@apply text-xl font-bold;
}
h5 {
@apply text-lg font-semibold;
}
h6 {
@apply text-base font-semibold;
}
}
.olist {
@ -570,7 +594,6 @@ @@ -570,7 +594,6 @@
}
}
}
}
/* Footnotes */
.footnote-ref {
@ -597,6 +620,7 @@ @@ -597,6 +620,7 @@
overflow: hidden;
text-overflow: ellipsis;
}
.footnotes li {
margin-bottom: 0.5rem;
}
@ -726,3 +750,4 @@ @@ -726,3 +750,4 @@
vertical-align: text-bottom;
font-weight: 500;
}
}

1
src/lib/a/index.ts

@ -1,6 +1,5 @@ @@ -1,6 +1,5 @@
export { default as AInput } from './primitives/AInput.svelte';
export { default as ACard } from './primitives/ACard.svelte';
export { default as ASwitch } from './primitives/ASwitch.svelte';
export { default as ADetails } from './primitives/ADetails.svelte';
export { default as ANostrUser } from './primitives/ANostrUser.svelte';
export { default as ANostrBadge } from './primitives/ANostrBadge.svelte';

2
src/lib/a/nav/AFooter.svelte

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
import { Footer, FooterCopyright, FooterLink, FooterLinkGroup } from "flowbite-svelte";
</script>
<Footer class="mx-2">
<Footer class="m-2">
<FooterCopyright href="/events?id=npub1s3ht77dq4zqnya8vjun5jp3p44pr794ru36d0ltxu65chljw8xjqd975wz" by="GitCitadel" year={2025} />
<FooterLinkGroup class="mt-3 flex flex-wrap items-center text-sm text-gray-500 sm:mt-0 dark:text-gray-400">
<FooterLink href="/about">About</FooterLink>

85
src/lib/a/nav/ANavbar.svelte

@ -6,79 +6,52 @@ @@ -6,79 +6,52 @@
NavUl,
NavHamburger,
NavBrand,
Dropdown,
DropdownItem
MegaMenu
} from "flowbite-svelte";
import { siteNav } from "$lib/nav/site-nav.js";
import { logoutUser, userStore } from "$lib/stores/userStore";
import Profile from "$components/util/Profile.svelte";
import type { NavItem } from "$lib/a/nav/nav-types.ts";
import { goto } from "$app/navigation";
import { ChevronDownOutline } from "flowbite-svelte-icons";
import { AThemeToggleMini } from "$lib/a";
import { getNdkContext } from "$lib/ndk.ts";
const ndk = getNdkContext();
let {
currentPath = "",
}: {
currentPath?: string;
} = $props();
let menu2 = [
{ name: 'Publications', href: '/', help: 'Browse publications' },
{ name: 'Events', href: '/events', help: 'Search and engage with events' },
{ name: 'Visualize', href: '/visualize', help: 'Visualize connections between publications and authors' },
let userState = $derived($userStore);
{ name: 'Compose notes', href: '/new/compose', help: 'Create individual notes (30041 events)'},
{ name: 'Publish events', href: '/events/compose', help: 'Create any kind' },
function handleNavClick(item: NavItem) {
if (item.href) {
goto(item.href);
} else if (item.id === 'logout') {
logoutUser(ndk);
}
}
{ name: 'Getting Started', href: '/start', help: 'A quick overview and tutorial' },
{ name: 'Relay Status', href: '/about/relay-stats', help: 'Relay status and monitoring' },
{ name: 'About', href: '/about', help: 'About the project' },
{ name: 'Contact', href: '/contact', help: 'Contact us or submit a bug report' }
];
function flattenNavItems(navItems: NavItem[]): NavItem[] {
const result: NavItem[] = [];
for (const item of navItems) {
if (item.children && item.children.length > 0) {
result.push(...flattenNavItems(item.children));
} else {
result.push(item);
}
}
return result;
}
</script>
<Navbar class="fixed start-0 top-0 z-50 flex flex-row bg-primary-50 dark:bg-primary-800 !p-0" navContainerClass="w-full flex-row justify-between items-center !p-0">
<Navbar id="navi" class="fixed start-0 top-0 z-50 flex flex-row bg-primary-50 dark:bg-primary-800 !p-0" navContainerClass="flex-row items-center !p-0">
<NavBrand href="/">
<h1>Alexandria</h1>
<div class="flex flex-col">
<h1 class="text-2xl font-bold mb-0">Alexandria</h1>
<p class="text-xs font-semibold tracking-wide max-sm:max-w-[11rem] mb-0">READ THE ORIGINAL. MAKE CONNECTIONS. CULTIVATE KNOWLEDGE.</p>
</div>
</NavBrand>
<div class="flex md:order-2">
<Profile isNav={true} />
<Profile />
<NavHamburger />
</div>
<NavUl class="order-1" activeUrl={currentPath}>
{#each siteNav as navSection}
{#if navSection.children && navSection.children.length > 0}
<NavUl class="order-1 ml-auto">
<NavLi class="cursor-pointer">
{navSection.title}<ChevronDownOutline class="text-primary-800 ms-2 inline h-6 w-6 dark:text-white" />
</NavLi>
<Dropdown simple class="w-44 z-20">
{#each flattenNavItems(navSection.children) as item}
<DropdownItem
href={item.href || undefined}
onclick={() => handleNavClick(item)}
>
{item.title}
</DropdownItem>
{/each}
</Dropdown>
{:else if navSection.href}
<NavLi href={navSection.href}>{navSection.title}</NavLi>
{/if}
{/each}
<NavLi>
Explore<ChevronDownOutline class="text-primary-800 ms-2 inline h-6 w-6 dark:text-white" />
</NavLi>
<MegaMenu full items={menu2}>
{#snippet children({ item })}
<a href={item.href} class="block h-full rounded-lg p-3 hover:bg-gray-50 dark:hover:bg-gray-700">
<div class="font-semibold dark:text-white">{item.name}</div>
<span class="text-sm font-light text-gray-500 dark:text-gray-400">{item.help}</span>
</a>
{/snippet}
</MegaMenu>
<AThemeToggleMini />
</NavUl>
</Navbar>

41
src/lib/a/nav/AUserDropdown.svelte

@ -1,41 +0,0 @@ @@ -1,41 +0,0 @@
<script lang="ts">
import type { NavItem, UserInfo } from './nav-types';
import { onMount } from 'svelte';
let { user = null as UserInfo | null, items = [] as NavItem[], onselect = undefined as undefined | ((i:NavItem)=>void) } = $props();
let open = $state(false); let btn: HTMLButtonElement;
function onDoc(e: MouseEvent){ if (!open) return; if (!(e.target instanceof Node)) return; if (!btn?.parentElement?.contains(e.target)) open = false; }
onMount(()=>{ document.addEventListener('mousedown', onDoc); return () => document.removeEventListener('mousedown', onDoc); });
</script>
<div class="relative">
<button bind:this={btn} class="inline-flex items-center gap-2 h-9 px-2 rounded-md border border-muted/30 hover:bg-primary/10" aria-haspopup="menu" aria-expanded={open} onclick={() => (open = !open)}>
<img src={user?.avatarUrl || 'https://via.placeholder.com/24'} alt="" class="h-6 w-6 rounded-full object-cover" />
<span class="hidden sm:block text-sm">{user?.name || 'Account'}</span>
<svg class="h-4 w-4 opacity-70" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
</button>
{#if open}
<div class="absolute right-0 mt-1 min-w-[14rem] rounded-lg border border-muted/20 bg-surface shadow-lg py-1 z-50">
{#if user}
<div class="px-3 py-2 text-sm">
<div class="font-medium">{user.name}</div>
</div>
<div class="my-1 h-px bg-muted/20" ></div>
{/if}
<ul>
{#each items as it}
{#if it.divider}
<li class="my-1 h-px bg-muted/20"></li>
{:else}
<li>
<a href={it.href || '#'} target={it.external ? '_blank':undefined} rel={it.external ? 'noreferrer':undefined}
class="flex items-center gap-2 px-3 py-2 text-sm hover:bg-primary/10"
onclick={(e)=>{ if (!it.href || it.href==='#'){ e.preventDefault(); open=false; onselect?.(it); } else { open=false; } }}>
{it.title}
{#if it.badge}<span class="ml-auto text-[10px] rounded px-1.5 py-0.5 border border-primary/30 text-primary bg-primary/5">{it.badge}</span>{/if}
</a>
</li>
{/if}
{/each}
</ul>
</div>
{/if}
</div>

15
src/lib/a/nav/nav-types.ts

@ -1,15 +0,0 @@ @@ -1,15 +0,0 @@
export type NavItem = {
id?: string;
title: string;
href?: string;
icon?: any;
badge?: string;
children?: NavItem[];
divider?: boolean;
external?: boolean;
};
export type UserInfo = {
name: string;
avatarUrl?: string;
};

2
src/lib/a/primitives/APagination.svelte

@ -37,7 +37,7 @@ @@ -37,7 +37,7 @@
{#if totalPages > 1}
<div class={`mt-4 flex flex-row items-center justify-between p-3 bg-gray-50 dark:bg-gray-800 rounded-lg ${className}`}>
<div class="text-sm text-gray-600 dark:text-gray-400">
<div class="text-sm !mb-0 text-gray-600 dark:text-gray-400">
Page {currentPage} of {totalPages} ({totalItems} total {itemsLabel})
</div>
<div class="flex flex-row items-center gap-2">

10
src/lib/a/primitives/ASwitch.svelte

@ -1,10 +0,0 @@ @@ -1,10 +0,0 @@
<script lang="ts">
let { checked = false, class: className = '', onchange = undefined as undefined | ((v:boolean)=>void) } = $props();
function toggle(){ checked = !checked; onchange?.(checked); }
</script>
<button type="button" role="switch" aria-checked={checked}
onclick={toggle}
class={`inline-flex items-center h-6 w-11 rounded-full border border-muted/30 transition px-0.5 ${checked ? 'bg-primary' : 'bg-surface'} ${className}`}
>
<span class={`inline-block h-5 w-5 rounded-full bg-white shadow transform transition ${checked ? 'translate-x-5' : 'translate-x-0'}`} />
</button>

4
src/lib/a/reader/ATechToggle.svelte

@ -1,11 +1,11 @@ @@ -1,11 +1,11 @@
<script lang="ts">
import { showTech } from '$lib/stores/techStore.ts';
import ASwitch from '../primitives/ASwitch.svelte';
import { Toggle } from "flowbite-svelte";
let label = 'Show technical details';
$: checked = $showTech;
</script>
<div class="inline-flex items-center gap-2 select-none">
<ASwitch bind:checked={$showTech} aria-label={label} />
<Toggle {checked} ontoggle={() => $showTech = checked} aria-label={label} />
<span class="text-sm">{label}</span>
</div>

194
src/lib/components/util/Profile.svelte

@ -8,11 +8,8 @@ @@ -8,11 +8,8 @@
loginWithAmber,
loginWithNpub
} from "$lib/stores/userStore";
import {
ArrowRightToBracketOutline,
UserOutline,
} from "flowbite-svelte-icons";
import { Avatar, Popover } from "flowbite-svelte";
import { Avatar, Popover, Dropdown, DropdownGroup, DropdownItem, DropdownHeader } from "flowbite-svelte";
import { Globe, Loader, Book, Smartphone } from "@lucide/svelte";
import { get } from "svelte/store";
import { goto } from "$app/navigation";
import NDK, { NDKNip46Signer, NDKPrivateKeySigner } from "@nostr-dev-kit/ndk";
@ -22,8 +19,6 @@ @@ -22,8 +19,6 @@
const ndk = getNdkContext();
let { isNav = false } = $props<{ isNav?: boolean }>();
// UI state for login functionality
let isLoadingExtension: boolean = $state(false);
let isLoadingAmber: boolean = $state(false);
@ -31,7 +26,6 @@ @@ -31,7 +26,6 @@
let nostrConnectUri: string | undefined = $state(undefined);
let showQrCode: boolean = $state(false);
let qrCodeDataUrl: string | undefined = $state(undefined);
let loginButtonRef: HTMLElement | undefined = $state();
let resultTimeout: ReturnType<typeof setTimeout> | null = null;
let profileAvatarId = "profile-avatar-btn";
let showAmberFallback = $state(false);
@ -390,57 +384,44 @@ @@ -390,57 +384,44 @@
<div class="relative h-fit my-auto">
{#if !userState.signedIn}
<!-- Login button -->
<div class="group">
<button
bind:this={loginButtonRef}
id="login-avatar"
class="h-6 w-6 rounded-full bg-gray-300 flex items-center justify-center cursor-pointer hover:bg-gray-400 transition-colors"
>
<UserOutline class="h-4 w-4 text-gray-600" />
</button>
<Popover
placement="bottom"
triggeredBy="#login-avatar"
class="popover-leather w-[200px]"
trigger="click"
>
<div class="flex flex-col space-y-2">
<h3 class="text-lg font-bold mb-2">Login with...</h3>
<button
class="btn-leather text-nowrap flex self-stretch align-middle hover:text-primary-400 dark:hover:text-primary-500 disabled:opacity-50"
<Avatar size="xs" id="login-menu"/>
<Dropdown placement="bottom" triggeredBy="#login-menu" class="min-w-xs">
<DropdownGroup>
<DropdownHeader>Login with...</DropdownHeader>
<DropdownItem
class="w-full"
onclick={handleBrowserExtensionLogin}
disabled={isLoadingExtension || isLoadingAmber}
>
disabled={isLoadingExtension || isLoadingAmber}>
<span class="w-full flex items-center justify-start gap-3">
{#if isLoadingExtension}
🔄 Connecting...
<Loader size={16} class="inline" /> Connecting...
{:else}
🌐 Browser extension
<Globe size={16} class="inline" /> Browser extension
{/if}
</button>
<button
class="btn-leather text-nowrap flex self-stretch align-middle hover:text-primary-400 dark:hover:text-primary-500 disabled:opacity-50"
</span></DropdownItem>
<DropdownItem
class="w-full"
onclick={handleAmberLogin}
disabled={isLoadingAmber || isLoadingExtension}
>
<span class="w-full flex items-center justify-start gap-3">
{#if isLoadingAmber}
🔄 Connecting...
<Loader size={16} class="inline" /> Connecting...
{:else}
📱 Amber: NostrConnect
<Smartphone size={16} class="inline" /> Amber: NostrConnect
{/if}
</button>
<button
class="btn-leather text-nowrap flex self-stretch align-middle hover:text-primary-400 dark:hover:text-primary-500"
</span>
</DropdownItem>
<DropdownItem
class="w-full"
onclick={handleReadOnlyLogin}
>
📖 npub (read only)
</button>
<div class="border-t border-gray-200 pt-2 mt-2">
<div class="text-xs text-gray-500 mb-1">Network Status:</div>
<NetworkStatus />
</div>
</div>
</Popover>
<span class="w-full flex items-center justify-start gap-3">
<Book size={16} class="inline" /> npub (read only)
</span>
</DropdownItem>
{#if result}
<DropdownHeader>
<div
class="absolute right-0 top-10 z-50 bg-gray-100 p-3 rounded text-sm break-words whitespace-pre-line max-w-lg shadow-lg border border-gray-300"
>
@ -450,63 +431,63 @@ @@ -450,63 +431,63 @@
onclick={() => (result = null)}>✖</button
>
</div>
</DropdownHeader>
{/if}
</div>
</DropdownGroup>
<DropdownGroup>
<DropdownHeader>
<NetworkStatus />
</DropdownHeader>
</DropdownGroup>
</Dropdown>
{:else}
<!-- User profile -->
<div class="group">
<button
class="h-6 w-6 rounded-full p-0 border-0 bg-transparent cursor-pointer"
id={profileAvatarId}
type="button"
aria-label="Open profile menu"
>
{#if !pfp}
<div class="h-6 w-6 rounded-full bg-gray-300 animate-pulse cursor-pointer"></div>
{:else}
<Avatar
rounded
class="h-6 w-6 cursor-pointer"
src={pfp}
alt={username || "User"}
/>
{/if}
</button>
<Popover
placement="bottom"
triggeredBy={`#${profileAvatarId}`}
class="popover-leather w-[220px]"
trigger="click"
>
<div class="flex flex-row justify-between space-x-4">
<div class="flex flex-col">
aria-label="Open profile menu"
size="xs" id={profileAvatarId}/>
<Dropdown placement="bottom" triggeredBy="#{profileAvatarId}" class="min-w-xs">
<DropdownHeader>
{#if username}
<h3 class="text-lg font-bold">{username}</h3>
{#if isNav}<h4 class="text-base">@{tag}</h4>{/if}
<span class="block text-sm">{username}</span>
<span class="block truncate text-sm font-medium">@{tag}</span>
{:else if !pfp}
<h3 class="text-lg font-bold">Loading profile...</h3>
<span>Loading profile...</span>
{:else}
<h3 class="text-lg font-bold">Loading...</h3>
<span>Loading...</span>
{/if}
<ul class="space-y-2 mt-2">
<li>
</DropdownHeader>
<DropdownGroup>
<DropdownItem class="w-full">
<CopyToClipboard
displayText={shortenNpub(npub) || "Loading..."}
copyText={npub || ""}
/>
</li>
<li>
<button
class="hover:text-primary-400 dark:hover:text-primary-500 text-nowrap mt-3 m-0 text-left"
onclick={handleViewProfile}
</DropdownItem>
</DropdownGroup>
<DropdownGroup>
<DropdownItem
class="w-full items-start"
onclick={() => goto('/profile')}
>
<UserOutline
class="mr-1 !h-6 !w-6 inline !fill-none dark:!fill-none"
/><span class="underline">View notifications</span>
</button>
</li>
<li class="text-xs text-gray-500">
View profile
</DropdownItem>
<DropdownItem
class="w-full"
onclick={() => goto('/profile/my-notes')}
>
My notes
</DropdownItem>
<DropdownItem
class="w-full"
onclick={() => goto('/profile/notifications')}
>
Notifications
</DropdownItem>
</DropdownGroup>
<DropdownGroup>
<DropdownHeader class="text-xs">
{#if userState.loginMethod === "extension"}
Logged in with extension
{:else if userState.loginMethod === "amber"}
@ -516,36 +497,19 @@ @@ -516,36 +497,19 @@
{:else}
Unknown login method
{/if}
</li>
<li>
<NetworkStatus />
</li>
{#if isNav}
<li>
<button
</DropdownHeader>
<DropdownHeader><NetworkStatus /></DropdownHeader>
</DropdownGroup>
<DropdownGroup>
<DropdownItem
id="sign-out-button"
class="btn-leather text-nowrap mt-3 flex self-stretch align-middle hover:text-primary-400 dark:hover:text-primary-500"
class="w-full"
onclick={handleSignOutClick}
>
<ArrowRightToBracketOutline
class="mr-1 !h-6 !w-6 inline !fill-none dark:!fill-none"
/> Sign out
</button>
</li>
{:else}
<!-- li>
<button
class='btn-leather text-nowrap mt-3 flex self-stretch align-middle hover:text-primary-400 dark:hover:text-primary-500'
>
<FileSearchOutline class='mr-1 !h-6 inline !fill-none dark:!fill-none' /> More content
</button>
</li -->
{/if}
</ul>
</div>
</div>
</Popover>
</div>
Sign out
</DropdownItem>
</DropdownGroup>
</Dropdown>
{/if}
</div>

41
src/lib/nav/site-nav.ts

@ -1,41 +0,0 @@ @@ -1,41 +0,0 @@
import type { NavItem } from '$lib/a/nav/nav-types';
export const siteNav: NavItem[] = [
{
title: 'Create',
children: [
{ title: 'Compose notes', href: '/new/compose' },
{ title: 'Publish events', href: '/events/compose' },
]
},
{
title: 'Explore',
children: [
{ title: 'Publications', children: [
{ title: 'Publications', href: '/' },
{ title: 'My Notes', href: '/my-notes' },
{ title: 'Events', href: '/events' },
{ title: 'Visualize', href: '/visualize' }
]
}
]
},
{
title: 'About',
children: [
{ title: 'Onboarding', children: [{ title: 'Getting Started', href: '/start' }] },
{ title: 'Project', children: [
{ title: 'About', href: '/about' },
{ title: 'Contact', href: '/contact' },
{ title: 'Relay Status', href: '/about/relay-stats' }
] }
]
}
];
export const userMenu: NavItem[] = [
{ title: 'Profile', href: '/me' },
{ title: 'Settings', href: '/settings' },
{ divider: true, title: '' },
{ id: 'logout', title: 'Sign out' } // <-- no href => action item
];

2
src/routes/+layout.svelte

@ -183,7 +183,7 @@ @@ -183,7 +183,7 @@
</svelte:head>
<div class="min-h-screen flex flex-col">
<ANavbar {currentPath} />
<ANavbar />
<main class="flex-1 flex-col w-full mt-[75px] self-center">
{@render children()}

3
src/routes/profile/+page.svelte

@ -128,7 +128,8 @@ @@ -128,7 +128,8 @@
{/if}
</div>
<div class="flex flex-row justify-end gap-4 text-sm">
<Button size="xs" onclick={() => goto('/profile/notifications')}>Notifications</Button>
<Button class="!mb-0" size="xs" onclick={() => goto('/profile/notifications')}>Notifications</Button>
<Button class="!mb-0" size="xs" onclick={() => goto('/profile/my-notes')}>My notes</Button>
</div>
{#if loading}
<AAlert color="primary">Loading profile…</AAlert>

10
src/routes/my-notes/+page.svelte → src/routes/profile/my-notes/+page.svelte

@ -1,13 +1,13 @@ @@ -1,13 +1,13 @@
<script lang="ts">
import { goto } from "$app/navigation";
import { userStore } from "$lib/stores/userStore";
import { userStore } from "$lib/stores/userStore.ts";
import type { NDKEvent } from "@nostr-dev-kit/ndk";
import { get } from "svelte/store";
import { getMatchingTags } from "$lib/utils/nostrUtils";
import { getTitleTagForEvent } from "$lib/utils/event_input_utils";
import { getMatchingTags } from "$lib/utils/nostrUtils.ts";
import { getTitleTagForEvent } from "$lib/utils/event_input_utils.ts";
import asciidoctor from "asciidoctor";
import { postProcessAsciidoctorHtml } from "$lib/utils/markup/asciidoctorPostProcessor";
import { getNdkContext } from "$lib/ndk";
import { postProcessAsciidoctorHtml } from "$lib/utils/markup/asciidoctorPostProcessor.ts";
import { getNdkContext } from "$lib/ndk.ts";
const ndk = getNdkContext();
Loading…
Cancel
Save