mirror of
https://github.com/jakejarvis/jarv.is.git
synced 2025-04-26 09:25:22 -04:00
add prefix to redis keys
This commit is contained in:
parent
774c3a5d96
commit
2b9c421d42
@ -17,6 +17,7 @@ export const GET = async (): Promise<
|
||||
> => {
|
||||
// get all keys (aka slugs)
|
||||
const slugs = await redis.scan(0, {
|
||||
match: "hits:*",
|
||||
type: "string",
|
||||
// set an arbitrary yet generous upper limit, just in case...
|
||||
count: 99,
|
||||
@ -27,7 +28,7 @@ export const GET = async (): Promise<
|
||||
|
||||
// pair the slugs with their hit values
|
||||
const pages = slugs[1].map((slug, index) => ({
|
||||
slug,
|
||||
slug: slug.split(":").pop() as string, // remove the "hits:" prefix
|
||||
hits: parseInt(values[index], 10),
|
||||
}));
|
||||
|
||||
|
@ -96,7 +96,7 @@ const ContactForm = () => {
|
||||
Markdown syntax
|
||||
</Link>{" "}
|
||||
is allowed here, e.g.: <strong>**bold**</strong>, <em>_italics_</em>, [
|
||||
<Link href="https://jarv.is" plain openInNewTab>
|
||||
<Link href="https://jarv.is" plain>
|
||||
links
|
||||
</Link>
|
||||
](https://jarv.is), and <code style={{ fontFamily: "var(--fonts-mono)" }}>`code`</code>.
|
||||
|
@ -54,7 +54,7 @@ const Page = () => {
|
||||
G4techTV Canada
|
||||
</Link>{" "}
|
||||
&{" "}
|
||||
<Link href="https://leolaporte.com/" style={{ fontWeight: 700 }}>
|
||||
<Link href="https://leo.fm/" style={{ fontWeight: 700 }}>
|
||||
Leo Laporte
|
||||
</Link>
|
||||
. © 2007 G4 Media, Inc.
|
||||
|
@ -12,7 +12,7 @@ const HitCounter = async ({ slug }: { slug: string }) => {
|
||||
// TODO: maybe don't allow this? or maybe it's fine? kinda unclear how secure this is:
|
||||
// https://nextjs.org/blog/security-nextjs-server-components-actions
|
||||
// https://nextjs.org/docs/app/building-your-application/rendering/server-components
|
||||
const hits = await redis.incr(slug);
|
||||
const hits = await redis.incr(`hits:${slug}`);
|
||||
|
||||
// we have data!
|
||||
return (
|
||||
|
@ -1,45 +1,28 @@
|
||||
import NextLink from "next/link";
|
||||
import clsx from "clsx";
|
||||
import objStr from "obj-str";
|
||||
import { BASE_URL } from "../../lib/config/constants";
|
||||
import type { ComponentPropsWithoutRef } from "react";
|
||||
|
||||
import styles from "./Link.module.css";
|
||||
|
||||
export type LinkProps = ComponentPropsWithoutRef<typeof NextLink> & {
|
||||
plain?: boolean; // disable fancy text-decoration effect
|
||||
openInNewTab?: boolean;
|
||||
};
|
||||
|
||||
const Link = ({ href, rel, target, prefetch = false, plain, openInNewTab, className, ...rest }: LinkProps) => {
|
||||
const Link = ({ href, rel, target, prefetch = false, plain, className, ...rest }: LinkProps) => {
|
||||
// This component auto-detects whether or not this link should open in the same window (the default for internal
|
||||
// links) or a new tab (the default for external links). Defaults can be overridden with `openInNewTab={true}`.
|
||||
const isExternal = typeof href === "string" && !(["/", "#"].includes(href[0]) || href.startsWith(BASE_URL));
|
||||
// links) or a new tab (the default for external links). Defaults can be overridden with `target="_blank"`.
|
||||
const isExternal = typeof href === "string" && !["/", "#"].includes(href[0]);
|
||||
|
||||
if (openInNewTab || isExternal) {
|
||||
return (
|
||||
<NextLink
|
||||
href={href}
|
||||
target={target || "_blank"}
|
||||
rel={objStr({
|
||||
[`${rel}`]: rel, // prepend whatever string is passed via optional `rel` prop
|
||||
noopener: true,
|
||||
noreferrer: isExternal, // don't add "noreferrer" if link isn't external, and only opening in a new tab
|
||||
})}
|
||||
prefetch={false}
|
||||
prefetch={prefetch}
|
||||
target={target || (isExternal ? "_blank" : undefined)}
|
||||
rel={`${rel ? `${rel} ` : ""}${target === "_blank" || isExternal ? "noopener noreferrer" : ""}` || undefined}
|
||||
className={clsx(styles.link, plain && styles.plain, className)}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// If link is to an internal page, simply pass *everything* along as-is to next/link.
|
||||
return (
|
||||
<NextLink
|
||||
className={clsx(styles.link, plain && styles.plain, className)}
|
||||
{...{ href, rel, target, prefetch, ...rest }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default Link;
|
||||
|
@ -64,6 +64,8 @@ const nextConfig: NextConfig = {
|
||||
},
|
||||
],
|
||||
},
|
||||
...(process.env.NEXT_PUBLIC_ONION_DOMAIN
|
||||
? [
|
||||
{
|
||||
// https://community.torproject.org/onion-services/advanced/onion-location/
|
||||
// only needed on actual pages, not static assets, so make a best effort by matching any path **without** a file
|
||||
@ -76,6 +78,8 @@ const nextConfig: NextConfig = {
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
source: "/tweets(|/.*)",
|
||||
headers: [
|
||||
@ -87,11 +91,15 @@ const nextConfig: NextConfig = {
|
||||
},
|
||||
],
|
||||
rewrites: async () => [
|
||||
...(process.env.NEXT_PUBLIC_UMAMI_WEBSITE_ID
|
||||
? [
|
||||
{
|
||||
// https://umami.is/docs/guides/running-on-vercel#proxy-umami-analytics-via-vercel
|
||||
source: "/_stream/u/:path(script.js|api/send)",
|
||||
destination: `${process.env.NEXT_PUBLIC_UMAMI_URL || "https://cloud.umami.is"}/:path`,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
// https://github.com/jakejarvis/tweets
|
||||
source: "/tweets/:path*",
|
||||
|
13
package.json
13
package.json
@ -39,7 +39,6 @@
|
||||
"lucide-react": "0.487.0",
|
||||
"modern-normalize": "^3.0.1",
|
||||
"next": "15.3.0-canary.29",
|
||||
"obj-str": "^1.1.0",
|
||||
"polished": "^4.3.1",
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "19.1.0",
|
||||
@ -126,17 +125,5 @@
|
||||
"stylelint",
|
||||
"prettier --check"
|
||||
]
|
||||
},
|
||||
"pnpm": {
|
||||
"onlyBuiltDependencies": [
|
||||
"sharp",
|
||||
"simple-git-hooks"
|
||||
],
|
||||
"peerDependencyRules": {
|
||||
"allowedVersions": {
|
||||
"react": "^19",
|
||||
"react-dom": "^19"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
47
pnpm-lock.yaml
generated
47
pnpm-lock.yaml
generated
@ -74,9 +74,6 @@ importers:
|
||||
next:
|
||||
specifier: 15.3.0-canary.29
|
||||
version: 15.3.0-canary.29(@babel/core@7.26.10)(babel-plugin-react-compiler@19.0.0-beta-e993439-20250328)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
obj-str:
|
||||
specifier: ^1.1.0
|
||||
version: 1.1.0
|
||||
polished:
|
||||
specifier: ^4.3.1
|
||||
version: 4.3.1
|
||||
@ -182,7 +179,7 @@ importers:
|
||||
version: 2.0.13
|
||||
'@types/node':
|
||||
specifier: ^22.13.17
|
||||
version: 22.13.17
|
||||
version: 22.14.0
|
||||
'@types/prop-types':
|
||||
specifier: ^15.7.14
|
||||
version: 15.7.14
|
||||
@ -884,8 +881,8 @@ packages:
|
||||
'@types/nlcst@2.0.3':
|
||||
resolution: {integrity: sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==}
|
||||
|
||||
'@types/node@22.13.17':
|
||||
resolution: {integrity: sha512-nAJuQXoyPj04uLgu+obZcSmsfOenUg6DxPKogeUy6yNCFwWaj5sBF8/G/pNo8EtBJjAfSVgfIlugR/BCOleO+g==}
|
||||
'@types/node@22.14.0':
|
||||
resolution: {integrity: sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA==}
|
||||
|
||||
'@types/prop-types@15.7.14':
|
||||
resolution: {integrity: sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==}
|
||||
@ -1217,8 +1214,8 @@ packages:
|
||||
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
caniuse-lite@1.0.30001707:
|
||||
resolution: {integrity: sha512-3qtRjw/HQSMlDWf+X79N206fepf4SOOU6SQLMaq/0KkZLmSjPxAkBOQQ+FxbHKfHmYLZFfdWsO3KA90ceHPSnw==}
|
||||
caniuse-lite@1.0.30001709:
|
||||
resolution: {integrity: sha512-NgL3vUTnDrPCZ3zTahp4fsugQ4dc7EKTSzwQDPEel6DMoMnfH2jhry9n2Zm8onbSR+f/QtKHFOA+iAQu4kbtWA==}
|
||||
|
||||
ccount@2.0.1:
|
||||
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
|
||||
@ -1454,8 +1451,8 @@ packages:
|
||||
eastasianwidth@0.2.0:
|
||||
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
|
||||
|
||||
electron-to-chromium@1.5.129:
|
||||
resolution: {integrity: sha512-JlXUemX4s0+9f8mLqib/bHH8gOHf5elKS6KeWG3sk3xozb/JTq/RLXIv8OKUWiK4Ah00Wm88EFj5PYkFr4RUPA==}
|
||||
electron-to-chromium@1.5.130:
|
||||
resolution: {integrity: sha512-Ou2u7L9j2XLZbhqzyX0jWDj6gA8D3jIfVzt4rikLf3cGBa0VdReuFimBKS9tQJA4+XpeCxj1NoWlfBXzbMa9IA==}
|
||||
|
||||
emoji-regex-xs@1.0.0:
|
||||
resolution: {integrity: sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==}
|
||||
@ -2687,10 +2684,6 @@ packages:
|
||||
resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
|
||||
obj-str@1.1.0:
|
||||
resolution: {integrity: sha512-iQNCv4NPzzVSnG4nVmkBsBwSq3+Z5/X/Yi4omFpzALC4ZbLXd4QByOFqWd+Khh2nQnbzhsklRxbDwhYKHotrYA==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
object-assign@4.1.1:
|
||||
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@ -3498,8 +3491,8 @@ packages:
|
||||
resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
undici-types@6.20.0:
|
||||
resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==}
|
||||
undici-types@6.21.0:
|
||||
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
|
||||
|
||||
unified-engine@11.2.2:
|
||||
resolution: {integrity: sha512-15g/gWE7qQl9tQ3nAEbMd5h9HV1EACtFs6N9xaRBZICoCwnNGbal1kOs++ICf4aiTdItZxU2s/kYWhW7htlqJg==}
|
||||
@ -4379,7 +4372,7 @@ snapshots:
|
||||
|
||||
'@types/concat-stream@2.0.3':
|
||||
dependencies:
|
||||
'@types/node': 22.13.17
|
||||
'@types/node': 22.14.0
|
||||
|
||||
'@types/debug@4.1.12':
|
||||
dependencies:
|
||||
@ -4413,9 +4406,9 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/unist': 3.0.3
|
||||
|
||||
'@types/node@22.13.17':
|
||||
'@types/node@22.14.0':
|
||||
dependencies:
|
||||
undici-types: 6.20.0
|
||||
undici-types: 6.21.0
|
||||
|
||||
'@types/prop-types@15.7.14': {}
|
||||
|
||||
@ -4725,8 +4718,8 @@ snapshots:
|
||||
|
||||
browserslist@4.24.4:
|
||||
dependencies:
|
||||
caniuse-lite: 1.0.30001707
|
||||
electron-to-chromium: 1.5.129
|
||||
caniuse-lite: 1.0.30001709
|
||||
electron-to-chromium: 1.5.130
|
||||
node-releases: 2.0.19
|
||||
update-browserslist-db: 1.1.3(browserslist@4.24.4)
|
||||
|
||||
@ -4765,7 +4758,7 @@ snapshots:
|
||||
|
||||
callsites@3.1.0: {}
|
||||
|
||||
caniuse-lite@1.0.30001707: {}
|
||||
caniuse-lite@1.0.30001709: {}
|
||||
|
||||
ccount@2.0.1: {}
|
||||
|
||||
@ -4979,7 +4972,7 @@ snapshots:
|
||||
|
||||
eastasianwidth@0.2.0: {}
|
||||
|
||||
electron-to-chromium@1.5.129: {}
|
||||
electron-to-chromium@1.5.130: {}
|
||||
|
||||
emoji-regex-xs@1.0.0: {}
|
||||
|
||||
@ -6677,7 +6670,7 @@ snapshots:
|
||||
'@swc/counter': 0.1.3
|
||||
'@swc/helpers': 0.5.15
|
||||
busboy: 1.6.0
|
||||
caniuse-lite: 1.0.30001707
|
||||
caniuse-lite: 1.0.30001709
|
||||
postcss: 8.4.31
|
||||
react: 19.1.0
|
||||
react-dom: 19.1.0(react@19.1.0)
|
||||
@ -6739,8 +6732,6 @@ snapshots:
|
||||
dependencies:
|
||||
path-key: 4.0.0
|
||||
|
||||
obj-str@1.1.0: {}
|
||||
|
||||
object-assign@4.1.1: {}
|
||||
|
||||
object-inspect@1.13.4: {}
|
||||
@ -7794,14 +7785,14 @@ snapshots:
|
||||
has-symbols: 1.1.0
|
||||
which-boxed-primitive: 1.1.1
|
||||
|
||||
undici-types@6.20.0: {}
|
||||
undici-types@6.21.0: {}
|
||||
|
||||
unified-engine@11.2.2:
|
||||
dependencies:
|
||||
'@types/concat-stream': 2.0.3
|
||||
'@types/debug': 4.1.12
|
||||
'@types/is-empty': 1.2.3
|
||||
'@types/node': 22.13.17
|
||||
'@types/node': 22.14.0
|
||||
'@types/unist': 3.0.3
|
||||
concat-stream: 2.0.0
|
||||
debug: 4.4.0
|
||||
|
8
pnpm-workspace.yaml
Normal file
8
pnpm-workspace.yaml
Normal file
@ -0,0 +1,8 @@
|
||||
onlyBuiltDependencies:
|
||||
- sharp
|
||||
- simple-git-hooks
|
||||
|
||||
peerDependencyRules:
|
||||
allowedVersions:
|
||||
react: "^19"
|
||||
react-dom: "^19"
|
Loading…
x
Reference in New Issue
Block a user