mirror of
https://github.com/BradNut/personal-website-sveltekit
synced 2025-09-08 23:20:18 +00:00
commit
2175792a31
18 changed files with 557 additions and 545 deletions
46
.github/workflows/node.js.yml
vendored
46
.github/workflows/node.js.yml
vendored
|
|
@ -1,46 +0,0 @@
|
||||||
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
|
|
||||||
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs
|
|
||||||
|
|
||||||
name: Node.js CI
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: ['master', 'development']
|
|
||||||
pull_request:
|
|
||||||
branches: ['master']
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
node-version: [18.x, 20.x]
|
|
||||||
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
|
||||||
uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: ${{ matrix.node-version }}
|
|
||||||
- uses: pnpm/action-setup@v2
|
|
||||||
name: Install pnpm
|
|
||||||
with:
|
|
||||||
version: 8
|
|
||||||
run_install: false
|
|
||||||
- name: Get pnpm store directory
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
name: Setup pnpm cache
|
|
||||||
with:
|
|
||||||
path: ${{ env.STORE_PATH }}
|
|
||||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-pnpm-store-
|
|
||||||
- name: Install dependencies
|
|
||||||
run: pnpm install
|
|
||||||
- run: pnpm run build
|
|
||||||
- run: pnpm test
|
|
||||||
47
.github/workflows/svelte_check.yml
vendored
Normal file
47
.github/workflows/svelte_check.yml
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
name: Run_Svelte_Check_on_PRs
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
env:
|
||||||
|
WALLABAG_MAX_ARTICLES: ${{ secrets.WALLABAG_MAX_ARTICLES }}
|
||||||
|
WALLABAG_MAX_PAGES: ${{ secrets.WALLABAG_MAX_PAGES }}
|
||||||
|
WALLABAG_CLIENT_ID: ${{ secrets.WALLABAG_CLIENT_ID }}
|
||||||
|
WALLABAG_CLIENT_SECRET: ${{ secrets.WALLABAG_CLIENT_SECRET }}
|
||||||
|
WALLABAG_USERNAME: ${{ secrets.WALLABAG_USERNAME }}
|
||||||
|
WALLABAG_PASSWORD: ${{ secrets.WALLABAG_PASSWORD }}
|
||||||
|
WALLABAG_URL: ${{ secrets.WALLABAG_URL }}
|
||||||
|
BANDCAMP_USERNAME: ${{ secrets.BANDCAMP_USERNAME }}
|
||||||
|
PUBLIC_SITE_URL: ${{ secrets.PUBLIC_SITE_URL }}
|
||||||
|
PUBLIC_URL: ${{ secrets.PUBLIC_URL }}
|
||||||
|
PUBLIC_UMAMI_DO_NOT_TRACK: ${{ secrets.PUBLIC_UMAMI_DO_NOT_TRACK }}
|
||||||
|
PUBLIC_UMAMI_URL: ${{ secrets.PUBLIC_UMAMI_URL }}
|
||||||
|
PUBLIC_UMAMI_ID: ${{ secrets.PUBLIC_UMAMI_ID }}
|
||||||
|
PAGE_SIZE: ${{ secrets.PAGE_SIZE }}
|
||||||
|
USE_REDIS_CACHE: ${{ secrets.USE_REDIS_CACHE }}
|
||||||
|
REDIS_URI: ${{ secrets.REDIS_URI }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: pnpm-setup
|
||||||
|
uses: pnpm/action-setup@v2
|
||||||
|
with:
|
||||||
|
version: 8
|
||||||
|
|
||||||
|
- name: Set up Node.js
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 18.18.2
|
||||||
|
cache: 'pnpm'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: pnpm install
|
||||||
|
|
||||||
|
- name: Run Svelte Check
|
||||||
|
run: pnpm check
|
||||||
22
package.json
22
package.json
|
|
@ -21,36 +21,35 @@
|
||||||
"@iconify-icons/radix-icons": "^1.2.9",
|
"@iconify-icons/radix-icons": "^1.2.9",
|
||||||
"@iconify-icons/simple-icons": "^1.2.74",
|
"@iconify-icons/simple-icons": "^1.2.74",
|
||||||
"@melt-ui/pp": "^0.1.4",
|
"@melt-ui/pp": "^0.1.4",
|
||||||
"@playwright/test": "^1.40.1",
|
"@playwright/test": "^1.41.1",
|
||||||
"@resvg/resvg-js": "^2.6.0",
|
"@resvg/resvg-js": "^2.6.0",
|
||||||
"@sveltejs/adapter-static": "^3.0.1",
|
"@sveltejs/adapter-static": "^3.0.1",
|
||||||
"@sveltejs/adapter-vercel": "^4.0.4",
|
|
||||||
"@sveltejs/enhanced-img": "^0.1.8",
|
"@sveltejs/enhanced-img": "^0.1.8",
|
||||||
"@sveltejs/kit": "^2.3.2",
|
"@sveltejs/kit": "^2.4.3",
|
||||||
"@sveltejs/vite-plugin-svelte": "^3.0.0",
|
"@sveltejs/vite-plugin-svelte": "^3.0.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
||||||
"@typescript-eslint/parser": "^5.62.0",
|
"@typescript-eslint/parser": "^5.62.0",
|
||||||
"@zerodevx/svelte-img": "^2.1.0",
|
"@zerodevx/svelte-img": "^2.1.0",
|
||||||
"autoprefixer": "^10.4.16",
|
"autoprefixer": "^10.4.17",
|
||||||
"eslint": "^8.56.0",
|
"eslint": "^8.56.0",
|
||||||
"eslint-config-prettier": "^8.10.0",
|
"eslint-config-prettier": "^8.10.0",
|
||||||
"eslint-plugin-svelte": "^2.35.1",
|
"eslint-plugin-svelte": "^2.35.1",
|
||||||
"iconify-icon": "^1.0.8",
|
"iconify-icon": "^1.0.8",
|
||||||
"just-intersect": "^4.3.0",
|
"just-intersect": "^4.3.0",
|
||||||
"mdsvex": "^0.10.6",
|
"mdsvex": "^0.11.0",
|
||||||
"mdsvex-relative-images": "^1.0.3",
|
"mdsvex-relative-images": "^1.0.3",
|
||||||
"postcss": "^8.4.33",
|
"postcss": "^8.4.33",
|
||||||
"postcss-import": "^15.1.0",
|
"postcss-import": "^15.1.0",
|
||||||
"postcss-load-config": "^4.0.2",
|
"postcss-load-config": "^4.0.2",
|
||||||
"postcss-preset-env": "^8.5.1",
|
"postcss-preset-env": "^8.5.1",
|
||||||
"prettier": "^2.8.8",
|
"prettier": "^3.2.4",
|
||||||
"prettier-plugin-svelte": "^2.10.1",
|
"prettier-plugin-svelte": "^3.1.2",
|
||||||
"sass": "^1.69.7",
|
"sass": "^1.70.0",
|
||||||
"satori": "^0.10.11",
|
"satori": "^0.10.11",
|
||||||
"satori-html": "^0.3.2",
|
"satori-html": "^0.3.2",
|
||||||
"scrape-it": "^6.1.0",
|
"scrape-it": "^6.1.0",
|
||||||
"sharp": "^0.32.6",
|
"sharp": "^0.32.6",
|
||||||
"svelte": "^4.2.8",
|
"svelte": "^4.2.9",
|
||||||
"svelte-check": "^3.6.3",
|
"svelte-check": "^3.6.3",
|
||||||
"svelte-meta-tags": "^3.1.0",
|
"svelte-meta-tags": "^3.1.0",
|
||||||
"svelte-preprocess": "^5.1.3",
|
"svelte-preprocess": "^5.1.3",
|
||||||
|
|
@ -58,9 +57,9 @@
|
||||||
"tslib": "^2.6.2",
|
"tslib": "^2.6.2",
|
||||||
"typescript": "^5.3.3",
|
"typescript": "^5.3.3",
|
||||||
"vanilla-lazyload": "^17.8.5",
|
"vanilla-lazyload": "^17.8.5",
|
||||||
"vite": "^5.0.11",
|
"vite": "^5.0.12",
|
||||||
"vite-imagetools": "^5.1.2",
|
"vite-imagetools": "^5.1.2",
|
||||||
"vitest": "^1.2.0"
|
"vitest": "^1.2.1"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
@ -70,6 +69,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@melt-ui/svelte": "^0.50.1",
|
"@melt-ui/svelte": "^0.50.1",
|
||||||
"@types/nprogress": "^0.2.3",
|
"@types/nprogress": "^0.2.3",
|
||||||
|
"@sveltejs/adapter-vercel": "^5.1.0",
|
||||||
"@vercel/og": "^0.5.20",
|
"@vercel/og": "^0.5.20",
|
||||||
"ioredis": "^5.3.2",
|
"ioredis": "^5.3.2",
|
||||||
"nprogress": "^0.2.0"
|
"nprogress": "^0.2.0"
|
||||||
|
|
|
||||||
786
pnpm-lock.yaml
786
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
|
@ -103,10 +103,6 @@
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
& a + svg {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 1000px) {
|
@media (max-width: 1000px) {
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
import linkedin from '@iconify-icons/radix-icons/linkedin-logo';
|
import linkedin from '@iconify-icons/radix-icons/linkedin-logo';
|
||||||
import twitter from '@iconify-icons/radix-icons/twitter-logo';
|
import twitter from '@iconify-icons/radix-icons/twitter-logo';
|
||||||
|
|
||||||
|
export let showGithub: boolean = false;
|
||||||
export let showTwitter: boolean = false;
|
export let showTwitter: boolean = false;
|
||||||
export let showLinkedIn: boolean = false;
|
export let showLinkedIn: boolean = false;
|
||||||
export let showEmail: boolean = false;
|
export let showEmail: boolean = false;
|
||||||
|
|
@ -42,7 +43,7 @@
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
{#if github && userNames?.github}
|
{#if showGithub && userNames?.github}
|
||||||
<span>
|
<span>
|
||||||
<a
|
<a
|
||||||
href={`https://www.github.com/${userNames.github}`}
|
href={`https://www.github.com/${userNames.github}`}
|
||||||
|
|
|
||||||
|
|
@ -39,19 +39,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hr {
|
|
||||||
display: block;
|
|
||||||
max-width: 100%;
|
|
||||||
height: 0;
|
|
||||||
max-height: 0;
|
|
||||||
border: solid;
|
|
||||||
width: 100%;
|
|
||||||
border-width: thin 0 0 0;
|
|
||||||
transition: inherit;
|
|
||||||
border-color: var(--lightShade);
|
|
||||||
color: var(--lightShade);
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
p {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0.2rem;
|
padding: 0.2rem;
|
||||||
|
|
@ -60,10 +47,6 @@
|
||||||
color: var(--lightShade);
|
color: var(--lightShade);
|
||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
|
||||||
margin: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer-list {
|
.footer-list {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|
|
||||||
|
|
@ -2,19 +2,26 @@
|
||||||
import beeIcon from '$lib/assets/images/bee.svg';
|
import beeIcon from '$lib/assets/images/bee.svg';
|
||||||
import shellIcon from '$lib/assets/images/shell.svg';
|
import shellIcon from '$lib/assets/images/shell.svg';
|
||||||
import nutIcon from '$lib/assets/images/hazelnut.svg';
|
import nutIcon from '$lib/assets/images/hazelnut.svg';
|
||||||
|
|
||||||
|
// @ts-expect-error: Type 'Record<string, any>' is not assignable to type 'string'.ts(2322)
|
||||||
|
const bee: string = beeIcon;
|
||||||
|
// @ts-expect-error: Type 'Record<string, any>' is not assignable to type 'string'.ts(2322)
|
||||||
|
const shell: string = shellIcon;
|
||||||
|
// @ts-expect-error: Type 'Record<string, any>' is not assignable to type 'string'.ts(2322)
|
||||||
|
const nut: string = nutIcon;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<a href="/" class="center">
|
<a href="/" class="center">
|
||||||
<img src={beeIcon} alt="Bee Icon" width="30" height="30"/>
|
<img src={bee} alt="Bee Icon" width="30" height="30"/>
|
||||||
<p>Bradley</p>
|
<p>Bradley</p>
|
||||||
</a>
|
</a>
|
||||||
<a href="/" class="center">
|
<a href="/" class="center">
|
||||||
<img src={shellIcon} alt="Shell Icon" width="30" height="30"/>
|
<img src={shell} alt="Shell Icon" width="30" height="30"/>
|
||||||
<p>Shell</p>
|
<p>Shell</p>
|
||||||
</a>
|
</a>
|
||||||
<a href="/" class="center">
|
<a href="/" class="center">
|
||||||
<img src={nutIcon} alt="Nut Icon" width="30" height="30"/>
|
<img src={nut} alt="Nut Icon" width="30" height="30"/>
|
||||||
<p>Nut</p>
|
<p>Nut</p>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
export let pageSize: number;
|
export let pageSize: number;
|
||||||
export let totalCount: number;
|
export let totalCount: number;
|
||||||
export let currentPage: number;
|
export let currentPage: number;
|
||||||
export let skip: number;
|
|
||||||
export let base: string;
|
export let base: string;
|
||||||
|
|
||||||
// make some variables
|
// make some variables
|
||||||
|
|
|
||||||
|
|
@ -17,11 +17,10 @@ type Sources = {
|
||||||
height: string;
|
height: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const { height, src, width }: ImageMeta = meta;
|
const { height, src, width } = meta as ImageMeta;
|
||||||
|
|
||||||
const sources: Sources[] = [];
|
const sources: Sources[] = [];
|
||||||
const imageFormatsMetadata: ImageMeta[] = JSON.parse(formatMeta);
|
const imageFormatsMetadata: ImageMeta[] = JSON.parse(`${formatMeta}`);
|
||||||
console.log(`Image format metadata: ${JSON.parse(imageFormatsMetadata)}`);
|
|
||||||
for (const metadata of imageFormatsMetadata) {
|
for (const metadata of imageFormatsMetadata) {
|
||||||
sources.push({
|
sources.push({
|
||||||
srcset: new URL(metadata.src),
|
srcset: new URL(metadata.src),
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,16 @@
|
||||||
import satori from 'satori';
|
import satori from 'satori';
|
||||||
import { Resvg } from '@resvg/resvg-js';
|
import { Resvg } from '@resvg/resvg-js';
|
||||||
import { html as toReactNode } from 'satori-html';
|
import { html as toReactNode } from 'satori-html';
|
||||||
|
import { dev } from '$app/environment';
|
||||||
|
import { read } from '$app/server';
|
||||||
|
|
||||||
// we use a Vite plugin to turn this import into the result of fs.readFileSync during build
|
// we use a Vite plugin to turn this import into the result of fs.readFileSync during build
|
||||||
import firaSansSemiBold from '$lib/fonts/FiraSans-SemiBold.ttf';
|
import firaSansSemiBold from '$lib/fonts/FiraSans-SemiBold.ttf';
|
||||||
import { dev } from '$app/environment';
|
import type { SvelteComponent } from 'svelte';
|
||||||
|
|
||||||
export async function componentToPng(component,
|
const fontData = read(firaSansSemiBold).arrayBuffer();
|
||||||
|
|
||||||
|
export async function componentToPng(component: SvelteComponent,
|
||||||
props: Record<string, string | undefined>,
|
props: Record<string, string | undefined>,
|
||||||
height: number, width: number) {
|
height: number, width: number) {
|
||||||
const result = component.render(props);
|
const result = component.render(props);
|
||||||
|
|
@ -16,7 +20,7 @@ export async function componentToPng(component,
|
||||||
fonts: [
|
fonts: [
|
||||||
{
|
{
|
||||||
name: 'Fira Sans',
|
name: 'Fira Sans',
|
||||||
data: Buffer.from(firaSansSemiBold),
|
data: await fontData,
|
||||||
style: 'normal'
|
style: 'normal'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
@ -31,9 +35,9 @@ export async function componentToPng(component,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const png = resvg.render();
|
const image = resvg.render();
|
||||||
|
|
||||||
return new Response(png.asPng(), {
|
return new Response(image.asPng(), {
|
||||||
headers: {
|
headers: {
|
||||||
'content-type': 'image/png',
|
'content-type': 'image/png',
|
||||||
'cache-control': dev ? 'no-cache, no-store' : 'public, immutable, no-transform, max-age=86400'
|
'cache-control': dev ? 'no-cache, no-store' : 'public, immutable, no-transform, max-age=86400'
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ export type Album = {
|
||||||
artwork: string;
|
artwork: string;
|
||||||
title: string;
|
title: string;
|
||||||
artist: string;
|
artist: string;
|
||||||
|
src: Record<string, any> | ExternalImageSource[] | undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ExternalImageSource = {
|
export type ExternalImageSource = {
|
||||||
|
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
export function getCookieLookup() {
|
|
||||||
if (typeof document !== 'object') {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
return document.cookie.split('; ').reduce((lookup, v) => {
|
|
||||||
const parts = v.split('=');
|
|
||||||
lookup[parts[0]] = parts[1];
|
|
||||||
|
|
||||||
return lookup;
|
|
||||||
}, {});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getCurrentCookieValue = (name) => {
|
|
||||||
const cookies = getCookieLookup();
|
|
||||||
return cookies[name] ?? '';
|
|
||||||
};
|
|
||||||
|
|
@ -7,117 +7,26 @@
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
let articles: Article[];
|
let articles: Article[];
|
||||||
let currentPage: number;
|
let currentPage: number;
|
||||||
let totalPages: number;
|
|
||||||
let totalArticles: number;
|
let totalArticles: number;
|
||||||
let limit: number;
|
let limit: number;
|
||||||
$: ({ articles, currentPage, totalPages, totalArticles, limit } = data);
|
$: ({ articles, currentPage, totalPages, totalArticles, limit } = data);
|
||||||
$: seoTitle = `Tech Articles - Page ${currentPage} | Bradley Shellnut`;
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="pageStyles">
|
<div>
|
||||||
<h1 style="margin-bottom: 2rem">Favorite Tech Articles</h1>
|
<h1 style="margin-bottom: 2rem">Favorite Tech Articles</h1>
|
||||||
<Pagination
|
<Pagination
|
||||||
additionalClasses="top-pagination"
|
additionalClasses="top-pagination"
|
||||||
pageSize={limit}
|
pageSize={limit}
|
||||||
totalCount={totalArticles}
|
totalCount={totalArticles}
|
||||||
currentPage={currentPage || 1}
|
currentPage={currentPage || 1}
|
||||||
skip={currentPage}
|
|
||||||
base="/articles"
|
base="/articles"
|
||||||
/>
|
/>
|
||||||
<Articles {articles} {totalArticles} classes={['columns']} />
|
<Articles {articles} {totalArticles} classes={['columns']} />
|
||||||
<!-- <div class="articlesStyles">
|
|
||||||
{#each articles as article (article.hashed_url)}
|
|
||||||
<div class="articleStyles card">
|
|
||||||
<section>
|
|
||||||
<h3>
|
|
||||||
<a
|
|
||||||
target="_blank"
|
|
||||||
aria-label={`Link to ${article.title}`}
|
|
||||||
href={article.url.toString()}
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
{article.title}
|
|
||||||
</a>
|
|
||||||
</h3>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<p>Reading time: {article.reading_time} minutes</p>
|
|
||||||
<div class="tagStyles">
|
|
||||||
<p>Tags:</p>
|
|
||||||
{#each article.tags as tag}
|
|
||||||
<p>{tag}</p>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
</div> -->
|
|
||||||
<Pagination
|
<Pagination
|
||||||
additionalClasses="bottom-pagination"
|
additionalClasses="bottom-pagination"
|
||||||
pageSize={limit}
|
pageSize={limit}
|
||||||
totalCount={totalArticles}
|
totalCount={totalArticles}
|
||||||
currentPage={currentPage || 1}
|
currentPage={currentPage || 1}
|
||||||
skip={currentPage}
|
|
||||||
base="/articles"
|
base="/articles"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="postcss">
|
|
||||||
.pageStyles {
|
|
||||||
.bottom-pagination {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 650px) {
|
|
||||||
.bottom-pagination {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.articlesStyles {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(2, minmax(250px, 1fr));
|
|
||||||
min-height: 800px;
|
|
||||||
|
|
||||||
@media (max-width: 1000px) {
|
|
||||||
grid-template-columns: repeat(2, minmax(250px, 1fr));
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 650px) {
|
|
||||||
grid-template-columns: minmax(250px, 1fr);
|
|
||||||
}
|
|
||||||
|
|
||||||
gap: 2.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.articleStyles {
|
|
||||||
display: grid;
|
|
||||||
grid-template-rows: 1fr auto;
|
|
||||||
align-items: start;
|
|
||||||
& a {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* p {
|
|
||||||
margin: 0.4rem 0.25rem;
|
|
||||||
} */
|
|
||||||
}
|
|
||||||
|
|
||||||
.tagStyles {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: left;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
& p + p {
|
|
||||||
background-color: var(--linkHover);
|
|
||||||
color: var(--buttonTextColor);
|
|
||||||
padding: 0.25rem 0.5rem;
|
|
||||||
margin: 0.5rem;
|
|
||||||
border-radius: 2px;
|
|
||||||
font-size: 1.2rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -4,18 +4,21 @@ import { componentToPng } from '$root/lib/renderImage';
|
||||||
const height = 630;
|
const height = 630;
|
||||||
const width = 1200;
|
const width = 1200;
|
||||||
|
|
||||||
|
/** @type {import('./$types').RequestHandler} */
|
||||||
export async function GET({ url }) {
|
export async function GET({ url }) {
|
||||||
try {
|
try {
|
||||||
const ogImage = `${new URL(url.origin).href}/b_shell_nut_favicon.png`;
|
const faviconImageName = 'b_shell_nut_favicon.png';
|
||||||
|
const image = `${new URL(url.origin).href}${faviconImageName}`;
|
||||||
const header = url.searchParams.get('header') ?? undefined;
|
const header = url.searchParams.get('header') ?? undefined;
|
||||||
const page = url.searchParams.get('page') ?? undefined;
|
const page = url.searchParams.get('page') ?? undefined;
|
||||||
const content = url.searchParams.get('content') ?? '';
|
const content = url.searchParams.get('content') ?? '';
|
||||||
|
|
||||||
|
// @ts-expect-error: Argument of type 'typeof SocialImageCard__SvelteComponent_' is not assignable to parameter of type 'SvelteComponent<any, any, any>'
|
||||||
return componentToPng(SocialImageCard, {
|
return componentToPng(SocialImageCard, {
|
||||||
header,
|
header,
|
||||||
page,
|
page,
|
||||||
content,
|
content,
|
||||||
image: ogImage,
|
image,
|
||||||
width: `${width}`,
|
width: `${width}`,
|
||||||
height: `${height}`,
|
height: `${height}`,
|
||||||
url: new URL(url.origin).href
|
url: new URL(url.origin).href
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,13 @@
|
||||||
import weddingWebsite from "$lib/assets/images/portfolio/Wedding_Website.png?as=run";
|
import weddingWebsite from "$lib/assets/images/portfolio/Wedding_Website.png?as=run";
|
||||||
import oldSite from '$lib/assets/images/portfolio/Old_Website_Bradley_Shellnut.png?as=run';
|
import oldSite from '$lib/assets/images/portfolio/Old_Website_Bradley_Shellnut.png?as=run';
|
||||||
import shellnutArchitectWebsite from "$lib/assets/images/portfolio/Mark_Shellnut_Architect.png?as=run";
|
import shellnutArchitectWebsite from "$lib/assets/images/portfolio/Mark_Shellnut_Architect.png?as=run";
|
||||||
|
// @ts-expect-error: Cannot find module '$lib/content/uses/development.md' or its corresponding type declarations.ts(2307)
|
||||||
import PersonalWebsiteSvelteKit from "$lib/content/portfolio/personal/personal-website-sveltekit.md";
|
import PersonalWebsiteSvelteKit from "$lib/content/portfolio/personal/personal-website-sveltekit.md";
|
||||||
|
// @ts-expect-error: Cannot find module '$lib/content/uses/development.md' or its corresponding type declarations.ts(2307)
|
||||||
import WeddingWebsite from '$lib/content/portfolio/personal/wedding-website.md';
|
import WeddingWebsite from '$lib/content/portfolio/personal/wedding-website.md';
|
||||||
|
// @ts-expect-error: Cannot find module '$lib/content/uses/development.md' or its corresponding type declarations.ts(2307)
|
||||||
import MarkShellnutArchitect from '$lib/content/portfolio/professional/mark-shellnut-architect.md';
|
import MarkShellnutArchitect from '$lib/content/portfolio/professional/mark-shellnut-architect.md';
|
||||||
|
// @ts-expect-error: Cannot find module '$lib/content/uses/development.md' or its corresponding type declarations.ts(2307)
|
||||||
import OldWebsite from '$lib/content/portfolio/personal/old-website.md';
|
import OldWebsite from '$lib/content/portfolio/personal/old-website.md';
|
||||||
import ExternalLink from '$lib/components/ExternalLink.svelte';
|
import ExternalLink from '$lib/components/ExternalLink.svelte';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,11 @@
|
||||||
import ExternalLink from '$lib/components/ExternalLink.svelte';
|
import ExternalLink from '$lib/components/ExternalLink.svelte';
|
||||||
import LazyImage from '$lib/components/LazyImage.svelte';
|
import LazyImage from '$lib/components/LazyImage.svelte';
|
||||||
import desktop from '$lib/assets/images/Desktop_so_clean.jpg?as=run';
|
import desktop from '$lib/assets/images/Desktop_so_clean.jpg?as=run';
|
||||||
|
// @ts-expect-error: Cannot find module '$lib/content/uses/development.md' or its corresponding type declarations.ts(2307)
|
||||||
import HardwareAccessories from '$lib/content/uses/hardware-accessories.md';
|
import HardwareAccessories from '$lib/content/uses/hardware-accessories.md';
|
||||||
|
// @ts-expect-error: Cannot find module '$lib/content/uses/development.md' or its corresponding type declarations.ts(2307)
|
||||||
import Development from '$lib/content/uses/development.md';
|
import Development from '$lib/content/uses/development.md';
|
||||||
|
// @ts-expect-error: Cannot find module '$lib/content/uses/development.md' or its corresponding type declarations.ts(2307)
|
||||||
import PrivacyHardwareSoftware from '$lib/content/uses/privacy-hardware-software.md';
|
import PrivacyHardwareSoftware from '$lib/content/uses/privacy-hardware-software.md';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { sveltekit } from '@sveltejs/kit/vite';
|
import { sveltekit } from '@sveltejs/kit/vite';
|
||||||
import fs from 'fs';
|
|
||||||
import type { UserConfig } from 'vite';
|
import type { UserConfig } from 'vite';
|
||||||
import { imagetools } from '@zerodevx/svelte-img/vite';
|
import { imagetools } from '@zerodevx/svelte-img/vite';
|
||||||
|
|
||||||
|
|
@ -12,27 +11,11 @@ const config: UserConfig = {
|
||||||
profiles: {
|
profiles: {
|
||||||
run: new URLSearchParams('?w=300;480;640;1024;1920&format=avif;webp;jpg&as=run:64')
|
run: new URLSearchParams('?w=300;480;640;1024;1920&format=avif;webp;jpg&as=run:64')
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
rawFonts(['.ttf'])
|
|
||||||
],
|
],
|
||||||
test: {
|
test: {
|
||||||
include: ['src/**/*.{test,spec}.{js,ts}']
|
include: ['src/**/*.{test,spec}.{js,ts}']
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function rawFonts(ext) {
|
|
||||||
return {
|
|
||||||
name: 'vite-plugin-raw-fonts',
|
|
||||||
resolveId(id) {
|
|
||||||
return ext.some((e) => id.endsWith(e)) ? id : null;
|
|
||||||
},
|
|
||||||
transform(code, id) {
|
|
||||||
if (ext.some((e) => id.endsWith(e))) {
|
|
||||||
const buffer = fs.readFileSync(id);
|
|
||||||
return { code: `export default ${JSON.stringify(buffer)}`, map: null };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue