This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / web / src / lib / components / shell / Topbar.svelte
5.1 kB 152 lines
1<script lang="ts"> 2 import { resolve } from "$app/paths"; 3 import Button from "../ui/Button.svelte"; 4 import Dropdown from "../ui/Dropdown.svelte"; 5 import DropdownItem from "../ui/DropdownItem.svelte"; 6 import ArrowRight from "$icon/arrow-right"; 7 import Bell from "$icon/bell"; 8 import BookMarked from "$icon/book-marked"; 9 import BookPlus from "$icon/book-plus"; 10 import Cog from "$icon/cog"; 11 import LineSquiggle from "$icon/line-squiggle"; 12 import LogOut from "$icon/log-out"; 13 import Plus from "$icon/plus"; 14 import Search from "$icon/search"; 15 import UserIcon from "$icon/user"; 16 import Spinner from "../ui/Spinner.svelte"; 17 import Logo from "../ui/Logo.svelte"; 18 import User from "../ui/User.svelte"; 19 import TopbarSearch from "./TopbarSearch.svelte"; 20 import type { CurrentUser } from "$lib/auth.svelte"; 21 22 interface Props { 23 variant: "marketing" | "app"; 24 onSignOut?: () => void | Promise<void>; 25 user: CurrentUser | null; 26 loading?: boolean; 27 } 28 29 let { variant, onSignOut, user, loading = false }: Props = $props(); 30 31 const appPath = (path: string) => resolve(path as "/"); 32</script> 33 34{#snippet divider(classes = "")} 35 <div 36 class={["hidden h-6 w-px self-center rounded-md bg-background-inset md:block", classes]} 37 ></div> 38{/snippet} 39 40<nav 41 class={`h-11 w-full px-5 42 ${variant === "marketing" ? "" : "border-b border-border-default bg-background-default shadow-[0_1px_1px_0_rgba(0,0,0,0.05)]"} 43 `} 44 aria-label="main" 45> 46 <div class="flex h-full items-center justify-between gap-4"> 47 <div class="flex shrink-0 items-center gap-2"> 48 <a 49 href={resolve("/")} 50 class="flex shrink-0 items-center gap-2 no-underline hover:no-underline" 51 > 52 <span class="hidden sm:inline-flex"> 53 <Logo wordmark alpha class="h-6.5" /> 54 </span> 55 <span class="inline-flex sm:hidden"> 56 <img src="/logos/dolly.svg" alt="tangled" class="size-8" /> 57 </span> 58 </a> 59 </div> 60 61 <div class={variant === "marketing" ? "flex items-center gap-3.5" : "flex items-center gap-4"}> 62 {#if variant === "marketing"} 63 <TopbarSearch /> 64 65 {@render divider()} 66 67 <Button variant="ghost" href={resolve("/login")}>Login</Button> 68 69 <span class="text-sm text-foreground-muted">or</span> 70 71 <Button variant="primary" href={resolve("/signup")} insetShadow={true}> 72 <span>Join now</span> 73 <ArrowRight class="size-3" aria-hidden="true" /> 74 </Button> 75 {:else} 76 {#if user || loading} 77 <div class="order-3 flex items-center md:order-1"> 78 <TopbarSearch /> 79 </div> 80 81 <div class="order-1 flex items-center md:order-3"> 82 <Dropdown id="new-menu" group="topbar" variant="button" align="right"> 83 {#snippet trigger()} 84 <Plus class="size-3.5" aria-hidden="true" /> 85 <span class="hidden md:inline">New</span> 86 {/snippet} 87 <DropdownItem href="/repo/new" icon={BookPlus}>New repository</DropdownItem> 88 <DropdownItem href="/strings/new" icon={LineSquiggle}>New string</DropdownItem> 89 </Dropdown> 90 </div> 91 92 <div class="order-2 flex items-center md:order-4"> 93 <a 94 href={appPath("/notifications")} 95 class="flex items-center text-foreground-default transition-colors hover:text-foreground-muted" 96 aria-label="Notifications" 97 > 98 <Bell class="size-4" aria-hidden="true" /> 99 </a> 100 </div> 101 102 <div class="order-3 md:hidden"> 103 <a href={appPath("/search")} class="text-foreground-subtle" aria-label="Search"> 104 <Search class="size-5" aria-hidden="true" /> 105 </a> 106 </div> 107 108 {@render divider("md:order-2")} 109 {/if} 110 111 <div class="order-4 flex items-center md:order-5"> 112 {#if loading} 113 <div class="flex items-center gap-1" role="status" aria-label="Signing in"> 114 <span 115 class="flex size-8 items-center justify-center rounded-full border border-border-default bg-background-inset text-foreground-placeholder md:size-5" 116 > 117 <Spinner class="size-4" /> 118 </span> 119 <span 120 class="hidden h-4 w-24 rounded-sm bg-background-inset md:block" 121 aria-hidden="true" 122 ></span> 123 </div> 124 {:else if user} 125 <Dropdown id="profile-menu" group="topbar" align="right"> 126 {#snippet trigger()} 127 <User 128 did={user.did} 129 handle={user.handle} 130 /> 131 {/snippet} 132 <DropdownItem href={`/${user.handle}`} icon={UserIcon}>Profile</DropdownItem> 133 <DropdownItem href={`/${user.handle}?tab=repos`} icon={BookMarked}> 134 Repositories 135 </DropdownItem> 136 <DropdownItem href={`/${user.handle}?tab=strings`} icon={LineSquiggle}> 137 Strings 138 </DropdownItem> 139 <DropdownItem href="/settings" icon={Cog}>Settings</DropdownItem> 140 <DropdownItem danger icon={LogOut} onclick={onSignOut}>Logout</DropdownItem> 141 </Dropdown> 142 {:else} 143 <div class="flex items-center gap-2" aria-hidden="true"> 144 <span class="size-8 rounded-full bg-background-inset md:size-5"></span> 145 <span class="hidden h-4 w-24 rounded-sm bg-background-inset md:block"></span> 146 </div> 147 {/if} 148 </div> 149 {/if} 150 </div> 151 </div> 152</nav>