Files
thoughtsync/frontend/src/router/index.ts
T
bvandeusenandClaude Opus 4.8 95b0e30fc7
CI & Build / Python lint (push) Successful in 3s
CI & Build / TypeScript typecheck (push) Successful in 5s
CI & Build / Python tests (push) Successful in 8s
CI & Build / Build & push image (push) Successful in 1m2s
M6: browse notes by creation date (Timeline lens)
A temporal recall path — find a note by WHEN it was captured, not just what it contains (task 1903, first of the M6 recall items).

Backend: list_notes gains an optional created_at range (created_after / created_before, half-open interval) + sort=created; also lays groundwork for the richer-search facets (task 1902). New _parse_iso_dt helper with a DB-free unit test.

Frontend: a Timeline view (sidebar nav + 'g t' + command palette) grouping active notes newest-first into local-time buckets (Today / Yesterday / Earlier this week / this month / Month YYYY), plus an optional From/To date filter. Built as a lens on the same NoteCard masonry, consistent with the existing Reminders/Search views.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FRgehjoz7Yv8LkUfADxACm
2026-07-22 12:26:35 -04:00

68 lines
2.3 KiB
TypeScript

import { createRouter, createWebHistory } from "vue-router";
import { useSessionStore } from "../stores/session";
import { useConfigStore } from "../stores/config";
const router = createRouter({
history: createWebHistory(),
routes: [
{
// Persistent authed shell (sidebar + top bar + search); children render in it.
path: "/",
component: () => import("../components/AppShell.vue"),
meta: { requiresAuth: true },
children: [
{ path: "", name: "board", component: () => import("../views/BoardView.vue") },
{ path: "archive", name: "archive", component: () => import("../views/BoardView.vue") },
{ path: "trash", name: "trash", component: () => import("../views/BoardView.vue") },
{ path: "label/:id", name: "label", component: () => import("../views/BoardView.vue") },
{ path: "search", name: "search", component: () => import("../views/SearchView.vue") },
{ path: "graph", name: "graph", component: () => import("../views/GraphView.vue") },
{ path: "reminders", name: "reminders", component: () => import("../views/RemindersView.vue") },
{ path: "timeline", name: "timeline", component: () => import("../views/TimelineView.vue") },
],
},
{
path: "/settings",
name: "settings",
component: () => import("../views/SettingsView.vue"),
meta: { requiresAuth: true, requiresAdmin: true },
},
{
path: "/login",
name: "login",
component: () => import("../views/LoginView.vue"),
meta: { guestOnly: true },
},
{
path: "/register",
name: "register",
component: () => import("../views/RegisterView.vue"),
meta: { guestOnly: true },
},
],
});
router.beforeEach(async (to) => {
const session = useSessionStore();
const config = useConfigStore();
await config.load();
if (!session.loaded) {
await session.fetchMe();
}
if (to.meta.requiresAuth && !session.user) {
return { name: "login", query: to.fullPath !== "/" ? { redirect: to.fullPath } : undefined };
}
if (to.meta.requiresAdmin && !session.user?.is_admin) {
return { name: "board" };
}
if (to.name === "register" && !config.allowRegistration) {
return { name: "login" };
}
if (to.meta.guestOnly && session.user) {
return { name: "board" };
}
return true;
});
export default router;