Add header dropdown and replace icon library
This commit is contained in:
parent
64dbe4a91b
commit
7eb58bfa90
|
@ -20,6 +20,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sveltejs/vite-plugin-svelte": "^1.0.2",
|
"@sveltejs/vite-plugin-svelte": "^1.0.2",
|
||||||
"@tsconfig/svelte": "^3.0.0",
|
"@tsconfig/svelte": "^3.0.0",
|
||||||
|
"lucide-svelte": "^0.102.0",
|
||||||
"prettier": "^2.7.1",
|
"prettier": "^2.7.1",
|
||||||
"prettier-plugin-svelte": "^2.8.0",
|
"prettier-plugin-svelte": "^2.8.0",
|
||||||
"sass": "^1.55.0",
|
"sass": "^1.55.0",
|
||||||
|
@ -30,5 +31,6 @@
|
||||||
"tslib": "^2.4.0",
|
"tslib": "^2.4.0",
|
||||||
"typescript": "^4.6.4",
|
"typescript": "^4.6.4",
|
||||||
"vite": "^3.1.0"
|
"vite": "^3.1.0"
|
||||||
}
|
},
|
||||||
|
"dependencies": {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,10 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {Router, Route, navigate, link} from "svelte-navigator";
|
import {Router, Route, navigate, link} from "svelte-navigator";
|
||||||
import {getUser} from "./api/login";
|
import {getUser} from "./api/login";
|
||||||
import Dropdown from "./lib/Dropdown.svelte";
|
import HeaderDropdown from "./lib/HeaderDropdown.svelte";
|
||||||
import LazyComponent from "./lib/LazyComponent.svelte";
|
import LazyComponent from "./lib/LazyComponent.svelte";
|
||||||
import {loginStore, profileStore, type LoginStore, type ProfileData} from "./stores/login";
|
import {loginStore, profileStore, type LoginStore, type ProfileData} from "./stores/login";
|
||||||
|
|
||||||
function logoutAction() {
|
|
||||||
loginStore.set(null);
|
|
||||||
navigate("/");
|
|
||||||
}
|
|
||||||
|
|
||||||
let profile: ProfileData;
|
let profile: ProfileData;
|
||||||
|
|
||||||
loginStore.subscribe((value: LoginStore) => {
|
loginStore.subscribe((value: LoginStore) => {
|
||||||
|
@ -44,23 +39,7 @@
|
||||||
|
|
||||||
<nav>
|
<nav>
|
||||||
{#if profile !== undefined}
|
{#if profile !== undefined}
|
||||||
<Dropdown>
|
<HeaderDropdown {profile} />
|
||||||
<div slot="header" class="dropdown-header">
|
|
||||||
{#if profile.icon == "0"}
|
|
||||||
<img
|
|
||||||
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=="
|
|
||||||
alt="Profile Icon"
|
|
||||||
class="header-icon"
|
|
||||||
/>
|
|
||||||
{:else}
|
|
||||||
<img src={profile.icon} alt="Profile Icon" class="header-icon" />
|
|
||||||
{/if}
|
|
||||||
<span>{profile.display_name}</span>
|
|
||||||
</div>
|
|
||||||
<div slot="body" class="dropdown-body">
|
|
||||||
<a href="/logout" on:click|preventDefault={logoutAction}>Logout</a>
|
|
||||||
</div>
|
|
||||||
</Dropdown>
|
|
||||||
{:else}
|
{:else}
|
||||||
<a href="/register" use:link>Register</a>
|
<a href="/register" use:link>Register</a>
|
||||||
<a href="/login" use:link>Login</a>
|
<a href="/login" use:link>Login</a>
|
||||||
|
@ -115,23 +94,6 @@
|
||||||
background-color: var(--primary-main);
|
background-color: var(--primary-main);
|
||||||
border-radius: 0 0 var(--large-curve) var(--large-curve);
|
border-radius: 0 0 var(--large-curve) var(--large-curve);
|
||||||
|
|
||||||
> nav {
|
|
||||||
.dropdown-header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
> .header-icon {
|
|
||||||
> img {
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dropdown-body {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .central-header {
|
> .central-header {
|
||||||
padding: 0 32px;
|
padding: 0 32px;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
|
@ -144,6 +106,12 @@
|
||||||
max-width: min(100%, 1000px);
|
max-width: min(100%, 1000px);
|
||||||
margin: auto;
|
margin: auto;
|
||||||
|
|
||||||
|
> nav {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: #eeeeee;
|
color: #eeeeee;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
@import "./assets/material-symbols.scss";
|
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
|
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
/* fallback */
|
|
||||||
@font-face {
|
|
||||||
font-family: "Material Symbols Outlined";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: url(~/assets/material-symbols.woff2) format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin mso {
|
|
||||||
font-family: "Material Symbols Outlined";
|
|
||||||
font-weight: normal;
|
|
||||||
font-style: normal;
|
|
||||||
font-size: 24px;
|
|
||||||
line-height: 1;
|
|
||||||
letter-spacing: normal;
|
|
||||||
text-transform: none;
|
|
||||||
display: inline-block;
|
|
||||||
white-space: nowrap;
|
|
||||||
word-wrap: normal;
|
|
||||||
direction: ltr;
|
|
||||||
-moz-font-feature-settings: "liga";
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
|
Binary file not shown.
|
@ -1,60 +0,0 @@
|
||||||
<script lang="ts">
|
|
||||||
export let align = "left";
|
|
||||||
|
|
||||||
let open = false;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="dropdown align-{align}">
|
|
||||||
<div class="dropdown-header">
|
|
||||||
<div>
|
|
||||||
<slot name="header" />
|
|
||||||
</div>
|
|
||||||
<div class="flex-gap" />
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 32 32"
|
|
||||||
fill="currentColor"
|
|
||||||
preserveAspectRatio="xMidYMid meet"
|
|
||||||
width="16"
|
|
||||||
height="16"
|
|
||||||
role="img"
|
|
||||||
aria-label="Open menu"
|
|
||||||
style="--darkreader-inline-fill: currentColor;"
|
|
||||||
data-darkreader-inline-fill=""><path d="M16 22L6 12 7.4 10.6 16 19.2 24.6 10.6 26 12z" /></svg
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
{#if open}
|
|
||||||
<div class="dropdown-body">
|
|
||||||
<slot name="body" />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.dropdown {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
> .dropdown-header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .dropdown-body {
|
|
||||||
position: absolute;
|
|
||||||
top: 100%;
|
|
||||||
background: var(--bg-panel);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.align-left > .dropdown-body {
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.align-right > .dropdown-body {
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-gap {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -0,0 +1,134 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import {loginStore, type ProfileData} from "~/stores/login";
|
||||||
|
import {User, Settings, LogOut, ChevronUp, ChevronDown} from "lucide-svelte";
|
||||||
|
import {link, navigate} from "svelte-navigator";
|
||||||
|
|
||||||
|
export let profile: ProfileData;
|
||||||
|
|
||||||
|
let open = false;
|
||||||
|
|
||||||
|
function handleClick() {
|
||||||
|
open = !open;
|
||||||
|
}
|
||||||
|
|
||||||
|
function logoutAction() {
|
||||||
|
loginStore.set(null);
|
||||||
|
navigate("/");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="dropdown {open ? 'dropdown-open' : ''}">
|
||||||
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
|
<div class="dropdown-header" on:click={handleClick}>
|
||||||
|
<div class="dropdown-title">
|
||||||
|
{#if profile.icon == "0"}
|
||||||
|
<img
|
||||||
|
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=="
|
||||||
|
alt="Profile Icon"
|
||||||
|
class="header-icon"
|
||||||
|
/>
|
||||||
|
{:else}
|
||||||
|
<img src={profile.icon} alt="Profile Icon" class="header-icon" />
|
||||||
|
{/if}
|
||||||
|
<span>{profile.display_name}</span>
|
||||||
|
</div>
|
||||||
|
{#if open}
|
||||||
|
<ChevronUp />
|
||||||
|
{:else}
|
||||||
|
<ChevronDown />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{#if open}
|
||||||
|
<div class="dropdown-floating">
|
||||||
|
<div class="dropdown-body">
|
||||||
|
<a href="/profile" use:link>
|
||||||
|
<User />
|
||||||
|
<span>Profile</span>
|
||||||
|
</a>
|
||||||
|
<a href="/settings" use:link>
|
||||||
|
<Settings />
|
||||||
|
<span>Settings</span>
|
||||||
|
</a>
|
||||||
|
<a href="/logout" on:click|preventDefault={logoutAction}>
|
||||||
|
<LogOut />
|
||||||
|
<span>Logout</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.dropdown {
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
z-index: 9999;
|
||||||
|
|
||||||
|
&.dropdown-open {
|
||||||
|
background-color: var(--bg-panel-action);
|
||||||
|
}
|
||||||
|
|
||||||
|
> .dropdown-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0 16px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--bg-panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
> .dropdown-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-right: 4px;
|
||||||
|
|
||||||
|
> .header-icon {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .dropdown-floating {
|
||||||
|
z-index: 9998;
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
right: 0;
|
||||||
|
background: var(--bg-panel-action);
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 0 0 8px 8px;
|
||||||
|
|
||||||
|
-webkit-box-shadow: 0px 0px 10px 2px rgba(0, 0, 0, 0.5);
|
||||||
|
-moz-box-shadow: 0px 0px 10px 2px rgba(0, 0, 0, 0.5);
|
||||||
|
box-shadow: 0px 0px 10px 2px rgba(0, 0, 0, 0.5);
|
||||||
|
clip-path: inset(0px -10px -10px -10px);
|
||||||
|
|
||||||
|
> .dropdown-body {
|
||||||
|
border-radius: 0 0 8px 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
> a {
|
||||||
|
display: flex;
|
||||||
|
padding: 8px 16px 8px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--bg-panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
> span {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -34,7 +34,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(async function () {
|
onMount(async function () {
|
||||||
updatePage(postLogin({}, ""));
|
updatePage(postLogin({}));
|
||||||
});
|
});
|
||||||
|
|
||||||
let loading = false;
|
let loading = false;
|
||||||
|
|
|
@ -442,6 +442,11 @@ lower-case@^2.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib "^2.0.3"
|
tslib "^2.0.3"
|
||||||
|
|
||||||
|
lucide-svelte@^0.102.0:
|
||||||
|
version "0.102.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/lucide-svelte/-/lucide-svelte-0.102.0.tgz#4a8bca665e6f01d21d60bb057996c35a6e878eb5"
|
||||||
|
integrity sha512-r8Nmz3XnRiesT3BxTaQvJnkbvutJMDv7HHADfDVZ1VLo3tWInfSBzWQya1V12dFfdBoz/bMwBX0abpccw77v4A==
|
||||||
|
|
||||||
magic-string@^0.25.7:
|
magic-string@^0.25.7:
|
||||||
version "0.25.9"
|
version "0.25.9"
|
||||||
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c"
|
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c"
|
||||||
|
|
Reference in New Issue