learn and share notes on atproto (wip) 🦉 malfestio.stormlightlabs.org/
readability solid axum atproto srs
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: add About page

* Footer component

* expand Landing page content

* add custom fonts

+469 -81
+5 -5
docs/todo.md
··· 63 63 64 64 **Marketing/Static Site:** 65 65 66 - - [ ] Landing page with hero section, feature highlights, social proof 67 - - Hero should have a graph paper/grid background 68 - - Floating flash cards, notes 69 - - [ ] "How it works" section with study flow visualization 70 - - [ ] About page with team/mission 66 + - [x] Landing page with hero section, feature highlights 67 + - Hero has graph paper/grid background 68 + - Floating flash cards, notes animations 69 + - [x] "How it works" section with study flow visualization 70 + - [x] About page with team/mission 71 71 72 72 **App Vision Content:** 73 73
+2
web/package.json
··· 12 12 "lint": "eslint ." 13 13 }, 14 14 "dependencies": { 15 + "@fontsource-variable/alegreya": "^5.2.8", 16 + "@fontsource-variable/lora": "^5.2.8", 15 17 "@solidjs/meta": "^0.29.4", 16 18 "@solidjs/router": "^0.15.4", 17 19 "@tailwindcss/vite": "^4.1.18",
+16
web/pnpm-lock.yaml
··· 11 11 12 12 .: 13 13 dependencies: 14 + '@fontsource-variable/alegreya': 15 + specifier: ^5.2.8 16 + version: 5.2.8 17 + '@fontsource-variable/lora': 18 + specifier: ^5.2.8 19 + version: 5.2.8 14 20 '@solidjs/meta': 15 21 specifier: ^0.29.4 16 22 version: 0.29.4(solid-js@1.9.10) ··· 309 315 peerDependenciesMeta: 310 316 '@exodus/crypto': 311 317 optional: true 318 + 319 + '@fontsource-variable/alegreya@5.2.8': 320 + resolution: {integrity: sha512-gQcIA7j76KYTOcdkfo1Xee9xLBi5mya4qTkzlgeoHf9SjOL/gJj5GSSOg/7ba/ciUU18K92i7VGxXzFhDsowGg==} 321 + 322 + '@fontsource-variable/lora@5.2.8': 323 + resolution: {integrity: sha512-cxjTJ9BbOWIzusewR4UMBLVePvTSWV6dtNaNsCkF/oKoyA68fJGWfaYCILOOP1BObE4dmjfZ3xo6m9hdHhtYhg==} 312 324 313 325 '@humanfs/core@0.19.1': 314 326 resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} ··· 2159 2171 levn: 0.4.1 2160 2172 2161 2173 '@exodus/bytes@1.6.0': {} 2174 + 2175 + '@fontsource-variable/alegreya@5.2.8': {} 2176 + 2177 + '@fontsource-variable/lora@5.2.8': {} 2162 2178 2163 2179 '@humanfs/core@0.19.1': {} 2164 2180
+3
web/public/tangled.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 25 25"> 2 + <path fill="currentColor" d="m 16.208435,23.914069 c -0.06147,-0.02273 -0.147027,-0.03034 -0.190158,-0.01691 -0.197279,0.06145 -1.31068,-0.230493 -1.388819,-0.364153 -0.01956,-0.03344 -0.163274,-0.134049 -0.319377,-0.223561 -0.550395,-0.315603 -1.010951,-0.696643 -1.428383,-1.181771 -0.264598,-0.307509 -0.597257,-0.785384 -0.597257,-0.857979 0,-0.0216 -0.02841,-0.06243 -0.06313,-0.0907 -0.04977,-0.04053 -0.160873,0.0436 -0.52488,0.397463 -0.479803,0.466432 -0.78924,0.689475 -1.355603,0.977118 -0.183693,0.0933 -0.323426,0.179989 -0.310516,0.192658 0.02801,0.02748 -0.7656391,0.270031 -1.209129,0.369517 -0.5378332,0.120647 -1.6341809,0.08626 -1.9721503,-0.06186 C 6.7977157,23.031391 6.56735,22.957551 6.3371134,22.889782 4.9717169,22.487902 3.7511914,21.481518 3.1172396,20.234838 2.6890391,19.392772 2.5582276,18.827446 2.5610489,17.831154 2.5639589,16.802192 2.7366641,16.125844 3.2142117,15.273187 3.3040457,15.112788 3.3713143,14.976533 3.3636956,14.9704 3.3560756,14.9643 3.2459634,14.90305 3.1189994,14.834381 1.7582586,14.098312 0.77760984,12.777439 0.44909837,11.23818 0.33531456,10.705039 0.33670119,9.7067968 0.45195381,9.1778795 0.72259241,7.9359287 1.3827188,6.8888436 2.4297498,6.0407205 2.6856126,5.8334648 3.2975489,5.4910878 3.6885849,5.3364049 L 4.0584319,5.190106 4.2333984,4.860432 C 4.8393906,3.7186139 5.8908314,2.7968028 7.1056396,2.3423025 7.7690673,2.0940921 8.2290216,2.0150935 9.01853,2.0137575 c 0.9625627,-0.00163 1.629181,0.1532762 2.485864,0.5776514 l 0.271744,0.1346134 0.42911,-0.3607688 c 1.082666,-0.9102346 2.185531,-1.3136811 3.578383,-1.3090327 0.916696,0.00306 1.573918,0.1517893 2.356121,0.5331927 1.465948,0.7148 2.54506,2.0625628 2.865177,3.57848 l 0.07653,0.362429 0.515095,0.2556611 c 1.022872,0.5076874 1.756122,1.1690944 2.288361,2.0641468 0.401896,0.6758594 0.537303,1.0442682 0.675505,1.8378683 0.288575,1.6570823 -0.266229,3.3548023 -1.490464,4.5608743 -0.371074,0.36557 -0.840205,0.718265 -1.203442,0.904754 -0.144112,0.07398 -0.271303,0.15826 -0.282647,0.187269 -0.01134,0.02901 0.02121,0.142764 0.07234,0.25279 0.184248,0.396467 0.451371,1.331823 0.619371,2.168779 0.463493,2.30908 -0.754646,4.693707 -2.92278,5.721632 -0.479538,0.227352 -0.717629,0.309322 -1.144194,0.39393 -0.321869,0.06383 -1.850573,0.09139 -2.000174,0.03604 z M 12.25443,18.636956 c 0.739923,-0.24652 1.382521,-0.718922 1.874623,-1.37812 0.0752,-0.100718 0.213883,-0.275851 0.308198,-0.389167 0.09432,-0.113318 0.210136,-0.271056 0.257381,-0.350531 0.416347,-0.700389 0.680936,-1.176102 0.766454,-1.378041 0.05594,-0.132087 0.114653,-0.239607 0.130477,-0.238929 0.01583,6.79e-4 0.08126,0.08531 0.145412,0.188069 0.178029,0.285173 0.614305,0.658998 0.868158,0.743878 0.259802,0.08686 0.656158,0.09598 0.911369,0.02095 0.213812,-0.06285 0.507296,-0.298016 0.645179,-0.516947 0.155165,-0.246374 0.327989,-0.989595 0.327989,-1.410501 0,-1.26718 -0.610975,-3.143405 -1.237774,-3.801045 -0.198483,-0.2082486 -0.208557,-0.2319396 -0.208557,-0.4904655 0,-0.2517771 -0.08774,-0.5704927 -0.258476,-0.938956 C 16.694963,8.50313 16.375697,8.1377479 16.135846,7.9543702 L 15.932296,7.7987471 15.683004,7.9356529 C 15.131767,8.2383821 14.435638,8.1945733 13.943459,7.8261812 L 13.782862,7.7059758 13.686773,7.8908012 C 13.338849,8.5600578 12.487087,8.8811064 11.743178,8.6233891 11.487199,8.5347109 11.358897,8.4505994 11.063189,8.1776138 L 10.69871,7.8411436 10.453484,8.0579255 C 10.318608,8.1771557 10.113778,8.3156283 9.9983037,8.3656417 9.7041488,8.4930449 9.1808299,8.5227884 8.8979004,8.4281886 8.7754792,8.3872574 8.6687415,8.3537661 8.6607053,8.3537661 c -0.03426,0 -0.3092864,0.3066098 -0.3791974,0.42275 -0.041935,0.069664 -0.1040482,0.1266636 -0.1380294,0.1266636 -0.1316419,0 -0.4197402,0.1843928 -0.6257041,0.4004735 -0.1923125,0.2017571 -0.6853701,0.9036038 -0.8926582,1.2706578 -0.042662,0.07554 -0.1803555,0.353687 -0.3059848,0.618091 -0.1256293,0.264406 -0.3270073,0.686768 -0.4475067,0.938581 -0.1204992,0.251816 -0.2469926,0.519654 -0.2810961,0.595199 -0.2592829,0.574347 -0.285919,1.391094 -0.057822,1.77304 0.1690683,0.283105 0.4224039,0.480895 0.7285507,0.568809 0.487122,0.139885 0.9109638,-0.004 1.6013422,-0.543768 l 0.4560939,-0.356568 0.0036,0.172041 c 0.01635,0.781837 0.1831084,1.813183 0.4016641,2.484154 0.1160449,0.356262 0.3781448,0.83968 0.5614081,1.035462 0.2171883,0.232025 0.7140951,0.577268 1.0100284,0.701749 0.121485,0.0511 0.351032,0.110795 0.510105,0.132647 0.396966,0.05452 1.2105,0.02265 1.448934,-0.05679 z"/> 3 + </svg>
+2
web/src/App.tsx
··· 1 1 import { AppLayout } from "$components/layout/AppLayout"; 2 2 import { authStore } from "$lib/store"; 3 + import About from "$pages/About"; 3 4 import DeckNew from "$pages/DeckNew"; 4 5 import DeckView from "$pages/DeckView"; 5 6 import Discovery from "$pages/Discovery"; ··· 31 32 return ( 32 33 <Router> 33 34 <Route path="/login" component={Login} /> 35 + <Route path="/about" component={About} /> 34 36 <Route path="/" component={() => <ProtectedRoute component={Home} />} /> 35 37 <Route path="/decks" component={() => <ProtectedRoute component={Home} />} /> 36 38 <Route path="/decks/new" component={() => <ProtectedRoute component={DeckNew} />} />
+9 -11
web/src/components/layout/AppLayout.tsx
··· 1 1 import { Toaster } from "$ui/Toast"; 2 2 import type { Component, JSX } from "solid-js"; 3 + import { Footer } from "./Footer"; 3 4 import { Header } from "./Header"; 4 5 5 - type AppLayoutProps = { children?: JSX.Element }; 6 - 7 - export const AppLayout: Component<AppLayoutProps> = (props) => { 8 - return ( 9 - <div class="min-h-screen bg-[#161616] text-[#F4F4F4] font-sans selection:bg-[#0F62FE]/30"> 10 - <Header /> 11 - <main class="container mx-auto px-4 py-8 md:px-6 lg:px-8 max-w-7xl">{props.children}</main> 12 - <Toaster /> 13 - </div> 14 - ); 15 - }; 6 + export const AppLayout: Component<{ children?: JSX.Element }> = (props) => ( 7 + <div class="min-h-screen bg-[#161616] text-[#F4F4F4] font-sans selection:bg-[#0F62FE]/30 flex flex-col"> 8 + <Header /> 9 + <main class="container mx-auto px-4 py-8 md:px-6 lg:px-8 max-w-7xl flex-1">{props.children}</main> 10 + <Footer /> 11 + <Toaster /> 12 + </div> 13 + );
+39
web/src/components/layout/Footer.test.tsx
··· 1 + import { MemoryRouter, Route } from "@solidjs/router"; 2 + import { cleanup, render, screen } from "@solidjs/testing-library"; 3 + import { afterEach, describe, expect, it } from "vitest"; 4 + import { Footer } from "./Footer"; 5 + 6 + describe("Footer", () => { 7 + afterEach(cleanup); 8 + 9 + function renderFooter() { 10 + render(() => ( 11 + <MemoryRouter> 12 + <Route path="/" component={Footer} /> 13 + </MemoryRouter> 14 + )); 15 + } 16 + 17 + it("renders copyright text", () => { 18 + renderFooter(); 19 + expect(screen.getByText(/© 2025 Stormlight Labs/)).toBeInTheDocument(); 20 + }); 21 + 22 + it("renders About link", () => { 23 + renderFooter(); 24 + const aboutLink = screen.getByRole("link", { name: "About" }); 25 + expect(aboutLink).toHaveAttribute("href", "/about"); 26 + }); 27 + 28 + it("renders Tangled link", () => { 29 + renderFooter(); 30 + const tangledLink = screen.getByRole("link", { name: "Tangled" }); 31 + expect(tangledLink).toHaveAttribute("href", "https://tangled.org/desertthunder.dev/malfestio"); 32 + }); 33 + 34 + it("renders GitHub link", () => { 35 + renderFooter(); 36 + const githubLink = screen.getByRole("link", { name: "GitHub" }); 37 + expect(githubLink).toHaveAttribute("href", "https://github.com/stormlightlabs"); 38 + }); 39 + });
+46
web/src/components/layout/Footer.tsx
··· 1 + import { A } from "@solidjs/router"; 2 + import type { Component } from "solid-js"; 3 + 4 + const TangledIcon: Component<{ class?: string }> = (props) => ( 5 + <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 25 25" class={props.class}> 6 + <path 7 + fill="currentColor" 8 + d="m 16.208435,23.914069 c -0.06147,-0.02273 -0.147027,-0.03034 -0.190158,-0.01691 -0.197279,0.06145 -1.31068,-0.230493 -1.388819,-0.364153 -0.01956,-0.03344 -0.163274,-0.134049 -0.319377,-0.223561 -0.550395,-0.315603 -1.010951,-0.696643 -1.428383,-1.181771 -0.264598,-0.307509 -0.597257,-0.785384 -0.597257,-0.857979 0,-0.0216 -0.02841,-0.06243 -0.06313,-0.0907 -0.04977,-0.04053 -0.160873,0.0436 -0.52488,0.397463 -0.479803,0.466432 -0.78924,0.689475 -1.355603,0.977118 -0.183693,0.0933 -0.323426,0.179989 -0.310516,0.192658 0.02801,0.02748 -0.7656391,0.270031 -1.209129,0.369517 -0.5378332,0.120647 -1.6341809,0.08626 -1.9721503,-0.06186 C 6.7977157,23.031391 6.56735,22.957551 6.3371134,22.889782 4.9717169,22.487902 3.7511914,21.481518 3.1172396,20.234838 2.6890391,19.392772 2.5582276,18.827446 2.5610489,17.831154 2.5639589,16.802192 2.7366641,16.125844 3.2142117,15.273187 3.3040457,15.112788 3.3713143,14.976533 3.3636956,14.9704 3.3560756,14.9643 3.2459634,14.90305 3.1189994,14.834381 1.7582586,14.098312 0.77760984,12.777439 0.44909837,11.23818 0.33531456,10.705039 0.33670119,9.7067968 0.45195381,9.1778795 0.72259241,7.9359287 1.3827188,6.8888436 2.4297498,6.0407205 2.6856126,5.8334648 3.2975489,5.4910878 3.6885849,5.3364049 L 4.0584319,5.190106 4.2333984,4.860432 C 4.8393906,3.7186139 5.8908314,2.7968028 7.1056396,2.3423025 7.7690673,2.0940921 8.2290216,2.0150935 9.01853,2.0137575 c 0.9625627,-0.00163 1.629181,0.1532762 2.485864,0.5776514 l 0.271744,0.1346134 0.42911,-0.3607688 c 1.082666,-0.9102346 2.185531,-1.3136811 3.578383,-1.3090327 0.916696,0.00306 1.573918,0.1517893 2.356121,0.5331927 1.465948,0.7148 2.54506,2.0625628 2.865177,3.57848 l 0.07653,0.362429 0.515095,0.2556611 c 1.022872,0.5076874 1.756122,1.1690944 2.288361,2.0641468 0.401896,0.6758594 0.537303,1.0442682 0.675505,1.8378683 0.288575,1.6570823 -0.266229,3.3548023 -1.490464,4.5608743 -0.371074,0.36557 -0.840205,0.718265 -1.203442,0.904754 -0.144112,0.07398 -0.271303,0.15826 -0.282647,0.187269 -0.01134,0.02901 0.02121,0.142764 0.07234,0.25279 0.184248,0.396467 0.451371,1.331823 0.619371,2.168779 0.463493,2.30908 -0.754646,4.693707 -2.92278,5.721632 -0.479538,0.227352 -0.717629,0.309322 -1.144194,0.39393 -0.321869,0.06383 -1.850573,0.09139 -2.000174,0.03604 z M 12.25443,18.636956 c 0.739923,-0.24652 1.382521,-0.718922 1.874623,-1.37812 0.0752,-0.100718 0.213883,-0.275851 0.308198,-0.389167 0.09432,-0.113318 0.210136,-0.271056 0.257381,-0.350531 0.416347,-0.700389 0.680936,-1.176102 0.766454,-1.378041 0.05594,-0.132087 0.114653,-0.239607 0.130477,-0.238929 0.01583,6.79e-4 0.08126,0.08531 0.145412,0.188069 0.178029,0.285173 0.614305,0.658998 0.868158,0.743878 0.259802,0.08686 0.656158,0.09598 0.911369,0.02095 0.213812,-0.06285 0.507296,-0.298016 0.645179,-0.516947 0.155165,-0.246374 0.327989,-0.989595 0.327989,-1.410501 0,-1.26718 -0.610975,-3.143405 -1.237774,-3.801045 -0.198483,-0.2082486 -0.208557,-0.2319396 -0.208557,-0.4904655 0,-0.2517771 -0.08774,-0.5704927 -0.258476,-0.938956 C 16.694963,8.50313 16.375697,8.1377479 16.135846,7.9543702 L 15.932296,7.7987471 15.683004,7.9356529 C 15.131767,8.2383821 14.435638,8.1945733 13.943459,7.8261812 L 13.782862,7.7059758 13.686773,7.8908012 C 13.338849,8.5600578 12.487087,8.8811064 11.743178,8.6233891 11.487199,8.5347109 11.358897,8.4505994 11.063189,8.1776138 L 10.69871,7.8411436 10.453484,8.0579255 C 10.318608,8.1771557 10.113778,8.3156283 9.9983037,8.3656417 9.7041488,8.4930449 9.1808299,8.5227884 8.8979004,8.4281886 8.7754792,8.3872574 8.6687415,8.3537661 8.6607053,8.3537661 c -0.03426,0 -0.3092864,0.3066098 -0.3791974,0.42275 -0.041935,0.069664 -0.1040482,0.1266636 -0.1380294,0.1266636 -0.1316419,0 -0.4197402,0.1843928 -0.6257041,0.4004735 -0.1923125,0.2017571 -0.6853701,0.9036038 -0.8926582,1.2706578 -0.042662,0.07554 -0.1803555,0.353687 -0.3059848,0.618091 -0.1256293,0.264406 -0.3270073,0.686768 -0.4475067,0.938581 -0.1204992,0.251816 -0.2469926,0.519654 -0.2810961,0.595199 -0.2592829,0.574347 -0.285919,1.391094 -0.057822,1.77304 0.1690683,0.283105 0.4224039,0.480895 0.7285507,0.568809 0.487122,0.139885 0.9109638,-0.004 1.6013422,-0.543768 l 0.4560939,-0.356568 0.0036,0.172041 c 0.01635,0.781837 0.1831084,1.813183 0.4016641,2.484154 0.1160449,0.356262 0.3781448,0.83968 0.5614081,1.035462 0.2171883,0.232025 0.7140951,0.577268 1.0100284,0.701749 0.121485,0.0511 0.351032,0.110795 0.510105,0.132647 0.396966,0.05452 1.2105,0.02265 1.448934,-0.05679 z" /> 9 + </svg> 10 + ); 11 + 12 + export const Footer: Component = () => ( 13 + <footer class="border-t border-[#393939] py-12 bg-[#161616]"> 14 + <div class="max-w-7xl mx-auto px-6 text-[#C6C6C6] text-xs font-light flex flex-col md:flex-row justify-between items-center gap-4"> 15 + <p> 16 + © 2025 Stormlight Labs. Made with ⚡️ by{" "} 17 + <a 18 + href="https://desertthunder.dev" 19 + target="_blank" 20 + rel="noopener noreferrer" 21 + class="hover:text-[#F4F4F4] transition-colors"> 22 + Owais. 23 + </a> 24 + </p> 25 + <div class="flex items-center gap-6"> 26 + <A href="/about" class="hover:text-[#F4F4F4] transition-colors">About</A> 27 + <a 28 + href="https://tangled.org/desertthunder.dev/malfestio" 29 + target="_blank" 30 + rel="noopener noreferrer" 31 + class="flex items-center gap-1.5 hover:text-[#F4F4F4] transition-colors"> 32 + <TangledIcon /> 33 + Tangled 34 + </a> 35 + <a 36 + href="https://github.com/stormlightlabs" 37 + target="_blank" 38 + rel="noopener noreferrer" 39 + class="flex items-center gap-1.5 hover:text-[#F4F4F4] transition-colors"> 40 + <span class="i-bi-github" /> 41 + GitHub 42 + </a> 43 + </div> 44 + </div> 45 + </footer> 46 + );
+3
web/src/fonts.d.ts
··· 1 + // CSS-only packages without TypeScript declarations 2 + declare module "@fontsource-variable/alegreya"; 3 + declare module "@fontsource-variable/lora";
+28
web/src/index.css
··· 1 1 @import "tailwindcss"; 2 2 @plugin "@egoist/tailwindcss-icons"; 3 + 4 + @theme { 5 + --font-display: "Lora Variable", serif; 6 + --font-body: "Alegreya Variable", serif; 7 + } 8 + 9 + * { 10 + @apply font-body; 11 + } 12 + 13 + h1, 14 + h2, 15 + h3, 16 + h4, 17 + h5, 18 + h6 { 19 + @apply font-display; 20 + } 21 + 22 + .grid-pattern { 23 + background-size: 32px 32px; 24 + background-image: linear-gradient( 25 + to right, 26 + rgba(85, 85, 85, 0.3) 1px, 27 + transparent 1px 28 + ), 29 + linear-gradient(to bottom, rgba(85, 85, 85, 0.3) 1px, transparent 1px); 30 + }
+2
web/src/index.tsx
··· 1 1 /* @refresh reload */ 2 + import "@fontsource-variable/alegreya"; 3 + import "@fontsource-variable/lora"; 2 4 import { render } from "solid-js/web"; 3 5 import "./index.css"; 4 6 import App from "./App.tsx";
+45
web/src/pages/About.test.tsx
··· 1 + import { MemoryRouter, Route } from "@solidjs/router"; 2 + import { cleanup, render, screen } from "@solidjs/testing-library"; 3 + import { afterEach, describe, expect, it } from "vitest"; 4 + import About from "./About"; 5 + 6 + describe("About Page", () => { 7 + afterEach(cleanup); 8 + 9 + function renderAbout() { 10 + render(() => ( 11 + <MemoryRouter> 12 + <Route path="/" component={About} /> 13 + </MemoryRouter> 14 + )); 15 + } 16 + 17 + it("renders page title", () => { 18 + renderAbout(); 19 + expect(screen.getByText("About Malfestio")).toBeInTheDocument(); 20 + }); 21 + 22 + it("renders mission statement", () => { 23 + renderAbout(); 24 + expect(screen.getByText(/decentralized learning platform/i)).toBeInTheDocument(); 25 + }); 26 + 27 + it("renders team section with Owais", () => { 28 + renderAbout(); 29 + expect(screen.getByText("Team")).toBeInTheDocument(); 30 + expect(screen.getByText("Owais")).toBeInTheDocument(); 31 + expect(screen.getByRole("link", { name: "desertthunder.dev" })).toHaveAttribute( 32 + "href", 33 + "https://desertthunder.dev", 34 + ); 35 + }); 36 + 37 + it("renders links section", () => { 38 + renderAbout(); 39 + expect(screen.getByText("Links")).toBeInTheDocument(); 40 + expect(screen.getByRole("link", { name: /Tangled Repository/i })).toHaveAttribute( 41 + "href", 42 + "https://tangled.org/desertthunder.dev/malfestio", 43 + ); 44 + }); 45 + });
+92
web/src/pages/About.tsx
··· 1 + import { Footer } from "$components/layout/Footer"; 2 + import { A } from "@solidjs/router"; 3 + import type { Component } from "solid-js"; 4 + 5 + const About: Component = () => ( 6 + <div class="min-h-screen bg-black text-white font-sans selection:bg-blue-500/30"> 7 + <header class="border-b border-neutral-900 sticky top-0 bg-black/80 backdrop-blur-md z-50"> 8 + <div class="max-w-7xl mx-auto px-6 h-16 flex items-center justify-between"> 9 + <A href="/" class="font-bold tracking-tight text-xl hover:text-blue-400 transition-colors">Malfestio</A> 10 + <div class="flex items-center gap-6"> 11 + <A href="/about" class="text-sm font-medium text-white">About</A> 12 + <A href="/login" class="text-sm font-medium text-neutral-400 hover:text-white transition-colors">Log in</A> 13 + </div> 14 + </div> 15 + </header> 16 + 17 + <main class="max-w-4xl mx-auto px-6 py-24"> 18 + <section class="mb-16"> 19 + <h1 class="text-4xl md:text-5xl font-light tracking-tight mb-8">About Malfestio</h1> 20 + <p class="text-xl text-neutral-400 font-light leading-relaxed mb-6"> 21 + Malfestio is a decentralized learning platform built on the AT Protocol. We believe knowledge should be 22 + portable, shareable, and owned by learners — not locked into proprietary platforms. 23 + </p> 24 + <p class="text-lg text-neutral-500 font-light leading-relaxed"> 25 + By combining spaced repetition, linked notes, and social features with decentralized identity and data 26 + ownership, we're creating a new way to learn and share knowledge across the open web. 27 + </p> 28 + </section> 29 + 30 + <section class="mb-16"> 31 + <h2 class="text-2xl font-light mb-6 text-white">Team</h2> 32 + <div class="border border-neutral-800 p-6 bg-neutral-900/50"> 33 + <div class="flex items-center gap-4 mb-4"> 34 + <div class="w-12 h-12 rounded-full bg-blue-600 flex items-center justify-center text-white font-semibold"> 35 + O 36 + </div> 37 + <div> 38 + <h3 class="text-lg font-medium text-white">Owais</h3> 39 + <p class="text-sm text-neutral-400"> 40 + <a 41 + href="https://desertthunder.dev" 42 + target="_blank" 43 + rel="noopener noreferrer" 44 + class="hover:text-blue-400 transition-colors"> 45 + desertthunder.dev 46 + </a> 47 + </p> 48 + </div> 49 + </div> 50 + <p class="text-neutral-400 font-light"> 51 + Building at Stormlight Labs. Passionate about decentralized systems, learning tools, and the AT Protocol. 52 + </p> 53 + </div> 54 + </section> 55 + 56 + <section> 57 + <h2 class="text-2xl font-light mb-6 text-white">Links</h2> 58 + <div class="flex flex-col gap-4"> 59 + <a 60 + href="https://tangled.org/desertthunder.dev/malfestio" 61 + target="_blank" 62 + rel="noopener noreferrer" 63 + class="flex items-center gap-3 text-neutral-400 hover:text-white transition-colors group"> 64 + <svg 65 + xmlns="http://www.w3.org/2000/svg" 66 + width="18" 67 + height="18" 68 + viewBox="0 0 25 25" 69 + class="group-hover:text-blue-400 transition-colors"> 70 + <path 71 + fill="currentColor" 72 + d="m 16.208435,23.914069 c -0.06147,-0.02273 -0.147027,-0.03034 -0.190158,-0.01691 -0.197279,0.06145 -1.31068,-0.230493 -1.388819,-0.364153 -0.01956,-0.03344 -0.163274,-0.134049 -0.319377,-0.223561 -0.550395,-0.315603 -1.010951,-0.696643 -1.428383,-1.181771 -0.264598,-0.307509 -0.597257,-0.785384 -0.597257,-0.857979 0,-0.0216 -0.02841,-0.06243 -0.06313,-0.0907 -0.04977,-0.04053 -0.160873,0.0436 -0.52488,0.397463 -0.479803,0.466432 -0.78924,0.689475 -1.355603,0.977118 -0.183693,0.0933 -0.323426,0.179989 -0.310516,0.192658 0.02801,0.02748 -0.7656391,0.270031 -1.209129,0.369517 -0.5378332,0.120647 -1.6341809,0.08626 -1.9721503,-0.06186 C 6.7977157,23.031391 6.56735,22.957551 6.3371134,22.889782 4.9717169,22.487902 3.7511914,21.481518 3.1172396,20.234838 2.6890391,19.392772 2.5582276,18.827446 2.5610489,17.831154 2.5639589,16.802192 2.7366641,16.125844 3.2142117,15.273187 3.3040457,15.112788 3.3713143,14.976533 3.3636956,14.9704 3.3560756,14.9643 3.2459634,14.90305 3.1189994,14.834381 1.7582586,14.098312 0.77760984,12.777439 0.44909837,11.23818 0.33531456,10.705039 0.33670119,9.7067968 0.45195381,9.1778795 0.72259241,7.9359287 1.3827188,6.8888436 2.4297498,6.0407205 2.6856126,5.8334648 3.2975489,5.4910878 3.6885849,5.3364049 L 4.0584319,5.190106 4.2333984,4.860432 C 4.8393906,3.7186139 5.8908314,2.7968028 7.1056396,2.3423025 7.7690673,2.0940921 8.2290216,2.0150935 9.01853,2.0137575 c 0.9625627,-0.00163 1.629181,0.1532762 2.485864,0.5776514 l 0.271744,0.1346134 0.42911,-0.3607688 c 1.082666,-0.9102346 2.185531,-1.3136811 3.578383,-1.3090327 0.916696,0.00306 1.573918,0.1517893 2.356121,0.5331927 1.465948,0.7148 2.54506,2.0625628 2.865177,3.57848 l 0.07653,0.362429 0.515095,0.2556611 c 1.022872,0.5076874 1.756122,1.1690944 2.288361,2.0641468 0.401896,0.6758594 0.537303,1.0442682 0.675505,1.8378683 0.288575,1.6570823 -0.266229,3.3548023 -1.490464,4.5608743 -0.371074,0.36557 -0.840205,0.718265 -1.203442,0.904754 -0.144112,0.07398 -0.271303,0.15826 -0.282647,0.187269 -0.01134,0.02901 0.02121,0.142764 0.07234,0.25279 0.184248,0.396467 0.451371,1.331823 0.619371,2.168779 0.463493,2.30908 -0.754646,4.693707 -2.92278,5.721632 -0.479538,0.227352 -0.717629,0.309322 -1.144194,0.39393 -0.321869,0.06383 -1.850573,0.09139 -2.000174,0.03604 z M 12.25443,18.636956 c 0.739923,-0.24652 1.382521,-0.718922 1.874623,-1.37812 0.0752,-0.100718 0.213883,-0.275851 0.308198,-0.389167 0.09432,-0.113318 0.210136,-0.271056 0.257381,-0.350531 0.416347,-0.700389 0.680936,-1.176102 0.766454,-1.378041 0.05594,-0.132087 0.114653,-0.239607 0.130477,-0.238929 0.01583,6.79e-4 0.08126,0.08531 0.145412,0.188069 0.178029,0.285173 0.614305,0.658998 0.868158,0.743878 0.259802,0.08686 0.656158,0.09598 0.911369,0.02095 0.213812,-0.06285 0.507296,-0.298016 0.645179,-0.516947 0.155165,-0.246374 0.327989,-0.989595 0.327989,-1.410501 0,-1.26718 -0.610975,-3.143405 -1.237774,-3.801045 -0.198483,-0.2082486 -0.208557,-0.2319396 -0.208557,-0.4904655 0,-0.2517771 -0.08774,-0.5704927 -0.258476,-0.938956 C 16.694963,8.50313 16.375697,8.1377479 16.135846,7.9543702 L 15.932296,7.7987471 15.683004,7.9356529 C 15.131767,8.2383821 14.435638,8.1945733 13.943459,7.8261812 L 13.782862,7.7059758 13.686773,7.8908012 C 13.338849,8.5600578 12.487087,8.8811064 11.743178,8.6233891 11.487199,8.5347109 11.358897,8.4505994 11.063189,8.1776138 L 10.69871,7.8411436 10.453484,8.0579255 C 10.318608,8.1771557 10.113778,8.3156283 9.9983037,8.3656417 9.7041488,8.4930449 9.1808299,8.5227884 8.8979004,8.4281886 8.7754792,8.3872574 8.6687415,8.3537661 8.6607053,8.3537661 c -0.03426,0 -0.3092864,0.3066098 -0.3791974,0.42275 -0.041935,0.069664 -0.1040482,0.1266636 -0.1380294,0.1266636 -0.1316419,0 -0.4197402,0.1843928 -0.6257041,0.4004735 -0.1923125,0.2017571 -0.6853701,0.9036038 -0.8926582,1.2706578 -0.042662,0.07554 -0.1803555,0.353687 -0.3059848,0.618091 -0.1256293,0.264406 -0.3270073,0.686768 -0.4475067,0.938581 -0.1204992,0.251816 -0.2469926,0.519654 -0.2810961,0.595199 -0.2592829,0.574347 -0.285919,1.391094 -0.057822,1.77304 0.1690683,0.283105 0.4224039,0.480895 0.7285507,0.568809 0.487122,0.139885 0.9109638,-0.004 1.6013422,-0.543768 l 0.4560939,-0.356568 0.0036,0.172041 c 0.01635,0.781837 0.1831084,1.813183 0.4016641,2.484154 0.1160449,0.356262 0.3781448,0.83968 0.5614081,1.035462 0.2171883,0.232025 0.7140951,0.577268 1.0100284,0.701749 0.121485,0.0511 0.351032,0.110795 0.510105,0.132647 0.396966,0.05452 1.2105,0.02265 1.448934,-0.05679 z" /> 73 + </svg> 74 + <span>Tangled Repository</span> 75 + </a> 76 + <a 77 + href="https://github.com/stormlightlabs" 78 + target="_blank" 79 + rel="noopener noreferrer" 80 + class="flex items-center gap-3 text-neutral-400 hover:text-white transition-colors group"> 81 + <span class="i-bi-github text-lg group-hover:text-blue-400" /> 82 + <span>GitHub Organization</span> 83 + </a> 84 + </div> 85 + </section> 86 + </main> 87 + 88 + <Footer /> 89 + </div> 90 + ); 91 + 92 + export default About;
+10 -1
web/src/pages/Landing.test.tsx
··· 17 17 renderLanding(); 18 18 19 19 expect(screen.getByText(/Learning on/i)).toBeInTheDocument(); 20 - expect(screen.getByText(/the AT Protocol/i)).toBeInTheDocument(); 20 + expect(screen.getAllByText(/the AT Protocol/i).length).toBeGreaterThanOrEqual(1); 21 21 expect(screen.getByText(/Master complex topics/i)).toBeInTheDocument(); 22 22 }); 23 23 ··· 35 35 expect(screen.getByText("Flashcards")).toBeInTheDocument(); 36 36 expect(screen.getByText("Linked Notes")).toBeInTheDocument(); 37 37 expect(screen.getByText("Social Learning")).toBeInTheDocument(); 38 + }); 39 + 40 + it("renders 'How it works' section", () => { 41 + renderLanding(); 42 + 43 + expect(screen.getByText("How it works")).toBeInTheDocument(); 44 + expect(screen.getByText("Import")).toBeInTheDocument(); 45 + expect(screen.getByText("Study")).toBeInTheDocument(); 46 + expect(screen.getByText("Share")).toBeInTheDocument(); 38 47 }); 39 48 });
+167 -64
web/src/pages/Landing.tsx
··· 1 + import { Footer } from "$components/layout/Footer"; 1 2 import { A } from "@solidjs/router"; 2 - import type { Component } from "solid-js"; 3 + import type { Component, JSX } from "solid-js"; 4 + import { For } from "solid-js"; 5 + import { Motion } from "solid-motionone"; 3 6 4 - const Feature: Component<{ title: string; desc: string }> = (props) => ( 5 - <div class="border border-neutral-800 p-6 hover:border-blue-600 transition-colors group h-full"> 6 - <h3 class="text-xl font-light text-white mb-2 group-hover:text-blue-500 transition-colors">{props.title}</h3> 7 + const features = [{ 8 + title: "Flashcards", 9 + desc: "Built-in spaced repetition system (SRS) ensuring you review the right material at the right time.", 10 + icon: <span class="i-bi-card-text text-4xl" />, 11 + }, { 12 + title: "Linked Notes", 13 + desc: "Connect concepts with bidirectional links. Build a knowledge graph that grows with your understanding.", 14 + icon: <span class="i-bi-link-45deg text-4xl" />, 15 + }, { 16 + title: "Lectures & Articles", 17 + desc: "Import content directly. Highlight, annotate, and turn key insights into flashcards instantly.", 18 + icon: <span class="i-bi-book text-4xl" />, 19 + }, { 20 + title: "Social Learning", 21 + desc: "Publish your decks, follow curators, and fork existing content to improve it for everyone.", 22 + icon: <span class="i-bi-people text-4xl" />, 23 + }, { 24 + title: "Local-First", 25 + desc: "Your data lives on your device. Offline-first architecture with ATProto for decentralized sync.", 26 + icon: <span class="i-bi-hdd text-4xl" />, 27 + }, { 28 + title: "Open Source", 29 + desc: "Validates knowledge, not proprietary locks. Inspect the code, extend the schema, own the platform.", 30 + icon: ( 31 + <svg xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 25 25" class="text-4xl"> 32 + <path 33 + fill="currentColor" 34 + d="m 16.208435,23.914069 c -0.06147,-0.02273 -0.147027,-0.03034 -0.190158,-0.01691 -0.197279,0.06145 -1.31068,-0.230493 -1.388819,-0.364153 -0.01956,-0.03344 -0.163274,-0.134049 -0.319377,-0.223561 -0.550395,-0.315603 -1.010951,-0.696643 -1.428383,-1.181771 -0.264598,-0.307509 -0.597257,-0.785384 -0.597257,-0.857979 0,-0.0216 -0.02841,-0.06243 -0.06313,-0.0907 -0.04977,-0.04053 -0.160873,0.0436 -0.52488,0.397463 -0.479803,0.466432 -0.78924,0.689475 -1.355603,0.977118 -0.183693,0.0933 -0.323426,0.179989 -0.310516,0.192658 0.02801,0.02748 -0.7656391,0.270031 -1.209129,0.369517 -0.5378332,0.120647 -1.6341809,0.08626 -1.9721503,-0.06186 C 6.7977157,23.031391 6.56735,22.957551 6.3371134,22.889782 4.9717169,22.487902 3.7511914,21.481518 3.1172396,20.234838 2.6890391,19.392772 2.5582276,18.827446 2.5610489,17.831154 2.5639589,16.802192 2.7366641,16.125844 3.2142117,15.273187 3.3040457,15.112788 3.3713143,14.976533 3.3636956,14.9704 3.3560756,14.9643 3.2459634,14.90305 3.1189994,14.834381 1.7582586,14.098312 0.77760984,12.777439 0.44909837,11.23818 0.33531456,10.705039 0.33670119,9.7067968 0.45195381,9.1778795 0.72259241,7.9359287 1.3827188,6.8888436 2.4297498,6.0407205 2.6856126,5.8334648 3.2975489,5.4910878 3.6885849,5.3364049 L 4.0584319,5.190106 4.2333984,4.860432 C 4.8393906,3.7186139 5.8908314,2.7968028 7.1056396,2.3423025 7.7690673,2.0940921 8.2290216,2.0150935 9.01853,2.0137575 c 0.9625627,-0.00163 1.629181,0.1532762 2.485864,0.5776514 l 0.271744,0.1346134 0.42911,-0.3607688 c 1.082666,-0.9102346 2.185531,-1.3136811 3.578383,-1.3090327 0.916696,0.00306 1.573918,0.1517893 2.356121,0.5331927 1.465948,0.7148 2.54506,2.0625628 2.865177,3.57848 l 0.07653,0.362429 0.515095,0.2556611 c 1.022872,0.5076874 1.756122,1.1690944 2.288361,2.0641468 0.401896,0.6758594 0.537303,1.0442682 0.675505,1.8378683 0.288575,1.6570823 -0.266229,3.3548023 -1.490464,4.5608743 -0.371074,0.36557 -0.840205,0.718265 -1.203442,0.904754 -0.144112,0.07398 -0.271303,0.15826 -0.282647,0.187269 -0.01134,0.02901 0.02121,0.142764 0.07234,0.25279 0.184248,0.396467 0.451371,1.331823 0.619371,2.168779 0.463493,2.30908 -0.754646,4.693707 -2.92278,5.721632 -0.479538,0.227352 -0.717629,0.309322 -1.144194,0.39393 -0.321869,0.06383 -1.850573,0.09139 -2.000174,0.03604 z M 12.25443,18.636956 c 0.739923,-0.24652 1.382521,-0.718922 1.874623,-1.37812 0.0752,-0.100718 0.213883,-0.275851 0.308198,-0.389167 0.09432,-0.113318 0.210136,-0.271056 0.257381,-0.350531 0.416347,-0.700389 0.680936,-1.176102 0.766454,-1.378041 0.05594,-0.132087 0.114653,-0.239607 0.130477,-0.238929 0.01583,6.79e-4 0.08126,0.08531 0.145412,0.188069 0.178029,0.285173 0.614305,0.658998 0.868158,0.743878 0.259802,0.08686 0.656158,0.09598 0.911369,0.02095 0.213812,-0.06285 0.507296,-0.298016 0.645179,-0.516947 0.155165,-0.246374 0.327989,-0.989595 0.327989,-1.410501 0,-1.26718 -0.610975,-3.143405 -1.237774,-3.801045 -0.198483,-0.2082486 -0.208557,-0.2319396 -0.208557,-0.4904655 0,-0.2517771 -0.08774,-0.5704927 -0.258476,-0.938956 C 16.694963,8.50313 16.375697,8.1377479 16.135846,7.9543702 L 15.932296,7.7987471 15.683004,7.9356529 C 15.131767,8.2383821 14.435638,8.1945733 13.943459,7.8261812 L 13.782862,7.7059758 13.686773,7.8908012 C 13.338849,8.5600578 12.487087,8.8811064 11.743178,8.6233891 11.487199,8.5347109 11.358897,8.4505994 11.063189,8.1776138 L 10.69871,7.8411436 10.453484,8.0579255 C 10.318608,8.1771557 10.113778,8.3156283 9.9983037,8.3656417 9.7041488,8.4930449 9.1808299,8.5227884 8.8979004,8.4281886 8.7754792,8.3872574 8.6687415,8.3537661 8.6607053,8.3537661 c -0.03426,0 -0.3092864,0.3066098 -0.3791974,0.42275 -0.041935,0.069664 -0.1040482,0.1266636 -0.1380294,0.1266636 -0.1316419,0 -0.4197402,0.1843928 -0.6257041,0.4004735 -0.1923125,0.2017571 -0.6853701,0.9036038 -0.8926582,1.2706578 -0.042662,0.07554 -0.1803555,0.353687 -0.3059848,0.618091 -0.1256293,0.264406 -0.3270073,0.686768 -0.4475067,0.938581 -0.1204992,0.251816 -0.2469926,0.519654 -0.2810961,0.595199 -0.2592829,0.574347 -0.285919,1.391094 -0.057822,1.77304 0.1690683,0.283105 0.4224039,0.480895 0.7285507,0.568809 0.487122,0.139885 0.9109638,-0.004 1.6013422,-0.543768 l 0.4560939,-0.356568 0.0036,0.172041 c 0.01635,0.781837 0.1831084,1.813183 0.4016641,2.484154 0.1160449,0.356262 0.3781448,0.83968 0.5614081,1.035462 0.2171883,0.232025 0.7140951,0.577268 1.0100284,0.701749 0.121485,0.0511 0.351032,0.110795 0.510105,0.132647 0.396966,0.05452 1.2105,0.02265 1.448934,-0.05679 z" /> 35 + </svg> 36 + ), 37 + }]; 38 + 39 + const steps = [{ title: "Import", desc: "Create cards from articles, lectures, or write your own notes." }, { 40 + title: "Study", 41 + desc: "Review with spaced repetition — the right card at the right time.", 42 + }, { title: "Share", desc: "Publish to the AT Protocol network and discover community content." }]; 43 + 44 + const Feature: Component<{ title: string; desc: string; icon: JSX.Element }> = (props) => ( 45 + <div class="border border-neutral-800 p-6 hover:border-blue-600 transition-colors group h-full bg-neutral-900/50 backdrop-blur-sm"> 46 + <div class="w-10 h-10 mb-4 text-blue-500 group-hover:text-blue-400 transition-colors">{props.icon}</div> 47 + <h3 class="text-xl font-light text-white mb-2 group-hover:text-blue-400 transition-colors">{props.title}</h3> 7 48 <p class="text-neutral-400 font-light leading-relaxed">{props.desc}</p> 8 49 </div> 9 50 ); 10 51 11 - const Landing: Component = () => { 12 - return ( 13 - <div class="min-h-screen bg-black text-white font-sans selection:bg-blue-500/30"> 14 - <header class="border-b border-neutral-900"> 15 - <div class="max-w-7xl mx-auto px-6 h-16 flex items-center justify-between"> 16 - <div class="font-bold tracking-tight text-xl">Malfestio</div> 52 + const FloatingCard: Component<{ position: string; delay: number; children: JSX.Element }> = (props) => ( 53 + <Motion.div 54 + initial={{ opacity: 0, y: 20 }} 55 + animate={{ opacity: 1, y: 0 }} 56 + transition={{ duration: 0.8, delay: props.delay, easing: "ease-out" }} 57 + class={`absolute ${props.position}`}> 58 + <Motion.div 59 + animate={{ y: [0, -8, 0] }} 60 + transition={{ duration: 4, repeat: Infinity, easing: "ease-in-out", delay: props.delay }}> 61 + {props.children} 62 + </Motion.div> 63 + </Motion.div> 64 + ); 65 + 66 + const StepCard: Component<{ step: number; title: string; desc: string }> = (props) => ( 67 + <div class="flex flex-col items-center text-center"> 68 + <div class="w-12 h-12 rounded-full bg-blue-600 text-white flex items-center justify-center text-lg font-semibold mb-4"> 69 + {props.step} 70 + </div> 71 + <h3 class="text-xl font-medium text-white mb-2">{props.title}</h3> 72 + <p class="text-neutral-400 font-light leading-relaxed">{props.desc}</p> 73 + </div> 74 + ); 75 + 76 + const Landing: Component = () => ( 77 + <div class="min-h-screen bg-black text-white font-sans selection:bg-blue-500/30"> 78 + <header class="border-b border-neutral-900 sticky top-0 bg-black/80 backdrop-blur-md z-50"> 79 + <div class="max-w-7xl mx-auto px-6 h-16 flex items-center justify-between"> 80 + <A href="/" class="font-bold tracking-tight text-xl hover:text-blue-400 transition-colors">Malfestio</A> 81 + <div class="flex items-center gap-6"> 82 + <A href="/about" class="text-sm font-medium text-neutral-400 hover:text-white transition-colors">About</A> 17 83 <A href="/login" class="text-sm font-medium text-neutral-400 hover:text-white transition-colors">Log in</A> 18 84 </div> 19 - </header> 20 - 21 - <main> 22 - <section class="max-w-7xl mx-auto px-6 py-24 md:py-32 border-b border-neutral-900"> 85 + </div> 86 + </header> 87 + <main> 88 + <section class="relative overflow-hidden border-b border-neutral-900"> 89 + <div class="absolute inset-0 grid-pattern" /> 90 + <div class="absolute inset-0 bg-linear-to-b from-transparent via-black/30 to-black" /> 91 + <div class="absolute inset-0 pointer-events-none hidden md:block"> 92 + <FloatingCard position="top-8 right-[3%]" delay={0.1}> 93 + <div class="bg-blue-600/20 border border-blue-500/30 rounded-lg p-3 w-48 shadow-2xl backdrop-blur-sm"> 94 + <div class="text-xs text-blue-400 mb-1 uppercase tracking-wide">Note</div> 95 + <div class="text-sm text-blue-100">Spaced repetition optimizes long-term memory retention</div> 96 + </div> 97 + </FloatingCard> 98 + <FloatingCard position="top-4 right-[28%]" delay={0.3}> 99 + <div class="bg-purple-600/20 border border-purple-500/30 rounded-lg p-3 w-44 shadow-2xl backdrop-blur-sm"> 100 + <div class="text-xs text-purple-400 mb-1 uppercase tracking-wide">Note</div> 101 + <div class="text-sm text-purple-100">AT Protocol enables decentralized data ownership</div> 102 + </div> 103 + </FloatingCard> 104 + <FloatingCard position="top-40 right-[2%]" delay={0.5}> 105 + <div class="bg-orange-600/20 border border-orange-500/30 rounded-lg p-3 w-40 shadow-2xl backdrop-blur-sm"> 106 + <div class="text-xs text-orange-400 mb-1 uppercase tracking-wide">Note</div> 107 + <div class="text-sm text-orange-100">Built with Rust for performance & safety</div> 108 + </div> 109 + </FloatingCard> 110 + <FloatingCard position="top-44 right-[22%]" delay={0.7}> 111 + <div class="bg-cyan-600/20 border border-cyan-500/30 rounded-lg p-3 w-44 shadow-2xl backdrop-blur-sm"> 112 + <div class="text-xs text-cyan-400 mb-1 uppercase tracking-wide">Note</div> 113 + <div class="text-sm text-cyan-100">SolidJS for reactive, fine-grained UI updates</div> 114 + </div> 115 + </FloatingCard> 116 + <FloatingCard position="bottom-40 right-[18%]" delay={0.4}> 117 + <div class="bg-neutral-800/90 border border-neutral-700 rounded-lg p-4 w-60 shadow-2xl backdrop-blur-sm"> 118 + <div class="text-xs text-neutral-500 mb-1 uppercase tracking-wide">Front</div> 119 + <div class="text-sm text-white leading-relaxed">What is spaced repetition?</div> 120 + </div> 121 + </FloatingCard> 122 + <FloatingCard position="bottom-8 right-[4%]" delay={0.6}> 123 + <div class="bg-neutral-800/90 border border-neutral-700 rounded-lg p-4 w-64 shadow-2xl backdrop-blur-sm"> 124 + <div class="text-xs text-green-400 mb-1 uppercase tracking-wide">✓ Back</div> 125 + <div class="text-sm text-white leading-relaxed"> 126 + A learning technique that schedules reviews at optimal intervals 127 + </div> 128 + </div> 129 + </FloatingCard> 130 + </div> 131 + <div class="max-w-7xl mx-auto px-6 py-24 md:py-32 relative z-10"> 23 132 <div class="max-w-3xl"> 24 - <h1 class="text-5xl md:text-7xl font-light tracking-tight mb-8 leading-[1.1]"> 133 + <Motion.h1 134 + initial={{ opacity: 0, y: 20 }} 135 + animate={{ opacity: 1, y: 0 }} 136 + transition={{ duration: 0.6 }} 137 + class="text-5xl md:text-7xl font-light tracking-tight mb-8 leading-[1.1]"> 25 138 Learning on <br /> 26 139 <span class="text-neutral-500">the AT Protocol.</span> 27 - </h1> 28 - <p class="text-xl text-neutral-400 font-light mb-12 max-w-2xl leading-relaxed"> 140 + </Motion.h1> 141 + <Motion.p 142 + initial={{ opacity: 0, y: 20 }} 143 + animate={{ opacity: 1, y: 0 }} 144 + transition={{ duration: 0.6, delay: 0.1 }} 145 + class="text-xl text-neutral-400 font-light mb-12 max-w-2xl leading-relaxed"> 29 146 Master complex topics with spaced repetition, linked notes, and active recall. Share your decks, notes, 30 147 and discoveries with the community. 31 - </p> 32 - <div class="flex gap-4"> 148 + </Motion.p> 149 + <Motion.div 150 + initial={{ opacity: 0, y: 20 }} 151 + animate={{ opacity: 1, y: 0 }} 152 + transition={{ duration: 0.6, delay: 0.2 }} 153 + class="flex gap-4"> 33 154 <A 34 155 href="/login" 35 156 class="bg-blue-600 hover:bg-blue-700 text-white px-8 py-4 font-medium text-lg transition-colors inline-flex items-center gap-2"> 36 157 Get Started 37 158 <span class="text-xl">→</span> 38 159 </A> 39 - </div> 160 + </Motion.div> 40 161 </div> 41 - </section> 42 - 43 - <section class="max-w-7xl mx-auto px-6 py-24"> 44 - <div class="grid grid-cols-1 md:grid-cols-3 gap-6"> 45 - <Feature 46 - title="Flashcards" 47 - desc="Built-in spaced repetition system (SRS) ensuring you review the right material at the right time." /> 48 - <Feature 49 - title="Linked Notes" 50 - desc="Connect concepts with bidirectional links. Build a knowledge graph that grows with your understanding." /> 51 - <Feature 52 - title="Lectures & Articles" 53 - desc="Import content directly. Highlight, annotate, and turn key insights into flashcards instantly." /> 54 - <Feature 55 - title="Social Learning" 56 - desc="Publish your decks, follow curators, and fork existing content to improve it for everyone." /> 57 - <Feature 58 - title="Local-First" 59 - desc="Your data lives on your device. Offline-first architecture with ATProto for decentralized sync." /> 60 - <Feature 61 - title="Open Source" 62 - desc="Validates knowledge, not proprietary locks. Inspect the code, extend the schema, own the platform." /> 63 - </div> 64 - </section> 65 - </main> 66 - 67 - <footer class="border-t border-[#393939] py-12 bg-[#161616]"> 68 - <div class="max-w-7xl mx-auto px-6 text-[#C6C6C6] text-xs font-light flex flex-col md:flex-row justify-between items-center gap-4"> 69 - <p> 70 - © 2025 Stormlight Labs. Made with ⚡️ by 71 - <a href="https://desertthunder.dev" target="_blank" class="hover:text-[#F4F4F4] transition-colors"> 72 - Owais. 73 - </a> 74 - </p> 75 - <div class="flex gap-6"> 76 - <a href="https://github.com/stormlightlabs" target="_blank" class="hover:text-[#F4F4F4] transition-colors"> 77 - GitHub 78 - </a> 79 - <a href="#" class="hover:text-[#F4F4F4] transition-colors">Docs</a> 80 - <a href="#" class="hover:text-[#F4F4F4] transition-colors">Privacy</a> 162 + </div> 163 + </section> 164 + <section class="max-w-7xl mx-auto px-6 py-24"> 165 + <div class="grid grid-cols-1 md:grid-cols-3 gap-6"> 166 + <For each={features}>{(f) => <Feature title={f.title} desc={f.desc} icon={f.icon} />}</For> 167 + </div> 168 + </section> 169 + <section class="border-t border-neutral-900 py-24 relative"> 170 + <div class="absolute inset-0 grid-pattern" /> 171 + <div class="absolute inset-0 bg-linear-to-t from-transparent via-black/30 to-black" /> 172 + <div class="max-w-5xl mx-auto px-6 relative z-10"> 173 + <h2 class="text-3xl md:text-4xl font-light text-center mb-16">How it works</h2> 174 + <div class="flex flex-col md:flex-row items-center justify-center gap-8 md:gap-4"> 175 + <For each={steps}> 176 + {(s, i) => ( 177 + <> 178 + <StepCard step={i() + 1} title={s.title} desc={s.desc} /> 179 + {i() < steps.length - 1 && <div class="hidden md:block text-neutral-500 text-3xl">→</div>} 180 + </> 181 + )} 182 + </For> 81 183 </div> 82 184 </div> 83 - </footer> 84 - </div> 85 - ); 86 - }; 185 + </section> 186 + </main> 187 + <Footer /> 188 + </div> 189 + ); 87 190 88 191 export default Landing;