Improved initial load time
This commit is contained in:
@@ -30,6 +30,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/typography": "^0.5.19",
|
"@tailwindcss/typography": "^0.5.19",
|
||||||
|
"@types/bun": "latest",
|
||||||
"@types/node": "^24.10.1",
|
"@types/node": "^24.10.1",
|
||||||
"typescript": "~5.9.3",
|
"typescript": "~5.9.3",
|
||||||
"vite": "^7.2.4",
|
"vite": "^7.2.4",
|
||||||
@@ -498,6 +499,8 @@
|
|||||||
|
|
||||||
"@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="],
|
"@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="],
|
||||||
|
|
||||||
|
"@types/bun": ["@types/bun@1.3.8", "", { "dependencies": { "bun-types": "1.3.8" } }, "sha512-3LvWJ2q5GerAXYxO2mffLTqOzEu5qnhEAlh48Vnu8WQfnmSwbgagjGZV6BoHKJztENYEDn6QmVd949W4uESRJA=="],
|
||||||
|
|
||||||
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
|
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
|
||||||
|
|
||||||
"@types/linkify-it": ["@types/linkify-it@5.0.0", "", {}, "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q=="],
|
"@types/linkify-it": ["@types/linkify-it@5.0.0", "", {}, "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q=="],
|
||||||
@@ -556,6 +559,8 @@
|
|||||||
|
|
||||||
"buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="],
|
"buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="],
|
||||||
|
|
||||||
|
"bun-types": ["bun-types@1.3.8", "", { "dependencies": { "@types/node": "*" } }, "sha512-fL99nxdOWvV4LqjmC+8Q9kW3M4QTtTR1eePs94v5ctGqU8OeceWrSUaRw3JYb7tU3FkMIAjkueehrHPPPGKi5Q=="],
|
||||||
|
|
||||||
"call-bind": ["call-bind@1.0.8", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", "get-intrinsic": "^1.2.4", "set-function-length": "^1.2.2" } }, "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww=="],
|
"call-bind": ["call-bind@1.0.8", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", "get-intrinsic": "^1.2.4", "set-function-length": "^1.2.2" } }, "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww=="],
|
||||||
|
|
||||||
"call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
|
"call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
|
||||||
|
|||||||
+14
-11
@@ -1,13 +1,16 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
<head>
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
<title>tasgrid</title>
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
</head>
|
<title>tasgrid</title>
|
||||||
<body>
|
</head>
|
||||||
<div id="root"></div>
|
|
||||||
<script type="module" src="/src/index.tsx"></script>
|
<body>
|
||||||
</body>
|
<div id="root"></div>
|
||||||
</html>
|
<script type="module" src="/src/index.tsx"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
+4
-2
@@ -37,6 +37,8 @@
|
|||||||
"@types/node": "^24.10.1",
|
"@types/node": "^24.10.1",
|
||||||
"typescript": "~5.9.3",
|
"typescript": "~5.9.3",
|
||||||
"vite": "^7.2.4",
|
"vite": "^7.2.4",
|
||||||
"vite-plugin-solid": "^2.11.10"
|
"vite-plugin-solid": "^2.11.10",
|
||||||
}
|
"@types/bun": "latest"
|
||||||
|
},
|
||||||
|
"module": "src/index.tsx"
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-11
@@ -1,17 +1,19 @@
|
|||||||
import { type Component, createSignal, Show, onMount, onCleanup } from 'solid-js';
|
import { type Component, createSignal, Show, onMount, onCleanup, lazy, Suspense } from 'solid-js';
|
||||||
import { Layout } from './components/Layout';
|
import { Layout } from './components/Layout';
|
||||||
import { CriticalView } from './views/CriticalView';
|
import { CriticalView } from './views/CriticalView';
|
||||||
import { UrgencyView } from './views/UrgencyView';
|
|
||||||
import { PriorityView } from './views/PriorityView';
|
|
||||||
import { MatrixView } from './views/MatrixView';
|
|
||||||
import { SettingsView } from './views/SettingsView';
|
|
||||||
import { AuthCallback } from './components/Auth';
|
import { AuthCallback } from './components/Auth';
|
||||||
import { pb } from './lib/pocketbase';
|
import { pb } from './lib/pocketbase';
|
||||||
import { initStore } from './store';
|
import { initStore } from './store';
|
||||||
|
|
||||||
|
// const CriticalView = lazy(() => import('./views/CriticalView').then(m => ({ default: m.CriticalView })));
|
||||||
|
const UrgencyView = lazy(() => import('./views/UrgencyView').then(m => ({ default: m.UrgencyView })));
|
||||||
|
const PriorityView = lazy(() => import('./views/PriorityView').then(m => ({ default: m.PriorityView })));
|
||||||
|
const MatrixView = lazy(() => import('./views/MatrixView').then(m => ({ default: m.MatrixView })));
|
||||||
|
const SettingsView = lazy(() => import('./views/SettingsView').then(m => ({ default: m.SettingsView })));
|
||||||
|
|
||||||
const App: Component = () => {
|
const App: Component = () => {
|
||||||
// Basic routing state
|
// Basic routing state
|
||||||
const [currentView, setCurrentView] = createSignal("matrix");
|
const [currentView, setCurrentView] = createSignal("critical");
|
||||||
const [isAuthenticated, setIsAuthenticated] = createSignal(pb.authStore.isValid);
|
const [isAuthenticated, setIsAuthenticated] = createSignal(pb.authStore.isValid);
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
@@ -23,16 +25,27 @@ const App: Component = () => {
|
|||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
onCleanup(() => removeListener());
|
onCleanup(() => removeListener());
|
||||||
|
|
||||||
|
// Background preload of other views
|
||||||
|
setTimeout(() => {
|
||||||
|
// CriticalView is now static
|
||||||
|
import('./views/UrgencyView');
|
||||||
|
import('./views/PriorityView');
|
||||||
|
import('./views/MatrixView');
|
||||||
|
import('./views/SettingsView');
|
||||||
|
}, 100);
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Show when={isAuthenticated()} fallback={<AuthCallback onSuccess={() => { }} />}>
|
<Show when={isAuthenticated()} fallback={<AuthCallback onSuccess={() => { }} />}>
|
||||||
<Layout currentView={currentView()} setView={setCurrentView}>
|
<Layout currentView={currentView()} setView={setCurrentView}>
|
||||||
<Show when={currentView() === "critical"}><CriticalView /></Show>
|
<Suspense fallback={<div class="flex items-center justify-center h-full"><div class="animate-spin rounded-full h-8 w-8 border-b-2 border-primary"></div></div>}>
|
||||||
<Show when={currentView() === "urgency"}><UrgencyView /></Show>
|
<Show when={currentView() === "critical"}><CriticalView /></Show>
|
||||||
<Show when={currentView() === "priority"}><PriorityView /></Show>
|
<Show when={currentView() === "urgency"}><UrgencyView /></Show>
|
||||||
<Show when={currentView() === "matrix"}><MatrixView /></Show>
|
<Show when={currentView() === "priority"}><PriorityView /></Show>
|
||||||
<Show when={currentView() === "settings"}><SettingsView /></Show>
|
<Show when={currentView() === "matrix"}><MatrixView /></Show>
|
||||||
|
<Show when={currentView() === "settings"}><SettingsView /></Show>
|
||||||
|
</Suspense>
|
||||||
</Layout>
|
</Layout>
|
||||||
</Show>
|
</Show>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { type Component, type JSX, createSignal, Show } from "solid-js";
|
import { type Component, type JSX, createSignal, Show, lazy, Suspense, onMount } from "solid-js";
|
||||||
import { Sidebar, BottomNav } from "./Navigation";
|
import { Sidebar, BottomNav } from "./Navigation";
|
||||||
import { QuickEntry } from "./QuickEntry";
|
|
||||||
import { TaskDetail } from "./TaskDetail";
|
|
||||||
import { store, activeTaskId, setActiveTaskId } from "@/store";
|
import { store, activeTaskId, setActiveTaskId } from "@/store";
|
||||||
import { PanelLeftOpen } from "lucide-solid";
|
import { PanelLeftOpen } from "lucide-solid";
|
||||||
|
|
||||||
|
const TaskDetail = lazy(() => import("./TaskDetail").then(m => ({ default: m.TaskDetail })));
|
||||||
|
const QuickEntry = lazy(() => import("./QuickEntry").then(m => ({ default: m.QuickEntry })));
|
||||||
import { Button } from "./ui/button";
|
import { Button } from "./ui/button";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
@@ -17,6 +18,14 @@ export const Layout: Component<LayoutProps> = (props) => {
|
|||||||
const [isSidebarLocked, setIsSidebarLocked] = createSignal(true);
|
const [isSidebarLocked, setIsSidebarLocked] = createSignal(true);
|
||||||
const [isSidebarPeeking, setIsSidebarPeeking] = createSignal(false);
|
const [isSidebarPeeking, setIsSidebarPeeking] = createSignal(false);
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
// Preload TaskDetail and QuickEntry in background
|
||||||
|
setTimeout(() => {
|
||||||
|
import("./TaskDetail");
|
||||||
|
import("./QuickEntry");
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
|
||||||
// Derived active task for the detail view
|
// Derived active task for the detail view
|
||||||
const activeTask = () => store.tasks.find(t => t.id === activeTaskId());
|
const activeTask = () => store.tasks.find(t => t.id === activeTaskId());
|
||||||
|
|
||||||
@@ -58,14 +67,18 @@ export const Layout: Component<LayoutProps> = (props) => {
|
|||||||
<BottomNav currentView={props.currentView} setView={props.setView} />
|
<BottomNav currentView={props.currentView} setView={props.setView} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<QuickEntry />
|
<Suspense>
|
||||||
|
<QuickEntry />
|
||||||
|
</Suspense>
|
||||||
|
|
||||||
<Show when={activeTask()}>
|
<Show when={activeTask()}>
|
||||||
<TaskDetail
|
<Suspense>
|
||||||
task={activeTask()!}
|
<TaskDetail
|
||||||
isOpen={!!activeTaskId()}
|
task={activeTask()!}
|
||||||
onClose={() => setActiveTaskId(null)}
|
isOpen={!!activeTaskId()}
|
||||||
/>
|
onClose={() => setActiveTaskId(null)}
|
||||||
|
/>
|
||||||
|
</Suspense>
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ export const TaskDetail: Component<TaskDetailProps> = (props) => {
|
|||||||
const taskId = props.task.id;
|
const taskId = props.task.id;
|
||||||
removeTask(taskId);
|
removeTask(taskId);
|
||||||
props.onClose();
|
props.onClose();
|
||||||
toast.info("Task moved to trash", {
|
toast.info("Task moved to trash. Find inside Settings.", {
|
||||||
action: {
|
action: {
|
||||||
label: "Undo",
|
label: "Undo",
|
||||||
onClick: () => restoreTask(taskId)
|
onClick: () => restoreTask(taskId)
|
||||||
|
|||||||
Reference in New Issue
Block a user