finish early dashboard prototype
This commit is contained in:
parent
14535219d9
commit
7d15d70432
13 changed files with 311 additions and 73 deletions
|
|
@ -60,3 +60,12 @@ hr {
|
||||||
border: none;
|
border: none;
|
||||||
border-bottom: 1px solid var(--bg-2);
|
border-bottom: 1px solid var(--bg-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--on-primary);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
|
||||||
74
src/web/frontend/src/components/ui/AccountAddButton.svelte
Normal file
74
src/web/frontend/src/components/ui/AccountAddButton.svelte
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Plus } from '@lucide/svelte';
|
||||||
|
|
||||||
|
let { onclick, onkeydown } = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="add-account" onclick={onclick} onkeydown={onkeydown} role="button" tabindex="0">
|
||||||
|
<div class="icon-container"><Plus /></div>
|
||||||
|
<hr>
|
||||||
|
<div class="info-container"><h2>Add Account</h2></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.add-account {
|
||||||
|
width: 480px;
|
||||||
|
height: var(--sp-xxxl);
|
||||||
|
padding: .5em;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
background-color: color-mix(in srgb, var(--on-primary), var(--bg-1) 33%);
|
||||||
|
border: 1px solid var(--on-primary);
|
||||||
|
border-radius: var(--radius-0);
|
||||||
|
|
||||||
|
box-shadow: 0 var(--sp-ssm) var(--sp-sm) #0001;
|
||||||
|
|
||||||
|
transition: background-color .1s, border-color .1s;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-account:hover {
|
||||||
|
background-color: color-mix(in srgb, var(--on-primary), var(--bg-1) 20%);
|
||||||
|
border-color: var(--on-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-account:active:not(:has(.email:active)) {
|
||||||
|
background-color: var(--on-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-container {
|
||||||
|
width: var(--sp-xxxl);
|
||||||
|
min-width: var(--sp-xxxl);
|
||||||
|
height: var(--sp-xxxl);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-container :global(svg) {
|
||||||
|
--size: 60%;
|
||||||
|
width: var(--size);
|
||||||
|
height: var(--size);
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-account hr {
|
||||||
|
margin: 0 .5em;
|
||||||
|
border: none;
|
||||||
|
border-left: 1px solid var(--on-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-container {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-container h2 {
|
||||||
|
margin-left: .2em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,25 +1,37 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Account } from '@jupiter/lib/account';
|
import { type Account } from '@jupiter/lib/account';
|
||||||
import { User } from '@lucide/svelte';
|
import { pushToast, ToastType } from '@jupiter/lib/toasts';
|
||||||
|
import { Copy, User } from '@lucide/svelte';
|
||||||
|
|
||||||
let {
|
let {
|
||||||
account,
|
account,
|
||||||
} = $props<{
|
} = $props<{
|
||||||
account: Account,
|
account: Account,
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
async function copyEmail() {
|
||||||
|
await navigator.clipboard.write([new ClipboardItem({
|
||||||
|
"text/plain": `${account.username}@${account.domain}`,
|
||||||
|
})]);
|
||||||
|
|
||||||
|
pushToast("Email copied to clipboard.", ToastType.SUCCESS);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="account">
|
<div class="account" role="button">
|
||||||
<div class="icon-container"><User /></div>
|
<div class="icon-container"><User /></div>
|
||||||
<hr>
|
<hr>
|
||||||
<div class="info-container">
|
<div class="info-container">
|
||||||
<h2 class="name">{account.username}</h2>
|
<h2 class="name">{account.username}</h2>
|
||||||
<p class="email">{account.username}@{account.domain}</p>
|
<button class="email" onclick={() => {copyEmail()}}>
|
||||||
|
{account.username}@{account.domain}<Copy />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.account {
|
.account {
|
||||||
|
width: 480px;
|
||||||
height: var(--sp-xxxl);
|
height: var(--sp-xxxl);
|
||||||
padding: .5em;
|
padding: .5em;
|
||||||
|
|
||||||
|
|
@ -30,6 +42,8 @@
|
||||||
border: 1px solid var(--bg-2);
|
border: 1px solid var(--bg-2);
|
||||||
border-radius: var(--radius-0);
|
border-radius: var(--radius-0);
|
||||||
|
|
||||||
|
box-shadow: 0 var(--sp-ssm) var(--sp-sm) #0001;
|
||||||
|
|
||||||
transition: background-color .1s, border-color .1s;
|
transition: background-color .1s, border-color .1s;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
|
@ -97,6 +111,10 @@
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
line-height: 1.6em;
|
line-height: 1.6em;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
color: var(--on-bg-3);
|
color: var(--on-bg-3);
|
||||||
background-color: var(--bg-1);
|
background-color: var(--bg-1);
|
||||||
border: 1px solid var(--bg-2);
|
border: 1px solid var(--bg-2);
|
||||||
|
|
@ -114,4 +132,9 @@
|
||||||
.email:active {
|
.email:active {
|
||||||
background-color: var(--bg-3);
|
background-color: var(--bg-3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.info-container .email :global(svg) {
|
||||||
|
height: 1em;
|
||||||
|
margin-left: var(--sp-sm);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
19
src/web/frontend/src/components/ui/Card.svelte
Normal file
19
src/web/frontend/src/components/ui/Card.svelte
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
<div class="card"><slot></slot></div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.card {
|
||||||
|
width: 480px;
|
||||||
|
min-height: var(--sp-xxxl);
|
||||||
|
padding: 1em;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
background-color: var(--bg-0);
|
||||||
|
border: 1px solid var(--bg-2);
|
||||||
|
border-radius: var(--radius-0);
|
||||||
|
box-shadow: 0 var(--sp-ssm) var(--sp-sm) #0001;
|
||||||
|
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
45
src/web/frontend/src/components/ui/SidebarLink.svelte
Normal file
45
src/web/frontend/src/components/ui/SidebarLink.svelte
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
<script lang="ts">
|
||||||
|
let {
|
||||||
|
children,
|
||||||
|
href,
|
||||||
|
} = $props<{
|
||||||
|
children: () => any,
|
||||||
|
href: string
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<a href="{href}">{@render children()}</a>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
a {
|
||||||
|
margin-left: var(--sp-sm);
|
||||||
|
padding: .5em;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: start;
|
||||||
|
align-items: center;
|
||||||
|
gap: .5em;
|
||||||
|
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
color: var(--on-bg-2);
|
||||||
|
background-color: var(--bg-0);
|
||||||
|
text-decoration: none;
|
||||||
|
border: 1px solid var(--bg-2);
|
||||||
|
border-radius: var(--radius-0);
|
||||||
|
|
||||||
|
box-shadow: calc(0px - var(--sp-sm)) 0 0 var(--on-primary);
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
background-color: var(--bg-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
a:active {
|
||||||
|
background-color: var(--bg-2);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
37
src/web/frontend/src/components/ui/Skeleton.svelte
Normal file
37
src/web/frontend/src/components/ui/Skeleton.svelte
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
<div class="skeleton"><slot></slot></div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--width: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skeleton {
|
||||||
|
border: 1px solid var(--bg-2);
|
||||||
|
border-radius: var(--sp-sm);
|
||||||
|
|
||||||
|
background-image: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
var(--bg-1),
|
||||||
|
var(--bg-0),
|
||||||
|
var(--bg-1)
|
||||||
|
);
|
||||||
|
background-size: var(--width) 100%;
|
||||||
|
background-repeat: repeat;
|
||||||
|
|
||||||
|
animation: skeleton 1s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes throb {
|
||||||
|
from { opacity: 1 }
|
||||||
|
to { opacity: .25 }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes skeleton {
|
||||||
|
from {
|
||||||
|
background-position: 0 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
background-position: var(--width) 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { X } from '@lucide/svelte';
|
import { X } from '@lucide/svelte';
|
||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
import { fade, fly } from "svelte/transition";
|
import { fly } from "svelte/transition";
|
||||||
import { ToastTypeToString } from '@jupiter/lib/toasts';
|
import { ToastTypeToString } from '@jupiter/lib/toasts';
|
||||||
|
|
||||||
let {
|
let {
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class={["notification", ToastTypeToString(type)]} in:fly={{ x: 100 }} out:fade>
|
<div class={["notification", ToastTypeToString(type)]} in:fly={{ x: 100 }}>
|
||||||
<span class="content">{text}</span>
|
<span class="content">{text}</span>
|
||||||
{#if sticky}
|
{#if sticky}
|
||||||
<div class="close"><X onclick={() => {dispatch("dismiss")}} /></div>
|
<div class="close"><X onclick={() => {dispatch("dismiss")}} /></div>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,9 @@
|
||||||
export interface Account {
|
import { writable } from "svelte/store";
|
||||||
|
|
||||||
|
export default interface Account {
|
||||||
username: string,
|
username: string,
|
||||||
domain: string,
|
domain: string,
|
||||||
mail_directory: string,
|
mail_directory: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export let accounts = writable<Account[] | null>(null);
|
||||||
|
|
|
||||||
|
|
@ -19,25 +19,21 @@ export const DEFAULT_NOTIFICATION_TIMEOUT = 5000;
|
||||||
|
|
||||||
export const toasts = writable<Toast[]>([]);
|
export const toasts = writable<Toast[]>([]);
|
||||||
|
|
||||||
export function pushToast(toast: Record<string, any>) {
|
export function pushToast(
|
||||||
|
text: string,
|
||||||
|
type: ToastType,
|
||||||
|
sticky: boolean = false,
|
||||||
|
timeout: number = DEFAULT_NOTIFICATION_TIMEOUT,
|
||||||
|
) {
|
||||||
const id = Math.floor(Math.random() * 1_000_000);
|
const id = Math.floor(Math.random() * 1_000_000);
|
||||||
const defaults: Toast = {
|
let toast: Toast = { id, text, type, sticky, timeout };
|
||||||
id,
|
|
||||||
text: "",
|
|
||||||
type: ToastType.INFO,
|
|
||||||
sticky: false,
|
|
||||||
timeout: DEFAULT_NOTIFICATION_TIMEOUT,
|
|
||||||
};
|
|
||||||
|
|
||||||
toast = { ...defaults, ...toast };
|
toasts.update((toasts) => [...toasts, toast]);
|
||||||
console.log(`adding toast ${toast.id} (timeout ${toast.timeout})...`);
|
|
||||||
toasts.update((toasts) => [...toasts, { ...defaults, ...toast }]);
|
|
||||||
|
|
||||||
if (!toast.sticky) setTimeout(() => { dismissToast(id) }, toast.timeout);
|
if (!toast.sticky) setTimeout(() => { dismissToast(id) }, toast.timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function dismissToast(id: number) {
|
export function dismissToast(id: number) {
|
||||||
console.log(`dismissing toast ${id}...`);
|
|
||||||
toasts.update((toasts) => toasts.filter((toast) => toast.id !== id));
|
toasts.update((toasts) => toasts.filter((toast) => toast.id !== id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
import { LayoutDashboard, Mail, Settings, User } from '@lucide/svelte';
|
import { LayoutDashboard, Mail, Settings, User } from '@lucide/svelte';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import ToastOverlay from '@jupiter/components/ui/ToastOverlay.svelte';
|
import ToastOverlay from '@jupiter/components/ui/ToastOverlay.svelte';
|
||||||
|
import SidebarLink from '@jupiter/components/ui/SidebarLink.svelte';
|
||||||
|
|
||||||
let { children } = $props();
|
let { children } = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -15,9 +16,9 @@
|
||||||
<div class="app">
|
<div class="app">
|
||||||
<header class="sidebar">
|
<header class="sidebar">
|
||||||
<h1><Mail /> Jupiter Mail</h1>
|
<h1><Mail /> Jupiter Mail</h1>
|
||||||
<a href="/"><LayoutDashboard /> Dashboard</a>
|
<SidebarLink href="/"><LayoutDashboard /> Dashboard</SidebarLink>
|
||||||
<a href="/accounts"><User /> Accounts</a>
|
<SidebarLink href="/accounts"><User /> Accounts</SidebarLink>
|
||||||
<a href="/settings"><Settings /> Settings</a>
|
<SidebarLink href="/settings"><Settings /> Settings</SidebarLink>
|
||||||
</header>
|
</header>
|
||||||
<main>
|
<main>
|
||||||
{@render children()}
|
{@render children()}
|
||||||
|
|
@ -60,36 +61,4 @@
|
||||||
|
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar a {
|
|
||||||
margin-left: var(--sp-sm);
|
|
||||||
padding: .5em;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: start;
|
|
||||||
align-items: center;
|
|
||||||
gap: .5em;
|
|
||||||
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
overflow: hidden;
|
|
||||||
white-space: nowrap;
|
|
||||||
|
|
||||||
color: var(--on-primary);
|
|
||||||
background-color: var(--bg-0);
|
|
||||||
text-decoration: none;
|
|
||||||
border: 1px solid var(--bg-2);
|
|
||||||
border-radius: var(--radius-0);
|
|
||||||
|
|
||||||
box-shadow: calc(0px - var(--sp-sm)) 0 0 var(--on-primary);
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar a:hover {
|
|
||||||
background-color: var(--bg-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar a:active {
|
|
||||||
background-color: var(--bg-2);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,16 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { LayoutDashboard } from '@lucide/svelte';
|
import { onMount } from 'svelte';
|
||||||
|
import { LayoutDashboard, User } from '@lucide/svelte';
|
||||||
|
import Card from '@jupiter/components/ui/Card.svelte';
|
||||||
import Header from '@jupiter/components/ui/Header.svelte';
|
import Header from '@jupiter/components/ui/Header.svelte';
|
||||||
|
import * as api from '@jupiter/lib/api';
|
||||||
|
import { type Account, accounts } from '@jupiter/lib/account';
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
if ($accounts == null) api.fetchAccounts().then(accs => {
|
||||||
|
accounts.update(() => accs);
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="page-container">
|
<div class="page-container">
|
||||||
|
|
@ -8,6 +18,13 @@
|
||||||
<LayoutDashboard />
|
<LayoutDashboard />
|
||||||
<h1>Dashboard</h1>
|
<h1>Dashboard</h1>
|
||||||
</Header>
|
</Header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<Card>
|
||||||
|
<h2><a href="/accounts">Accounts</a></h2>
|
||||||
|
<p class="active-accounts">Active: {$accounts.length}</p>
|
||||||
|
</Card>
|
||||||
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
@ -16,4 +33,26 @@
|
||||||
|
|
||||||
background-color: var(--bg-0);
|
background-color: var(--bg-0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
margin: 0;
|
||||||
|
padding: 2em;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.active-accounts {
|
||||||
|
margin-top: .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 a {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,23 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { User } from '@lucide/svelte';
|
import { User } from '@lucide/svelte';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
import * as api from '@jupiter/lib/api';
|
||||||
|
import { type Account, accounts } from '@jupiter/lib/account';
|
||||||
|
import { pushToast, ToastType } from '@jupiter/lib/toasts';
|
||||||
import Header from '@jupiter/components/ui/Header.svelte';
|
import Header from '@jupiter/components/ui/Header.svelte';
|
||||||
import AccountListItem from '@jupiter/components/ui/AccountListItem.svelte';
|
import AccountListItem from '@jupiter/components/ui/AccountListItem.svelte';
|
||||||
import { type Account } from '@jupiter/lib/account';
|
import AccountAddButton from '@jupiter/components/ui/AccountAddButton.svelte';
|
||||||
import * as api from '@jupiter/lib/api';
|
import Skeleton from '@jupiter/components/ui/Skeleton.svelte';
|
||||||
import { pushToast, ToastType } from '@jupiter/lib/toasts';
|
|
||||||
|
|
||||||
let accounts: Account[] = $state([]);
|
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
pushToast({ text: "Fetching accounts...", type: ToastType.INFO });
|
if ($accounts == null) api.fetchAccounts().then(accs => {
|
||||||
accounts = await api.fetchAccounts();
|
accounts.update(() => accs);
|
||||||
pushToast({ text: "Accounts loaded successfully.", type: ToastType.SUCCESS });
|
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function addAccount() {
|
||||||
|
alert("TODO: this");
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="page-container">
|
<div class="page-container">
|
||||||
|
|
@ -26,9 +30,21 @@
|
||||||
<p>Click an account below to configure:</p>
|
<p>Click an account below to configure:</p>
|
||||||
<hr>
|
<hr>
|
||||||
<div class="account-list">
|
<div class="account-list">
|
||||||
{#each accounts as account}
|
{#if $accounts}
|
||||||
|
{#each $accounts as account}
|
||||||
<AccountListItem account={account} />
|
<AccountListItem account={account} />
|
||||||
{/each}
|
{/each}
|
||||||
|
<AccountAddButton
|
||||||
|
onclick={() => { addAccount() }}
|
||||||
|
onkeydown={(event: KeyboardEvent) => {
|
||||||
|
if (event.key === "Enter") addAccount()
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{:else}
|
||||||
|
{#each {length: 4} as i}
|
||||||
|
<Skeleton><div class="account-skeleton"></div></Skeleton>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -48,8 +64,15 @@
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
||||||
display: grid;
|
display: flex;
|
||||||
grid-template-columns: 1fr 1fr;
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
gap: 1em;
|
gap: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.account-skeleton {
|
||||||
|
width: 480px;
|
||||||
|
height: var(--sp-xxxl);
|
||||||
|
padding: .5em;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"moduleResolution": "nodenext"
|
"moduleResolution": "bundler"
|
||||||
}
|
}
|
||||||
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
|
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
|
||||||
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
|
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue