(null) - const [loading, setLoading] = useState(true) - const [error, setError] = useState (null) + const [quote, setQuote] = useState (null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState (null); useEffect(() => { const getQuote = async () => { try { - const record = await pb.collection(params.collection as string).getOne (params.quoteId as string, { requestKey: null }); + const record = await pb + .collection(params.collection as string) + .getOne(params.quoteId as string, { requestKey: null }); setQuote(record); } catch (err: any) { - setError(err) - console.error("Error:", err) + setError(err); + console.error("Error:", err); } finally { - setLoading(false) + setLoading(false); } - } - getQuote() - }, []) + }; + getQuote(); + }, []); // returnLoading...
if (loading) { - returnLoading...
+ returnLoading...
; } if (error) { - returnError: {error.message}
+ returnError: {error.message}
; } - return quote ?:No quote found.
+ return quote ? ( +++ ) : ( ++ No quote found.
+ ); } diff --git a/src/QuoteInfo.tsx b/src/QuoteInfo.tsx index 84562ae..1f944fa 100644 --- a/src/QuoteInfo.tsx +++ b/src/QuoteInfo.tsx @@ -1,36 +1,61 @@ import { NavLink } from "react-router"; -import { Quote } from "./pocketbase-types" +import { Quote } from "./pocketbase-types"; -import ClipboardIcon from "pixelarticons/svg/clipboard.svg?react" -import LinkIcon from "pixelarticons/svg/link.svg?react" +import ClipboardIcon from "pixelarticons/svg/clipboard.svg?react"; +import LinkIcon from "pixelarticons/svg/link.svg?react"; interface QuoteInfoProps { quote: Quote; } export default function QuoteInfo({ quote }: QuoteInfoProps) { - return ( //TODO: Bettes Colors ---{quote.quote}
+++- ) + ); } - diff --git a/src/QuoteList.tsx b/src/QuoteList.tsx index 702c91d..c1ae4ba 100644 --- a/src/QuoteList.tsx +++ b/src/QuoteList.tsx @@ -1,123 +1,145 @@ -import PocketBase from 'pocketbase' -import { ChangeEvent, useEffect, useState } from 'react' -import QuoteInfo from './QuoteInfo.tsx' -import { Collections, Quote, TypedPocketBase } from './pocketbase-types.ts' -import AddIcon from "pixelarticons/svg/note-plus.svg?react" -import { NavLink } from 'react-router' +import PocketBase from "pocketbase"; +import { ChangeEvent, useEffect, useState } from "react"; +import QuoteInfo from "./QuoteInfo.tsx"; +import { Collections, Quote, TypedPocketBase } from "./pocketbase-types.ts"; +import AddIcon from "pixelarticons/svg/note-plus.svg?react"; +import { NavLink } from "react-router"; //TODO: Add Comments export default function QuoteList() { - // const { quotes, loading, error } = getAllQuotes(collection) - const pb = new PocketBase("https://api.m3.fyi") as TypedPocketBase + const pb = new PocketBase("https://api.m3.fyi") as TypedPocketBase; - const [quotes, setQuotes] = useState+ {quote.quote} +
{/*TODO: Let items grow vertically */} --- {quote.context &&{ navigator.clipboard.writeText(quote.quote) }}>
-- +
+{ + navigator.clipboard.writeText(quote.quote); + }} + > +
++ + +
+ {quote.context}
} + {quote.context && ( ++ {quote.context} +
+ )}-Author:
-{quote.author}
++ Author: +
++ {quote.author} +
-Date:
-{quote.date}
++ Date: +
++ {quote.date} +
(null) - const [filteredQuotes, setFilteredQuotes] = useState(null) - const [loading, setLoading] = useState(true) - const [error, setError] = useState (null) - const [collection, setCollection] = useState (Collections.QtBit) - const [searchItem, setSearchItem] = useState ("") - const [searchFilter, setSearchFilter] = useState ("quote") + const [quotes, setQuotes] = useState (null); + const [filteredQuotes, setFilteredQuotes] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState (null); + const [collection, setCollection] = useState ( + Collections.QtBit, + ); + const [searchItem, setSearchItem] = useState (""); + const [searchFilter, setSearchFilter] = useState ("quote"); const handleInputChange = (e: ChangeEvent ) => { const searchTerm = e.target.value; - setSearchItem(searchTerm) + setSearchItem(searchTerm); let filteredItems; switch (searchFilter) { case "quote": - filteredItems = quotes?.filter((quote) => quote.quote.toLowerCase().includes(searchTerm.toLowerCase())); + filteredItems = quotes?.filter((quote) => + quote.quote.toLowerCase().includes(searchTerm.toLowerCase()), + ); break; case "context": - filteredItems = quotes?.filter((quote) => quote.context?.toLowerCase().includes(searchTerm.toLowerCase())); + filteredItems = quotes?.filter((quote) => + quote.context?.toLowerCase().includes(searchTerm.toLowerCase()), + ); break; case "author": - filteredItems = quotes?.filter((quote) => quote.author.toLowerCase().includes(searchTerm.toLowerCase())); + filteredItems = quotes?.filter((quote) => + quote.author.toLowerCase().includes(searchTerm.toLowerCase()), + ); break; default: break; } - setFilteredQuotes(filteredItems!) - } + setFilteredQuotes(filteredItems!); + }; useEffect(() => { pb.realtime.subscribe(`${collection}`, function (e) { console.log("realtime", e.record); let x = quotes!.filter((quote) => quote.id !== e.record.id); - setQuotes([e.record, ...x]) - setFilteredQuotes([e.record, ...x]) + setQuotes([e.record, ...x]); + setFilteredQuotes([e.record, ...x]); }); return () => { pb.realtime.unsubscribe(); - } - }) + }; + }); const getQuotes = async () => { try { - const records = await pb.collection(`${collection}`).getFullList ({ sort: "-created", requestKey: null }); + const records = await pb + .collection(`${collection}`) + .getFullList({ sort: "-created", requestKey: null }); setQuotes(records); setFilteredQuotes(records); } catch (err: any) { - setError(err) - console.error("Error:", error) + setError(err); + console.error("Error:", error); } finally { - setLoading(false) + setLoading(false); } - } + }; useEffect(() => { - getQuotes() - }, [collection]) + getQuotes(); + }, [collection]); return ( //TODO: Add Quote source selection --++-- - ) + ); } - diff --git a/src/index.css b/src/index.css index 19e4a1a..c84f6b2 100644 --- a/src/index.css +++ b/src/index.css @@ -1,6 +1,7 @@ @import "tailwindcss"; -:root,#root { - @apply bg-zinc-100 dark:bg-slate-700 text-black dark:text-white min-h-screen font-mono; +:root, +#root { + @apply min-h-screen bg-zinc-100 font-mono text-black dark:bg-slate-700 dark:text-white; --box: -20px 20px 0px 0px #000000; } diff --git a/src/main.tsx b/src/main.tsx index 4e388da..1c5e08a 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,19 +1,19 @@ -import { StrictMode } from 'react' -import { createRoot } from 'react-dom/client' -import './index.css' -import App from './App.tsx' -import { BrowserRouter, Routes, Route } from 'react-router' -import QuoteDetail from './QuoteDetail.tsx' -import QuoteAdd from './QuoteAdd.tsx' +import { StrictMode } from "react"; +import { createRoot } from "react-dom/client"; +import "./index.css"; +import App from "./App.tsx"; +import { BrowserRouter, Routes, Route } from "react-router"; +import QuoteDetail from "./QuoteDetail.tsx"; +import QuoteAdd from "./QuoteAdd.tsx"; -createRoot(document.getElementById('root')!).render( +createRoot(document.getElementById("root")!).render(|
-+- {loading ? (|
+handleInputChange(e)} - className='placeholder:text-slate-400 bg-slate-700' /> --|
+ onChange={(e) => handleInputChange(e)} + className="bg-slate-700 placeholder:text-slate-400" + /> +|
|
-Loading...
) : ( + {loading ? ( +Loading...
+ ) : ( //TODO: Replace div with styled QuoteInfo component{/* {filteredQuotes.map(quote =>- ) - } + )})} */} {/* {quotes != null ? (quotes.map((quote) => ( {quote.quote}))) : (No Quotes
)} */} - {filteredQuotes != null ? (filteredQuotes.map((quote) => ( -))) : ( No Quotes
)} + {filteredQuotes != null ? ( + filteredQuotes.map((quote) => ( ++ )) + ) : ( + No Quotes
+ )}, -) +); diff --git a/src/pocketbase-types.ts b/src/pocketbase-types.ts index 19eea25..f3e59b3 100644 --- a/src/pocketbase-types.ts +++ b/src/pocketbase-types.ts @@ -1,9 +1,9 @@ /** -* This file was @generated using pocketbase-typegen -*/ + * This file was @generated using pocketbase-typegen + */ -import type PocketBase from 'pocketbase' -import type { RecordService } from 'pocketbase' +import type PocketBase from "pocketbase"; +import type { RecordService } from "pocketbase"; export enum Collections { QtBit = "qt_bit", @@ -12,62 +12,65 @@ export enum Collections { } // Alias types for improved usability -export type IsoDateString = string -export type RecordIdString = string -export type HTMLString = string +export type IsoDateString = string; +export type RecordIdString = string; +export type HTMLString = string; // System fields export type BaseSystemFields - } /> - } /> - } /> + } /> + } /> + } /> = { - id: RecordIdString - collectionId: string - collectionName: Collections - expand?: T -} + id: RecordIdString; + collectionId: string; + collectionName: Collections; + expand?: T; +}; export type AuthSystemFields = { - email: string - emailVisibility: boolean - username: string - verified: boolean -} & BaseSystemFields + email: string; + emailVisibility: boolean; + username: string; + verified: boolean; +} & BaseSystemFields ; // Record types for each collection export type Quote = { - author: string - context?: string - collectionName: string - created?: IsoDateString - date: IsoDateString - id: string - quote: string - updated?: IsoDateString -} + author: string; + context?: string; + collectionName: string; + created?: IsoDateString; + date: IsoDateString; + id: string; + quote: string; + updated?: IsoDateString; +}; // Response types include system fields and match responses from the PocketBase API -export type QtBitResponse = Required & BaseSystemFields-export type QtKfkResponse = Required & BaseSystemFields-export type QtTheshegaysResponse = Required & BaseSystemFields+export type QtBitResponse = Required & + BaseSystemFields; +export type QtKfkResponse = Required & + BaseSystemFields; +export type QtTheshegaysResponse = Required & + BaseSystemFields; // Types containing all Records and Responses, useful for creating typing helper functions export type CollectionRecords = { - qt_bit: Quote - qt_kfk: Quote - qt_theshegays: Quote -} + qt_bit: Quote; + qt_kfk: Quote; + qt_theshegays: Quote; +}; export type CollectionResponses = { - qt_bit: QtBitResponse - qt_kfk: QtKfkResponse - qt_theshegays: QtTheshegaysResponse -} + qt_bit: QtBitResponse; + qt_kfk: QtKfkResponse; + qt_theshegays: QtTheshegaysResponse; +}; // Type for usage with type asserted PocketBase instance // https://github.com/pocketbase/js-sdk#specify-typescript-definitions export type TypedPocketBase = PocketBase & { - collection(idOrName: 'qt_bit'): RecordService - collection(idOrName: 'qt_kfk'): RecordService - collection(idOrName: 'qt_theshegays'): RecordService -} + collection(idOrName: "qt_bit"): RecordService ; + collection(idOrName: "qt_kfk"): RecordService ; + collection(idOrName: "qt_theshegays"): RecordService ; +}; diff --git a/src/quoteHook.tsx b/src/quoteHook.tsx index 736aca2..c40250c 100644 --- a/src/quoteHook.tsx +++ b/src/quoteHook.tsx @@ -1,29 +1,31 @@ -import PocketBase from 'pocketbase' -import { Quote, Collections, TypedPocketBase } from './pocketbase-types' -import { useEffect, useState } from 'react' +import PocketBase from "pocketbase"; +import { Quote, Collections, TypedPocketBase } from "./pocketbase-types"; +import { useEffect, useState } from "react"; -const pb = new PocketBase("https://api.m3.fyi") as TypedPocketBase +const pb = new PocketBase("https://api.m3.fyi") as TypedPocketBase; //TODO: See if logic can be moved here from QuoteList.tsx, otherwise delete this file as it is no longer needed. function getAllQuotes(collectionName: Collections) { - const [quotes, setQuotes] = useState (null) - const [loading, setLoading] = useState(true) - const [error, setError] = useState (null) + const [quotes, setQuotes] = useState (null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState (null); useEffect(() => { async function fetchQuotes() { try { - const result: Quote[] = await pb.collection(collectionName).getFullList(); - setQuotes(result) + const result: Quote[] = await pb + .collection(collectionName) + .getFullList(); + setQuotes(result); } catch (err: any) { - setError(err) - console.error("Couldn't fetch data", err) + setError(err); + console.error("Couldn't fetch data", err); } finally { - setLoading(false) + setLoading(false); } } fetchQuotes(); - }, [collectionName]) //Re-fetch on collection change - return { quotes, loading, error } + }, [collectionName]); //Re-fetch on collection change + return { quotes, loading, error }; } export default getAllQuotes; diff --git a/vite.config.ts b/vite.config.ts index a857aee..1d767c6 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,8 +1,8 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react-swc' -import tailwindcss from '@tailwindcss/vite' -import svgr from 'vite-plugin-svgr' +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react-swc"; +import tailwindcss from "@tailwindcss/vite"; +import svgr from "vite-plugin-svgr"; // https://vite.dev/config/ export default defineConfig({ plugins: [react(), tailwindcss(), svgr()], -}) +});