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.

initial commit

Owais Jamil 92e2f56e

+366
+21
.gitignore
··· 1 + # Generated by Cargo 2 + # will have compiled files and executables 3 + debug 4 + target 5 + 6 + # These are backup files generated by rustfmt 7 + **/*.rs.bk 8 + 9 + # MSVC Windows builds of rustc generate these, which store debugging information 10 + *.pdb 11 + 12 + # Generated by cargo mutants 13 + # Contains mutation testing data 14 + **/mutants.out*/ 15 + 16 + # RustRover 17 + # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 18 + # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 19 + # and can be added to the global gitignore or merged into this file. For a more nuclear 20 + # option (not recommended) you can uncomment the following to ignore the entire idea folder. 21 + #.idea/
+3
Cargo.toml
··· 1 + [workspace] 2 + resolver = "2" 3 + members = ["crates/cli", "crates/core", "crates/server"]
+22
README.md
··· 1 + # Malfestio 2 + 3 + Malfestio is a learning OS: flashcards + notes + lectures + articles, designed for daily study. 4 + 5 + Social layer: publish/share/remix learning artifacts; follow curators; discuss. 6 + 7 + ## Principles 8 + 9 + - Local-first study experience; offline study must not feel "second-class". 10 + - Shareable artifacts are portable: Lexicon-defined schemas + stable IDs. 11 + - Privacy by design: progress + recall history are private unless explicitly 12 + shared. 13 + 14 + ### Data Model 15 + 16 + - Note: markdown + structure + citations + links to sources. 17 + - Card: front/back (+ optional cloze, audio, image, code block). 18 + - Deck: ordered/clustered cards (+ metadata, tags). 19 + - Lecture: external URL + outline + timestamps + linked notes/cards. 20 + - Article: URL + extracted text (readability style heuristics) + highlights + 21 + linked notes/cards. 22 + - Collection/Path: curated bundle of decks + notes + sources.
+6
crates/cli/Cargo.toml
··· 1 + [package] 2 + name = "malfestio-cli" 3 + version = "0.1.0" 4 + edition = "2024" 5 + 6 + [dependencies]
+3
crates/cli/src/main.rs
··· 1 + fn main() { 2 + println!("Hello, world!"); 3 + }
+6
crates/core/Cargo.toml
··· 1 + [package] 2 + name = "malfestio-core" 3 + version = "0.1.0" 4 + edition = "2024" 5 + 6 + [dependencies]
+14
crates/core/src/lib.rs
··· 1 + pub fn add(left: u64, right: u64) -> u64 { 2 + left + right 3 + } 4 + 5 + #[cfg(test)] 6 + mod tests { 7 + use super::*; 8 + 9 + #[test] 10 + fn it_works() { 11 + let result = add(2, 2); 12 + assert_eq!(result, 4); 13 + } 14 + }
+6
crates/server/Cargo.toml
··· 1 + [package] 2 + name = "malfestio-server" 3 + version = "0.1.0" 4 + edition = "2024" 5 + 6 + [dependencies]
+14
crates/server/src/lib.rs
··· 1 + pub fn add(left: u64, right: u64) -> u64 { 2 + left + right 3 + } 4 + 5 + #[cfg(test)] 6 + mod tests { 7 + use super::*; 8 + 9 + #[test] 10 + fn it_works() { 11 + let result = add(2, 2); 12 + assert_eq!(result, 4); 13 + } 14 + }
+24
web/.gitignore
··· 1 + # Logs 2 + logs 3 + *.log 4 + npm-debug.log* 5 + yarn-debug.log* 6 + yarn-error.log* 7 + pnpm-debug.log* 8 + lerna-debug.log* 9 + 10 + node_modules 11 + dist 12 + dist-ssr 13 + *.local 14 + 15 + # Editor directories and files 16 + .vscode/* 17 + !.vscode/extensions.json 18 + .idea 19 + .DS_Store 20 + *.suo 21 + *.ntvs* 22 + *.njsproj 23 + *.sln 24 + *.sw?
+1
web/README.md
··· 1 + # Malfestio Web
+13
web/index.html
··· 1 + <!doctype html> 2 + <html lang="en"> 3 + <head> 4 + <meta charset="UTF-8" /> 5 + <link rel="icon" type="image/svg+xml" href="/vite.svg" /> 6 + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 7 + <title>frontend</title> 8 + </head> 9 + <body> 10 + <div id="root"></div> 11 + <script type="module" src="/src/index.tsx"></script> 12 + </body> 13 + </html>
+25
web/package.json
··· 1 + { 2 + "name": "malfestio-web", 3 + "private": true, 4 + "version": "0.0.0", 5 + "type": "module", 6 + "scripts": { 7 + "dev": "vite", 8 + "build": "tsc -b && vite build", 9 + "preview": "vite preview" 10 + }, 11 + "dependencies": { 12 + "solid-js": "^1.9.10" 13 + }, 14 + "devDependencies": { 15 + "@types/node": "^24.10.1", 16 + "typescript": "~5.9.3", 17 + "vite": "npm:rolldown-vite@7.2.5", 18 + "vite-plugin-solid": "^2.11.10" 19 + }, 20 + "pnpm": { 21 + "overrides": { 22 + "vite": "npm:rolldown-vite@7.2.5" 23 + } 24 + } 25 + }
+1
web/public/vite.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
+27
web/src/App.css
··· 1 + #root { 2 + max-width: 1280px; 3 + margin: 0 auto; 4 + padding: 2rem; 5 + text-align: center; 6 + } 7 + 8 + .logo { 9 + height: 6em; 10 + padding: 1.5em; 11 + will-change: filter; 12 + transition: filter 300ms; 13 + } 14 + .logo:hover { 15 + filter: drop-shadow(0 0 2em #646cffaa); 16 + } 17 + .logo.solid:hover { 18 + filter: drop-shadow(0 0 2em #61dafbaa); 19 + } 20 + 21 + .card { 22 + padding: 2em; 23 + } 24 + 25 + .read-the-docs { 26 + color: #888; 27 + }
+35
web/src/App.tsx
··· 1 + import { createSignal } from 'solid-js' 2 + import solidLogo from './assets/solid.svg' 3 + import viteLogo from '/vite.svg' 4 + import './App.css' 5 + 6 + function App() { 7 + const [count, setCount] = createSignal(0) 8 + 9 + return ( 10 + <> 11 + <div> 12 + <a href="https://vite.dev" target="_blank"> 13 + <img src={viteLogo} class="logo" alt="Vite logo" /> 14 + </a> 15 + <a href="https://solidjs.com" target="_blank"> 16 + <img src={solidLogo} class="logo solid" alt="Solid logo" /> 17 + </a> 18 + </div> 19 + <h1>Vite + Solid</h1> 20 + <div class="card"> 21 + <button onClick={() => setCount((count) => count + 1)}> 22 + count is {count()} 23 + </button> 24 + <p> 25 + Edit <code>src/App.tsx</code> and save to test HMR 26 + </p> 27 + </div> 28 + <p class="read-the-docs"> 29 + Click on the Vite and Solid logos to learn more 30 + </p> 31 + </> 32 + ) 33 + } 34 + 35 + export default App
+1
web/src/assets/solid.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 166 155.3"><path d="M163 35S110-4 69 5l-3 1c-6 2-11 5-14 9l-2 3-15 26 26 5c11 7 25 10 38 7l46 9 18-30z" fill="#76b3e1"/><linearGradient id="a" gradientUnits="userSpaceOnUse" x1="27.5" y1="3" x2="152" y2="63.5"><stop offset=".1" stop-color="#76b3e1"/><stop offset=".3" stop-color="#dcf2fd"/><stop offset="1" stop-color="#76b3e1"/></linearGradient><path d="M163 35S110-4 69 5l-3 1c-6 2-11 5-14 9l-2 3-15 26 26 5c11 7 25 10 38 7l46 9 18-30z" opacity=".3" fill="url(#a)"/><path d="M52 35l-4 1c-17 5-22 21-13 35 10 13 31 20 48 15l62-21S92 26 52 35z" fill="#518ac8"/><linearGradient id="b" gradientUnits="userSpaceOnUse" x1="95.8" y1="32.6" x2="74" y2="105.2"><stop offset="0" stop-color="#76b3e1"/><stop offset=".5" stop-color="#4377bb"/><stop offset="1" stop-color="#1f3b77"/></linearGradient><path d="M52 35l-4 1c-17 5-22 21-13 35 10 13 31 20 48 15l62-21S92 26 52 35z" opacity=".3" fill="url(#b)"/><linearGradient id="c" gradientUnits="userSpaceOnUse" x1="18.4" y1="64.2" x2="144.3" y2="149.8"><stop offset="0" stop-color="#315aa9"/><stop offset=".5" stop-color="#518ac8"/><stop offset="1" stop-color="#315aa9"/></linearGradient><path d="M134 80a45 45 0 00-48-15L24 85 4 120l112 19 20-36c4-7 3-15-2-23z" fill="url(#c)"/><linearGradient id="d" gradientUnits="userSpaceOnUse" x1="75.2" y1="74.5" x2="24.4" y2="260.8"><stop offset="0" stop-color="#4377bb"/><stop offset=".5" stop-color="#1a336b"/><stop offset="1" stop-color="#1a336b"/></linearGradient><path d="M114 115a45 45 0 00-48-15L4 120s53 40 94 30l3-1c17-5 23-21 13-34z" fill="url(#d)"/></svg>
+68
web/src/index.css
··· 1 + :root { 2 + font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; 3 + line-height: 1.5; 4 + font-weight: 400; 5 + 6 + color-scheme: light dark; 7 + color: rgba(255, 255, 255, 0.87); 8 + background-color: #242424; 9 + 10 + font-synthesis: none; 11 + text-rendering: optimizeLegibility; 12 + -webkit-font-smoothing: antialiased; 13 + -moz-osx-font-smoothing: grayscale; 14 + } 15 + 16 + a { 17 + font-weight: 500; 18 + color: #646cff; 19 + text-decoration: inherit; 20 + } 21 + a:hover { 22 + color: #535bf2; 23 + } 24 + 25 + body { 26 + margin: 0; 27 + display: flex; 28 + place-items: center; 29 + min-width: 320px; 30 + min-height: 100vh; 31 + } 32 + 33 + h1 { 34 + font-size: 3.2em; 35 + line-height: 1.1; 36 + } 37 + 38 + button { 39 + border-radius: 8px; 40 + border: 1px solid transparent; 41 + padding: 0.6em 1.2em; 42 + font-size: 1em; 43 + font-weight: 500; 44 + font-family: inherit; 45 + background-color: #1a1a1a; 46 + cursor: pointer; 47 + transition: border-color 0.25s; 48 + } 49 + button:hover { 50 + border-color: #646cff; 51 + } 52 + button:focus, 53 + button:focus-visible { 54 + outline: 4px auto -webkit-focus-ring-color; 55 + } 56 + 57 + @media (prefers-color-scheme: light) { 58 + :root { 59 + color: #213547; 60 + background-color: #ffffff; 61 + } 62 + a:hover { 63 + color: #747bff; 64 + } 65 + button { 66 + background-color: #f9f9f9; 67 + } 68 + }
+8
web/src/index.tsx
··· 1 + /* @refresh reload */ 2 + import { render } from 'solid-js/web' 3 + import './index.css' 4 + import App from './App.tsx' 5 + 6 + const root = document.getElementById('root') 7 + 8 + render(() => <App />, root!)
+29
web/tsconfig.app.json
··· 1 + { 2 + "compilerOptions": { 3 + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", 4 + "target": "ES2022", 5 + "useDefineForClassFields": true, 6 + "module": "ESNext", 7 + "lib": ["ES2022", "DOM", "DOM.Iterable"], 8 + "types": ["vite/client"], 9 + "skipLibCheck": true, 10 + 11 + /* Bundler mode */ 12 + "moduleResolution": "bundler", 13 + "allowImportingTsExtensions": true, 14 + "verbatimModuleSyntax": true, 15 + "moduleDetection": "force", 16 + "noEmit": true, 17 + "jsx": "preserve", 18 + "jsxImportSource": "solid-js", 19 + 20 + /* Linting */ 21 + "strict": true, 22 + "noUnusedLocals": true, 23 + "noUnusedParameters": true, 24 + "erasableSyntaxOnly": true, 25 + "noFallthroughCasesInSwitch": true, 26 + "noUncheckedSideEffectImports": true 27 + }, 28 + "include": ["src"] 29 + }
+7
web/tsconfig.json
··· 1 + { 2 + "files": [], 3 + "references": [ 4 + { "path": "./tsconfig.app.json" }, 5 + { "path": "./tsconfig.node.json" } 6 + ] 7 + }
+26
web/tsconfig.node.json
··· 1 + { 2 + "compilerOptions": { 3 + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 4 + "target": "ES2023", 5 + "lib": ["ES2023"], 6 + "module": "ESNext", 7 + "types": ["node"], 8 + "skipLibCheck": true, 9 + 10 + /* Bundler mode */ 11 + "moduleResolution": "bundler", 12 + "allowImportingTsExtensions": true, 13 + "verbatimModuleSyntax": true, 14 + "moduleDetection": "force", 15 + "noEmit": true, 16 + 17 + /* Linting */ 18 + "strict": true, 19 + "noUnusedLocals": true, 20 + "noUnusedParameters": true, 21 + "erasableSyntaxOnly": true, 22 + "noFallthroughCasesInSwitch": true, 23 + "noUncheckedSideEffectImports": true 24 + }, 25 + "include": ["vite.config.ts"] 26 + }
+6
web/vite.config.ts
··· 1 + import { defineConfig } from 'vite' 2 + import solid from 'vite-plugin-solid' 3 + 4 + export default defineConfig({ 5 + plugins: [solid()], 6 + })