From 2d270706a514e2d1db660f1f873f200f3007fd55 Mon Sep 17 00:00:00 2001 From: Aslam Date: Mon, 26 Aug 2024 19:35:00 +0700 Subject: [PATCH] fix: link (#115) * start * . * seeding connections * . * wip * wip: learning state * wip: notes section * wip: many * topics * chore: update schema * update package * update sidebar * update page section * feat: profile * fix: remove z index * fix: wrong type * add avatar * add avatar * wip * . * store page section key * remove atom page section * fix rerender * fix rerender * fix rerender * fix rerender * fix link * search light/dark mode * bubble menu ui * . * fix: remove unecessary code * chore: mark as old for old schema * chore: adapt new schema * fix: add topic schema but null for now * fix: add icon on personal link * fix: list item * fix: set url fetched when editing * fix: remove image * feat: add icon to link * feat: custom url zod validation * fix: metadata test * chore: update utils * fix: link * fix: url fetcher * . * . * fix: add link, section * chore: seeder * . * . * . * . * fix: change checkbox to learning state * fix: click outside editing form * feat: constant * chore: move to master folder * chore: adapt new schema * chore: cli for new schema * fix: new schema for dev seed * fix: seeding * update package * chore: forcegraph seed * bottombar * if isEdit delete icon * showCreate X button * . * options * chore: implement topic from public global group * chore: update learning state * fix: change implementation for outside click * chore: implement new form param * chore: update env example * feat: link form refs exception * new page button layout, link topic search fixed * chore: enable topic * chore: update seed * profile * chore: move framer motion package from root to web and add nuqs * chore: add LearningStateValue * chore: implement active state * profile * chore: use fancy switch and update const * feat: filter implementation * dropdown menu * . * sidebar topics * topic selected color * feat: topic detail * fix: collapsible page * pages - sorted by, layout, visible mode * . * . * . * topic status sidebar * topic button and count * fix: topic * page delete/topic buttons * search ui * selected topic for page * selected topic status sidebar * removed footer * update package * . --------- Co-authored-by: Nikita Co-authored-by: marshennikovaolga Co-authored-by: Kisuyo --- .gitignore | 2 +- bun.lockb | Bin 383784 -> 383000 bytes cli/run.ts | 81 ++- cli/seed.ts | 492 ++++++++++++++++-- package.json | 58 +-- web/.env.example | 4 +- web/app/(pages)/(topics)/[name]/page.tsx | 5 + web/app/(pages)/edit-profile/page.tsx | 5 + web/app/(pages)/layout.tsx | 25 +- web/app/(pages)/links/page.tsx | 5 - web/app/(pages)/page.tsx | 5 + .../(pages)/profile/_components/wrapper.tsx | 133 ++++- web/app/(topics)/[topic]/layout.tsx | 14 - web/app/(topics)/[topic]/page.tsx | 5 - web/app/api/metadata/route.test.ts | 18 +- web/app/api/metadata/route.ts | 31 +- web/app/globals.css | 30 +- web/app/page.tsx | 12 - web/components/LinkOptions.tsx | 25 + web/components/custom/ai-search.tsx | 8 +- web/components/custom/content-header.tsx | 4 +- web/components/custom/delete-modal.tsx | 37 ++ web/components/custom/la-icon.tsx | 22 + web/components/custom/page-loader.tsx | 14 + .../custom/sidebar/partial/page-section.tsx | 163 ++++-- .../sidebar/partial/profile-section.tsx | 108 ++++ .../custom/sidebar/partial/topic-section.tsx | 110 ++-- web/components/custom/sidebar/sidebar.tsx | 41 +- web/components/custom/textarea-autosize.tsx | 23 + .../components/bubble-menu/bubble-menu.tsx | 92 +++- web/components/routes/AuthHomeRoute.tsx | 19 + web/components/routes/EditProfileRoute.tsx | 45 ++ web/components/routes/PublicHomeRoute.tsx | 31 ++ web/components/routes/force-graph.tsx | 26 + .../routes/globalTopic/globalTopic.tsx | 174 ------- .../link/{wrapper.tsx => AuthHomeRoute.tsx} | 2 +- web/components/routes/link/form/index.ts | 1 + web/components/routes/link/form/link-form.tsx | 253 +++++++++ web/components/routes/link/form/manage.tsx | 468 +++-------------- .../link/form/partial/description-input.tsx | 33 ++ .../link/form/partial/floating-button.tsx | 28 + .../form/partial/learning-state-selector.tsx | 90 ++++ .../link/form/partial/notes-section.tsx | 36 ++ .../routes/link/form/partial/title-input.tsx | 36 ++ .../link/form/partial/topic-section.tsx | 74 --- .../link/form/partial/topic-selector.tsx | 90 ++++ .../routes/link/form/partial/url-badge.tsx | 35 ++ .../routes/link/form/partial/url-input.tsx | 71 +++ web/components/routes/link/form/schema.ts | 23 +- web/components/routes/link/header.tsx | 116 +++-- web/components/routes/link/list-item.tsx | 133 +++-- web/components/routes/link/list.tsx | 85 +-- web/components/routes/page/detail/wrapper.tsx | 104 ++-- web/components/routes/search/wrapper.tsx | 37 +- .../routes/topics/detail/Header.tsx | 33 ++ .../routes/topics/detail/TopicDetailRoute.tsx | 108 ++++ web/components/ui/Keybind.tsx | 42 ++ web/components/ui/avatar.tsx | 50 ++ web/components/ui/command.tsx | 8 +- web/components/ui/skeleton.tsx | 15 + web/lib/constants.ts | 15 + .../{global-link.ts => global-link.old.ts} | 2 +- .../{global-topic.ts => global-topic.old.ts} | 0 web/lib/schema/index.ts | 18 +- web/lib/schema/master/force-graph.ts | 15 + web/lib/schema/master/public-group.ts | 12 + web/lib/schema/master/topic.ts | 33 ++ web/lib/schema/personal-link.ts | 74 ++- web/lib/schema/personal-page.ts | 4 +- web/lib/utils/schema.test.ts | 39 ++ web/lib/utils/schema.ts | 42 ++ web/lib/utils/urls.ts | 6 +- web/next.config.mjs | 18 +- web/package.json | 207 ++++---- web/store/link.ts | 2 + web/store/page.ts | 3 + web/tailwind.config.ts | 1 + 77 files changed, 3002 insertions(+), 1327 deletions(-) create mode 100644 web/app/(pages)/(topics)/[name]/page.tsx create mode 100644 web/app/(pages)/edit-profile/page.tsx delete mode 100644 web/app/(pages)/links/page.tsx create mode 100644 web/app/(pages)/page.tsx delete mode 100644 web/app/(topics)/[topic]/layout.tsx delete mode 100644 web/app/(topics)/[topic]/page.tsx delete mode 100644 web/app/page.tsx create mode 100644 web/components/LinkOptions.tsx create mode 100644 web/components/custom/delete-modal.tsx create mode 100644 web/components/custom/la-icon.tsx create mode 100644 web/components/custom/page-loader.tsx create mode 100644 web/components/custom/sidebar/partial/profile-section.tsx create mode 100644 web/components/custom/textarea-autosize.tsx create mode 100644 web/components/routes/AuthHomeRoute.tsx create mode 100644 web/components/routes/EditProfileRoute.tsx create mode 100644 web/components/routes/PublicHomeRoute.tsx create mode 100644 web/components/routes/force-graph.tsx delete mode 100644 web/components/routes/globalTopic/globalTopic.tsx rename web/components/routes/link/{wrapper.tsx => AuthHomeRoute.tsx} (93%) create mode 100644 web/components/routes/link/form/index.ts create mode 100644 web/components/routes/link/form/link-form.tsx create mode 100644 web/components/routes/link/form/partial/description-input.tsx create mode 100644 web/components/routes/link/form/partial/floating-button.tsx create mode 100644 web/components/routes/link/form/partial/learning-state-selector.tsx create mode 100644 web/components/routes/link/form/partial/notes-section.tsx create mode 100644 web/components/routes/link/form/partial/title-input.tsx delete mode 100644 web/components/routes/link/form/partial/topic-section.tsx create mode 100644 web/components/routes/link/form/partial/topic-selector.tsx create mode 100644 web/components/routes/link/form/partial/url-badge.tsx create mode 100644 web/components/routes/link/form/partial/url-input.tsx create mode 100644 web/components/routes/topics/detail/Header.tsx create mode 100644 web/components/routes/topics/detail/TopicDetailRoute.tsx create mode 100644 web/components/ui/Keybind.tsx create mode 100644 web/components/ui/avatar.tsx create mode 100644 web/components/ui/skeleton.tsx create mode 100644 web/lib/constants.ts rename web/lib/schema/{global-link.ts => global-link.old.ts} (97%) rename web/lib/schema/{global-topic.ts => global-topic.old.ts} (100%) create mode 100644 web/lib/schema/master/force-graph.ts create mode 100644 web/lib/schema/master/public-group.ts create mode 100644 web/lib/schema/master/topic.ts create mode 100644 web/lib/utils/schema.test.ts create mode 100644 web/lib/utils/schema.ts create mode 100644 web/store/page.ts diff --git a/.gitignore b/.gitignore index b946812b..c589c424 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -# base .DS_Store .env .env*.local @@ -13,3 +12,4 @@ pnpm-lock.yaml # other private past-* +output diff --git a/bun.lockb b/bun.lockb index 7a133c972bc043da90615e8ba80f4aa3f0d772bb..569990d66eb59d0cc176f2e5cc59e81eb83515a1 100755 GIT binary patch delta 95036 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 Xre+g-Nx=Eqr7Q2#FVTlrc+UR?u~cPF delta 96757 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 + const globalGroup = await PublicGlobalGroup.load(globalGroupId, worker, { + root: { + topics: [ + { + latestGlobalGuide: { + sections: [ + { + links: [{}] + } + ] + } + } + ], + forceGraphs: [ + { + connections: [{}] + } + ] + } + }) + + if (!globalGroup) return // TODO: err + + // wait 10 seconds + await new Promise(resolve => setTimeout(resolve, 10000)) + + /* + * Log forceGraphs + */ + const asJsonForceGraphs = globalGroup.root.forceGraphs.map(node => { + console.log({ node }, "node") + return { + name: node.name, + prettyName: node.prettyName, + connections: node.connections?.map(connection => { + return { + name: connection?.name + } + }) + } + }) + + const asJson = globalGroup.root.topics?.map(node => { + return { + name: node.name, + prettyName: node.prettyName, + latestGlobalGuide: { + sections: node.latestGlobalGuide.sections.map(section => { + return { + title: section?.title, + links: section?.links?.map(link => { + return { + title: link?.title, + url: link?.url + } + }) + } + }) + } + } + }) + + console.log({ asJsonForceGraphs }, "asJsonForceGraphs") + console.log({ asJson }, "asJson") +} + await run() diff --git a/cli/seed.ts b/cli/seed.ts index c88d838d..0145fa48 100644 --- a/cli/seed.ts +++ b/cli/seed.ts @@ -1,11 +1,466 @@ import { getEnvOrThrow } from "@/lib/utils" -import { LaAccount } from "@/web/lib/schema" +import { Connection, ForceGraph, ListOfConnections, ListOfForceGraphs } from "@/web/lib/schema/master/force-graph" +import { PublicGlobalGroup, PublicGlobalGroupRoot } from "@/web/lib/schema/master/public-group" +import { + LatestGlobalGuide, + Link, + ListOfLinks, + ListOfSections, + ListOfTopics, + Section, + Topic +} from "@/web/lib/schema/master/topic" +import fs from "fs/promises" import { startWorker } from "jazz-nodejs" -import { Group, ID } from "jazz-tools" +import { ID } from "jazz-tools" import { appendFile } from "node:fs/promises" +import path from "path" +// Define interfaces for JSON data structures +interface LinkJson { + id?: ID + title: string + url: string +} + +interface SectionJson { + title: string + links: LinkJson[] +} + +interface TopicJson { + name: string + prettyName: string + latestGlobalGuide: { + sections: SectionJson[] + } | null +} + +// Get the Jazz worker secret from environment variables const JAZZ_WORKER_SECRET = getEnvOrThrow("JAZZ_WORKER_SECRET") +/** + * Manages links, handling deduplication and tracking duplicates. + */ +class LinkManager { + private links: Map = new Map() + private duplicateCount: number = 0 + + /** + * Adds a link to the manager, tracking duplicates. + * @param link - The link to add. + */ + addLink(link: LinkJson) { + const key = link.url + if (this.links.has(key)) { + this.duplicateCount++ + } else { + this.links.set(key, link) + } + } + + /** + * Gets all unique links. + * @returns An array of unique links. + */ + getAllLinks() { + return Array.from(this.links.values()) + } + + /** + * Gets the count of duplicate links. + * @returns The number of duplicate links. + */ + getDuplicateCount() { + return this.duplicateCount + } +} + +/** + * Starts a Jazz worker. + * @returns A Promise that resolves to the started worker. + */ +async function startJazzWorker() { + const { worker } = await startWorker({ + accountID: "co_zhvp7ryXJzDvQagX61F6RCZFJB9", + accountSecret: JAZZ_WORKER_SECRET + }) + return worker +} + +/** + * Sets up the global and admin groups. + */ +async function setup() { + console.log("Starting setup") + + const worker = await startJazzWorker() + + /* + * Create global group + */ + const publicGlobalGroup = PublicGlobalGroup.create({ owner: worker }) + publicGlobalGroup.root = PublicGlobalGroupRoot.create( + { + topics: ListOfTopics.create([], { owner: publicGlobalGroup }), + forceGraphs: ListOfForceGraphs.create([], { owner: publicGlobalGroup }) + }, + { owner: publicGlobalGroup } + ) + publicGlobalGroup.addMember("everyone", "reader") + await appendFile("./.env", `\nJAZZ_PUBLIC_GLOBAL_GROUP=${JSON.stringify(publicGlobalGroup.id)}`) + + /* + * Create admin group + */ + // const user = (await await LaAccount.createAs(worker, { + // creationProps: { name: "nikiv" } + // }))! + // const adminGlobalGroup = Group.create({ owner: worker }) + // adminGlobalGroup.addMember(user, "admin") + // await appendFile("./.env", `\nJAZZ_ADMIN_GLOBAL_GROUP=${JSON.stringify(adminGlobalGroup.id)}`) + + console.log("Setup completed successfully", publicGlobalGroup.id) +} + +/** + * Loads the global group. + * @returns A Promise that resolves to the loaded global group. + * @throws Error if the global group fails to load. + */ +async function loadGlobalGroup() { + const worker = await startJazzWorker() + + const globalGroupId = getEnvOrThrow("JAZZ_PUBLIC_GLOBAL_GROUP") as ID + + const globalGroup = await PublicGlobalGroup.load(globalGroupId, worker, { + root: { + topics: [{ latestGlobalGuide: { sections: [] } }], + forceGraphs: [{ connections: [] }] + } + }) + + if (!globalGroup) throw new Error("Failed to load global group") + + return globalGroup +} + +/** + * Processes JSON files to extract link and topic data. + * @returns A Promise that resolves to a tuple containing a LinkManager and an array of TopicJson. + */ +async function processJsonFiles(): Promise<[LinkManager, TopicJson[]]> { + const directory = path.join(__dirname, "..", "private", "data", "edgedb", "topics") + + const linkManager = new LinkManager() + const processedData: TopicJson[] = [] + + let files = await fs.readdir(directory) + files.sort((a, b) => a.localeCompare(b)) // sort files alphabetically + + files = files.slice(0, 1) // get only 1 file for testing + + for (const file of files) { + if (path.extname(file) === ".json") { + const filePath = path.join(directory, file) + try { + const data = JSON.parse(await fs.readFile(filePath, "utf-8")) as TopicJson + if (data.latestGlobalGuide) { + for (const section of data.latestGlobalGuide.sections) { + for (const link of section.links) { + linkManager.addLink(link) + } + } + } + processedData.push(data) + } catch (error) { + console.error(`Error processing file ${file}:`, error) + } + } + } + + return [linkManager, processedData] +} + +/** + * Creates a simple progress bar string. + * @param progress - Current progress (0-100). + * @param total - Total width of the progress bar. + * @returns A string representing the progress bar. + */ +function createProgressBar(progress: number, total: number = 30): string { + const filledWidth = Math.round((progress / 100) * total) + const emptyWidth = total - filledWidth + return `[${"=".repeat(filledWidth)}${" ".repeat(emptyWidth)}]` +} + +/** + * Updates the progress display in the terminal. + * @param message - The message to display. + * @param current - Current progress value. + * @param total - Total progress value. + */ +function updateProgress(message: string, current: number, total: number) { + const percentage = Math.round((current / total) * 100) + const progressBar = createProgressBar(percentage) + process.stdout.write(`\r${message} ${progressBar} ${percentage}% (${current}/${total})`) +} + +async function insertLinksInBatch(links: LinkJson[], chunkSize: number = 100) { + const globalGroup = await loadGlobalGroup() + const allCreatedLinks: Link[] = [] + const totalLinks = links.length + + for (let i = 0; i < totalLinks; i += chunkSize) { + const chunk = links.slice(i, i + chunkSize) + const rows = chunk.map(link => + Link.create( + { + title: link.title, + url: link.url + }, + { owner: globalGroup } + ) + ) + allCreatedLinks.push(...rows) + + updateProgress("Processing links:", i + chunk.length, totalLinks) + + // Add a small delay between chunks to avoid overwhelming the system + await new Promise(resolve => setTimeout(resolve, 1000)) + } + + console.log("\nFinished processing links") + return allCreatedLinks +} + +async function saveProcessedData(linkLists: Link[], topics: TopicJson[], chunkSize: number = 10) { + const globalGroup = await loadGlobalGroup() + const totalTopics = topics.length + + for (let i = 0; i < totalTopics; i += chunkSize) { + const topicChunk = topics.slice(i, i + chunkSize) + + topicChunk.forEach(topic => { + const topicModel = Topic.create( + { + name: topic.name, + prettyName: topic.prettyName, + latestGlobalGuide: LatestGlobalGuide.create( + { + sections: ListOfSections.create([], { owner: globalGroup }) + }, + { owner: globalGroup } + ) + }, + { owner: globalGroup } + ) + + if (!topic.latestGlobalGuide) { + console.error("No sections found in", topic.name) + return + } + + topic.latestGlobalGuide.sections.map(section => { + const sectionModel = Section.create( + { + title: section.title, + links: ListOfLinks.create([], { owner: globalGroup }) + }, + { owner: globalGroup } + ) + + section.links.map(link => { + const linkModel = linkLists.find(l => l.url === link.url) + if (linkModel) { + sectionModel.links?.push(linkModel) + } + }) + + topicModel.latestGlobalGuide?.sections?.push(sectionModel) + }) + + globalGroup.root.topics?.push(topicModel) + }) + + updateProgress("Processing topics:", i + topicChunk.length, totalTopics) + + // Add a small delay between chunks to avoid overwhelming the system + await new Promise(resolve => setTimeout(resolve, 1000)) + } + + console.log("\nFinished processing topics") +} + +/** + * Seeds production data. + */ +async function prodSeed() { + console.log("Starting to seed data") + + const [linkManager, processedData] = await processJsonFiles() + + console.log(`Collected ${linkManager.getAllLinks().length} unique links.`) + console.log(`Found ${linkManager.getDuplicateCount()} duplicate links.`) + + console.log("\nInserting links:") + const insertedLinks = await insertLinksInBatch(linkManager.getAllLinks(), 100) + + console.log("\nSaving processed data:") + await saveProcessedData(insertedLinks, processedData, 10) + + console.log("\nFinished seeding data") +} + +interface ForceGraphJson { + name: string + prettyName: string + connections: string[] +} + +/** + * Manages links, handling deduplication and tracking duplicates. + */ +class ConnectionManager { + private connections: Map = new Map() + private duplicateCount: number = 0 + + /** + * Adds a connection to the manager, tracking duplicates. + * @param connection - The connection to add. + */ + addConnection(connection: string) { + if (this.connections.has(connection)) { + this.duplicateCount++ + } else { + this.connections.set(connection, connection) + } + } + + /** + * Gets all unique connections. + * @returns An array of unique connections. + */ + getAllConnections() { + return Array.from(this.connections.values()) + } + + /** + * Gets the count of duplicate connections. + * @returns The number of duplicate connections. + */ + getDuplicateCount() { + return this.duplicateCount + } +} + +/** + * Inserts connections in batch. + * @param connections - An array of string objects to insert. + * @returns A Promise that resolves to an array of created Connection models. + */ +async function insertConnectionsInBatch(connections: string[]) { + const globalGroup = await loadGlobalGroup() + const rows = [] + + for (const connection of connections) { + const connectionModel = Connection.create( + { + name: connection + }, + { owner: globalGroup } + ) + rows.push(connectionModel) + } + + return rows +} + +/** + * Saves force graph data to the global group. + * @param connectionLists - An array of Connection models. + * @param forceGraphs - An array of ForceGraphJson objects. + */ +async function saveForceGraph(connectionLists: Connection[], forceGraphs: ForceGraphJson[]) { + const globalGroup = await loadGlobalGroup() + + forceGraphs.map(forceGraph => { + const forceGraphModel = ForceGraph.create( + { + name: forceGraph.name, + prettyName: forceGraph.prettyName, + connections: ListOfConnections.create([], { owner: globalGroup }) + }, + { owner: globalGroup } + ) + + forceGraph.connections.map(connection => { + const connectionModel = connectionLists.find(c => c.name === connection) + if (connectionModel) { + forceGraphModel.connections?.push(connectionModel) + } + }) + + globalGroup.root.forceGraphs?.push(forceGraphModel) + }) +} + +async function forceGraphSeed() { + console.log("Starting to seed force graph data") + + const directory = path.join(__dirname, "..", "private", "data", "edgedb") + + const connectionManager = new ConnectionManager() + const processedData: ForceGraphJson[] = [] + + const files = await fs.readdir(directory) + const file = files.find(file => file === "force-graphs.json") + + if (!file) { + console.error("No force-graphs.json file found") + return + } + + const filePath = path.join(directory, file) + + try { + const forceGraphs = JSON.parse(await fs.readFile(filePath, "utf-8")) as ForceGraphJson[] + + for (const forceGraph of forceGraphs) { + if (forceGraph.connections.length) { + for (const connection of forceGraph.connections) { + connectionManager.addConnection(connection) + } + } + + processedData.push(forceGraph) + } + } catch (error) { + console.error(`Error processing file ${file}:`, error) + } + + console.log(`Collected ${connectionManager.getAllConnections().length} unique connections.`) + console.log(`Found ${connectionManager.getDuplicateCount()} duplicate connections.`) + + const insertedConnections = await insertConnectionsInBatch(connectionManager.getAllConnections()) + await saveForceGraph(insertedConnections, processedData) + + // wait 3 seconds before finishing + await new Promise(resolve => setTimeout(resolve, 3000)) + console.log("Finished seeding force graph data") +} + +/** + * Performs a full production rebuild. + */ +async function fullProdRebuild() { + await prodSeed() + await forceGraphSeed() +} + +/** + * Main seed function to handle different commands. + */ async function seed() { const args = Bun.argv const command = args[2] @@ -20,40 +475,19 @@ async function seed() { case "prod": await prodSeed() break + case "fullProdRebuild": + await fullProdRebuild() + break + case "forceGraph": + await forceGraphSeed() + break default: console.log("Unknown command") break } - console.log("done") } catch (err) { console.error("Error occurred:", err) } } -// sets up jazz global group and writes it to .env -async function setup() { - const { worker } = await startWorker({ - accountID: "co_zhvp7ryXJzDvQagX61F6RCZFJB9", - accountSecret: JAZZ_WORKER_SECRET - }) - const user = (await await LaAccount.createAs(worker, { - creationProps: { name: "nikiv" } - }))! - const publicGlobalGroup = Group.create({ owner: worker }) - publicGlobalGroup.addMember("everyone", "reader") - await appendFile("./.env", `\nJAZZ_PUBLIC_GLOBAL_GROUP=${JSON.stringify(publicGlobalGroup.id)}`) - const adminGlobalGroup = Group.create({ owner: worker }) - adminGlobalGroup.addMember(user, "admin") - await appendFile("./.env", `\nJAZZ_ADMIN_GLOBAL_GROUP=${JSON.stringify(adminGlobalGroup.id)}`) -} - -async function prodSeed() { - const { worker } = await startWorker({ - accountID: "co_zhvp7ryXJzDvQagX61F6RCZFJB9", - accountSecret: JAZZ_WORKER_SECRET - }) - const globalGroup = await Group.load(process.env.JAZZ_PUBLIC_GLOBAL_GROUP as ID, worker, {}) - if (!globalGroup) return // TODO: err - // TODO: complete full seed (connections, topics from old LA) -} await seed() diff --git a/package.json b/package.json index e1b4a655..70c25964 100644 --- a/package.json +++ b/package.json @@ -1,31 +1,31 @@ { - "name": "learn-anything", - "scripts": { - "dev": "bun web", - "web": "cd web && bun dev", - "web:build": "bun run --filter '*' build", - "cli": "bun run --watch cli/run.ts", - "seed": "bun --watch cli/seed.ts" - }, - "workspaces": [ - "web" - ], - "dependencies": { - "jazz-nodejs": "^0.7.23", - "react-icons": "^5.2.1" - }, - "devDependencies": { - "bun-types": "^1.1.21" - }, - "prettier": { - "plugins": [ - "prettier-plugin-tailwindcss" - ], - "useTabs": true, - "semi": false, - "trailingComma": "none", - "printWidth": 120, - "arrowParens": "avoid" - }, - "license": "MIT" + "name": "learn-anything", + "scripts": { + "dev": "bun web", + "web": "cd web && bun dev", + "web:build": "bun run --filter '*' build", + "cli": "bun run --watch cli/run.ts", + "seed": "bun --watch cli/seed.ts" + }, + "workspaces": [ + "web" + ], + "dependencies": { + "jazz-nodejs": "^0.7.34", + "react-icons": "^5.3.0" + }, + "devDependencies": { + "bun-types": "^1.1.26" + }, + "prettier": { + "plugins": [ + "prettier-plugin-tailwindcss" + ], + "useTabs": true, + "semi": false, + "trailingComma": "none", + "printWidth": 120, + "arrowParens": "avoid" + }, + "license": "MIT" } diff --git a/web/.env.example b/web/.env.example index d0c69440..37112a6d 100644 --- a/web/.env.example +++ b/web/.env.example @@ -1,2 +1,4 @@ NEXT_PUBLIC_APP_NAME="Learn Anything" -NEXT_PUBLIC_APP_URL=http://localhost:3000 \ No newline at end of file +NEXT_PUBLIC_APP_URL=http://localhost:3000 + +NEXT_PUBLIC_JAZZ_GLOBAL_GROUP="" \ No newline at end of file diff --git a/web/app/(pages)/(topics)/[name]/page.tsx b/web/app/(pages)/(topics)/[name]/page.tsx new file mode 100644 index 00000000..28e0f249 --- /dev/null +++ b/web/app/(pages)/(topics)/[name]/page.tsx @@ -0,0 +1,5 @@ +import { TopicDetailRoute } from "@/components/routes/topics/detail/TopicDetailRoute" + +export default function DetailTopicPage({ params }: { params: { name: string } }) { + return +} diff --git a/web/app/(pages)/edit-profile/page.tsx b/web/app/(pages)/edit-profile/page.tsx new file mode 100644 index 00000000..3e492911 --- /dev/null +++ b/web/app/(pages)/edit-profile/page.tsx @@ -0,0 +1,5 @@ +import EditProfileRoute from "@/components/routes/EditProfileRoute" + +export default function EditProfilePage() { + return +} diff --git a/web/app/(pages)/layout.tsx b/web/app/(pages)/layout.tsx index 1c296d0d..5fecb9a3 100644 --- a/web/app/(pages)/layout.tsx +++ b/web/app/(pages)/layout.tsx @@ -1,15 +1,22 @@ import { Sidebar } from "@/components/custom/sidebar/sidebar" +import PublicHomeRoute from "@/components/routes/PublicHomeRoute" export default async function RootLayout({ children }: { children: React.ReactNode }) { - return ( -
- + // TODO: get it from jazz/clerk + const loggedIn = true -
-
- {children} -
+ if (loggedIn) { + return ( +
+ + +
+
+ {children} +
+
-
- ) + ) + } + return } diff --git a/web/app/(pages)/links/page.tsx b/web/app/(pages)/links/page.tsx deleted file mode 100644 index a8361cae..00000000 --- a/web/app/(pages)/links/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { LinkWrapper } from "@/components/routes/link/wrapper" - -export default function LinkPage() { - return -} diff --git a/web/app/(pages)/page.tsx b/web/app/(pages)/page.tsx new file mode 100644 index 00000000..5b0fdb1d --- /dev/null +++ b/web/app/(pages)/page.tsx @@ -0,0 +1,5 @@ +import AuthHomeRoute from "@/components/routes/AuthHomeRoute" + +export default function HomePage() { + return +} diff --git a/web/app/(pages)/profile/_components/wrapper.tsx b/web/app/(pages)/profile/_components/wrapper.tsx index 8db87158..829d83bb 100644 --- a/web/app/(pages)/profile/_components/wrapper.tsx +++ b/web/app/(pages)/profile/_components/wrapper.tsx @@ -1,14 +1,137 @@ "use client" import { useAccount } from "@/lib/providers/jazz-provider" +import { useParams, useRouter } from "next/navigation" +import Link from "next/link" +import { LaIcon } from "@/components/custom/la-icon" +import { Icon } from "@/components/la-editor/components/ui/icon" +import { Button } from "@/components/ui/button" -export const ProfileWrapper = () => { - const account = useAccount() +interface ProfileStatsProps { + number: number + label: string +} +interface ProfileLinksProps { + linklabel?: string + link?: string + topic?: string +} + +interface ProfilePagesProps { + topic?: string +} + +const ProfileStats: React.FC = ({ number, label }) => { return ( -
-

{account.me.profile?.name}

-

Profile Page

+
+

{number}

+

{label}

+
+ ) +} + +const ProfileLinks: React.FC = ({ linklabel, link, topic }) => { + return ( +
+
+

{linklabel || "Untitled"}

+
+ +

{link || "#"}

+
+
+
{topic || "Uncategorized"}
+
+ ) +} + +const ProfilePages: React.FC = ({ topic }) => { + return ( +
+
{topic || "Uncategorized"}
+
+ ) +} + +export const ProfileWrapper = () => { + const account = useAccount() + const params = useParams() + const username = params.username as string + + const router = useRouter() + + const clickEdit = () => router.push("/edit-profile") + + if (!account.me || !account.me.profile) { + return ( +
+
+

+ Oops! This account doesn't exist. +

+

Try searching for another.

+

+ The link you followed may be broken, or the page may have been removed. Go back to + + homepage + + . +

+
+
+ ) + } + + return ( +
+
+

Profile

+ +
+

{username}

+
+
+
+
+

{account.me.profile.name}

+
+ @

{account.me.root?.username}

+
+ + +

{account.me.root?.website}

+
+
+ +
+
+
+
+ + + +
+
+ + {/*
+

Public Pages

+ {account.me.root?.personalPages?.map((page, index) => )} +
+
+

Public Links

+ {account.me.root?.personalLinks?.map((link, index) => ( + + ))} +
*/}
) } diff --git a/web/app/(topics)/[topic]/layout.tsx b/web/app/(topics)/[topic]/layout.tsx deleted file mode 100644 index f1c3e520..00000000 --- a/web/app/(topics)/[topic]/layout.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { Sidebar } from "@/components/custom/sidebar/sidebar" - -export default function TopicsLayout({ children }: { children: React.ReactNode }) { - return ( -
- -
-
- {children} -
-
-
- ) -} diff --git a/web/app/(topics)/[topic]/page.tsx b/web/app/(topics)/[topic]/page.tsx deleted file mode 100644 index 3ead540f..00000000 --- a/web/app/(topics)/[topic]/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import GlobalTopic from "@/components/routes/globalTopic/globalTopic" - -export default function GlobalTopicPage({ params }: { params: { topic: string } }) { - return -} diff --git a/web/app/api/metadata/route.test.ts b/web/app/api/metadata/route.test.ts index 83c96baa..2567b77e 100644 --- a/web/app/api/metadata/route.test.ts +++ b/web/app/api/metadata/route.test.ts @@ -3,7 +3,7 @@ */ import { NextRequest } from "next/server" import axios from "axios" -import { GET } from "./route" +import { DEFAULT_VALUES, GET } from "./route" jest.mock("axios") const mockedAxios = axios as jest.Mocked @@ -19,7 +19,7 @@ describe("Metadata Fetcher", () => { Test Title - + ` @@ -37,7 +37,7 @@ describe("Metadata Fetcher", () => { expect(data).toEqual({ title: "Test Title", description: "Test Description", - favicon: "https://example.com/favicon.ico", + icon: "https://example.com/icon.ico", url: "https://example.com" }) }) @@ -66,9 +66,9 @@ describe("Metadata Fetcher", () => { expect(response.status).toBe(200) expect(data).toEqual({ - title: "No title available", - description: "No description available", - favicon: null, + title: DEFAULT_VALUES.TITLE, + description: DEFAULT_VALUES.DESCRIPTION, + icon: null, url: "https://example.com" }) }) @@ -92,9 +92,9 @@ describe("Metadata Fetcher", () => { expect(response.status).toBe(200) expect(data).toEqual({ - title: "No title available", - description: "No description available", - favicon: null, + title: DEFAULT_VALUES.TITLE, + description: DEFAULT_VALUES.DESCRIPTION, + icon: null, url: "https://example.com" }) }) diff --git a/web/app/api/metadata/route.ts b/web/app/api/metadata/route.ts index b0b458d5..b9487a47 100644 --- a/web/app/api/metadata/route.ts +++ b/web/app/api/metadata/route.ts @@ -1,29 +1,39 @@ import { NextRequest, NextResponse } from "next/server" import axios from "axios" import * as cheerio from "cheerio" +import { ensureUrlProtocol } from "@/lib/utils" +import { urlSchema } from "@/lib/utils/schema" interface Metadata { title: string description: string - favicon: string | null + icon: string | null url: string } -const DEFAULT_VALUES = { - TITLE: "No title available", - DESCRIPTION: "No description available", - IMAGE: null, +export const DEFAULT_VALUES = { + TITLE: "", + DESCRIPTION: "", FAVICON: null } export async function GET(request: NextRequest) { const { searchParams } = new URL(request.url) - const url = searchParams.get("url") + let url = searchParams.get("url") + + await new Promise(resolve => setTimeout(resolve, 1000)) if (!url) { return NextResponse.json({ error: "URL is required" }, { status: 400 }) } + const result = urlSchema.safeParse(url) + if (!result.success) { + throw new Error(result.error.issues.map(issue => issue.message).join(", ")) + } + + url = ensureUrlProtocol(url) + try { const { data } = await axios.get(url, { timeout: 5000, @@ -41,13 +51,12 @@ export async function GET(request: NextRequest) { $('meta[name="description"]').attr("content") || $('meta[property="og:description"]').attr("content") || DEFAULT_VALUES.DESCRIPTION, - favicon: - $('link[rel="icon"]').attr("href") || $('link[rel="shortcut icon"]').attr("href") || DEFAULT_VALUES.FAVICON, + icon: $('link[rel="icon"]').attr("href") || $('link[rel="shortcut icon"]').attr("href") || DEFAULT_VALUES.FAVICON, url: url } - if (metadata.favicon && !metadata.favicon.startsWith("http")) { - metadata.favicon = new URL(metadata.favicon, url).toString() + if (metadata.icon && !metadata.icon.startsWith("http")) { + metadata.icon = new URL(metadata.icon, url).toString() } return NextResponse.json(metadata) @@ -55,7 +64,7 @@ export async function GET(request: NextRequest) { const defaultMetadata: Metadata = { title: DEFAULT_VALUES.TITLE, description: DEFAULT_VALUES.DESCRIPTION, - favicon: DEFAULT_VALUES.FAVICON, + icon: DEFAULT_VALUES.FAVICON, url: url } return NextResponse.json(defaultMetadata) diff --git a/web/app/globals.css b/web/app/globals.css index 0214df23..29d3758a 100644 --- a/web/app/globals.css +++ b/web/app/globals.css @@ -1,26 +1,6 @@ @tailwind base; @tailwind components; @tailwind utilities; -@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"); - -body { - font-family: "Inter", sans-serif; -} - -@layer base { - body { - @apply bg-background text-foreground; - font-feature-settings: - "rlig" 1, - "calt" 1; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - overflow-x: hidden; - min-height: 100vh; - line-height: 1.5; - } -} @layer base { :root { @@ -42,17 +22,19 @@ body { --destructive-foreground: 0 0% 98%; --border: 240 5.9% 90%; --input: 240 5.9% 90%; - --ring: 240 10% 3.9%; + --result: 240 5.9% 96%; + --ring: 240 5.9% 10%; --radius: 0.5rem; --chart-1: 12 76% 61%; --chart-2: 173 58% 39%; --chart-3: 197 37% 24%; --chart-4: 43 74% 66%; --chart-5: 27 87% 67%; + --boxShadow: rgba(0, 0, 0, 0.05); } .dark { - --background: 240 10% 3.9%; + --background: 240 10% 4.5%; --foreground: 0 0% 98%; --card: 240 10% 3.9%; --card-foreground: 0 0% 98%; @@ -69,13 +51,15 @@ body { --destructive: 0 62.8% 30.6%; --destructive-foreground: 0 0% 98%; --border: 240 3.7% 15.9%; - --input: 240 3.7% 15.9%; + --input: 220 9% 10%; + --result: 0 0% 7%; --ring: 240 4.9% 83.9%; --chart-1: 220 70% 50%; --chart-2: 160 60% 45%; --chart-3: 30 80% 55%; --chart-4: 280 65% 60%; --chart-5: 340 75% 55%; + --boxShadow: rgba(255, 255, 255, 0.04); } } diff --git a/web/app/page.tsx b/web/app/page.tsx deleted file mode 100644 index 70761f42..00000000 --- a/web/app/page.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { Button } from "@/components/ui/button" -import Link from "next/link" - -export default function HomePage() { - return ( -
- - - -
- ) -} diff --git a/web/components/LinkOptions.tsx b/web/components/LinkOptions.tsx new file mode 100644 index 00000000..51f12518 --- /dev/null +++ b/web/components/LinkOptions.tsx @@ -0,0 +1,25 @@ +import { LaIcon } from "@/components/custom/la-icon" + +export default function LinkOptions() { + const buttonClass = + "block w-full flex flex-row items-center px-4 py-2 rounded-lg text-left text-sm hover:bg-gray-700/20" + + return ( +
+
+ + + +
+
+ ) +} diff --git a/web/components/custom/ai-search.tsx b/web/components/custom/ai-search.tsx index d0904d51..d670334b 100644 --- a/web/components/custom/ai-search.tsx +++ b/web/components/custom/ai-search.tsx @@ -71,14 +71,14 @@ const AiSearch: React.FC = (props: { searchQuery: string }) => { return (
-
-
+
+

✨ This is what I have found:

-
+

{error}

-
diff --git a/web/components/custom/content-header.tsx b/web/components/custom/content-header.tsx index 54870dbd..a1cffd7b 100644 --- a/web/components/custom/content-header.tsx +++ b/web/components/custom/content-header.tsx @@ -16,7 +16,7 @@ export const ContentHeader = React.forwardRef { size="icon" variant="ghost" aria-label="Menu" - className="text-primary/60 z-50" + className="text-primary/60" onClick={handleClick} > diff --git a/web/components/custom/delete-modal.tsx b/web/components/custom/delete-modal.tsx new file mode 100644 index 00000000..be8e0551 --- /dev/null +++ b/web/components/custom/delete-modal.tsx @@ -0,0 +1,37 @@ +import { Button } from "@/components/ui/button" +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle +} from "@/components/ui/dialog" + +interface DeleteModalProps { + isOpen: boolean + onClose: () => void + onConfirm: () => void + title: string +} + +export default function DeletePageModal({ isOpen, onClose, onConfirm, title }: DeleteModalProps) { + return ( + + + + Delete "{title}"? + This action cannot be undone. + + + + + + + + ) +} diff --git a/web/components/custom/la-icon.tsx b/web/components/custom/la-icon.tsx new file mode 100644 index 00000000..c0686f96 --- /dev/null +++ b/web/components/custom/la-icon.tsx @@ -0,0 +1,22 @@ +import * as React from "react" +import { cn } from "@/lib/utils" +import { icons } from "lucide-react" + +export type IconProps = { + name: keyof typeof icons + className?: string + strokeWidth?: number + [key: string]: any +} + +export const LaIcon = React.memo(({ name, className, size, strokeWidth, ...props }: IconProps) => { + const IconComponent = icons[name] + + if (!IconComponent) { + return null + } + + return +}) + +LaIcon.displayName = "LaIcon" diff --git a/web/components/custom/page-loader.tsx b/web/components/custom/page-loader.tsx new file mode 100644 index 00000000..9fb2c087 --- /dev/null +++ b/web/components/custom/page-loader.tsx @@ -0,0 +1,14 @@ +export const PageLoader = () => { + return ( +
+
+
+
Preparing application
+
+
+
+
+
+
+ ) +} diff --git a/web/components/custom/sidebar/partial/page-section.tsx b/web/components/custom/sidebar/partial/page-section.tsx index e93517cb..e9762231 100644 --- a/web/components/custom/sidebar/partial/page-section.tsx +++ b/web/components/custom/sidebar/partial/page-section.tsx @@ -1,19 +1,23 @@ -import { SidebarItem } from "../sidebar" import { z } from "zod" +import { useAtom } from "jotai" +import { useState } from "react" +import { useForm } from "react-hook-form" +import { usePathname, useRouter } from "next/navigation" import { useAccount } from "@/lib/providers/jazz-provider" -import { Input } from "@/components/ui/input" +import { cn, generateUniqueSlug } from "@/lib/utils" +import { atomWithStorage } from "jotai/utils" import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover" import { Form, FormField, FormItem, FormLabel, FormControl, FormMessage } from "@/components/ui/form" -import { PlusIcon } from "lucide-react" -import { generateUniqueSlug } from "@/lib/utils" -import { PersonalPage } from "@/lib/schema/personal-page" -import { toast } from "sonner" -import { Button } from "@/components/ui/button" -import { useForm } from "react-hook-form" +import { PersonalPage, PersonalPageLists } from "@/lib/schema/personal-page" import { zodResolver } from "@hookform/resolvers/zod" -import { useState, useEffect, useCallback } from "react" -import { useRouter } from "next/navigation" +import { Button } from "@/components/ui/button" +import { Input } from "@/components/ui/input" +import { LaIcon } from "../../la-icon" +import { toast } from "sonner" +import Link from "next/link" +import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu" +const pageSortAtom = atomWithStorage("pageSort", "title") const createPageSchema = z.object({ title: z.string({ message: "Please enter a valid title" }).min(1, { message: "Please enter a valid title" }) }) @@ -21,47 +25,114 @@ const createPageSchema = z.object({ type PageFormValues = z.infer export const PageSection: React.FC = () => { - const { me } = useAccount() - const [personalPages, setPersonalPages] = useState([]) + const [pagesSorted, setPagesSorted] = useAtom(pageSortAtom) - useEffect(() => { - if (me.root?.personalPages) { - setPersonalPages(prevPages => { - const newPages = Array.from(me.root?.personalPages ?? []).filter((page): page is PersonalPage => page !== null) - return [...prevPages, ...newPages.filter(newPage => !prevPages.some(prevPage => prevPage.id === newPage.id))] - }) - } - }, [me.root?.personalPages]) + const { me } = useAccount({ + root: { personalPages: [] } + }) - const onPageCreated = useCallback((newPage: PersonalPage) => { - setPersonalPages(prevPages => [...prevPages, newPage]) - }, []) + const pageCount = me?.root.personalPages?.length || 0 + + const sortedPages = (filter: string) => { + setPagesSorted(filter) + } return ( -
-
-
+
+ +
+ +
-
-
- {personalPages.map(page => ( - - ))} -
-
+ {me?.root.personalPages && }
) } -const CreatePageForm: React.FC<{ onPageCreated: (page: PersonalPage) => void }> = ({ onPageCreated }) => { +const PageList: React.FC<{ personalPages: PersonalPageLists; sortBy: string }> = ({ personalPages, sortBy }) => { + const pathname = usePathname() + + const sortedPages = [...personalPages] + .sort((a, b) => { + if (sortBy === "title") { + return (a?.title || "").localeCompare(b?.title || "") + } else if (sortBy === "latest") { + return ((b as any)?.createdAt?.getTime?.() ?? 0) - ((a as any)?.createdAt?.getTime?.() ?? 0) + } + return 0 + }) + .slice(0, 6) + + return ( +
+ {sortedPages.map( + page => + page?.id && ( +
+
+ +
+ +

{page.title}

+
+ +
+
+ ) + )} +
+ ) +} + +interface ShowAllFormProps { + filteredPages: (filter: string) => void +} +const ShowAllForm: React.FC = ({ filteredPages }) => { + const [pagesSorted, setPagesSorted] = useAtom(pageSortAtom) + + const handleSort = (newSort: string) => { + setPagesSorted(newSort.toLowerCase()) + filteredPages(newSort.toLowerCase()) + } + + return ( + + + + + + handleSort("title")}> + Title + {pagesSorted === "title" && } + + handleSort("manual")}> + Manual + {pagesSorted === "manual" && } + + + + ) +} + +const CreatePageForm: React.FC = () => { const [open, setOpen] = useState(false) const { me } = useAccount() const route = useRouter() @@ -88,7 +159,6 @@ const CreatePageForm: React.FC<{ onPageCreated: (page: PersonalPage) => void }> ) me.root?.personalPages?.push(newPersonalPage) - onPageCreated(newPersonalPage) form.reset() setOpen(false) @@ -103,9 +173,16 @@ const CreatePageForm: React.FC<{ onPageCreated: (page: PersonalPage) => void }> return ( - +
diff --git a/web/components/custom/sidebar/partial/profile-section.tsx b/web/components/custom/sidebar/partial/profile-section.tsx new file mode 100644 index 00000000..c150ae75 --- /dev/null +++ b/web/components/custom/sidebar/partial/profile-section.tsx @@ -0,0 +1,108 @@ +import { LaIcon } from "../../la-icon" +import { useState } from "react" +import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar" +import { Button } from "@/components/ui/button" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger +} from "@/components/ui/dropdown-menu" +import { useAccount } from "@/lib/providers/jazz-provider" +import Link from "next/link" + +const MenuItem = ({ + icon, + text, + href, + onClick, + onClose +}: { + icon: string + text: string + href?: string + onClick?: () => void + onClose: () => void +}) => { + const handleClick = () => { + onClose() + if (onClick) { + onClick() + } + } + + return ( +
+ + {href ? ( + + {text} + + ) : ( + + {text} + + )} +
+ ) +} +export const ProfileSection: React.FC = () => { + const { me, logOut } = useAccount({ + profile: true + }) + const [menuOpen, setMenuOpen] = useState(false) + + const closeMenu = () => setMenuOpen(false) + + return ( +
+
+
+ + + + + + + + + + + + + + + + + + +
+ {/*
+
+ + + + +
*/} +
+
+ ) +} diff --git a/web/components/custom/sidebar/partial/topic-section.tsx b/web/components/custom/sidebar/partial/topic-section.tsx index b713a50b..3e35de07 100644 --- a/web/components/custom/sidebar/partial/topic-section.tsx +++ b/web/components/custom/sidebar/partial/topic-section.tsx @@ -1,100 +1,66 @@ -import { useState, useEffect, useRef } from "react" -import { usePathname } from "next/navigation" -import Link from "next/link" +import { useState, useRef } from "react" import { Button } from "@/components/ui/button" -import { ChevronDown, BookOpen, Bookmark, GraduationCap, Check } from "lucide-react" +import { LaIcon } from "@/components/custom/la-icon" import { SidebarItem } from "../sidebar" -const TOPICS = ["Nix", "Javascript", "Kubernetes", "Figma", "Hiring", "Java", "IOS", "Design"] +// const TOPICS = ["Nix", "Javascript", "Kubernetes", "Figma", "Hiring", "Java", "IOS", "Design"] export const TopicSection = () => { - const [showOptions, setShowOptions] = useState(false) const [selectedStatus, setSelectedStatus] = useState(null) const sectionRef = useRef(null) const learningOptions = [ - { text: "To Learn", icon: , color: "text-white/70" }, { - text: "Learning", - icon: , - color: "text-[#D29752]" + text: "To Learn", + icon: , + color: "text-black dark:text-white" }, { - text: "Learned", - icon: , - color: "text-[#708F51]" - } + text: "Learning", + icon: , + color: "text-[#D29752]" + }, + { text: "Learned", icon: , color: "text-[#708F51]" } ] const statusSelect = (status: string) => { - setSelectedStatus(status === "Show All" ? null : status) - setShowOptions(false) + setSelectedStatus(prevStatus => (prevStatus === status ? null : status)) } - useEffect(() => { - const overlayClick = (event: MouseEvent) => { - if (sectionRef.current && !sectionRef.current.contains(event.target as Node)) { - setShowOptions(false) - } + const topicCounts = { + "To Learn": 2, + Learning: 5, + Learned: 3, + get total() { + return this["To Learn"] + this.Learning + this.Learned } - - document.addEventListener("mousedown", overlayClick) - return () => { - document.removeEventListener("mousedown", overlayClick) - } - }, []) - - const availableOptions = selectedStatus - ? [ - { - text: "Show All", - icon: , - color: "text-white" - }, - ...learningOptions.filter(option => option.text !== selectedStatus) - ] - : learningOptions - - // const topicClick = (topic: string) => { - // router.push(`/${topic.toLowerCase()}`) - // } + } return (
- - - {showOptions && ( -
- {availableOptions.map(option => ( - +
+
+ {learningOptions.map(option => ( + - ))} -
- )} -
- {TOPICS.map(topic => ( - +
+ {topicCounts[option.text as keyof typeof topicCounts]} + ))}
) } - -export default TopicSection diff --git a/web/components/custom/sidebar/sidebar.tsx b/web/components/custom/sidebar/sidebar.tsx index 1dd7ec13..22336d93 100644 --- a/web/components/custom/sidebar/sidebar.tsx +++ b/web/components/custom/sidebar/sidebar.tsx @@ -5,14 +5,14 @@ import Link from "next/link" import { usePathname } from "next/navigation" import { useMedia } from "react-use" import { useAtom } from "jotai" -import { LinkIcon, SearchIcon } from "lucide-react" +import { SearchIcon } from "lucide-react" import { Logo } from "@/components/custom/logo" import { Button } from "@/components/ui/button" import { cn } from "@/lib/utils" import { isCollapseAtom } from "@/store/sidebar" - import { PageSection } from "./partial/page-section" import { TopicSection } from "./partial/topic-section" +import { ProfileSection } from "./partial/profile-section" interface SidebarContextType { isCollapsed: boolean @@ -73,14 +73,14 @@ export const SidebarItem: React.FC = React.memo(({ label, url, const LogoAndSearch: React.FC = React.memo(() => { const pathname = usePathname() return ( -
-
- +
+
+
{pathname === "/search" ? ( - + @@ -104,21 +104,20 @@ const LogoAndSearch: React.FC = React.memo(() => { }) const SidebarContent: React.FC = React.memo(() => { - const { isCollapsed } = React.useContext(SidebarContext) - const isTablet = useMedia("(max-width: 1024px)") - return ( - + <> + + + ) }) @@ -132,7 +131,7 @@ export const Sidebar: React.FC = () => { ) const sidebarInnerClasses = cn( - "h-full w-auto min-w-56 transition-transform duration-300 ease-in-out", + "h-full w-56 min-w-56 transition-transform duration-300 ease-in-out", isCollapsed ? "-translate-x-full" : "translate-x-0" ) diff --git a/web/components/custom/textarea-autosize.tsx b/web/components/custom/textarea-autosize.tsx new file mode 100644 index 00000000..82bd33b3 --- /dev/null +++ b/web/components/custom/textarea-autosize.tsx @@ -0,0 +1,23 @@ +import * as React from "react" +import BaseTextareaAutosize from "react-textarea-autosize" +import { TextareaAutosizeProps as BaseTextareaAutosizeProps } from "react-textarea-autosize" +import { cn } from "@/lib/utils" + +export interface TextareaProps extends Omit {} + +const TextareaAutosize = React.forwardRef(({ className, style, ...props }, ref) => { + return ( + + ) +}) + +TextareaAutosize.displayName = "TextareaAutosize" + +export { TextareaAutosize } diff --git a/web/components/la-editor/components/bubble-menu/bubble-menu.tsx b/web/components/la-editor/components/bubble-menu/bubble-menu.tsx index e56e30c9..cec9a11d 100644 --- a/web/components/la-editor/components/bubble-menu/bubble-menu.tsx +++ b/web/components/la-editor/components/bubble-menu/bubble-menu.tsx @@ -5,6 +5,7 @@ import { BubbleMenu as TiptapBubbleMenu, Editor } from "@tiptap/react" import { ToolbarButton } from "../ui/toolbar-button" import { Icon } from "../ui/icon" import * as React from "react" +import { Keybind } from "@/components/ui/Keybind" export type BubbleMenuProps = { editor: Editor @@ -14,38 +15,93 @@ export const BubbleMenu = ({ editor }: BubbleMenuProps) => { const commands = useTextmenuCommands(editor) const states = useTextmenuStates(editor) + const toolbarButtonClassname = + "hover:opacity-100 transition-all dark:border-slate-500/10 border-gray-400 hover:border-b-2 active:translate-y-0 hover:translate-y-[-1.5px] hover:bg-zinc-300 dark:hover:bg-neutral-800 shadow-md rounded-[10px]" + return ( - -
- - - - - - - - - + +
+ + + + + + + + + + + + + + + + {/* */} - - - - - - - + + + + + + + + + + + {/* diff --git a/web/components/routes/AuthHomeRoute.tsx b/web/components/routes/AuthHomeRoute.tsx new file mode 100644 index 00000000..2a27c1b5 --- /dev/null +++ b/web/components/routes/AuthHomeRoute.tsx @@ -0,0 +1,19 @@ +"use client" + +import { LinkHeader } from "@/components/routes/link/header" +import { LinkList } from "@/components/routes/link/list" +import { LinkManage } from "@/components/routes/link/form/manage" +import { useAtom } from "jotai" +import { linkEditIdAtom } from "@/store/link" + +export default function AuthHomeRoute() { + const [editId] = useAtom(linkEditIdAtom) + + return ( +
+ + + +
+ ) +} diff --git a/web/components/routes/EditProfileRoute.tsx b/web/components/routes/EditProfileRoute.tsx new file mode 100644 index 00000000..69e232d3 --- /dev/null +++ b/web/components/routes/EditProfileRoute.tsx @@ -0,0 +1,45 @@ +"use client" + +import { useAccount } from "@/lib/providers/jazz-provider" + +export default function EditProfileRoute() { + const account = useAccount() + + return ( +
+

Profile

+
+
+ +
+ + +

learn-anything.xyz/@

+ +