style: change theme and header
All checks were successful
Deploy Blog / deploy (push) Successful in 1m38s
All checks were successful
Deploy Blog / deploy (push) Successful in 1m38s
This commit is contained in:
parent
899e3d8cb7
commit
50751e0c20
20 changed files with 574 additions and 232 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1,3 +1,5 @@
|
|||
.env
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
|
|
|||
199
package-lock.json
generated
199
package-lock.json
generated
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
11
src/api/fosstodon-api.ts
Normal file
11
src/api/fosstodon-api.ts
Normal file
|
|
@ -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
|
||||
|
|
@ -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 = () => {
|
|||
<NavigationMenu>
|
||||
<NavigationMenuList>
|
||||
{/* Desktop menu - hidden on mobile, visible on md+ */}
|
||||
<div className="hidden md:flex md:space-x-1">
|
||||
<NavigationMenuItem className="border">
|
||||
<div className="hidden md:flex md:space-x-3">
|
||||
<NavigationMenuItem className="">
|
||||
<NavigationMenuLink
|
||||
asChild
|
||||
className={navigationMenuTriggerStyle()}
|
||||
className={`${navigationMenuTriggerStyle()} border-0 rounded bg-accent/20 backdrop-blur-md hover:bg-accent/40 active:bg-accent/40 focus-visible:outline-none font-semibold transition-colors`}
|
||||
>
|
||||
<Link to="/posts/page/1">Posts</Link>
|
||||
</NavigationMenuLink>
|
||||
</NavigationMenuItem>
|
||||
<NavigationMenuItem className="border">
|
||||
<NavigationMenuItem className="">
|
||||
<NavigationMenuLink
|
||||
asChild
|
||||
className={navigationMenuTriggerStyle()}
|
||||
className={`${navigationMenuTriggerStyle()} border-0 rounded bg-accent/20 backdrop-blur-md hover:bg-accent/40 active:bg-accent/40 focus-visible:outline-none font-semibold transition-colors`}
|
||||
>
|
||||
<Link to="/about">About</Link>
|
||||
</NavigationMenuLink>
|
||||
|
|
@ -41,11 +43,11 @@ const Menu = () => {
|
|||
|
||||
{/* Mobile dropdown - visible only on small screens */}
|
||||
<NavigationMenuItem className="md:hidden px-4">
|
||||
<NavigationMenuTrigger className="border rounded-none">
|
||||
<NavigationMenuTrigger className="border-0 rounded bg-accent/20 backdrop-blur-md hover:bg-accent/40 active:bg-accent/40 focus-visible:outline-none font-semibold border-none">
|
||||
<MenuIcon />
|
||||
</NavigationMenuTrigger>
|
||||
|
||||
<NavigationMenuContent>
|
||||
<NavigationMenuContent className="bg-accent/20 border-none active:border-none">
|
||||
<NavigationMenuLink asChild>
|
||||
<Link to="/posts/page/1" className="block">
|
||||
Posts
|
||||
|
|
@ -67,29 +69,52 @@ const Menu = () => {
|
|||
const Header = () => {
|
||||
const { theme, setTheme } = useTheme()
|
||||
return (
|
||||
<header className="w-full h-12 flex items-center justify-center border-b fixed top-0 z-20 bg-sidebar">
|
||||
<header className="w-full h-15 flex items-center justify-center border-b border-border border-b-1 fixed top-0 z-20 bg-sidebar">
|
||||
<div
|
||||
className="absolute inset-0 opacity-70 dark:opacity-40"
|
||||
style={{
|
||||
backgroundImage: `url(${headerImage})`,
|
||||
backgroundSize: "cover",
|
||||
backgroundPosition: "center 30%",
|
||||
backgroundRepeat: "no-repeat",
|
||||
filter: "blur(0px) grayscale(10%)",
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-background/40 via-background/30 to-background/40 dark:from-background/60 dark:via-background/50 dark:to-background/60" />
|
||||
|
||||
<div className="w-full px-0 md:px-4 flex items-center justify-between">
|
||||
<div className="flex items-center md:px-0 px-4">
|
||||
<Button
|
||||
variant="ghost"
|
||||
asChild
|
||||
className="border md:border-none rounded-none"
|
||||
className="border-0 rounded bg-accent/40 backdrop-blur-sm hover:bg-background/40 active:bg-background/40 focus-visible:outline-none transition-colors"
|
||||
// className="border-0 rounded-none bg-background/20 backdrop-blur-sm hover:bg-background/40 transition-colors"
|
||||
// className="border-0 rounded-none bg-background/40 backdrop-blur-md hover:bg-background transition-colors"
|
||||
//
|
||||
//className="border md:border-none rounded-none z-500"
|
||||
>
|
||||
<Link to="/">
|
||||
<span className="text-lg font-semibold">Systems Obscure</span>
|
||||
<span className="text-xl tracking-normal font-bold">
|
||||
Systems Obscure
|
||||
</span>
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex itemr justify-between md:gap-4">
|
||||
<Toggle
|
||||
className="border bg-background rounded-none"
|
||||
pressed={theme === "dark"}
|
||||
onPressedChange={() =>
|
||||
setTheme(theme === "dark" ? "light" : "dark")
|
||||
}
|
||||
>
|
||||
<MoonStar size={10} />
|
||||
</Toggle>
|
||||
<div className="flex itemr justify-between md:gap-4 z-500">
|
||||
{/*
|
||||
<Toggle
|
||||
className="border bg-background rounded-none"
|
||||
pressed={theme === "dark"}
|
||||
onPressedChange={() =>
|
||||
setTheme(theme === "dark" ? "light" : "dark")
|
||||
}
|
||||
>
|
||||
<MoonStar size={10} />
|
||||
</Toggle>
|
||||
|
||||
*/}
|
||||
|
||||
<Menu />
|
||||
|
||||
{/*
|
||||
|
|
|
|||
27
src/components/TodayILearnedCard.tsx
Normal file
27
src/components/TodayILearnedCard.tsx
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import { Card, CardFooter } from "./ui/card"
|
||||
|
||||
const TodayILearnedCard = ({ tootBody, avatar }) => {
|
||||
return (
|
||||
<>
|
||||
<Card className="flex flex-col h-full hover:bg-primary/5 py-6 px-0 rounded-none">
|
||||
<div
|
||||
className="px-5 font-mono text-[14px]"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: tootBody.replace("#TIL", " ").substring(0, 220),
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="px-6 text-sm font-semibold flex items-center gap-2">
|
||||
{/*
|
||||
|
||||
|
||||
<img src={avatar} className="object-contain rounded-full" />
|
||||
*/}
|
||||
systemsobscure@fosstodon.org
|
||||
</div>
|
||||
</Card>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default TodayILearnedCard
|
||||
|
|
@ -14,9 +14,7 @@ const PostListing = ({ posts, title, showAllButton }) => {
|
|||
return (
|
||||
<>
|
||||
<div className="mb-5">
|
||||
<h2 className="scroll-m-20 text-[1.3rem] font-semibold border-b pb-2">
|
||||
{title}
|
||||
</h2>
|
||||
<h2 className="scroll-m-20 text-[1.5rem] font-bold ">{title}</h2>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-1 gap-3">
|
||||
{posts.map((post) => (
|
||||
|
|
@ -27,10 +25,10 @@ const PostListing = ({ posts, title, showAllButton }) => {
|
|||
>
|
||||
<Card
|
||||
key={post.slug}
|
||||
className="flex flex-col h-full hover:bg-primary/5 py-4 rounded-none"
|
||||
className="flex flex-col h-full hover:bg-primary/5 py-4 rounded border-none "
|
||||
>
|
||||
<CardHeader className="">
|
||||
<CardTitle className="leading-snug font-semibold ">
|
||||
<CardTitle className="leading-snug font-bold ">
|
||||
{post.title}
|
||||
</CardTitle>
|
||||
<CardDescription className="text-sm text-muted-foreground">
|
||||
|
|
@ -47,7 +45,7 @@ const PostListing = ({ posts, title, showAllButton }) => {
|
|||
<Button
|
||||
asChild
|
||||
variant="secondary"
|
||||
className="w-full mt-4 rounded-none border-1"
|
||||
className="w-full mt-4 rounded bg-accent/20 hover:bg-accent/40"
|
||||
>
|
||||
<Link to="/posts/page/1">View all</Link>
|
||||
</Button>
|
||||
|
|
|
|||
38
src/containers/TodayILearned.tsx
Normal file
38
src/containers/TodayILearned.tsx
Normal file
|
|
@ -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 (
|
||||
<>
|
||||
<div className="mt-8">
|
||||
<h2 className="scroll-m-20 text-[1.3rem] font-semibold border-b pb-2 mb-5">
|
||||
Today I learned...
|
||||
</h2>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-1 gap-3">
|
||||
{data &&
|
||||
data.map((toot, i) => (
|
||||
<TodayILearnedCard
|
||||
key={i}
|
||||
tootBody={toot?.content}
|
||||
avatar={toot?.account.header}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default TodayILearned
|
||||
|
|
@ -23,7 +23,7 @@ const ThemeProviderContext = createContext<ThemeProviderState>(initialState)
|
|||
|
||||
export function ThemeProvider({
|
||||
children,
|
||||
defaultTheme = "system",
|
||||
defaultTheme = "dark",
|
||||
storageKey = "vite-ui-theme",
|
||||
...props
|
||||
}: ThemeProviderProps) {
|
||||
|
|
|
|||
BIN
src/images/control-panel.png
Normal file
BIN
src/images/control-panel.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.3 MiB |
BIN
src/images/radigue_gruvbox.png
Normal file
BIN
src/images/radigue_gruvbox.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 139 KiB |
50
src/main.tsx
50
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(
|
||||
<StrictMode>
|
||||
<BrowserRouter>
|
||||
<ScrollToTop />
|
||||
<Routes>
|
||||
<Route index element={<HomePage />} />
|
||||
<Route path="/about" element={<AboutPage />} />
|
||||
<Route path="/posts/page/:page" element={<PostsPage />} />
|
||||
<Route path="/posts/:slug" element={<BlogTemplate />} />
|
||||
<Route path="/tags/:tag" element={<TagTemplate />} />
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
</StrictMode>
|
||||
<StrictMode>
|
||||
<BrowserRouter>
|
||||
<ScrollToTop />
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<Routes>
|
||||
<Route index element={<HomePage />} />
|
||||
<Route path="/about" element={<AboutPage />} />
|
||||
<Route path="/posts/page/:page" element={<PostsPage />} />
|
||||
<Route path="/posts/:slug" element={<BlogTemplate />} />
|
||||
<Route path="/tags/:tag" element={<TagTemplate />} />
|
||||
</Routes>
|
||||
|
||||
<ReactQueryDevtools initialIsOpen={false} />
|
||||
</QueryClientProvider>
|
||||
</BrowserRouter>
|
||||
</StrictMode>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ const AboutPage = () => {
|
|||
return (
|
||||
<MainTemplate>
|
||||
<div className="mb-5 ">
|
||||
<h2 className="scroll-m-20 text-2xl font-semibold lg:text-2xl border-b pb-3">
|
||||
<h2 className="scroll-m-20 text-3xl font-semibold lg:text-3xl pb-3">
|
||||
About
|
||||
</h2>
|
||||
</div>
|
||||
|
|
@ -21,7 +21,7 @@ const AboutPage = () => {
|
|||
<a
|
||||
href="https://www.tnmoc.org/"
|
||||
target="_blank"
|
||||
className="text-primary hover:text-primary/80"
|
||||
className="text-[#83a598] hover:text-accent/90"
|
||||
>
|
||||
National Museum of Computing
|
||||
</a>
|
||||
|
|
@ -43,7 +43,7 @@ const AboutPage = () => {
|
|||
<a
|
||||
href="https://en.wikipedia.org/wiki/ITV_(TV_network)"
|
||||
target="_blank"
|
||||
className="underline decoration-1 hover:text-primary/80 underline-offset-4"
|
||||
className="underline decoration-1 text-[#83a598] hover:text-accent/90 underline-offset-4"
|
||||
>
|
||||
ITV
|
||||
</a>{" "}
|
||||
|
|
@ -53,7 +53,7 @@ const AboutPage = () => {
|
|||
<a
|
||||
href="https://en.wikipedia.org/wiki/BBC"
|
||||
target="_blank"
|
||||
className="underline decoration-1 hover:text-primary/80 underline-offset-4"
|
||||
className="underline decoration-1 text-[#83a598] hover:text-accent/90underline-offset-4"
|
||||
>
|
||||
BBC
|
||||
</a>{" "}
|
||||
|
|
@ -61,7 +61,7 @@ const AboutPage = () => {
|
|||
<a
|
||||
href="https://www.arria.com/"
|
||||
target="_blank"
|
||||
className="underline decoration-1 hover:text-primary/80 underline-offset-4"
|
||||
className="underline decoration-1 text-[#83a598] hover:text-accent/90 underline-offset-4"
|
||||
>
|
||||
Arria NLG
|
||||
</a>{" "}
|
||||
|
|
@ -96,7 +96,7 @@ const AboutPage = () => {
|
|||
I self-host my own Git forge at{" "}
|
||||
<a
|
||||
href="https://forgejo.systemsobscure.net/thomasabishop"
|
||||
className="underline decoration-1 hover:text-primary/80 underline-offset-2"
|
||||
className="underline decoration-1 text-[#83a598] hover:text-accent/90 underline-offset-2"
|
||||
>
|
||||
forgejo.systemsobscure.net
|
||||
</a>{" "}
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<MainTemplate>
|
||||
<div className="mb-7 border border-foreground py-6 px-6 md:px-8 md:pt-9 dark:bg-sidebar">
|
||||
<div className="mb-7 border-none border-accent/40 py-6 px-6 md:px-8 md:pt-6 bg-accent/15 opacity-90 rounded">
|
||||
<div className="flex flex-col items-center md:flex-row md:items-start gap-4 md:gap-8 md:flex-row-reverse">
|
||||
<div className="flex-shrink-0">
|
||||
{/*
|
||||
<div className="flex-shrink-0">
|
||||
<img
|
||||
src={roundedPortrait}
|
||||
alt="Profile picture"
|
||||
className="rounded-image w-36 h-36 md:w-38 md:h-38 object-contain border-2 rounded-full"
|
||||
/>
|
||||
</div>
|
||||
*/}
|
||||
|
||||
<div className="text-center md:text-left flex-1">
|
||||
<h1 className="scroll-m-20 text-2xl font-semibold">
|
||||
<h1 className="scroll-m-20 text-3xl font-bold">
|
||||
Another software engineer with a blog
|
||||
</h1>
|
||||
<p className="leading-[1.7] mt-5">
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<MainTemplate>
|
||||
<div className="mb-5 ">
|
||||
<h2 className="scroll-m-20 text-2xl font-semibold lg:text-2xl border-b pb-3">
|
||||
All posts
|
||||
</h2>
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
<div className="grid grid-cols-1 md:grid-cols-1 gap-3 flex-grow">
|
||||
{currentPosts.map((post) => (
|
||||
<Link
|
||||
to={`/posts/${post.slug}`}
|
||||
key={post.slug}
|
||||
className="block no-underline"
|
||||
>
|
||||
<Card
|
||||
key={post.slug}
|
||||
className="flex flex-col h-full hover:bg-primary/5 py-4 px-0 rounded-none"
|
||||
>
|
||||
<CardHeader>
|
||||
<CardTitle className="leading-snug font-semibold">
|
||||
{post.title}
|
||||
</CardTitle>
|
||||
<CardDescription className="text-sm text-muted-foreground">
|
||||
<div className="flex justify-between gap-2">
|
||||
<span className="text-sm">{convertDate(post.date)}</span>
|
||||
<div className="hidden md:block">
|
||||
{post.tags.map((tag, i) => (
|
||||
<Badge
|
||||
className="ml-2 cursor-pointer"
|
||||
key={i}
|
||||
variant="secondary"
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
navigate(`/tags/${tag}`)
|
||||
}}
|
||||
>
|
||||
{tag}
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
<Pagination className="mt-4">
|
||||
<PaginationContent>
|
||||
<PaginationItem>
|
||||
<PaginationPrevious
|
||||
className={`select-none ${hasPrevPage ? "cursor-pointer" : "cursor-not-allowed opacity-50"}`}
|
||||
onClick={goToPrevPage}
|
||||
/>
|
||||
</PaginationItem>
|
||||
<PaginationItem>
|
||||
<PaginationNext
|
||||
className={`select-none ${hasNextPage ? "cursor-pointer" : "cursor-not-allowed opacity-50"}`}
|
||||
onClick={goToNextPage}
|
||||
/>
|
||||
</PaginationItem>
|
||||
</PaginationContent>
|
||||
</Pagination>
|
||||
</div>
|
||||
</MainTemplate>
|
||||
)
|
||||
return (
|
||||
<MainTemplate>
|
||||
<div className="mb-5 ">
|
||||
<h2 className="scroll-m-20 text-3xl font-bold lg:text-3xl">
|
||||
All posts
|
||||
</h2>
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
<div className="grid grid-cols-1 md:grid-cols-1 gap-3 flex-grow">
|
||||
{currentPosts.map((post) => (
|
||||
<Link
|
||||
to={`/posts/${post.slug}`}
|
||||
key={post.slug}
|
||||
className="block no-underline"
|
||||
>
|
||||
<Card
|
||||
key={post.slug}
|
||||
className="flex flex-col h-full hover:bg-primary/5 py-4 rounded border-none"
|
||||
>
|
||||
<CardHeader>
|
||||
<CardTitle className="leading-snug font-bold">
|
||||
{post.title}
|
||||
</CardTitle>
|
||||
<CardDescription className="text-sm text-muted-foreground">
|
||||
<div className="flex justify-between gap-2">
|
||||
<span className="text-sm">{convertDate(post.date)}</span>
|
||||
<div className="hidden md:block">
|
||||
{post.tags.map((tag, i) => (
|
||||
<Badge
|
||||
className="ml-2 cursor-pointer"
|
||||
key={i}
|
||||
variant="secondary"
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
navigate(`/tags/${tag}`)
|
||||
}}
|
||||
>
|
||||
{tag}
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
<Pagination className="mt-4">
|
||||
<PaginationContent>
|
||||
<PaginationItem>
|
||||
<PaginationPrevious
|
||||
className={`select-none ${hasPrevPage ? "cursor-pointer" : "cursor-not-allowed opacity-50"}`}
|
||||
onClick={goToPrevPage}
|
||||
/>
|
||||
</PaginationItem>
|
||||
<PaginationItem>
|
||||
<PaginationNext
|
||||
className={`select-none ${hasNextPage ? "cursor-pointer" : "cursor-not-allowed opacity-50"}`}
|
||||
onClick={goToNextPage}
|
||||
/>
|
||||
</PaginationItem>
|
||||
</PaginationContent>
|
||||
</Pagination>
|
||||
</div>
|
||||
</MainTemplate>
|
||||
)
|
||||
}
|
||||
|
||||
export { PostsPage }
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
max-width: auto;
|
||||
min-width: auto;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ const BlogTemplate = () => {
|
|||
) : (
|
||||
<>
|
||||
<div className="mb-5">
|
||||
<h2 className="text-2xl font-semibold lg:text-2xl border-b pb-3">
|
||||
<h2 className="text-3xl font-semibold lg:text-3xl">
|
||||
{post?.title}
|
||||
</h2>
|
||||
</div>
|
||||
|
|
@ -27,7 +27,7 @@ const BlogTemplate = () => {
|
|||
</span>
|
||||
<div className="flex gap-1 mt-3 md:mt-0">
|
||||
{post?.tags?.map((tag, i) => (
|
||||
<Badge asChild variant="secondary">
|
||||
<Badge asChild variant="secondary" className="">
|
||||
<Link key={i} to={`/tags/${tag}`}>
|
||||
{tag}
|
||||
</Link>
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -4,29 +4,29 @@ import { ThemeProvider } from "@/context/ThemeProvider"
|
|||
import { useTheme } from "@/context/ThemeProvider"
|
||||
|
||||
const MainTemplate = (props) => {
|
||||
return (
|
||||
<ThemeProvider defaultTheme="light" storageKey="vite-ui-theme">
|
||||
<MainContent>{props.children}</MainContent>
|
||||
</ThemeProvider>
|
||||
)
|
||||
return (
|
||||
<ThemeProvider defaultTheme="light" storageKey="vite-ui-theme">
|
||||
<MainContent>{props.children}</MainContent>
|
||||
</ThemeProvider>
|
||||
)
|
||||
}
|
||||
|
||||
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 (
|
||||
<div className={classes}>
|
||||
<Header />
|
||||
<main className="flex-1 w-full px-2 md:px-4 flex justify-center pt-16">
|
||||
<div className="w-full max-w-3xl lg:max-w-3xl xl:max-w-3xl px-2 md:px-4 md:py-3 py-0">
|
||||
{children}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
return (
|
||||
<div className={classes}>
|
||||
<Header />
|
||||
<main className="flex-1 w-full px-2 md:px-4 flex justify-center pt-22">
|
||||
<div className="w-full max-w-3xl lg:max-w-3xl xl:max-w-3xl px-2 md:px-4 md:py-3 py-0">
|
||||
{children}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default MainTemplate
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue