Compare commits

...

3 Commits

@ -1,8 +1,7 @@
import Image from 'next/image'
import Image from 'components/Image'
import system from '~/config/system.json'
import styles from '~/styles/about.module.css'
import profilePics from '~/utils/profiles'
export interface Member {
name: string,
@ -11,6 +10,7 @@ export interface Member {
color: string,
bioShort: string,
readMore: string,
profileImg: string,
}
export default function About() {
@ -32,7 +32,7 @@ export default function About() {
alt=""
width={150}
height={150}
src={profilePics[member.name.toLowerCase()]}
src={member.profileImg}
/>
<h2>{member.name}</h2>
<p className={styles.pronouns}>{member.mainPronouns}</p>
@ -61,7 +61,7 @@ export default function About() {
alt=""
width={80}
height={80}
src={profilePics[member.name.toLowerCase()]}
src={member.profileImg}
/>
<h2>{member.name}</h2>
<p className={styles.pronouns}>{member.mainPronouns}</p>

@ -1,56 +1,7 @@
'use client'
import { useState, useRef, FormEvent } from 'react'
import InfoBar from "~/components/InfoBar/"
import styles from '~/styles/form.module.css'
const submitUrl = 'https://contact.tempest.dev/api/contact/me'
import ContactForm from "~/components/ContactForm"
export default function Contact() {
const [submitting, setSubmitting] = useState(false)
const [status, setStatus] = useState('')
const nameRef = useRef<HTMLInputElement>()
const emailRef = useRef<HTMLInputElement>()
const messageRef = useRef<HTMLTextAreaElement>()
const submit = async (ev: FormEvent<HTMLFormElement>) => {
ev.preventDefault()
setStatus('')
const name = nameRef.current.value
const email = emailRef.current.value
const message = messageRef.current.value
if (!name) setStatus(s => s + ' Name required.')
if (!email) setStatus(s => s + ' Email required.')
if (!message) setStatus(s => s + ' Message required.')
if (!name || !email || !message)
return
setSubmitting(true)
try {
await fetch(submitUrl, {
method: 'post',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
name, email, message
})
})
setStatus('Message sent successfully')
} catch {
setStatus('Error submitting message, please try again')
} finally {
setSubmitting(false)
}
}
return (
<>
@ -61,30 +12,7 @@ export default function Contact() {
<InfoBar>
Be nice. Please don't make us regret putting this here
</InfoBar>
<form className={styles.form} onSubmit={submit}>
<label htmlFor="name">Name:</label>
<input disabled={submitting} name="name" ref={nameRef} />
<label htmlFor="email">Email:</label>
<input disabled={submitting} name="email" ref={emailRef} />
<label htmlFor="message">Message:</label>
<textarea disabled={submitting} name="message" ref={messageRef} />
<button disabled={submitting} type="submit">Submit</button>
{status && <span className={styles.status}>{status}</span>}
{/*<FormController
url="https://kae.tempest.dev/api/contact/tempest"
afterSubmit={() => setStatus('Message sent successfully!')}
onError={() => setStatus('Error submitting message, please try again.')}
>
<Input name="name" validate={v => !!v} />
<Input name="email" validate={v => !!v && v.includes('@')} />
<TextArea name="message" validate={v => !!v && v.length < 1000} />
<Button onClick={() => setStatus(null)} type="submit">submit</Button>
{status && <p>{status}</p>}
</FormController>*/}
</form>
<ContactForm/>
</main>
</>
)

@ -0,0 +1,69 @@
'use client'
import styles from '~/styles/form.module.css'
const submitUrl = 'https://contact.tempest.dev/api/contact/me'
import { useState, useRef, FormEvent } from 'react'
export default function ContactForm() {
const [submitting, setSubmitting] = useState(false)
const [status, setStatus] = useState('')
const nameRef = useRef<HTMLInputElement>()
const emailRef = useRef<HTMLInputElement>()
const messageRef = useRef<HTMLTextAreaElement>()
const submit = async (ev: FormEvent<HTMLFormElement>) => {
ev.preventDefault()
setStatus('')
const name = nameRef.current.value
const email = emailRef.current.value
const message = messageRef.current.value
if (!name) setStatus(s => s + ' Name required.')
if (!email) setStatus(s => s + ' Email required.')
if (!message) setStatus(s => s + ' Message required.')
if (!name || !email || !message)
return
setSubmitting(true)
try {
await fetch(submitUrl, {
method: 'post',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
name, email, message
})
})
setStatus('Message sent successfully')
} catch {
setStatus('Error submitting message, please try again')
} finally {
setSubmitting(false)
}
}
return (
<form className={styles.form} onSubmit={submit}>
<label htmlFor="name">Name:</label>
<input disabled={submitting} name="name" ref={nameRef} />
<label htmlFor="email">Email:</label>
<input disabled={submitting} name="email" ref={emailRef} />
<label htmlFor="message">Message:</label>
<textarea disabled={submitting} name="message" ref={messageRef} />
<button disabled={submitting} type="submit">Submit</button>
{status && <span className={styles.status}>{status}</span>}
</form>
)
}

@ -0,0 +1,121 @@
import { promises as fs } from 'fs'
import { createHash } from 'node:crypto'
import path from 'path'
import { ImgHTMLAttributes } from 'react'
import sharp from 'sharp'
const outputDir = path.join(process.cwd(), '.next/static/images')
const serverPath = '/_next/static/images/'
interface ReqProps {
src: string,
alt: string,
}
type FixedSingleDimension = {width: number} | {height: number}
type FixedBothDimension = {width: number, height: number}
type MultiSize = {width: number[]} | {height: number[]}
type SizeProps = FixedSingleDimension | FixedBothDimension | MultiSize
type ImageAttrs = Omit<ImgHTMLAttributes<HTMLImageElement>, "width" | "height" | "src">
type ImageProps = ImageAttrs
& SizeProps
& ReqProps
interface ProcessedImage {
hostPath: string,
randPrefix: string,
origSrc: string,
aspectRatio: number,
}
async function ImageServer({src,...imgAttrs}: ImageProps) {
const width = 'width' in imgAttrs ? imgAttrs.width : null
const height = 'height' in imgAttrs ? imgAttrs.height : null
// Handle where we have an array of widths
if (Array.isArray(width)) {
let _src : string = src
const srcSet = (await Promise.all(width.map(async width => {
const {outputPath, origSrc} = await processImage(src, {width})
_src = origSrc
return `${outputPath} ${width}w`
}))).join(',')
return (
<img
src={_src}
srcSet={srcSet}
{...imgAttrs}
width={undefined}
height={undefined}
/>
)
}else if (Array.isArray(height)) {
let _src : string = src
const srcSet = (await Promise.all(height.map(async height => {
const {outputPath, origSrc} = await processImage(src, {height})
_src = origSrc
return `${outputPath} ${width}w`
}))).join(',')
return (
<img
src={_src}
srcSet={srcSet}
{...imgAttrs}
width={undefined}
height={undefined}
/>
)
} else {
const {outputPath, resolvedWidth} = await processImage(src, {width, height})
return <img src={outputPath} {...imgAttrs} height={undefined} width={resolvedWidth} />
}
}
async function processImage(sourcePath: string, {width, height} : {width?: number, height?: number}) : Promise<{outputPath: string, resolvedWidth: number, origSrc: string}> {
await fs.mkdir(outputDir, {recursive: true})
const hostPath = path.join(process.cwd(), sourcePath)
const srcImg = sharp(hostPath)
const metadata = await srcImg.metadata()
const extension = path.extname(hostPath)
const filename = path.basename(hostPath, extension)
const hashPrefix = createHash('sha256').update(hostPath).digest('hex').substr(0, 7)
const origSrc = `${hashPrefix}-${filename}${extension}`
const aspectRatio = metadata.width / metadata.height
const resolvedWidth = width ? width : aspectRatio * height
const outputName = `${hashPrefix}-${filename}-${resolvedWidth}w${extension}`
const origCopyStat = await fs.stat(path.join(outputDir, origSrc)).catch(() => undefined)
if (!origCopyStat?.isFile()) {
console.log(`copying file ${hostPath}`)
await fs.copyFile(hostPath, path.join(outputDir, origSrc))
}
const outputStat = await fs.stat(path.join(outputDir, outputName)).catch(() => undefined)
if (!outputStat?.isFile()) {
console.log(`resizing file ${hostPath} for width ${resolvedWidth}`)
await srcImg
.resize({width: resolvedWidth})
.toFile(path.join(outputDir, outputName))
}
return {
outputPath: serverPath + outputName,
resolvedWidth,
origSrc,
}
}
export default function ImageServerWrap(props: ImageProps) {
return (
<>
{/* @ts-expect-error Async Server Component */}
<ImageServer {...props} />
</>
)
}

@ -1,8 +1,7 @@
import { ReactNode } from 'react'
import Image from 'next/image'
import Image from 'components/Image'
import system from '~/config/system.json'
import profilePics from '~/utils/profiles'
import styles from './InfoBar.module.css'
interface ArbitraryChildrenProps {
@ -39,10 +38,9 @@ export default function InfoBar(props: InfobarProps) {
}
if ('authorName' in props) {
const authorKey = props.authorName.toLowerCase()
const author = system.members.find((member) => member.name === props.authorName)
const style = { '--author-color': author?.color } as React.CSSProperties
const picture = profilePics[authorKey]
const picture = author.profileImg
return (
<aside className={`${styles.infobar} ${styles.postMeta}`} style={style}>
@ -59,7 +57,7 @@ export default function InfoBar(props: InfobarProps) {
const memberKey = props.memberName.toLowerCase()
const member = system.members.find((member) => member.name === props.memberName)
const style = { '--member-color': member?.color } as React.CSSProperties
const picture = profilePics[memberKey]
const picture = member.profileImg
return (
<aside className={`${styles.infobar} ${styles.memberProfile}`} style={style}>

@ -1,11 +1,9 @@
'use client'
import React from 'react'
import Image from 'next/image'
import Image from 'components/Image'
import { usePathname } from 'next/navigation'
import header from '~/images/aurora-1197753.jpg'
const header = 'images/aurora-1197753.jpg'
export default function Title() {
const pathname = usePathname()
@ -29,7 +27,7 @@ export default function Title() {
src={header}
alt=""
role="presentation"
fill={true}
width={[2560,1920,1280,800,600]}
sizes={`
(max-width: 2560) 100vw,
(max-width: 1920) 100vw,

@ -12,7 +12,8 @@
{"name": "names:", "value": "rose, rosalyn, occasionally callista"},
{"name": "pronouns:", "value": "they/them. very occasionally she/her but i'm not usually in the mood"},
{"name": "orientation:", "value": "the hell if i know"}
]
],
"profileImg": "images/profile/rose.png"
},{
"name": "Dawn",
"featured": true,
@ -25,7 +26,8 @@
{"name": "Names:", "value": "Dawn. Perhaps \"Ashelyn Dawn\" if you're feeling fancy"},
{"name": "Pronouns:", "value": "She/her, no exceptions"},
{"name": "Orientation:", "value": "Asexual, polyromantic lesbian"}
]
],
"profileImg": "images/profile/dawn.png"
},{
"name": "echo",
"mainPronouns": "it/its",
@ -37,7 +39,8 @@
{"name": "name:", "value": "echo"},
{"name": "pronouns:", "value": "it/its, “that one”, most neopronouns okay"},
{"name": "orientation:", "value": "aroace"}
]
],
"profileImg": "images/profile/echo.png"
},{
"name": "Corona",
"featured": true,
@ -50,6 +53,7 @@
{"name": "Names:", "value": "Corona (previously known as Harrow)"},
{"name": "Pronouns:", "value": "she/her or they/them with equal preference"},
{"name": "Orientation", "value": "Indeterminate"}
]
],
"profileImg": "images/profile/corona.png"
}]
}

@ -21,26 +21,42 @@
nodejs = pkgs.nodejs-18_x;
node_modules = pkgs.stdenv.mkDerivation {
name = "node_modules";
src = filter {
root = ./.;
include = [
./package.json
./package-lock.json
];
};
src = filter {
root = ./.;
include = [
./package.json
./package-lock.json
];
};
packageLock = builtins.fromJSON(builtins.readFile (src + "/package-lock.json"));
__noChroot = true;
deps = builtins.attrValues (removeAttrs packageLock.packages [ "" ])
++ builtins.attrValues (removeAttrs (packageLock.dependencies or {} ) [ "" ])
;
tarballs = map (p: pkgs.fetchurl { url = p.resolved; hash = p.integrity; }) deps;
tarballsFile = pkgs.writeTextFile {
name = "tarballs";
text = builtins.concatStringsSep "\n" tarballs;
};
configurePhase = ''
export HOME=$TMP
'';
tempestdev_modules = pkgs.stdenv.mkDerivation {
inherit src;
name = "node_modules";
buildInputs = [ nodejs ];
buildPhase = ''
export HOME=$PWD/.home
export npm_config_cache=$PWD/.npm
while read package
do
echo "caching $(echo $package | sed 's/\/nix\/store\/[^-]*-//')"
npm cache add "$package"
done <${tarballsFile}
${nodejs}/bin/npm ci
'';
@ -65,38 +81,17 @@
nativeBuildInputs = [ nodejs ];
buildPhase = ''npm run build'';
configurePhase = ''
ln -sf ${node_modules}/node_modules node_modules
ln -sf ${tempestdev_modules}/node_modules node_modules
export HOME=$TMP
'';
buildPhase = ''
npm run build
'';
installPhase = ''
# Use the standalone nextjs version
mv .next/standalone $out
# Copy non-generated static files
if [ -d "public" ]; then
cp -R public $out/public
fi
# Also copy generated static files
mv .next/static $out/.next/static
# Re-link the node_modules
rm $out/node_modules
mv node_modules $out/node_modules
# Link cache directory
ln -s /tmp $out/.next/cache
# Wrap the script
cat <<ENTRYPOINT > $out/entrypoint
#!${pkgs.stdenv.shell}
exec "$(type -p node)" "$out/server.js" "$$@"
ENTRYPOINT
chmod +x $out/entrypoint
mv out $out
'';
};
};
@ -109,14 +104,6 @@
options.ashe.services."tempest.dev" = {
enable = mkEnableOption "Enables the tempest.dev HTTP service";
port = mkOption rec {
type = types.int;
default = 8000;
example = default;
description = "The port for this service to listen on";
};
domain = mkOption rec {
type = types.str;
default = "tempest.dev";
@ -126,29 +113,14 @@
};
config = mkIf cfg.enable {
systemd.services."ashe.tempest.dev" = {
wantedBy = [ "multi-user.target" ];
serviceConfig = let pkg = self.packages.${pkgs.system}.default;
in {
Restart = "on-failure";
ExecStart = "${pkg}/entrypoint";
DynamicUser = "yes";
PrivateTmp = "yes";
Environment = [
"PORT=${toString cfg.port}"
];
};
};
services.nginx.virtualHosts.${cfg.domain} = {
locations."/" = { proxyPass = "http://127.0.0.1:${toString cfg.port}"; };
locations."/" = {
root = "${pkg}";
};
forceSSL = true;
enableACME = true;
};
};
};
};
}

1
next-env.d.ts vendored

@ -1,5 +1,4 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.

@ -1,3 +1,7 @@
module.exports = {
output: 'standalone',
output: 'export',
trailingSlash: true,
images: {
disableStaticImages: true
},
}

166
package-lock.json generated

@ -11,7 +11,7 @@
"dependencies": {
"front-matter": "^4.0.2",
"markdown-to-jsx": "^7.2.0",
"next": "^13.4.1",
"next": "^14.0.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"sharp": "^0.32.1",
@ -19,7 +19,7 @@
},
"devDependencies": {
"@types/node": "20.1.0",
"@types/react": "^18.2.6",
"@types/react": "^18.2.41",
"typescript": "5.0.4"
}
},
@ -35,14 +35,14 @@
}
},
"node_modules/@next/env": {
"version": "13.4.1",
"resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.1.tgz",
"integrity": "sha512-eD6WCBMFjLFooLM19SIhSkWBHtaFrZFfg2Cxnyl3vS3DAdFRfnx5TY2RxlkuKXdIRCC0ySbtK9JXXt8qLCqzZg=="
"version": "14.0.3",
"resolved": "https://registry.npmjs.org/@next/env/-/env-14.0.3.tgz",
"integrity": "sha512-7xRqh9nMvP5xrW4/+L0jgRRX+HoNRGnfJpD+5Wq6/13j3dsdzxO3BCXn7D3hMqsDb+vjZnJq+vI7+EtgrYZTeA=="
},
"node_modules/@next/swc-darwin-arm64": {
"version": "13.4.1",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.1.tgz",
"integrity": "sha512-eF8ARHtYfnoYtDa6xFHriUKA/Mfj/cCbmKb3NofeKhMccs65G6/loZ15a6wYCCx4rPAd6x4t1WmVYtri7EdeBg==",
"version": "14.0.3",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.0.3.tgz",
"integrity": "sha512-64JbSvi3nbbcEtyitNn2LEDS/hcleAFpHdykpcnrstITFlzFgB/bW0ER5/SJJwUPj+ZPY+z3e+1jAfcczRLVGw==",
"cpu": [
"arm64"
],
@ -55,9 +55,9 @@
}
},
"node_modules/@next/swc-darwin-x64": {
"version": "13.4.1",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.1.tgz",
"integrity": "sha512-7cmDgF9tGWTgn5Gw+vP17miJbH4wcraMHDCOHTYWkO/VeKT73dUWG23TNRLfgtCNSPgH4V5B4uLHoZTanx9bAw==",
"version": "14.0.3",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.0.3.tgz",
"integrity": "sha512-RkTf+KbAD0SgYdVn1XzqE/+sIxYGB7NLMZRn9I4Z24afrhUpVJx6L8hsRnIwxz3ERE2NFURNliPjJ2QNfnWicQ==",
"cpu": [
"x64"
],
@ -70,9 +70,9 @@
}
},
"node_modules/@next/swc-linux-arm64-gnu": {
"version": "13.4.1",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.1.tgz",
"integrity": "sha512-qwJqmCri2ie8aTtE5gjTSr8S6O8B67KCYgVZhv9gKH44yvc/zXbAY8u23QGULsYOyh1islWE5sWfQNLOj9iryg==",
"version": "14.0.3",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.0.3.tgz",
"integrity": "sha512-3tBWGgz7M9RKLO6sPWC6c4pAw4geujSwQ7q7Si4d6bo0l6cLs4tmO+lnSwFp1Tm3lxwfMk0SgkJT7EdwYSJvcg==",
"cpu": [
"arm64"
],
@ -85,9 +85,9 @@
}
},
"node_modules/@next/swc-linux-arm64-musl": {
"version": "13.4.1",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.1.tgz",
"integrity": "sha512-qcC54tWNGDv/VVIFkazxhqH1Bnagjfs4enzELVRlUOoJPD2BGJTPI7z08pQPbbgxLtRiu8gl2mXvpB8WlOkMeA==",
"version": "14.0.3",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.0.3.tgz",
"integrity": "sha512-v0v8Kb8j8T23jvVUWZeA2D8+izWspeyeDGNaT2/mTHWp7+37fiNfL8bmBWiOmeumXkacM/AB0XOUQvEbncSnHA==",
"cpu": [
"arm64"
],
@ -100,9 +100,9 @@
}
},
"node_modules/@next/swc-linux-x64-gnu": {
"version": "13.4.1",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.1.tgz",
"integrity": "sha512-9TeWFlpLsBosZ+tsm/rWBaMwt5It9tPH8m3nawZqFUUrZyGRfGcI67js774vtx0k3rL9qbyY6+3pw9BCVpaYUA==",
"version": "14.0.3",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.0.3.tgz",
"integrity": "sha512-VM1aE1tJKLBwMGtyBR21yy+STfl0MapMQnNrXkxeyLs0GFv/kZqXS5Jw/TQ3TSUnbv0QPDf/X8sDXuMtSgG6eg==",
"cpu": [
"x64"
],
@ -115,9 +115,9 @@
}
},
"node_modules/@next/swc-linux-x64-musl": {
"version": "13.4.1",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.1.tgz",
"integrity": "sha512-sNDGaWmSqTS4QRUzw61wl4mVPeSqNIr1OOjLlQTRuyInxMxtqImRqdvzDvFTlDfdeUMU/DZhWGYoHrXLlZXe6A==",
"version": "14.0.3",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.0.3.tgz",
"integrity": "sha512-64EnmKy18MYFL5CzLaSuUn561hbO1Gk16jM/KHznYP3iCIfF9e3yULtHaMy0D8zbHfxset9LTOv6cuYKJgcOxg==",
"cpu": [
"x64"
],
@ -130,9 +130,9 @@
}
},
"node_modules/@next/swc-win32-arm64-msvc": {
"version": "13.4.1",
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.1.tgz",
"integrity": "sha512-+CXZC7u1iXdLRudecoUYbhbsXpglYv8KFYsFxKBPn7kg+bk7eJo738wAA4jXIl8grTF2mPdmO93JOQym+BlYGA==",
"version": "14.0.3",
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.0.3.tgz",
"integrity": "sha512-WRDp8QrmsL1bbGtsh5GqQ/KWulmrnMBgbnb+59qNTW1kVi1nG/2ndZLkcbs2GX7NpFLlToLRMWSQXmPzQm4tog==",
"cpu": [
"arm64"
],
@ -145,9 +145,9 @@
}
},
"node_modules/@next/swc-win32-ia32-msvc": {
"version": "13.4.1",
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.1.tgz",
"integrity": "sha512-vIoXVVc7UYO68VwVMDKwJC2+HqAZQtCYiVlApyKEeIPIQpz2gpufzGxk1z3/gwrJt/kJ5CDZjlhYDCzd3hdz+g==",
"version": "14.0.3",
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.0.3.tgz",
"integrity": "sha512-EKffQeqCrj+t6qFFhIFTRoqb2QwX1mU7iTOvMyLbYw3QtqTw9sMwjykyiMlZlrfm2a4fA84+/aeW+PMg1MjuTg==",
"cpu": [
"ia32"
],
@ -160,9 +160,9 @@
}
},
"node_modules/@next/swc-win32-x64-msvc": {
"version": "13.4.1",
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.1.tgz",
"integrity": "sha512-n8V5ImLQZibKTu10UUdI3nIeTLkliEXe628qxqW9v8My3BAH2a7H0SaCqkV2OgqFnn8sG1wxKYw9/SNJ632kSA==",
"version": "14.0.3",
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.0.3.tgz",
"integrity": "sha512-ERhKPSJ1vQrPiwrs15Pjz/rvDHZmkmvbf/BjPN/UCOI++ODftT0GtasDPi0j+y6PPJi5HsXw+dpRaXUaw4vjuQ==",
"cpu": [
"x64"
],
@ -175,9 +175,9 @@
}
},
"node_modules/@swc/helpers": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz",
"integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==",
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz",
"integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==",
"dependencies": {
"tslib": "^2.4.0"
}
@ -195,9 +195,9 @@
"dev": true
},
"node_modules/@types/react": {
"version": "18.2.6",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.6.tgz",
"integrity": "sha512-wRZClXn//zxCFW+ye/D2qY65UsYP1Fpex2YXorHc8awoNamkMZSvBxwxdYVInsHOZZd2Ppq8isnSzJL5Mpf8OA==",
"version": "18.2.41",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.41.tgz",
"integrity": "sha512-CwOGr/PiLiNBxEBqpJ7fO3kocP/2SSuC9fpH5K7tusrg4xPSRT/193rzolYwQnTN02We/ATXKnb6GqA5w4fRxw==",
"dev": true,
"dependencies": {
"@types/prop-types": "*",
@ -517,6 +517,16 @@
"resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
"integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw=="
},
"node_modules/glob-to-regexp": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
"integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="
},
"node_modules/graceful-fs": {
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
},
"node_modules/granim": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/granim/-/granim-2.0.0.tgz",
@ -653,39 +663,37 @@
"integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg=="
},
"node_modules/next": {
"version": "13.4.1",
"resolved": "https://registry.npmjs.org/next/-/next-13.4.1.tgz",
"integrity": "sha512-JBw2kAIyhKDpjhEWvNVoFeIzNp9xNxg8wrthDOtMctfn3EpqGCmW0FSviNyGgOSOSn6zDaX48pmvbdf6X2W9xA==",
"version": "14.0.3",
"resolved": "https://registry.npmjs.org/next/-/next-14.0.3.tgz",
"integrity": "sha512-AbYdRNfImBr3XGtvnwOxq8ekVCwbFTv/UJoLwmaX89nk9i051AEY4/HAWzU0YpaTDw8IofUpmuIlvzWF13jxIw==",
"dependencies": {
"@next/env": "13.4.1",
"@swc/helpers": "0.5.1",
"@next/env": "14.0.3",
"@swc/helpers": "0.5.2",
"busboy": "1.6.0",
"caniuse-lite": "^1.0.30001406",
"postcss": "8.4.14",
"postcss": "8.4.31",
"styled-jsx": "5.1.1",
"zod": "3.21.4"
"watchpack": "2.4.0"
},
"bin": {
"next": "dist/bin/next"
},
"engines": {
"node": ">=16.8.0"
"node": ">=18.17.0"
},
"optionalDependencies": {
"@next/swc-darwin-arm64": "13.4.1",
"@next/swc-darwin-x64": "13.4.1",
"@next/swc-linux-arm64-gnu": "13.4.1",
"@next/swc-linux-arm64-musl": "13.4.1",
"@next/swc-linux-x64-gnu": "13.4.1",
"@next/swc-linux-x64-musl": "13.4.1",
"@next/swc-win32-arm64-msvc": "13.4.1",
"@next/swc-win32-ia32-msvc": "13.4.1",
"@next/swc-win32-x64-msvc": "13.4.1"
"@next/swc-darwin-arm64": "14.0.3",
"@next/swc-darwin-x64": "14.0.3",
"@next/swc-linux-arm64-gnu": "14.0.3",
"@next/swc-linux-arm64-musl": "14.0.3",
"@next/swc-linux-x64-gnu": "14.0.3",
"@next/swc-linux-x64-musl": "14.0.3",
"@next/swc-win32-arm64-msvc": "14.0.3",
"@next/swc-win32-ia32-msvc": "14.0.3",
"@next/swc-win32-x64-msvc": "14.0.3"
},
"peerDependencies": {
"@opentelemetry/api": "^1.1.0",
"fibers": ">= 3.1.0",
"node-sass": "^6.0.0 || ^7.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"sass": "^1.3.0"
@ -694,12 +702,6 @@
"@opentelemetry/api": {
"optional": true
},
"fibers": {
"optional": true
},
"node-sass": {
"optional": true
},
"sass": {
"optional": true
}
@ -740,9 +742,9 @@
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
},
"node_modules/postcss": {
"version": "8.4.14",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz",
"integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==",
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
"funding": [
{
"type": "opencollective",
@ -751,10 +753,14 @@
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/postcss"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"dependencies": {
"nanoid": "^3.3.4",
"nanoid": "^3.3.6",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
},
@ -1072,9 +1078,9 @@
}
},
"node_modules/tslib": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
"integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg=="
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
},
"node_modules/tunnel-agent": {
"version": "0.6.0",
@ -1198,6 +1204,18 @@
"resolved": "https://registry.npmjs.org/vue2-transitions/-/vue2-transitions-0.3.0.tgz",
"integrity": "sha512-m1ad8K8kufqiEhj5gXHkkqOioI5sW0FaMbRiO0Tv2WFfGbO2eIKrfkFiO3HPQtMJboimaLCN4p/zL81clLbG4w=="
},
"node_modules/watchpack": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
"integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
"dependencies": {
"glob-to-regexp": "^0.4.1",
"graceful-fs": "^4.1.2"
},
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
@ -1207,14 +1225,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"node_modules/zod": {
"version": "3.21.4",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz",
"integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==",
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
}
}
}

@ -12,7 +12,7 @@
"dependencies": {
"front-matter": "^4.0.2",
"markdown-to-jsx": "^7.2.0",
"next": "^13.4.1",
"next": "^14.0.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"sharp": "^0.32.1",
@ -20,7 +20,7 @@
},
"devDependencies": {
"@types/node": "20.1.0",
"@types/react": "^18.2.6",
"@types/react": "^18.2.41",
"typescript": "5.0.4"
}
}

@ -141,9 +141,10 @@ header .headerBackground {
}
header .headerBackground img {
z-index: -1;
object-fit: cover;
object-position: center 75%;
width: 100%;
height: 100%;
}
header .headerBackground::after {
@ -152,6 +153,8 @@ header .headerBackground::after {
width: 100%;
height: 100%;
background: rgba(0,0,0,.35);
position: absolute;
top: 0;
}
header:not(.homepage) ~ h1.pageTitle {

@ -1,8 +0,0 @@
import rose from '~/images/profile/rose.png'
import dawn from '~/images/profile/dawn.png'
import echo from '~/images/profile/echo.png'
import corona from '~/images/profile/corona.png'
export default {
rose, dawn, echo, corona
}
Loading…
Cancel
Save