mirror of
https://github.com/BradNut/personal-website-sveltekit
synced 2025-09-08 23:20:18 +00:00
Svelte 5 for portfolio page.
This commit is contained in:
parent
e6a2f8fcb6
commit
e8c6b83a1e
6 changed files with 132 additions and 65 deletions
|
|
@ -63,6 +63,7 @@
|
||||||
"@resvg/resvg-js": "^2.6.2",
|
"@resvg/resvg-js": "^2.6.2",
|
||||||
"@sveltejs/adapter-vercel": "^5.5.0",
|
"@sveltejs/adapter-vercel": "^5.5.0",
|
||||||
"@types/nprogress": "^0.2.3",
|
"@types/nprogress": "^0.2.3",
|
||||||
|
"@unpic/svelte": "^0.0.56",
|
||||||
"@vercel/og": "^0.6.4",
|
"@vercel/og": "^0.6.4",
|
||||||
"bits-ui": "^0.21.16",
|
"bits-ui": "^0.21.16",
|
||||||
"flexsearch": "^0.7.43",
|
"flexsearch": "^0.7.43",
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,9 @@ importers:
|
||||||
'@types/nprogress':
|
'@types/nprogress':
|
||||||
specifier: ^0.2.3
|
specifier: ^0.2.3
|
||||||
version: 0.2.3
|
version: 0.2.3
|
||||||
|
'@unpic/svelte':
|
||||||
|
specifier: ^0.0.56
|
||||||
|
version: 0.0.56(svelte@5.3.1)
|
||||||
'@vercel/og':
|
'@vercel/og':
|
||||||
specifier: ^0.6.4
|
specifier: ^0.6.4
|
||||||
version: 0.6.4
|
version: 0.6.4
|
||||||
|
|
@ -1395,6 +1398,14 @@ packages:
|
||||||
'@types/unist@2.0.6':
|
'@types/unist@2.0.6':
|
||||||
resolution: {integrity: sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==}
|
resolution: {integrity: sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==}
|
||||||
|
|
||||||
|
'@unpic/core@0.0.52':
|
||||||
|
resolution: {integrity: sha512-XRX0ePG0nH/K9x/coCQwFzSzg66INBNgPZR2FeSis6BHyxw3sBjL4KDzYse6d/Zx0F3APWsWkK2htaGRznjHMw==}
|
||||||
|
|
||||||
|
'@unpic/svelte@0.0.56':
|
||||||
|
resolution: {integrity: sha512-YkZaHLYEQycs4MoBH0YXt29hdSaS6RoUOpSf1IaZ4MnfJOrRcjpAxIsN8uMaLu8g7IyxO9dWHmPmmECpKluA5g==}
|
||||||
|
peerDependencies:
|
||||||
|
svelte: '*'
|
||||||
|
|
||||||
'@vercel/nft@0.27.1':
|
'@vercel/nft@0.27.1':
|
||||||
resolution: {integrity: sha512-K6upzYHCV1cq2gP83r1o8uNV1vwvAlozvMqp7CEjYWxo0CMI8/4jKcDkVjlypVhrfZ54SXwh9QbH0ZIk/vQCsw==}
|
resolution: {integrity: sha512-K6upzYHCV1cq2gP83r1o8uNV1vwvAlozvMqp7CEjYWxo0CMI8/4jKcDkVjlypVhrfZ54SXwh9QbH0ZIk/vQCsw==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
|
|
@ -2634,6 +2645,9 @@ packages:
|
||||||
strip-literal@2.1.0:
|
strip-literal@2.1.0:
|
||||||
resolution: {integrity: sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==}
|
resolution: {integrity: sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==}
|
||||||
|
|
||||||
|
style-object-to-css-string@1.1.3:
|
||||||
|
resolution: {integrity: sha512-bISQoUsir/qGfo7vY8rw00ia9nnyE1jvYt3zZ2jhdkcXZ6dAEi74inMzQ6On57vFI+I4Fck6wOv5UI9BEwJDgw==}
|
||||||
|
|
||||||
supports-preserve-symlinks-flag@1.0.0:
|
supports-preserve-symlinks-flag@1.0.0:
|
||||||
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
|
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
@ -2789,6 +2803,9 @@ packages:
|
||||||
unist-util-visit@3.1.0:
|
unist-util-visit@3.1.0:
|
||||||
resolution: {integrity: sha512-Szoh+R/Ll68QWAyQyZZpQzZQm2UPbxibDvaY8Xc9SUtYgPsDzx5AWSk++UUt2hJuow8mvwR+rG+LQLw+KsuAKA==}
|
resolution: {integrity: sha512-Szoh+R/Ll68QWAyQyZZpQzZQm2UPbxibDvaY8Xc9SUtYgPsDzx5AWSk++UUt2hJuow8mvwR+rG+LQLw+KsuAKA==}
|
||||||
|
|
||||||
|
unpic@3.20.0:
|
||||||
|
resolution: {integrity: sha512-reWY4Ez9FCjw8J7fGByyyi1Z1fv20xjkFgDa9xI7vqdg89fcLzUYkROKo7yZ5WHRelq6x+pL4ohPRzEdU020aQ==}
|
||||||
|
|
||||||
update-browserslist-db@1.1.0:
|
update-browserslist-db@1.1.0:
|
||||||
resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==}
|
resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
@ -3944,6 +3961,17 @@ snapshots:
|
||||||
|
|
||||||
'@types/unist@2.0.6': {}
|
'@types/unist@2.0.6': {}
|
||||||
|
|
||||||
|
'@unpic/core@0.0.52':
|
||||||
|
dependencies:
|
||||||
|
unpic: 3.20.0
|
||||||
|
|
||||||
|
'@unpic/svelte@0.0.56(svelte@5.3.1)':
|
||||||
|
dependencies:
|
||||||
|
'@unpic/core': 0.0.52
|
||||||
|
style-object-to-css-string: 1.1.3
|
||||||
|
svelte: 5.3.1
|
||||||
|
unpic: 3.20.0
|
||||||
|
|
||||||
'@vercel/nft@0.27.1':
|
'@vercel/nft@0.27.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@mapbox/node-pre-gyp': 1.0.11
|
'@mapbox/node-pre-gyp': 1.0.11
|
||||||
|
|
@ -5335,6 +5363,8 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
js-tokens: 9.0.0
|
js-tokens: 9.0.0
|
||||||
|
|
||||||
|
style-object-to-css-string@1.1.3: {}
|
||||||
|
|
||||||
supports-preserve-symlinks-flag@1.0.0: {}
|
supports-preserve-symlinks-flag@1.0.0: {}
|
||||||
|
|
||||||
svelte-check@4.1.0(picomatch@4.0.2)(svelte@5.3.1)(typescript@5.7.2):
|
svelte-check@4.1.0(picomatch@4.0.2)(svelte@5.3.1)(typescript@5.7.2):
|
||||||
|
|
@ -5483,6 +5513,8 @@ snapshots:
|
||||||
unist-util-is: 5.2.0
|
unist-util-is: 5.2.0
|
||||||
unist-util-visit-parents: 4.1.1
|
unist-util-visit-parents: 4.1.1
|
||||||
|
|
||||||
|
unpic@3.20.0: {}
|
||||||
|
|
||||||
update-browserslist-db@1.1.0(browserslist@4.23.3):
|
update-browserslist-db@1.1.0(browserslist@4.23.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
browserslist: 4.23.3
|
browserslist: 4.23.3
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,30 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import LazyImage from './LazyImage.svelte';
|
import type { Picture } from 'vite-imagetools';
|
||||||
|
import type { Snippet } from 'svelte';
|
||||||
|
import { ExternalLinkType } from '../types/externalLinkType';
|
||||||
|
|
||||||
export let name: string;
|
const {
|
||||||
export let src: Record<string, any>;
|
links,
|
||||||
export let alt: string;
|
details,
|
||||||
export let style = "";
|
portfolioDetails,
|
||||||
export let loading: "lazy" | "eager" = "lazy";
|
externalLinks,
|
||||||
|
name,
|
||||||
|
src,
|
||||||
|
alt,
|
||||||
|
style,
|
||||||
|
fetchpriority = 'auto',
|
||||||
|
loading = 'lazy',
|
||||||
|
}: { links: Snippet<ExternalLinkType[]>, details: Snippet<string>, portfolioDetails: string, externalLinks: ExternalLinkType[], name: string; src: string | Picture; alt: string; style: string; fetchpriority?: 'high' | 'low' | 'auto'; loading?: 'lazy' | 'eager' } = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="portfolio">
|
<div class="portfolio">
|
||||||
<div class="portfolio-picture">
|
<div class="portfolio-picture">
|
||||||
<h2>{name}</h2>
|
<h2>{name}</h2>
|
||||||
<LazyImage {style} {src} {alt} {loading} />
|
<enhanced:img {src} {style} {alt} {fetchpriority} {loading} />
|
||||||
<slot name="portfolio-links" />
|
{@render links(externalLinks)}
|
||||||
</div>
|
</div>
|
||||||
<div class="portfolio-details">
|
<div class="portfolio-details">
|
||||||
<slot name="portfolio-details" />
|
{@render details()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
9
src/lib/types/externalLinkType.ts
Normal file
9
src/lib/types/externalLinkType.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
import type { IconifyIcon } from "iconify-icon";
|
||||||
|
|
||||||
|
export type ExternalLinkType = {
|
||||||
|
ariaLabel: string;
|
||||||
|
href: string;
|
||||||
|
icon?: IconifyIcon;
|
||||||
|
showIcon: boolean;
|
||||||
|
text: string;
|
||||||
|
};
|
||||||
|
|
@ -43,10 +43,10 @@ export const load: PageServerLoad = async ({ fetch, setHeaders, url }) => {
|
||||||
url: currentPageUrl
|
url: currentPageUrl
|
||||||
});
|
});
|
||||||
|
|
||||||
const [albums, articles]: [Album[], ArticlePageLoad] = await Promise.all([
|
// const [albums, articles]: [Album[], ArticlePageLoad] = await Promise.all([
|
||||||
await fetchBandcampAlbums(),
|
// await fetchBandcampAlbums(),
|
||||||
(await fetch('/api/articles?page=1&limit=3')).json()
|
// (await fetch('/api/articles?page=1&limit=3')).json()
|
||||||
]);
|
// ]);
|
||||||
|
|
||||||
setHeaders({
|
setHeaders({
|
||||||
'cache-control': 'max-age=43200'
|
'cache-control': 'max-age=43200'
|
||||||
|
|
@ -54,7 +54,7 @@ export const load: PageServerLoad = async ({ fetch, setHeaders, url }) => {
|
||||||
return {
|
return {
|
||||||
baseUrl,
|
baseUrl,
|
||||||
metaTagsChild: metaTags,
|
metaTagsChild: metaTags,
|
||||||
albums,
|
albums: await fetchBandcampAlbums(),
|
||||||
articlesData: articles
|
articlesData: await (await fetch('/api/articles?page=1&limit=3')).json()
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
@ -1,33 +1,53 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createTabs, melt } from '@melt-ui/svelte';
|
import ExternalLink from '$lib/components/ExternalLink.svelte';
|
||||||
import GitHub from '@iconify-icons/simple-icons/github';
|
import Portfolio from '$lib/components/Portfolio.svelte';
|
||||||
import Portfolio from '$lib/components/Portfolio.svelte';
|
// @ts-expect-error: Cannot find module '$lib/content/uses/development.md' or its corresponding type declarations.ts(2307)
|
||||||
import personalSite from "$lib/assets/images/portfolio/Bradley_Shellnut_New_Site.png?as=run";
|
import OldWebsite from '$lib/content/portfolio/personal/old-website.md';
|
||||||
import weddingWebsite from "$lib/assets/images/portfolio/Wedding_Website.png?as=run";
|
// @ts-expect-error: Cannot find module '$lib/content/uses/development.md' or its corresponding type declarations.ts(2307)
|
||||||
import oldSite from '$lib/assets/images/portfolio/Old_Website_Bradley_Shellnut.png?as=run';
|
import PersonalWebsiteSvelteKit from '$lib/content/portfolio/personal/personal-website-sveltekit.md';
|
||||||
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)
|
||||||
// @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 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)
|
||||||
// @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 WeddingWebsite from '$lib/content/portfolio/personal/wedding-website.md';
|
import type { ExternalLinkType } from '$lib/types/externalLinkType';
|
||||||
// @ts-expect-error: Cannot find module '$lib/content/uses/development.md' or its corresponding type declarations.ts(2307)
|
import GitHub from '@iconify-icons/simple-icons/github';
|
||||||
import MarkShellnutArchitect from '$lib/content/portfolio/professional/mark-shellnut-architect.md';
|
import { createTabs, melt } from '@melt-ui/svelte';
|
||||||
// @ts-expect-error: Cannot find module '$lib/content/uses/development.md' or its corresponding type declarations.ts(2307)
|
import personalSite from '../../lib/assets/images/portfolio/Bradley_Shellnut_New_Site.png?enhanced';
|
||||||
import OldWebsite from '$lib/content/portfolio/personal/old-website.md';
|
import shellnutArchitectWebsite from '../../lib/assets/images/portfolio/Mark_Shellnut_Architect.png?enhanced';
|
||||||
import ExternalLink from '$lib/components/ExternalLink.svelte';
|
import oldSite from '../../lib/assets/images/portfolio/Old_Website_Bradley_Shellnut.png?enhanced';
|
||||||
|
import weddingWebsite from '../../lib/assets/images/portfolio/Wedding_Website.png?enhanced';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
elements: { root, list, content, trigger }
|
elements: { root, list, content, trigger },
|
||||||
} = createTabs({
|
} = createTabs({
|
||||||
defaultValue: 'personal'
|
defaultValue: 'personal',
|
||||||
});
|
});
|
||||||
|
|
||||||
const triggers = [
|
const triggers = [
|
||||||
{ id: 'personal', title: 'Personal Sites' },
|
{ id: 'personal', title: 'Personal Sites' },
|
||||||
{ id: 'professional', title: 'Professional Sites'}
|
{ id: 'professional', title: 'Professional Sites' },
|
||||||
];
|
];
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
{#snippet links(externalLinks: ExternalLinkType[])}
|
||||||
|
<span>
|
||||||
|
{#each externalLinks as link}
|
||||||
|
<ExternalLink
|
||||||
|
ariaLabel={link.ariaLabel}
|
||||||
|
href={link.href}
|
||||||
|
icon={link.icon}
|
||||||
|
showIcon={link.showIcon}
|
||||||
|
>
|
||||||
|
{link.text}
|
||||||
|
</ExternalLink>
|
||||||
|
{/each}
|
||||||
|
</span>
|
||||||
|
{/snippet}
|
||||||
|
|
||||||
|
{#snippet details(portfolioDetails: string)}
|
||||||
|
{portfolioDetails}
|
||||||
|
{/snippet}
|
||||||
|
|
||||||
<h1>Portfolio!</h1>
|
<h1>Portfolio!</h1>
|
||||||
<div use:melt={$root} class="root tab-group">
|
<div use:melt={$root} class="root tab-group">
|
||||||
<div use:melt={$list} aria-label="tabs portfolios" class="list tab-list">
|
<div use:melt={$list} aria-label="tabs portfolios" class="list tab-list">
|
||||||
|
|
@ -42,42 +62,38 @@
|
||||||
style="max-height: 550px;"
|
style="max-height: 550px;"
|
||||||
src={personalSite}
|
src={personalSite}
|
||||||
loading="eager"
|
loading="eager"
|
||||||
alt="Picture of Bradley Shellnut's Personal Website">
|
alt="Picture of Bradley Shellnut's Personal Website"
|
||||||
<span slot="portfolio-links">
|
{links}
|
||||||
<ExternalLink ariaLabel="View GitHub repository for my personal website" href="https://github.com/BradNut/personal-website-sveltekit" icon={GitHub} showIcon>GitHub repository</ExternalLink>
|
{details}
|
||||||
</span>
|
portfolioDetails={PersonalWebsiteSvelteKit}
|
||||||
<PersonalWebsiteSvelteKit slot="portfolio-details" />
|
externalLinks={[{ ariaLabel: 'View GitHub repository for my personal website', href: 'https://github.com/BradNut/personal-website-sveltekit', icon: GitHub, showIcon: true, text: 'GitHub repository'}]}>
|
||||||
</Portfolio>
|
</Portfolio>
|
||||||
<Portfolio name="Wedding Website"
|
<Portfolio name="Wedding Website"
|
||||||
style="max-height: 550px;"
|
style="max-height: 550px;"
|
||||||
src={weddingWebsite}
|
src={weddingWebsite}
|
||||||
alt="Picture of NextJS Wedding Website">
|
alt="Picture of NextJS Wedding Website"
|
||||||
<span slot="portfolio-links">
|
{links}
|
||||||
<ExternalLink ariaLabel="View Wedding Website" href="https://weddingsite-six.vercel.app/" showIcon>View Site</ExternalLink>
|
{details}
|
||||||
<ExternalLink ariaLabel="View GitHub repository for the wedding site" href="https://github.com/BradNut/weddingsite" icon={GitHub} showIcon>GitHub repository</ExternalLink>
|
portfolioDetails={WeddingWebsite}
|
||||||
</span>
|
externalLinks={[{ ariaLabel: 'View GitHub repository for the wedding site', href: 'https://github.com/BradNut/weddingsite', icon: GitHub, showIcon: true, text: 'GitHub repository'}]}/>
|
||||||
<WeddingWebsite slot="portfolio-details" />
|
<Portfolio name="Old Personal Website"
|
||||||
</Portfolio>
|
|
||||||
<Portfolio name="Old Personal Website"
|
|
||||||
style="max-height: 320px;"
|
style="max-height: 320px;"
|
||||||
src={oldSite}
|
src={oldSite}
|
||||||
alt="Home Page of the old bradleyshellnut.com website">
|
alt="Home Page of the old bradleyshellnut.com website"
|
||||||
<span slot="portfolio-links">
|
{links}
|
||||||
<ExternalLink ariaLabel="Archive of bradleyshellnut.com" href="https://web.archive.org/web/20201205233507/https://bradleyshellnut.com/about" showIcon>Link to an archive snapshot</ExternalLink>
|
{details}
|
||||||
</span>
|
portfolioDetails={OldWebsite}
|
||||||
<OldWebsite slot="portfolio-details" />
|
externalLinks={[{ ariaLabel: 'Archive of bradleyshellnut.com', href: 'https://web.archive.org/web/20201205233507/https://bradleyshellnut.com/about', icon: GitHub, showIcon: true, text: 'Link to an archive snapshot'}]}/>
|
||||||
</Portfolio>
|
|
||||||
</div>
|
</div>
|
||||||
<div use:melt={$content('professional')} class="content">
|
<div use:melt={$content('professional')} class="content">
|
||||||
<Portfolio name="Mark Shellnut Architect"
|
<Portfolio name="Mark Shellnut Architect"
|
||||||
style="max-height: 550px;"
|
style="max-height: 550px;"
|
||||||
src={shellnutArchitectWebsite}
|
src={shellnutArchitectWebsite}
|
||||||
alt="Picture of Mark Shellnut Architect's Website">
|
alt="Picture of Mark Shellnut Architect's Website"
|
||||||
<span slot="portfolio-links">
|
{links}
|
||||||
<ExternalLink ariaLabel="View markshellnutarchitect.com" href="https://markshellnutarchitect.com" showIcon>Link to Mark Shellnut's Website</ExternalLink>
|
{details}
|
||||||
</span>
|
portfolioDetails={MarkShellnutArchitect}
|
||||||
<MarkShellnutArchitect slot="portfolio-details" />
|
externalLinks={[{ ariaLabel: 'View Mark Shellnut Architect', href: 'https://markshellnutarchitect.com', showIcon: false, text: 'Link to Mark Shellnut Architect'}]} />
|
||||||
</Portfolio>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue