diff --git a/.gitignore b/.gitignore index 866fc4c..d89fb01 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +.env + # Logs logs *.log diff --git a/package-lock.json b/package-lock.json index 81d7736..89aac81 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,10 @@ "@radix-ui/react-toggle": "^1.1.8", "@shikijs/colorized-brackets": "^3.6.0", "@tailwindcss/vite": "^4.1.6", + "@tanstack/react-query": "^5.90.5", + "@tanstack/react-query-devtools": "^5.90.2", "@vitejs/plugin-react-swc": "^3.10.2", + "axios": "^1.12.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "gray-matter": "^4.0.3", @@ -2706,6 +2709,59 @@ "vite": "^5.2.0 || ^6" } }, + "node_modules/@tanstack/query-core": { + "version": "5.90.5", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.5.tgz", + "integrity": "sha512-wLamYp7FaDq6ZnNehypKI5fNvxHPfTYylE0m/ZpuuzJfJqhR5Pxg9gvGBHZx4n7J+V5Rg5mZxHHTlv25Zt5u+w==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/query-devtools": { + "version": "5.90.1", + "resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.90.1.tgz", + "integrity": "sha512-GtINOPjPUH0OegJExZ70UahT9ykmAhmtNVcmtdnOZbxLwT7R5OmRztR5Ahe3/Cu7LArEmR6/588tAycuaWb1xQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.90.5", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.5.tgz", + "integrity": "sha512-pN+8UWpxZkEJ/Rnnj2v2Sxpx1WFlaa9L6a4UO89p6tTQbeo+m0MS8oYDjbggrR8QcTyjKoYWKS3xJQGr3ExT8Q==", + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "5.90.5" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, + "node_modules/@tanstack/react-query-devtools": { + "version": "5.90.2", + "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.90.2.tgz", + "integrity": "sha512-vAXJzZuBXtCQtrY3F/yUNJCV4obT/A/n81kb3+YqLbro5Z2+phdAbceO+deU3ywPw8B42oyJlp4FhO0SoivDFQ==", + "license": "MIT", + "dependencies": { + "@tanstack/query-devtools": "5.90.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@tanstack/react-query": "^5.90.2", + "react": "^18 || ^19" + } + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -3153,6 +3209,23 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz", + "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -3252,7 +3325,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -3428,6 +3500,18 @@ "simple-swizzle": "^0.2.2" } }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/comma-separated-tokens": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", @@ -3556,6 +3640,15 @@ "dev": true, "license": "MIT" }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -3601,7 +3694,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -3653,7 +3745,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -3663,7 +3754,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -3673,7 +3763,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -3682,6 +3771,21 @@ "node": ">= 0.4" } }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/esbuild": { "version": "0.25.4", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz", @@ -4192,6 +4296,63 @@ "dev": true, "license": "ISC" }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/form-data/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -4230,7 +4391,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4250,7 +4410,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -4275,7 +4434,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dev": true, "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", @@ -4315,7 +4473,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -4388,7 +4545,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -4397,11 +4553,25 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -5014,7 +5184,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -5555,6 +5724,12 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", diff --git a/package.json b/package.json index 5f9639a..7dc7dd8 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,10 @@ "@radix-ui/react-toggle": "^1.1.8", "@shikijs/colorized-brackets": "^3.6.0", "@tailwindcss/vite": "^4.1.6", + "@tanstack/react-query": "^5.90.5", + "@tanstack/react-query-devtools": "^5.90.2", "@vitejs/plugin-react-swc": "^3.10.2", + "axios": "^1.12.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "gray-matter": "^4.0.3", diff --git a/src/api/fosstodon-api.ts b/src/api/fosstodon-api.ts new file mode 100644 index 0000000..f120d76 --- /dev/null +++ b/src/api/fosstodon-api.ts @@ -0,0 +1,11 @@ +import axios from "axios" + +const fosstodonApi = axios.create({ + baseURL: import.meta.env.VITE_FOSSTODON_API_URL, + timeout: 10000, + headers: { + Authorization: import.meta.env.VITE_FOSSTODON_BEARER_TOKEN, + }, +}) + +export default fosstodonApi diff --git a/src/components/Header.tsx b/src/components/Header.tsx index ad53b64..0cf0cbc 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -3,6 +3,8 @@ import { Button } from "@/components/ui/button" import { useTheme } from "@/context/ThemeProvider" import { MoonStar, MenuIcon } from "lucide-react" import { Link } from "react-router" +import headerImage from "../images/radigue_gruvbox.png" +import controlPanel from "../images/control-panel.png" import { NavigationMenu, NavigationMenuContent, @@ -20,19 +22,19 @@ const Menu = () => { {/* Desktop menu - hidden on mobile, visible on md+ */} -
- +
+ Posts - + About @@ -41,11 +43,11 @@ const Menu = () => { {/* Mobile dropdown - visible only on small screens */} - + - + Posts @@ -67,29 +69,52 @@ const Menu = () => { const Header = () => { const { theme, setTheme } = useTheme() return ( -
+
+
+ +
+
-
- - setTheme(theme === "dark" ? "light" : "dark") - } - > - - +
+ {/* + + setTheme(theme === "dark" ? "light" : "dark") + } + > + + + + */} + {/* diff --git a/src/components/TodayILearnedCard.tsx b/src/components/TodayILearnedCard.tsx new file mode 100644 index 0000000..392227d --- /dev/null +++ b/src/components/TodayILearnedCard.tsx @@ -0,0 +1,27 @@ +import { Card, CardFooter } from "./ui/card" + +const TodayILearnedCard = ({ tootBody, avatar }) => { + return ( + <> + +
+ +
+ {/* + + + + */} + systemsobscure@fosstodon.org +
+ + + ) +} + +export default TodayILearnedCard diff --git a/src/containers/PostListing.tsx b/src/containers/PostListing.tsx index 8e820c5..e83040b 100644 --- a/src/containers/PostListing.tsx +++ b/src/containers/PostListing.tsx @@ -14,9 +14,7 @@ const PostListing = ({ posts, title, showAllButton }) => { return ( <>
-

- {title} -

+

{title}

{posts.map((post) => ( @@ -27,10 +25,10 @@ const PostListing = ({ posts, title, showAllButton }) => { > - + {post.title} @@ -47,7 +45,7 @@ const PostListing = ({ posts, title, showAllButton }) => { diff --git a/src/containers/TodayILearned.tsx b/src/containers/TodayILearned.tsx new file mode 100644 index 0000000..0013f7b --- /dev/null +++ b/src/containers/TodayILearned.tsx @@ -0,0 +1,38 @@ +// @ts-nocheck + +import { useQuery } from "@tanstack/react-query" +import fosstodonApi from "@/api/fosstodon-api" +import TodayILearnedCard from "@/components/TodayILearnedCard" + +const TodayILearned = ({}) => { + const { data, isLoading } = useQuery({ + queryKey: [`today_I_learned_toots`], + queryFn: () => + fosstodonApi.get(`statuses?tagged=TIL`).then((res) => res.data), + }) + + console.log(data) + + return ( + <> +
+

+ Today I learned... +

+ +
+ {data && + data.map((toot, i) => ( + + ))} +
+
+ + ) +} + +export default TodayILearned diff --git a/src/context/ThemeProvider.tsx b/src/context/ThemeProvider.tsx index d82f993..43d0c14 100644 --- a/src/context/ThemeProvider.tsx +++ b/src/context/ThemeProvider.tsx @@ -23,7 +23,7 @@ const ThemeProviderContext = createContext(initialState) export function ThemeProvider({ children, - defaultTheme = "system", + defaultTheme = "dark", storageKey = "vite-ui-theme", ...props }: ThemeProviderProps) { diff --git a/src/images/control-panel.png b/src/images/control-panel.png new file mode 100644 index 0000000..82ffd78 Binary files /dev/null and b/src/images/control-panel.png differ diff --git a/src/images/radigue_gruvbox.png b/src/images/radigue_gruvbox.png new file mode 100644 index 0000000..9edcb2a Binary files /dev/null and b/src/images/radigue_gruvbox.png differ diff --git a/src/main.tsx b/src/main.tsx index 1d45371..7fe8a5f 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -7,28 +7,44 @@ import BlogTemplate from "./templates/BlogTemplate" import "./index.css" import { PostsPage } from "./pages/posts" import TagTemplate from "./templates/TagTemplate" +import { QueryClient, QueryClientProvider } from "@tanstack/react-query" +import { ReactQueryDevtools } from "@tanstack/react-query-devtools" + +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + staleTime: 15 * 60 * 1000, // 15 minutes + retry: 3, + refetchOnWindowFocus: false, + }, + }, +}) export default function ScrollToTop() { - const { pathname } = useLocation() + const { pathname } = useLocation() - useEffect(() => { - window.scrollTo(1, 1) - }, [pathname]) + useEffect(() => { + window.scrollTo(1, 1) + }, [pathname]) - return null + return null } ReactDOM.createRoot(document.getElementById("root")!).render( - - - - - } /> - } /> - } /> - } /> - } /> - - - + + + + + + } /> + } /> + } /> + } /> + } /> + + + + + + ) diff --git a/src/pages/about.tsx b/src/pages/about.tsx index b6d7b11..838ed80 100644 --- a/src/pages/about.tsx +++ b/src/pages/about.tsx @@ -5,7 +5,7 @@ const AboutPage = () => { return (
-

+

About

@@ -21,7 +21,7 @@ const AboutPage = () => { National Museum of Computing @@ -43,7 +43,7 @@ const AboutPage = () => { ITV {" "} @@ -53,7 +53,7 @@ const AboutPage = () => { BBC {" "} @@ -61,7 +61,7 @@ const AboutPage = () => { Arria NLG {" "} @@ -96,7 +96,7 @@ const AboutPage = () => { I self-host my own Git forge at{" "} forgejo.systemsobscure.net {" "} diff --git a/src/pages/home.tsx b/src/pages/home.tsx index 93aeec2..8fff842 100644 --- a/src/pages/home.tsx +++ b/src/pages/home.tsx @@ -2,23 +2,26 @@ import MainTemplate from "@/templates/MainTemplate" import PostListing from "@/containers/PostListing" import { usePosts } from "@/hooks/usePosts" import roundedPortrait from "../images/round-portrait.png" +import TodayILearned from "@/containers/TodayILearned" const HomePage = () => { const { posts } = usePosts() return ( -
+
-
+ {/* +
Profile picture
+ */}
-

+

Another software engineer with a blog

diff --git a/src/pages/posts.tsx b/src/pages/posts.tsx index 47a557f..ba659a6 100644 --- a/src/pages/posts.tsx +++ b/src/pages/posts.tsx @@ -4,129 +4,129 @@ import MainTemplate from "@/templates/MainTemplate" import { useParams, useNavigate } from "react-router" import { convertDate } from "@/utils/convertDate" import { - Pagination, - PaginationContent, - PaginationItem, - PaginationNext, - PaginationPrevious, + Pagination, + PaginationContent, + PaginationItem, + PaginationNext, + PaginationPrevious, } from "@/components/ui/pagination" import { - Card, - CardDescription, - CardHeader, - CardTitle, + Card, + CardDescription, + CardHeader, + CardTitle, } from "@/components/ui/card" import { Badge } from "@/components/ui/badge" import { Link } from "react-router" import { usePosts } from "@/hooks/usePosts" const PostsPage = () => { - const { page } = useParams() + const { page } = useParams() - const navigate = useNavigate() + const navigate = useNavigate() - const { posts } = usePosts() - const postsPerPage = 8 + const { posts } = usePosts() + const postsPerPage = 8 - const currentPage = Number(page) || 1 - const totalPages = Math.ceil(posts.length / postsPerPage) + const currentPage = Number(page) || 1 + const totalPages = Math.ceil(posts.length / postsPerPage) - useEffect(() => { - // Only redirect if we have posts and the page is definitively invalid - if (totalPages > 0 && (currentPage < 1 || currentPage > totalPages)) { - navigate(`/posts/page/1`, { replace: true }) - } - }, [currentPage, totalPages, navigate]) + useEffect(() => { + // Only redirect if we have posts and the page is definitively invalid + if (totalPages > 0 && (currentPage < 1 || currentPage > totalPages)) { + navigate(`/posts/page/1`, { replace: true }) + } + }, [currentPage, totalPages, navigate]) - const currentPosts = useMemo(() => { - const startIndex = (currentPage - 1) * postsPerPage - const endIndex = startIndex + postsPerPage - return posts.slice(startIndex, endIndex) - }, [posts, currentPage, postsPerPage]) + const currentPosts = useMemo(() => { + const startIndex = (currentPage - 1) * postsPerPage + const endIndex = startIndex + postsPerPage + return posts.slice(startIndex, endIndex) + }, [posts, currentPage, postsPerPage]) - const hasNextPage = currentPage < totalPages - const hasPrevPage = currentPage > 1 + const hasNextPage = currentPage < totalPages + const hasPrevPage = currentPage > 1 - const goToNextPage = () => { - if (hasNextPage) { - navigate(`/posts/page/${currentPage + 1}`) - } - } + const goToNextPage = () => { + if (hasNextPage) { + navigate(`/posts/page/${currentPage + 1}`) + } + } - const goToPrevPage = () => { - if (hasPrevPage) { - navigate(`/posts/page/${currentPage - 1}`) - } - } + const goToPrevPage = () => { + if (hasPrevPage) { + navigate(`/posts/page/${currentPage - 1}`) + } + } - return ( - -

-

- All posts -

-
-
-
- {currentPosts.map((post) => ( - - - - - {post.title} - - -
- {convertDate(post.date)} -
- {post.tags.map((tag, i) => ( - { - e.preventDefault() - e.stopPropagation() - navigate(`/tags/${tag}`) - }} - > - {tag} - - ))} -
-
-
-
-
- - ))} -
- - - - - - - - - - -
- - ) + return ( + +
+

+ All posts +

+
+
+
+ {currentPosts.map((post) => ( + + + + + {post.title} + + +
+ {convertDate(post.date)} +
+ {post.tags.map((tag, i) => ( + { + e.preventDefault() + e.stopPropagation() + navigate(`/tags/${tag}`) + }} + > + {tag} + + ))} +
+
+
+
+
+ + ))} +
+ + + + + + + + + + +
+
+ ) } export { PostsPage } diff --git a/src/styles/_variables.css b/src/styles/_variables.css index e3bb3c2..16caaeb 100644 --- a/src/styles/_variables.css +++ b/src/styles/_variables.css @@ -35,37 +35,80 @@ --font-sansserif: "Inter", sans-serif; } +/* .dark { */ +/* --background: oklch(0.145 0 0); */ +/* --foreground: oklch(0.985 0 0); */ +/* --card: oklch(0.205 0 0); */ +/* --card-foreground: oklch(0.985 0 0); */ +/* --popover: oklch(0.205 0 0); */ +/* --popover-foreground: oklch(0.985 0 0); */ +/* --primary: oklch(0.922 0 0); */ +/* --primary-foreground: oklch(0.205 0 0); */ +/* --secondary: oklch(0.269 0 0); */ +/* --secondary-foreground: oklch(0.985 0 0); */ +/* --muted: oklch(0.269 0 0); */ +/* --muted-foreground: oklch(0.708 0 0); */ +/* --accent: oklch(0.269 0 0); */ +/* --accent-foreground: oklch(0.985 0 0); */ +/* --destructive: oklch(0.704 0.191 22.216); */ +/* --border: oklch(1 0 0 / 10%); */ +/* --input: oklch(1 0 0 / 15%); */ +/* --ring: oklch(0.556 0 0); */ +/* --chart-1: oklch(0.488 0.243 264.376); */ +/* --chart-2: oklch(0.696 0.17 162.48); */ +/* --chart-3: oklch(0.769 0.188 70.08); */ +/* --chart-4: oklch(0.627 0.265 303.9); */ +/* --chart-5: oklch(0.645 0.246 16.439); */ +/* --sidebar: oklch(0.205 0 0); */ +/* --sidebar-foreground: oklch(0.985 0 0); */ +/* --sidebar-primary: oklch(0.488 0.243 264.376); */ +/* --sidebar-primary-foreground: oklch(0.985 0 0); */ +/* --sidebar-accent: oklch(0.269 0 0); */ +/* --sidebar-accent-foreground: oklch(0.985 0 0); */ +/* --sidebar-border: oklch(1 0 0 / 10%); */ +/* --sidebar-ring: oklch(0.556 0 0); */ +/* } */ + .dark { - --background: oklch(0.145 0 0); - --foreground: oklch(0.985 0 0); - --card: oklch(0.205 0 0); - --card-foreground: oklch(0.985 0 0); - --popover: oklch(0.205 0 0); - --popover-foreground: oklch(0.985 0 0); - --primary: oklch(0.922 0 0); - --primary-foreground: oklch(0.205 0 0); - --secondary: oklch(0.269 0 0); - --secondary-foreground: oklch(0.985 0 0); - --muted: oklch(0.269 0 0); - --muted-foreground: oklch(0.708 0 0); - --accent: oklch(0.269 0 0); - --accent-foreground: oklch(0.985 0 0); + --background: oklch(0.2 0 0); + /* Softer dark gray instead of 0.145 */ + --foreground: oklch(0.9 0 0); + /* Softer off-white instead of 0.985 */ + --card: oklch(0.22 0 0); + /* Slightly lighter card */ + --card-foreground: oklch(0.9 0 0); + /* Match foreground */ + --popover: oklch(0.22 0 0); + --popover-foreground: oklch(0.9 0 0); + --primary: oklch(0.85 0 0); + /* Less harsh white */ + --primary-foreground: oklch(0.22 0 0); + --secondary: oklch(0.3 0 0); + /* Lighter secondary */ + --secondary-foreground: oklch(0.9 0 0); + --muted: oklch(0.3 0 0); + --muted-foreground: oklch(0.65 0 0); + /* Slightly softer */ + --accent: #458588; + + --accent-foreground: oklch(0.9 0 0); --destructive: oklch(0.704 0.191 22.216); - --border: oklch(1 0 0 / 10%); - --input: oklch(1 0 0 / 15%); + --border: oklch(1 0 0 / 15%); + /* Slightly more visible borders */ + --input: oklch(1 0 0 / 18%); --ring: oklch(0.556 0 0); --chart-1: oklch(0.488 0.243 264.376); --chart-2: oklch(0.696 0.17 162.48); --chart-3: oklch(0.769 0.188 70.08); --chart-4: oklch(0.627 0.265 303.9); --chart-5: oklch(0.645 0.246 16.439); - --sidebar: oklch(0.205 0 0); - --sidebar-foreground: oklch(0.985 0 0); + --sidebar: oklch(0.22 0 0); + /* Match card */ + --sidebar-foreground: oklch(0.9 0 0); --sidebar-primary: oklch(0.488 0.243 264.376); - --sidebar-primary-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.269 0 0); - --sidebar-accent-foreground: oklch(0.985 0 0); - --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-primary-foreground: oklch(0.9 0 0); + --sidebar-accent: oklch(0.3 0 0); + --sidebar-accent-foreground: oklch(0.9 0 0); + --sidebar-border: oklch(1 0 0 / 15%); --sidebar-ring: oklch(0.556 0 0); } - diff --git a/src/styles/shadcn-overrides.css b/src/styles/shadcn-overrides.css index eab1f04..c42bfd9 100644 --- a/src/styles/shadcn-overrides.css +++ b/src/styles/shadcn-overrides.css @@ -1,15 +1,15 @@ * { - border-color: var(--border); - outline-color: color-mix(in srgb, var(--ring) 50%, transparent); + /* border-color: var(--border);*/ + outline-color: color-mix(in srgb, var(--ring) 50%, transparent); } html { - font-family: var(--font-sansserif); + font-family: var(--font-sansserif); } body { - background-color: var(--background); - color: var(--foreground); + background-color: var(--background); + color: var(--foreground); } button, @@ -19,7 +19,7 @@ button, .btn, a[href]:not([aria-disabled="true"]), [role="button"] { - cursor: pointer; + cursor: pointer; } .shadow, @@ -29,22 +29,23 @@ a[href]:not([aria-disabled="true"]), .shadow-xl, .shadow-2xl, [class*="shadow"] { - box-shadow: none !important; + box-shadow: none !important; } .card, .dialog, .popover, .dropdown-menu { - box-shadow: none !important; + box-shadow: none !important; } -img { - max-width: 600px; - min-width: 300px; +figure > img { + max-width: 600px; + min-width: 300px; } img.rounded-image { - max-width: auto; - min-width: auto; -} \ No newline at end of file + max-width: auto; + min-width: auto; +} + diff --git a/src/styles/syntax-highlighting.css b/src/styles/syntax-highlighting.css index b65dd25..2bab701 100644 --- a/src/styles/syntax-highlighting.css +++ b/src/styles/syntax-highlighting.css @@ -4,7 +4,7 @@ code { p code { color: var(--foreground); - background: var(--color-accent); + background: var(--muted); font-size: 14px; padding: 0.2rem 0.3rem; border-radius: var(--radius); diff --git a/src/templates/BlogTemplate.tsx b/src/templates/BlogTemplate.tsx index 4bee606..1dd67eb 100644 --- a/src/templates/BlogTemplate.tsx +++ b/src/templates/BlogTemplate.tsx @@ -17,7 +17,7 @@ const BlogTemplate = () => { ) : ( <>
-

+

{post?.title}

@@ -27,7 +27,7 @@ const BlogTemplate = () => {
{post?.tags?.map((tag, i) => ( - + {tag} @@ -60,7 +60,7 @@ const BlogTemplate = () => { [&>li]:leading-[1.6] [&_li_code]:relative [&_li_code]:rounded [&_li_code]:bg-muted [&_li_code]:px-[0.3rem] [&_li_code]:py-[0.2rem] [&_li_code]:font-mono [&_li_code]:text-sm [&_li_code]:font-normal [&>p]:mt-6 [&>p]:leading-[1.6] - [&_a]:underline [&_a]:underline-offset-4 [&_a]:hover:text-muted-foreground + [&_a]:underline [&_a]:underline-offset-4 [&_a]:hover:text-accent/80 [&_a]:text-[#83a598] [&>figure]:w-full [&>figure]:flex [&>figure]:flex-col [&>figure]:items-center [&>figure]:justify-center [&>figure]:mb-6 [&>figure]:mx-auto [&>figure>img]:w-full [&>figure>figcaption]:text-sm [&>figure>figcaption]:text-muted-foreground [&>figure>figcaption]:mt-3 [&>figure>figcaption]:text-center diff --git a/src/templates/MainTemplate.tsx b/src/templates/MainTemplate.tsx index a7d88b9..635d831 100644 --- a/src/templates/MainTemplate.tsx +++ b/src/templates/MainTemplate.tsx @@ -4,29 +4,29 @@ import { ThemeProvider } from "@/context/ThemeProvider" import { useTheme } from "@/context/ThemeProvider" const MainTemplate = (props) => { - return ( - - {props.children} - - ) + return ( + + {props.children} + + ) } const MainContent = ({ children }) => { - const { theme } = useTheme() - const classes = - theme === "light" - ? "min-h-screen w-full flex flex-col overflow-x-hidden mb-15" - : "min-h-screen w-full flex flex-col overflow-x-hidden mb-15" + const { theme } = useTheme() + const classes = + theme === "light" + ? "min-h-screen w-full flex flex-col overflow-x-hidden mb-15" + : "min-h-screen w-full flex flex-col overflow-x-hidden mb-15" - return ( -
-
-
-
- {children} -
-
-
- ) + return ( +
+
+
+
+ {children} +
+
+
+ ) } export default MainTemplate