feat: 1-to-1 message render + web data-lake backend
This commit is contained in:
@@ -1,9 +1,47 @@
|
||||
<script lang="ts">
|
||||
import "./layout.css";
|
||||
import favicon from "$lib/assets/favicon.svg";
|
||||
import "$lib/styles/reboot.css";
|
||||
import "$lib/styles/icons.css";
|
||||
import "$lib/styles/global.scss";
|
||||
import { goto } from "$app/navigation";
|
||||
import { page } from "$app/state";
|
||||
import ToastHost from "$lib/components/ui/ToastHost.svelte";
|
||||
import { auth } from "$lib/stores/auth.svelte";
|
||||
import { theme } from "$lib/stores/theme.svelte";
|
||||
|
||||
let { children } = $props();
|
||||
|
||||
let previousTheme: string | null = null;
|
||||
let themeTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
|
||||
$effect(() => theme.watchSystem());
|
||||
|
||||
$effect(() => {
|
||||
const next = theme.resolved;
|
||||
const root = document.documentElement;
|
||||
if (previousTheme !== null && previousTheme !== next) {
|
||||
root.classList.add("theme-transition");
|
||||
if (themeTimer) {
|
||||
clearTimeout(themeTimer);
|
||||
}
|
||||
themeTimer = setTimeout(
|
||||
() => root.classList.remove("theme-transition"),
|
||||
300
|
||||
);
|
||||
}
|
||||
previousTheme = next;
|
||||
root.classList.toggle("theme-dark", next === "dark");
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
const onLogin = page.url.pathname === "/login";
|
||||
if (!(auth.isAuthenticated || onLogin)) {
|
||||
goto("/login");
|
||||
} else if (auth.isAuthenticated && onLogin) {
|
||||
goto("/app");
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:head><link rel="icon" href={favicon}></svelte:head>
|
||||
{@render children()}
|
||||
<ToastHost />
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
export const ssr = false;
|
||||
export const prerender = false;
|
||||
@@ -1,5 +1,8 @@
|
||||
<h1>Welcome to SvelteKit</h1>
|
||||
<p>
|
||||
Visit <a href="https://svelte.dev/docs/kit">svelte.dev/docs/kit</a> to read
|
||||
the documentation
|
||||
</p>
|
||||
<script lang="ts">
|
||||
import { goto } from "$app/navigation";
|
||||
import { auth } from "$lib/stores/auth.svelte";
|
||||
|
||||
$effect(() => {
|
||||
goto(auth.isAuthenticated ? "/app" : "/login", { replaceState: true });
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
<script lang="ts">
|
||||
import AccountSwitcher from "$lib/components/AccountSwitcher.svelte";
|
||||
import ChatList from "$lib/components/ChatList.svelte";
|
||||
import FolderTabs from "$lib/components/FolderTabs.svelte";
|
||||
import Button from "$lib/components/ui/Button.svelte";
|
||||
import Icon from "$lib/components/ui/Icon.svelte";
|
||||
import { accounts } from "$lib/stores/accounts.svelte";
|
||||
import { theme } from "$lib/stores/theme.svelte";
|
||||
import { toasts } from "$lib/stores/toasts.svelte";
|
||||
|
||||
let { children } = $props();
|
||||
|
||||
$effect(() => {
|
||||
if (!accounts.loaded) {
|
||||
accounts.load().catch(() => toasts.error("Failed to load accounts"));
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div id="Main">
|
||||
<div id="LeftColumn">
|
||||
<header class="left-header">
|
||||
<AccountSwitcher />
|
||||
<Button
|
||||
variant="translucent"
|
||||
round
|
||||
smaller
|
||||
onclick={() => theme.toggle()}
|
||||
aria-label="Toggle theme"
|
||||
>
|
||||
<Icon name={theme.resolved === "dark" ? "sun" : "moon"} />
|
||||
</Button>
|
||||
</header>
|
||||
<div class="folder-tabs">
|
||||
<FolderTabs />
|
||||
</div>
|
||||
<ChatList />
|
||||
</div>
|
||||
<div id="MiddleColumn">
|
||||
{@render children()}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
#Main {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(16rem, 26.5rem) 1fr;
|
||||
grid-template-rows: 100%;
|
||||
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#LeftColumn {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
border-right: 1px solid var(--color-borders);
|
||||
|
||||
background-color: var(--color-background);
|
||||
}
|
||||
|
||||
.left-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
|
||||
height: var(--header-height);
|
||||
padding: 0 0.625rem;
|
||||
border-bottom: 1px solid var(--color-borders);
|
||||
}
|
||||
|
||||
.folder-tabs {
|
||||
flex-shrink: 0;
|
||||
padding: 0.25rem 0.5rem 0;
|
||||
}
|
||||
|
||||
#MiddleColumn {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
background-color: var(--color-background-secondary);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,23 @@
|
||||
<div class="placeholder">
|
||||
<span class="pill">Select a chat to view its archive</span>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.placeholder {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.pill {
|
||||
padding: 0.4375rem 1rem;
|
||||
border-radius: 1rem;
|
||||
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-white);
|
||||
|
||||
background-color: var(--color-default-shadow);
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,38 @@
|
||||
<script lang="ts">
|
||||
import { page } from "$app/state";
|
||||
import ChatHeader from "$lib/components/ChatHeader.svelte";
|
||||
import MessageList from "$lib/components/MessageList.svelte";
|
||||
import { accounts } from "$lib/stores/accounts.svelte";
|
||||
import { chats } from "$lib/stores/chats.svelte";
|
||||
|
||||
const chatId = $derived(Number(page.params.chatId));
|
||||
|
||||
$effect(() => {
|
||||
if (accounts.selectedId === null) {
|
||||
return;
|
||||
}
|
||||
chats.enrich(chatId);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="chat-view">
|
||||
{#key chatId}
|
||||
<ChatHeader {chatId} />
|
||||
<div class="chat-body">
|
||||
<MessageList {chatId} />
|
||||
</div>
|
||||
{/key}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.chat-view {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.chat-body {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,5 @@
|
||||
<script lang="ts">
|
||||
import LoginScreen from "$lib/components/LoginScreen.svelte";
|
||||
</script>
|
||||
|
||||
<LoginScreen />
|
||||
Reference in New Issue
Block a user