Skip to content

Commit

Permalink
Added routes
Browse files Browse the repository at this point in the history
  • Loading branch information
talentedunicorn committed Jan 3, 2025
1 parent 545d1e3 commit 5583d13
Show file tree
Hide file tree
Showing 12 changed files with 231 additions and 121 deletions.
5 changes: 5 additions & 0 deletions About.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# ToDone

An offline-first note-taking app that gets you from _To Do_ to **Done**

Made by [Talentedunicorn](https://talentedunicorn.com) with 🫰 and [Svelte](https://svelte.dev)
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"svelte": "^5.16.0",
"svelte-check": "^4.1.1",
"svelte-loader": "^3.2.4",
"svelte-routing": "^2.13.0",
"tslib": "^2.8.1",
"typescript": "^5.7.2",
"vite": "^6.0.6",
Expand Down
8 changes: 8 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

183 changes: 67 additions & 116 deletions src/App.svelte
Original file line number Diff line number Diff line change
@@ -1,37 +1,30 @@
<script lang="ts">
import './app.css';
import Logo from './components/Logo.svelte';
import Menu from './components/Menu.svelte';
import { isLoggedin, tabs, currentTab, status, user } from './stores';
import Button from './components/Button.svelte';
import { checkAuth, initAuth0Client, login, logout } from './auth';
import { onMount } from 'svelte';
import { pwaInfo } from 'virtual:pwa-info';
import { Router, Route, navigate, links } from 'svelte-routing';
import { fly } from 'svelte/transition';
import List from './List.svelte';
import type { Auth0Client } from '@auth0/auth0-spa-js';
import './app.css';
import Button from './components/Button.svelte';
import ReloadPrompt from './components/ReloadPrompt.svelte';
import { pwaInfo } from 'virtual:pwa-info';
import ExportImport from './components/ExportImport.svelte';
import Toast from './components/Toast.svelte';
import Logo from './components/Logo.svelte';
import ToggleTheme from './components/ToggleTheme.svelte';
import { toastActions, toastMessage } from './stores';
let auth0: Auth0Client;
import About from './routes/About.svelte';
import NotFound from './routes/NotFound.svelte';
import Login from './routes/Login.svelte';
import Home from './routes/Home.svelte';
import { checkAuth, initAuth0Client, logout } from './auth';
import { toastActions, toastMessage, status, isLoggedin } from './stores';
let auth0 = $state<Auth0Client>();
let wrapper: HTMLElement;
let menuItems = $derived(
tabs.map((item) => ({
...item,
selected: item.label === $currentTab
}))
);
let showBackToTop = $state(false);
const handleMenu = (path: string) => {
currentTab.set(path);
scrollToTop();
};
const { url } = $props<{ url: string }>();
const synced = import.meta.env.VITE_SYNCED === 'true';
const scrollToTop = () => {
wrapper.scrollIntoView({
Expand All @@ -46,20 +39,24 @@
});
};
onMount(async () => {
handleBackToTop();
if (import.meta.env.VITE_SYNCED === 'true' && navigator.onLine) {
const initializeAuth = async () => {
if (synced && navigator.onLine) {
if (!auth0) {
auth0 = await initAuth0Client();
}
try {
await checkAuth(auth0);
if (!$isLoggedin) return;
if (!$isLoggedin) navigate('/login');
} catch (e) {
// Log out on failure
logout(auth0);
}
}
};
$effect(() => {
handleBackToTop();
initializeAuth();
});
</script>

Expand All @@ -70,33 +67,19 @@
</svelte:head>

<main class="Wrapper" bind:this={wrapper}>
{#if import.meta.env.VITE_SYNCED === 'true' && !$isLoggedin}
<div class="Login">
<Logo />
<Button onclick={() => login(auth0)}>Log in</Button>
<ToggleTheme />
</div>
{:else}
<aside class="Menu">
<Menu {menuItems} goTo={handleMenu}>
<ExportImport />
</Menu>
</aside>
<header class="Header">
<h1 data-syncing={$status} class="Logo" title="ToDone"><Logo /></h1>

<ToggleTheme />
</header>
<section class="Content">
{#if $isLoggedin}
<div class="Profile">
<img src={$user.picture} alt={$user.nickname} />
<Button onclick={() => logout(auth0)}>Log out</Button>
</div>
{/if}
<List />
</section>
{/if}
<header class="Header" use:links>
<h1 data-syncing={$status} class="Logo" title="ToDone"><a href="/"><Logo /></a></h1>

<ToggleTheme />
</header>
<Router {url}>
<Route path="*"><NotFound /></Route>
<Route path="/"><Home {auth0} /></Route>
<Route path="/about"><About /></Route>
{#if synced}
<Route path="/login"><Login {auth0} /></Route>
{/if}
</Router>
{#if showBackToTop}
<footer class="Footer" transition:fly={{ y: 100, duration: 500 }}>
<Button onclick={scrollToTop}
Expand Down Expand Up @@ -137,82 +120,50 @@
{/if}

<style>
.Wrapper,
.Login {
.Wrapper {
flex-flow: column;
display: flex;
min-height: 100vh;
}
.Login {
padding: 2rem;
gap: 2rem;
align-items: flex-start;
:global(.ColorToggle) {
margin-left: auto;
.Footer {
align-self: flex-end;
position: sticky;
bottom: 2rem;
padding: 0 1rem 0 0;
display: flex;
justify-content: flex-end;
}
}
.Menu {
position: fixed;
top: 0;
z-index: 9;
}
.Header {
align-self: flex-end;
display: flex;
gap: 2rem;
flex-direction: row-reverse;
padding-top: 1rem;
.Header {
align-self: flex-end;
display: flex;
gap: 2rem;
flex-direction: row-reverse;
padding-top: 1rem;
}
}
.Logo {
margin: 1rem;
padding: 0.2em;
background: var(--white);
position: relative;
}
.Footer {
align-self: flex-end;
position: sticky;
bottom: 2rem;
padding: 0 1rem 0 0;
display: flex;
justify-content: flex-end;
}
.Profile {
display: flex;
gap: 1rem;
margin: 2rem;
justify-content: end;
align-items: center;
&[data-syncing] {
--indicator-color: var(--primary);
}
img {
inline-size: 3rem;
&[data-syncing]:not([data-syncing='NOT_SYNCED'])::after {
content: '';
width: 0.5em;
height: 0.5em;
border-radius: 100%;
background: var(--indicator-color);
position: absolute;
top: -0.2em;
left: -0.2em;
}
}
[data-syncing] {
--indicator-color: var(--primary);
}
[data-syncing]:not([data-syncing='NOT_SYNCED'])::after {
content: '';
width: 0.5em;
height: 0.5em;
border-radius: 100%;
background: var(--indicator-color);
position: absolute;
top: -0.2em;
left: -0.2em;
}
[data-syncing='ERROR'] {
--indicator-color: var(--red);
&[data-syncing='ERROR'] {
--indicator-color: var(--red);
}
}
</style>
3 changes: 0 additions & 3 deletions src/List.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -235,9 +235,6 @@
.Search {
align-self: flex-end;
position: sticky;
z-index: 1;
top: 1rem;
display: inline-flex;
gap: 1rem;
padding: 0.5rem;
Expand Down
4 changes: 4 additions & 0 deletions src/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ img {
max-width: 100%;
}

a {
color: var(--primary);
}

.visually-hidden {
position: absolute;
margin: -1px;
Expand Down
4 changes: 3 additions & 1 deletion src/auth.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { type Auth0Client, createAuth0Client } from '@auth0/auth0-spa-js';
import { navigate } from 'svelte-routing';
import { user, isLoggedin, token } from './stores';

// Default Auth0 expiration time is 10 hours or something like that.
Expand All @@ -14,7 +15,7 @@ export const initAuth0Client = async () => {
domain: import.meta.env.VITE_AUTH0_DOMAIN,
cacheLocation: 'localstorage',
authorizationParams: {
redirect_uri: window.location.origin
redirect_uri
}
});
};
Expand Down Expand Up @@ -78,4 +79,5 @@ export const logout = async (auth0: Auth0Client) => {
window.location.replace(url);
}
});
navigate('/login');
};
3 changes: 2 additions & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ if (import.meta.env.MODE === 'production') {
}

const app = mount(App, {
target: document.getElementById('app') as HTMLElement
target: document.getElementById('app') as HTMLElement,
props: { url: '' }
});

export default app;
39 changes: 39 additions & 0 deletions src/routes/About.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<script lang="ts">
import { marked } from 'marked';
import ExportImport from '../components/ExportImport.svelte';
import content from '../../About.md?raw';
</script>

<svelte:head>
<title>About ToDone &#8212; Get it done!</title>
</svelte:head>

<section>
<div>
{@html marked(content)}
</div>

<div>
<h2>You own your data</h2>
<nav>
<ExportImport />
</nav>
</div>
</section>

<style>
section {
padding: 2rem;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
gap: 2rem;
nav {
display: inline-flex;
align-items: flex-start;
gap: 2rem;
}
}
</style>
Loading

0 comments on commit 5583d13

Please sign in to comment.