Compare commits
18 Commits
757924d786
...
2.15.1
| Author | SHA1 | Date | |
|---|---|---|---|
| c5cda006bb | |||
| 959d3bd71d | |||
| f3b8d10106 | |||
| 0c63c6bef4 | |||
| 5e37e2bb53 | |||
| b3c377f62d | |||
| 0d87af3aca | |||
| 9eb0f37cb2 | |||
| 76dfef4177 | |||
| d415dda661 | |||
| ea9ae016d7 | |||
| 0416ab7f9e | |||
| 6f1728a909 | |||
| db2711d878 | |||
| 7f2a27248a | |||
| c927235a5a | |||
| 8d5c02e2d1 | |||
| 1a34b932b0 |
@@ -25,9 +25,10 @@ jobs:
|
|||||||
RENOVATE_ENDPOINT: ${{ vars.INSTANCE_URL }}
|
RENOVATE_ENDPOINT: ${{ vars.INSTANCE_URL }}
|
||||||
RENOVATE_REPOSITORIES: alexlebens/site-profile
|
RENOVATE_REPOSITORIES: alexlebens/site-profile
|
||||||
RENOVATE_GIT_AUTHOR: Renovate Bot <renovate-bot@alexlebens.net>
|
RENOVATE_GIT_AUTHOR: Renovate Bot <renovate-bot@alexlebens.net>
|
||||||
|
RENOVATE_REDIS_URL: ${{ vars.RENOVATE_REDIS_URL }}
|
||||||
LOG_LEVEL: info
|
LOG_LEVEL: info
|
||||||
RENOVATE_TOKEN: ${{ secrets.RENOVATE_TOKEN }}
|
RENOVATE_TOKEN: ${{ secrets.RENOVATE_TOKEN }}
|
||||||
RENOVATE_GIT_PRIVATE_KEY: ${{ secrets.RENOVATE_GIT_PRIVATE_KEY }}
|
RENOVATE_GIT_PRIVATE_KEY: ${{ secrets.RENOVATE_GIT_PRIVATE_KEY }}
|
||||||
RENOVATE_GITHUB_COM_TOKEN: ${{ secrets.RENOVATE_GITHUB_COM_TOKEN }}
|
RENOVATE_GITHUB_COM_TOKEN: ${{ secrets.RENOVATE_GITHUB_COM_TOKEN }}
|
||||||
|
RENOVATE_REGISTRY_ALIASES: '{"dhi.io": "dhi.io"}'
|
||||||
RENOVATE_HOST_RULES: '[{"matchHost":"dhi.io","hostType":"docker","username":"${{ secrets.RENOVATE_DHI_USER }}","password":"${{ secrets.RENOVATE_DHI_TOKEN }}"}]'
|
RENOVATE_HOST_RULES: '[{"matchHost":"dhi.io","hostType":"docker","username":"${{ secrets.RENOVATE_DHI_USER }}","password":"${{ secrets.RENOVATE_DHI_TOKEN }}"}]'
|
||||||
RENOVATE_REDIS_URL: ${{ vars.RENOVATE_REDIS_URL }}
|
|
||||||
|
|||||||
10
Dockerfile
10
Dockerfile
@@ -22,13 +22,11 @@ WORKDIR /app
|
|||||||
COPY --from=prod-deps /app/node_modules /app/node_modules
|
COPY --from=prod-deps /app/node_modules /app/node_modules
|
||||||
COPY --from=build /app/dist /app/dist
|
COPY --from=build /app/dist /app/dist
|
||||||
|
|
||||||
ENV HOST=0.0.0.0
|
LABEL version="2.15.1"
|
||||||
ENV SITE_URL=https://www.alexlebens.dev
|
|
||||||
ENV DIRECTUS_URL=https://directus.alexlebens.net
|
|
||||||
ENV PORT=4321
|
|
||||||
|
|
||||||
LABEL version="2.13.0"
|
|
||||||
LABEL description="Astro based personal website"
|
LABEL description="Astro based personal website"
|
||||||
|
|
||||||
|
ENV HOST=0.0.0.0
|
||||||
|
ENV PORT=4321
|
||||||
|
|
||||||
EXPOSE $PORT
|
EXPOSE $PORT
|
||||||
CMD ["node", "./dist/server/entry.mjs"]
|
CMD ["node", "./dist/server/entry.mjs"]
|
||||||
|
|||||||
@@ -9,12 +9,7 @@ import tailwindcss from '@tailwindcss/vite';
|
|||||||
import icon from 'astro-icon';
|
import icon from 'astro-icon';
|
||||||
import swup from '@swup/astro';
|
import swup from '@swup/astro';
|
||||||
|
|
||||||
const getSiteURL = () => {
|
import { getSiteURL } from './src/support/url';
|
||||||
if (process.env.SITE_URL) {
|
|
||||||
return `https://${process.env.SITE_URL}`;
|
|
||||||
}
|
|
||||||
return 'http://localhost:4321';
|
|
||||||
};
|
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
site: getSiteURL(),
|
site: getSiteURL(),
|
||||||
@@ -23,6 +18,7 @@ export default defineConfig({
|
|||||||
remotePatterns: [
|
remotePatterns: [
|
||||||
{ protocol: 'https', hostname: '*.alexlebens.net' },
|
{ protocol: 'https', hostname: '*.alexlebens.net' },
|
||||||
{ protocol: 'https', hostname: '*.jsdelivr.net' },
|
{ protocol: 'https', hostname: '*.jsdelivr.net' },
|
||||||
|
{ protocol: 'https', hostname: '*.icons8.com' },
|
||||||
],
|
],
|
||||||
service: {
|
service: {
|
||||||
entrypoint: 'astro/assets/services/sharp',
|
entrypoint: 'astro/assets/services/sharp',
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "site-profile",
|
"name": "site-profile",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "2.13.0",
|
"version": "2.15.1",
|
||||||
"homepage": "https://www.alexlebens.dev",
|
"homepage": "https://www.alexlebens.dev",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://gitea.alexlebens.dev/alexlebens/site-profile/issues",
|
"url": "https://gitea.alexlebens.dev/alexlebens/site-profile/issues",
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
|
import { Image } from 'astro:assets';
|
||||||
import { readSingleton } from '@directus/sdk';
|
import { readSingleton } from '@directus/sdk';
|
||||||
|
|
||||||
import BrandLogo from '@components/ui/logos/BrandLogo.astro';
|
import BrandLogo from '@components/images/BrandLogo.astro';
|
||||||
import Image from '@components/ui/images/Image.astro';
|
|
||||||
import directus from '@lib/directus';
|
import directus from '@lib/directus';
|
||||||
import { NavigationLinks, FooterLinks } from '@/config';
|
import { NavigationLinks, FooterLinks } from '@/config';
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ const currentYear = new Date().getFullYear();
|
|||||||
format="webp"
|
format="webp"
|
||||||
quality="low"
|
quality="low"
|
||||||
widths={[440]}
|
widths={[440]}
|
||||||
disableBlur={true}
|
inferSize={true}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
import BrandLogo from '@components/ui/logos/BrandLogo.astro';
|
import BrandLogo from '@components/images/BrandLogo.astro';
|
||||||
import ThemeToggleButton from '@components/buttons/ThemeToggleButton.astro';
|
import ThemeToggleButton from '@components/buttons/ThemeToggleButton.astro';
|
||||||
import { NavigationLinks } from '@/config';
|
import { NavigationLinks } from '@/config';
|
||||||
|
|
||||||
@@ -11,7 +11,6 @@ const currentPath = pathname.slice(1);
|
|||||||
id="nav"
|
id="nav"
|
||||||
class="fixed flex flex-wrap md:flex-nowrap md:justify-start inset-x-0 top-0 w-full z-50"
|
class="fixed flex flex-wrap md:flex-nowrap md:justify-start inset-x-0 top-0 w-full z-50"
|
||||||
>
|
>
|
||||||
<div class="bg-linear-to-b from-background from-65% to-transparent to-90% absolute top-0 bottom-0 left-0 w-full h-36 z-0"/>
|
|
||||||
<nav
|
<nav
|
||||||
class="nav-base relative md:flex md:items-center md:justify-between rounded-[36px] w-full px-4 mx-2 py-3 mt-4"
|
class="nav-base relative md:flex md:items-center md:justify-between rounded-[36px] w-full px-4 mx-2 py-3 mt-4"
|
||||||
aria-label="Global"
|
aria-label="Global"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
import Icon from '@components/ui/icons/icon.astro';
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<button
|
<button
|
||||||
@@ -7,7 +7,22 @@ import Icon from '@components/ui/icons/icon.astro';
|
|||||||
class="button-base button-bg-blue group inline-flex items-center rounded-lg p-2.5"
|
class="button-base button-bg-blue group inline-flex items-center rounded-lg p-2.5"
|
||||||
data-bookmark-button="bookmark-button"
|
data-bookmark-button="bookmark-button"
|
||||||
>
|
>
|
||||||
<Icon name="bookmark" />
|
<svg
|
||||||
|
class="h-6 w-6 fill-none transition duration-300"
|
||||||
|
height=24
|
||||||
|
width=24
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="1.5"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12Z"
|
||||||
|
class="fill-current text-neutral-500 transition duration-300 group-hover:text-red-400 group-hover:dark:text-red-400"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
import Icon from '@components/ui/icons/icon.astro';
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<button
|
<button
|
||||||
@@ -8,7 +8,19 @@ import Icon from '@components/ui/icons/icon.astro';
|
|||||||
data-astro-prefetch
|
data-astro-prefetch
|
||||||
>
|
>
|
||||||
<div class="button-text-title flex relative items-center text-center">
|
<div class="button-text-title flex relative items-center text-center">
|
||||||
<Icon name="arrowLeft" />
|
<svg
|
||||||
|
class=" shrink-0 group-hover:-translate-x-1 transition duration-300 h-4 w-4"
|
||||||
|
height=24
|
||||||
|
width=24
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
>
|
||||||
|
<path d="m15 18-6-6 6-6"/>
|
||||||
|
</svg>
|
||||||
<span class="ml-2">
|
<span class="ml-2">
|
||||||
Go Back
|
Go Back
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
---
|
---
|
||||||
import Icon from '@components/ui/icons/icon.astro';
|
import Logo from "@components/images/Logo.astro"
|
||||||
|
|
||||||
type SocialPlatform = {
|
type SocialPlatform = {
|
||||||
name: string;
|
name: string;
|
||||||
url: string;
|
url: string;
|
||||||
svg: string;
|
iconLight: string;
|
||||||
|
iconDark: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -17,17 +18,20 @@ const socialPlatforms: SocialPlatform[] = [
|
|||||||
{
|
{
|
||||||
name: 'Facebook',
|
name: 'Facebook',
|
||||||
url: `https://www.facebook.com/sharer/sharer.php?u=${Astro.url}`,
|
url: `https://www.facebook.com/sharer/sharer.php?u=${Astro.url}`,
|
||||||
svg: 'facebook',
|
iconLight: 'https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/facebook.webp',
|
||||||
|
iconDark: 'https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/facebook.webp',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'X',
|
name: 'Twitter',
|
||||||
url: `https://x.com/intent/tweet?url=${Astro.url}&text=${pageTitle}`,
|
url: `https://x.com/intent/tweet?url=${Astro.url}&text=${pageTitle}`,
|
||||||
svg: 'x',
|
iconLight: 'https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/twitter.webp',
|
||||||
|
iconDark: 'https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/twitter.webp',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'LinkedIn',
|
name: 'LinkedIn',
|
||||||
url: `https://www.linkedin.com/sharing/share-offsite/?url=${Astro.url}`,
|
url: `https://www.linkedin.com/sharing/share-offsite/?url=${Astro.url}`,
|
||||||
svg: 'linkedIn',
|
iconLight: 'https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/linkedin.webp',
|
||||||
|
iconDark: 'https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/linkedin.webp',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
---
|
---
|
||||||
@@ -42,9 +46,12 @@ const socialPlatforms: SocialPlatform[] = [
|
|||||||
title={`Share on ${platform.name}`}
|
title={`Share on ${platform.name}`}
|
||||||
>
|
>
|
||||||
<div class="button-text-title-hidden flex relative items-center text-center">
|
<div class="button-text-title-hidden flex relative items-center text-center">
|
||||||
<Icon
|
<Logo
|
||||||
name={platform.svg}
|
srcLight={platform.iconLight}
|
||||||
class="h-5 w-5"
|
srcDark={platform.iconDark}
|
||||||
|
alt={platform.name}
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
---
|
---
|
||||||
import { Icon } from 'astro-icon/components';
|
import { Icon } from 'astro-icon/components';
|
||||||
|
import { Image } from 'astro:assets';
|
||||||
|
|
||||||
import type { Post } from '@lib/directusTypes';
|
import type { Post } from '@lib/directusTypes';
|
||||||
|
|
||||||
import Image from '@components/ui/images/Image.astro';
|
|
||||||
import { getDirectusImageURL } from '@lib/directusFunctions';
|
|
||||||
import { formatDate } from '@support/time';
|
import { formatDate } from '@support/time';
|
||||||
|
import { getDirectusImageURL } from '@/support/url';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
post: Post;
|
post: Post;
|
||||||
@@ -28,6 +28,7 @@ const { post } = Astro.props;
|
|||||||
draggable="false"
|
draggable="false"
|
||||||
loading="eager"
|
loading="eager"
|
||||||
format="webp"
|
format="webp"
|
||||||
|
inferSize={true}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="rounded-xl p-4 md:p-5">
|
<div class="rounded-xl p-4 md:p-5">
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
import { Icon } from 'astro-icon/components';
|
import { Icon } from 'astro-icon/components';
|
||||||
|
|
||||||
import Logo from '@components/ui/logos/Logo.astro';
|
import Logo from '@components/images/Logo.astro';
|
||||||
import { getDirectusImageURL } from '@lib/directusFunctions';
|
import { getDirectusImageURL } from '@/support/url';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
topic: string;
|
topic: string;
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
---
|
---
|
||||||
import { Icon } from 'astro-icon/components';
|
import Logo from "@components/images/Logo.astro"
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
title?: string;
|
title?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
url?: string;
|
url?: string;
|
||||||
icon?: string;
|
logoUrlLight?: string;
|
||||||
|
logoUrlDark?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { title, description, url, icon } = Astro.props;
|
const { title, description, url, logoUrlLight }: Props = Astro.props;
|
||||||
|
const logoUrlDark = Astro.props.logoUrlDark || logoUrlLight;
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="smooth-reveal-2 group flex flex-col">
|
<div class="smooth-reveal-2 group flex flex-col">
|
||||||
@@ -19,10 +21,15 @@ const { title, description, url, icon } = Astro.props;
|
|||||||
>
|
>
|
||||||
<div class="p-5 w-full">
|
<div class="p-5 w-full">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<Icon
|
{logoUrlLight && (
|
||||||
name={icon}
|
<div class="card-hover-icon-scale">
|
||||||
class="card-hover-icon-scale shrink-0 h-6 w-6 md:h-8 md:w-8 "
|
<Logo
|
||||||
/>
|
srcLight={logoUrlLight}
|
||||||
|
srcDark={logoUrlDark}
|
||||||
|
alt={`Logo of ${title}`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div class="ms-5 grow text-left">
|
<div class="ms-5 grow text-left">
|
||||||
<span class="card-text-title card-hover-text-title block text-lg">
|
<span class="card-text-title card-hover-text-title block text-lg">
|
||||||
{title}
|
{title}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
import { Icon } from 'astro-icon/components';
|
import { Icon } from 'astro-icon/components';
|
||||||
|
|
||||||
import Logo from '@components/ui/logos/Logo.astro';
|
import Logo from '@components/images/Logo.astro';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
title?: string;
|
title?: string;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
import { Icon } from 'astro-icon/components';
|
import { Icon } from 'astro-icon/components';
|
||||||
|
import { Image } from 'astro:assets';
|
||||||
|
|
||||||
import Image from '@components/ui/images/Image.astro';
|
import { getDirectusImageURL } from '@/support/url';
|
||||||
import { getDirectusImageURL } from '@lib/directusFunctions';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
title: string;
|
title: string;
|
||||||
@@ -30,6 +30,7 @@ const { title, subTitle, url, img, imgAlt } = Astro.props;
|
|||||||
loading="lazy"
|
loading="lazy"
|
||||||
width="850"
|
width="850"
|
||||||
height="420"
|
height="420"
|
||||||
|
inferSize={true}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-background-card md:bg-transparent group-hover:bg-neutral-100 md:group-hover:bg-transparent dark:group-hover:bg-neutral-800/90 md:dark:group-hover:bg-transparent rounded-b-2xl transition-all duration-300 p-6">
|
<div class="bg-background-card md:bg-transparent group-hover:bg-neutral-100 md:group-hover:bg-transparent dark:group-hover:bg-neutral-800/90 md:dark:group-hover:bg-transparent rounded-b-2xl transition-all duration-300 p-6">
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
import { Icon } from 'astro-icon/components';
|
import { Icon } from 'astro-icon/components';
|
||||||
|
import { Image } from 'astro:assets';
|
||||||
|
|
||||||
import Image from '@components/ui/images/Image.astro';
|
import { getDirectusImageURL } from '@/support/url';
|
||||||
import { getDirectusImageURL } from '@lib/directusFunctions';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
title: string;
|
title: string;
|
||||||
@@ -53,6 +53,7 @@ const { title, subTitle, url, single, imgOne, imgOneAlt, imgTwo, imgTwoAlt } = A
|
|||||||
loading="lazy"
|
loading="lazy"
|
||||||
width="850"
|
width="850"
|
||||||
height="420"
|
height="420"
|
||||||
|
inferSize={true}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
@@ -66,6 +67,7 @@ const { title, subTitle, url, single, imgOne, imgOneAlt, imgTwo, imgTwoAlt } = A
|
|||||||
loading="lazy"
|
loading="lazy"
|
||||||
width="400"
|
width="400"
|
||||||
height="230"
|
height="230"
|
||||||
|
inferSize={true}
|
||||||
/>
|
/>
|
||||||
<Image
|
<Image
|
||||||
class="rounded-xl w-full mt-4 lg:mt-10"
|
class="rounded-xl w-full mt-4 lg:mt-10"
|
||||||
@@ -76,6 +78,7 @@ const { title, subTitle, url, single, imgOne, imgOneAlt, imgTwo, imgTwoAlt } = A
|
|||||||
loading="lazy"
|
loading="lazy"
|
||||||
width="400"
|
width="400"
|
||||||
height="230"
|
height="230"
|
||||||
|
inferSize={true}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,11 +1,18 @@
|
|||||||
---
|
---
|
||||||
|
import { Image } from 'astro:assets';
|
||||||
import { readSingleton } from '@directus/sdk';
|
import { readSingleton } from '@directus/sdk';
|
||||||
|
|
||||||
import Image from '@components/ui/images/Image.astro';
|
|
||||||
import logo from '@images/brand_logo.png';
|
import logo from '@images/brand_logo.png';
|
||||||
import directus from '@lib/directus';
|
import directus from '@lib/directus';
|
||||||
|
|
||||||
const global = await directus.request(readSingleton('site_global'));
|
const global = await directus.request(readSingleton('site_global'));
|
||||||
---
|
---
|
||||||
|
|
||||||
<Image src={logo} alt={global.name} {...Astro.props} draggable="false" loading="eager" />
|
<Image
|
||||||
|
src={logo}
|
||||||
|
alt={global.name}
|
||||||
|
draggable="false"
|
||||||
|
loading="eager"
|
||||||
|
inferSize={true}
|
||||||
|
{...Astro.props}
|
||||||
|
/>
|
||||||
@@ -1,13 +1,7 @@
|
|||||||
---
|
---
|
||||||
import { Image } from 'astro:assets';
|
import { Image } from 'astro:assets';
|
||||||
import { blurStyle } from '@support/image';
|
|
||||||
|
|
||||||
const { srcLight, srcDark, alt, style, disableBlur, width, height } = Astro.props;
|
const { srcLight, srcDark, alt, style, width, height } = Astro.props;
|
||||||
|
|
||||||
const showBlur = !disableBlur;
|
|
||||||
|
|
||||||
const blurLight = (srcLight?.fsPath && showBlur) ? await blurStyle(srcLight.fsPath) : {};
|
|
||||||
const blurDark = (srcDark?.fsPath && showBlur) ? await blurStyle(srcDark.fsPath) : {};
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="themed-image-container">
|
<div class="themed-image-container">
|
||||||
@@ -15,20 +9,20 @@ const blurDark = (srcDark?.fsPath && showBlur) ? await blurStyle(srcDark.fsPath)
|
|||||||
src={srcLight}
|
src={srcLight}
|
||||||
alt={alt}
|
alt={alt}
|
||||||
class={`light-logo ${style}`}
|
class={`light-logo ${style}`}
|
||||||
style={blurLight}
|
|
||||||
inferSize={true}
|
inferSize={true}
|
||||||
width={width}
|
width={width}
|
||||||
height={height}
|
height={height}
|
||||||
|
inferSize={true}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Image
|
<Image
|
||||||
src={srcDark}
|
src={srcDark}
|
||||||
alt={alt}
|
alt={alt}
|
||||||
class={`dark-logo ${style}`}
|
class={`dark-logo ${style}`}
|
||||||
style={blurDark}
|
|
||||||
inferSize={true}
|
inferSize={true}
|
||||||
width={width}
|
width={width}
|
||||||
height={height}
|
height={height}
|
||||||
|
inferSize={true}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
22
src/components/images/Logo.astro
Normal file
22
src/components/images/Logo.astro
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
---
|
||||||
|
import ImageTheme from '@components/images/ImageTheme.astro';
|
||||||
|
|
||||||
|
const {
|
||||||
|
srcLight,
|
||||||
|
srcDark,
|
||||||
|
alt,
|
||||||
|
width = 48,
|
||||||
|
height = 48,
|
||||||
|
} = Astro.props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<ImageTheme
|
||||||
|
srcLight={srcLight}
|
||||||
|
srcDark={srcDark}
|
||||||
|
alt={alt}
|
||||||
|
style=`color: transparent; width: ${width}px; height: ${height}px; object-fit: contain; max-height: 100%; max-width: 100%;`
|
||||||
|
draggable="false"
|
||||||
|
loading="lazy"
|
||||||
|
width={width}
|
||||||
|
height={height}
|
||||||
|
/>
|
||||||
@@ -55,7 +55,8 @@ const certificates = ((await directus.request(
|
|||||||
area={certificate.issuer}
|
area={certificate.issuer}
|
||||||
date={certificate.issuerDate}
|
date={certificate.issuerDate}
|
||||||
url={certificate.url}
|
url={certificate.url}
|
||||||
logoIcon={certificate.logoName}
|
logoUrlLight={certificate.logo}
|
||||||
|
logoUrlDark={certificate.logoDark}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ const experiences = ((await directus.request(
|
|||||||
<h3 class="smooth-reveal card-text-header flex relative items-center w-full gap-3 pb-10">
|
<h3 class="smooth-reveal card-text-header flex relative items-center w-full gap-3 pb-10">
|
||||||
Experience
|
Experience
|
||||||
</h3>
|
</h3>
|
||||||
<ul class="ml-8 w-full flex flex-col">
|
<ul class="flex flex-col w-full ml-8 pr-8">
|
||||||
{experiences.map((experience: Experience) => {
|
{experiences.map((experience: Experience) => {
|
||||||
const startYear = new Date(experience.startDate).getFullYear();
|
const startYear = new Date(experience.startDate).getFullYear();
|
||||||
const endYear = experience.endDate != null ? new Date(experience.endDate).getFullYear() : 'Present';
|
const endYear = experience.endDate != null ? new Date(experience.endDate).getFullYear() : 'Present';
|
||||||
@@ -36,7 +36,7 @@ const experiences = ((await directus.request(
|
|||||||
</time>
|
</time>
|
||||||
</header>
|
</header>
|
||||||
<div class="relative flex flex-col sm:col-span-12 pb-6">
|
<div class="relative flex flex-col sm:col-span-12 pb-6">
|
||||||
<div class="absolute bg-stone-400 -translate-x-[1.71rem] rounded-full h-2 w-2 mt-4"/>
|
<div class="absolute bg-accent -translate-x-[1.71rem] rounded-full h-2 w-2 mt-3"/>
|
||||||
<h3>
|
<h3>
|
||||||
<div
|
<div
|
||||||
class="inline-flex items-center text-2xl leading-tight font-semibold"
|
class="inline-flex items-center text-2xl leading-tight font-semibold"
|
||||||
@@ -78,7 +78,7 @@ const experiences = ((await directus.request(
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{(experience.responsibilities || experience.achievements) && (
|
{(experience.responsibilities || experience.achievements) && (
|
||||||
<div class="relative flex flex-col gap-4 max-sm:h-auto! md:after:absolute md:after:bottom-0 md:after:h-12 md:after:w-full md:after:bg-linear-to-t md:after:from-neutral-200 dark:md:after:from-stone-700 md:after:content-[''] " :class="expanded ? 'after:hidden' : ''" x-show="expanded" x-collapse.min.50px>
|
<div class="relative flex flex-col gap-4" :class="expanded ? '' : 'mask-[linear-gradient(to_bottom,black_50%,transparent)]'" x-show="expanded" x-collapse.min.50px>
|
||||||
{experience.responsibilities && (
|
{experience.responsibilities && (
|
||||||
<div class="flex flex-col gap-1">
|
<div class="flex flex-col gap-1">
|
||||||
<h4 class="text-header font-semibold">
|
<h4 class="text-header font-semibold">
|
||||||
@@ -129,7 +129,7 @@ const experiences = ((await directus.request(
|
|||||||
</button>
|
</button>
|
||||||
|
|
||||||
<ul
|
<ul
|
||||||
class="flex print:hidden flex-wrap gap-2"
|
class="flex print:hidden flex-wrap gap-2 mt-2"
|
||||||
aria-label="Technologies used"
|
aria-label="Technologies used"
|
||||||
>
|
>
|
||||||
{experience.skills && experience.skills.map(skill => {
|
{experience.skills && experience.skills.map(skill => {
|
||||||
|
|||||||
@@ -7,33 +7,33 @@ import directus from '@lib/directus';
|
|||||||
const global = await directus.request(readSingleton('site_global'));
|
const global = await directus.request(readSingleton('site_global'));
|
||||||
---
|
---
|
||||||
|
|
||||||
<section class="mx-auto mb-20 max-w-340 px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full">
|
<section class="max-w-340 2xl:max-w-full px-4 sm:px-6 lg:px-8 py-10 lg:py-14 mx-auto mb-2 md:mb-8">
|
||||||
<div class="flex flex-col items-center justify-center gap-y-2 sm:flex-row sm:gap-x-12 sm:gap-y-0 lg:gap-x-24">
|
<div class="flex flex-col sm:flex-row items-center justify-center gap-y-2 sm:gap-x-12 sm:gap-y-0 lg:gap-x-24">
|
||||||
<div class="max-w-5xl sm:px-6 lg:px-8">
|
<div class="max-w-5xl sm:px-6 lg:px-8">
|
||||||
<div class="flex flex-wrap gap-6 sm:grid-cols-2 sm:gap-6 lg:grid-cols-3 justify-center">
|
<div class="flex flex-wrap gap-6 sm:grid-cols-2 sm:gap-6 lg:grid-cols-3 justify-center">
|
||||||
<FeaturesCard
|
<FeaturesCard
|
||||||
title="Cloud Engineer"
|
title="Cloud Engineer"
|
||||||
description="Full stack and cloud engineer."
|
description="Full stack and cloud engineer."
|
||||||
url="/about"
|
url="/about"
|
||||||
icon="mdi:cloud-outline"
|
logoUrlLight="https://img.icons8.com/cotton/64/cloud-development--v2.png"
|
||||||
/>
|
/>
|
||||||
<FeaturesCard
|
<FeaturesCard
|
||||||
title="Homelab"
|
title="Homelab"
|
||||||
description="Tinkering, testing, deploying, etc, etc ..."
|
description="Tinkering, testing, deploying, etc, etc ..."
|
||||||
url="/categories/homelab/"
|
url="/categories/homelab/"
|
||||||
icon="mdi:home-variant-outline"
|
logoUrlLight="https://img.icons8.com/cotton/64/smart-home-connection.png"
|
||||||
/>
|
/>
|
||||||
<FeaturesCard
|
<FeaturesCard
|
||||||
title="Documentation"
|
title="Documentation"
|
||||||
description="Reference and guides for my homelab."
|
description="Reference and guides for my homelab."
|
||||||
url="https://docs.alexlebens.dev"
|
url="https://docs.alexlebens.dev"
|
||||||
icon="mdi:file-document-multiple"
|
logoUrlLight="https://img.icons8.com/cotton/64/bookmarked-document--v1.png"
|
||||||
/>
|
/>
|
||||||
<FeaturesCard
|
<FeaturesCard
|
||||||
title="Email"
|
title="Email"
|
||||||
description={`Send me a message.`}
|
description={`Send me a message.`}
|
||||||
url=`mailto:${global.email}`
|
url=`mailto:${global.email}`
|
||||||
icon="mdi:email-fast"
|
logoUrlLight="https://img.icons8.com/cotton/64/secured-letter--v3.png"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ interface Props {
|
|||||||
const { title, subTitle, url } = Astro.props;
|
const { title, subTitle, url } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<section class="lg:px- relative mx-auto mb-20 max-w-340 px-4 pt-30 pb-30 sm:px-6">
|
<section class="relative max-w-340 pt-30 pb-30 px-4 sm:px-6 lg:px- mx-auto mb-2 md:mb-10">
|
||||||
<!-- Animated shapes -->
|
<!-- Animated shapes -->
|
||||||
<div class="smooth-reveal absolute top-[55%] left-0 scale-90 md:top-[20%] xl:top-[25%] xl:left-[10%]">
|
<div class="smooth-reveal absolute top-[55%] left-0 scale-90 md:top-[20%] xl:top-[25%] xl:left-[10%]">
|
||||||
<svg
|
<svg
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
---
|
---
|
||||||
|
import { Image } from 'astro:assets';
|
||||||
|
|
||||||
import GoLinkPrimaryButton from '@components/buttons/GoLinkPrimaryButton.astro';
|
import GoLinkPrimaryButton from '@components/buttons/GoLinkPrimaryButton.astro';
|
||||||
import GoLinkSecondaryButton from '@components/buttons/GoLinkSecondaryButton.astro';
|
import GoLinkSecondaryButton from '@components/buttons/GoLinkSecondaryButton.astro';
|
||||||
import Image from '@components/ui/images/Image.astro';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
title: string;
|
title: string;
|
||||||
@@ -48,7 +49,7 @@ const roundedClasses = Astro.props.rounded ? "rounded-2xl" : null;
|
|||||||
format="webp"
|
format="webp"
|
||||||
quality="low"
|
quality="low"
|
||||||
widths={[840]}
|
widths={[840]}
|
||||||
disableBlur={true}
|
inferSize={true}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ interface Props {
|
|||||||
const { posts, title, subTitle } = Astro.props;
|
const { posts, title, subTitle } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<section class="mx-auto mb-20 max-w-340 px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full">
|
<section class="max-w-340 2xl:max-w-full px-4 sm:px-6 lg:px-8 py-10 lg:py-14 mx-auto mb-2 md:mb-8">
|
||||||
<div class="mx-auto mb-10 max-w-2xl text-center lg:mb-14">
|
<div class="text-center max-w-2xl mx-auto mb-10 lg:mb-14">
|
||||||
<h1 class="smooth-reveal card-text-header block">
|
<h1 class="smooth-reveal card-text-header block">
|
||||||
{title}
|
{title}
|
||||||
</h1>
|
</h1>
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ const skills = ((await directus.request(
|
|||||||
<h3 class="smooth-reveal card-text-header flex relative items-center w-full gap-3 pb-5">
|
<h3 class="smooth-reveal card-text-header flex relative items-center w-full gap-3 pb-5">
|
||||||
Skills
|
Skills
|
||||||
</h3>
|
</h3>
|
||||||
<div class="">
|
<div>
|
||||||
<div class="tech-stack-slider relative overflow-hidden py-4 sm:py-8">
|
<div class="tech-stack-slider relative overflow-hidden py-4 sm:py-8 mask-[linear-gradient(to_right,transparent,black_10%,black_90%,transparent)]">
|
||||||
<!-- Main slider container -->
|
<!-- Main slider container -->
|
||||||
<div class="slider-track animate-slide flex">
|
<div class="slider-track animate-slide flex">
|
||||||
{[...skills, ...skills, ...skills].map((skill: Skill) => {
|
{[...skills, ...skills, ...skills].map((skill: Skill) => {
|
||||||
@@ -54,9 +54,6 @@ const skills = ((await directus.request(
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
<!-- Gradient overlays -->
|
|
||||||
<div class="bg-linear-to-r from-neutral-200 to-transparent dark:from-stone-700 absolute top-0 bottom-0 left-0 z-10 w-12 sm:w-24"/>
|
|
||||||
<div class="bg-linear-to-l from-neutral-200 to-transparent dark:from-stone-700 absolute top-0 bottom-0 right-0 z-10 w-12 sm:w-24"/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ const { latitude = "44.95", longitude = "-93.09", cityName = "St. Paul, Minnesot
|
|||||||
const { forecastDays, error } = await getFiveDayForecast(latitude, longitude, timezone);
|
const { forecastDays, error } = await getFiveDayForecast(latitude, longitude, timezone);
|
||||||
---
|
---
|
||||||
|
|
||||||
<section class="mx-auto mb-20 max-w-340 px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full">
|
<section class="max-w-340 2xl:max-w-fullpx-4 sm:px-6 lg:px-8 py-10 lg:py-14 mx-auto mb-2 md:mb-8">
|
||||||
<div class="mx-auto mb-10 max-w-2xl text-center lg:mb-14">
|
<div class="text-center max-w-2xl mx-auto mb-10 lg:mb-14">
|
||||||
<h1 class="smooth-reveal card-text-header block">
|
<h1 class="smooth-reveal card-text-header block">
|
||||||
Weather in my Area
|
Weather in my Area
|
||||||
</h1>
|
</h1>
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
---
|
|
||||||
import { Icons } from './icons.ts';
|
|
||||||
|
|
||||||
interface Path {
|
|
||||||
d: string;
|
|
||||||
class?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { name } = Astro.props;
|
|
||||||
|
|
||||||
const icon = (Icons as any)[name] || {};
|
|
||||||
const paths: Path[] = icon.paths || [];
|
|
||||||
---
|
|
||||||
|
|
||||||
{
|
|
||||||
icon ? (
|
|
||||||
<svg
|
|
||||||
class={icon.class}
|
|
||||||
height={icon.height}
|
|
||||||
viewBox={icon.viewBox}
|
|
||||||
width={icon.width}
|
|
||||||
fill={icon.fill}
|
|
||||||
clip-rule={icon.clipRule}
|
|
||||||
fill-rule={icon.fillRule}
|
|
||||||
stroke={icon.stroke}
|
|
||||||
stroke-width={icon.strokeWidth}
|
|
||||||
stroke-linecap={icon.strokeLinecap}
|
|
||||||
stroke-linejoin={icon.strokeLinejoin}
|
|
||||||
>
|
|
||||||
<title>{icon.title}</title>
|
|
||||||
<circle cx={icon.circleCx} cy={icon.circleCy} r={icon.circleR} />
|
|
||||||
{paths.map((path) => (
|
|
||||||
<path d={path.d} class={path.class || ''} />
|
|
||||||
))}
|
|
||||||
</svg>
|
|
||||||
) : (
|
|
||||||
'Icon not found'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,573 +0,0 @@
|
|||||||
export const Icons = {
|
|
||||||
groups: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'm150-400 82-80-82-82-80 82 80 80Zm573-10 87-140 88 140H723Zm-243-70q-50 0-85-35t-35-85q0-51 35-85.5t85-34.5q51 0 85.5 34.5T600-600q0 50-34.5 85T480-480Zm.351-180Q455-660 437.5-642.851t-17.5 42.5Q420-575 437.351-557.5t43 17.5Q506-540 523-557.351t17-43Q540-626 522.851-643t-42.5-17ZM480-600ZM0-240v-53q0-39.464 42-63.232T150.398-380q12.158 0 23.38.5T196-377.273q-8 17.273-12 34.842-4 17.57-4 37.431v65H0Zm240 0v-65q0-65 66.5-105T480-450q108 0 174 40t66 105v65H240Zm570-140q67.5 0 108.75 23.768T960-293v53H780v-65q0-19.861-3.5-37.431Q773-360 765-377.273q11-1.727 22.171-2.227 11.172-.5 22.829-.5Zm-330.2-10Q400-390 350-366q-50 24-50 61v5h360v-6q0-36-49.5-60t-130.7-24Zm.2 90Z',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class: 'mt-1 h-8 w-8 flex-shrink-0 fill-orange-400 dark:fill-orange-300',
|
|
||||||
width: 48,
|
|
||||||
height: 48,
|
|
||||||
viewBox: '0 -960 960 960',
|
|
||||||
},
|
|
||||||
books: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'M343-420h225v-60H343v60Zm0-90h395v-60H343v60Zm0-90h395v-60H343v60Zm-83 400q-24 0-42-18t-18-42v-560q0-24 18-42t42-18h560q24 0 42 18t18 42v560q0 24-18 42t-42 18H260Zm0-60h560v-560H260v560ZM140-80q-24 0-42-18t-18-42v-620h60v620h620v60H140Zm120-740v560-560Z',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class: 'mt-1 h-8 w-8 flex-shrink-0 fill-orange-400 dark:fill-orange-300',
|
|
||||||
width: 48,
|
|
||||||
height: 48,
|
|
||||||
viewBox: '0 -960 960 960',
|
|
||||||
},
|
|
||||||
verified: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'm346-60-76-130-151-31 17-147-96-112 96-111-17-147 151-31 76-131 134 62 134-62 77 131 150 31-17 147 96 111-96 112 17 147-150 31-77 130-134-62-134 62Zm27-79 107-45 110 45 67-100 117-30-12-119 81-92-81-94 12-119-117-28-69-100-108 45-110-45-67 100-117 28 12 119-81 94 81 92-12 121 117 28 70 100Zm107-341Zm-43 133 227-225-45-41-182 180-95-99-46 45 141 140Z',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class: 'mt-1 h-8 w-8 flex-shrink-0 fill-orange-400 dark:fill-orange-300',
|
|
||||||
width: 48,
|
|
||||||
height: 48,
|
|
||||||
viewBox: '0 -960 960 960',
|
|
||||||
},
|
|
||||||
frame: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'M480-480q-51 0-85.5-34.5T360-600q0-50 34.5-85t85.5-35q50 0 85 35t35 85q0 51-35 85.5T480-480Zm-.351-60Q505-540 522.5-557.149t17.5-42.5Q540-625 522.649-642.5t-43-17.5Q454-660 437-642.649t-17 43Q420-574 437.149-557t42.5 17ZM240-240v-76q0-27 17.5-47.5T300-397q42-22 86.943-32.5 44.942-10.5 93-10.5Q528-440 573-429.5t87 32.5q25 13 42.5 33.5T720-316v76H240Zm240-140q-47.546 0-92.773 13T300-328v28h360v-28q-42-26-87.227-39-45.227-13-92.773-13Zm0-220Zm0 300h180-360 180ZM140-80q-24 0-42-18t-18-42v-172h60v172h172v60H140ZM80-648v-172q0-24 18-42t42-18h172v60H140v172H80ZM648-80v-60h172v-172h60v172q0 24-18 42t-42 18H648Zm172-568v-172H648v-60h172q24 0 42 18t18 42v172h-60Z',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class: 'mt-1 h-8 w-8 flex-shrink-0 fill-orange-400 dark:fill-orange-300',
|
|
||||||
width: 48,
|
|
||||||
height: 48,
|
|
||||||
viewBox: '0 -960 960 960',
|
|
||||||
},
|
|
||||||
tools: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'M764-80q-6 0-11-2t-10-7L501-331q-5-5-7-10t-2-11q0-6 2-11t7-10l85-85q5-5 10-7t11-2q6 0 11 2t10 7l242 242q5 5 7 10t2 11q0 6-2 11t-7 10l-85 85q-5 5-10 7t-11 2Zm0-72 43-43-200-200-43 43 200 200ZM195-80q-6 0-11.5-2T173-89l-84-84q-5-5-7-10.5T80-195q0-6 2-11t7-10l225-225h85l38-38-175-175h-57L80-779l99-99 125 125v57l175 175 130-130-67-67 56-56H485l-18-18 128-128 18 18v113l56-56 169 169q15 15 23.5 34.5T870-600q0 20-6.5 38.5T845-528l-85-85-56 56-52-52-211 211v84L216-89q-5 5-10 7t-11 2Zm0-72 200-200v-43h-43L152-195l43 43Zm0 0-43-43 22 21 21 22Zm569 0 43-43-43 43Z',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class:
|
|
||||||
'mt-2 h-6 w-6 flex-shrink-0 fill-neutral-700 hs-tab-active:fill-orange-400 dark:fill-neutral-300 dark:hs-tab-active:fill-orange-300 md:h-7 md:w-7',
|
|
||||||
width: 48,
|
|
||||||
height: 48,
|
|
||||||
viewBox: '0 -960 960 960',
|
|
||||||
},
|
|
||||||
dashboard: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'M510-570v-270h330v270H510ZM120-450v-390h330v390H120Zm390 330v-390h330v390H510Zm-390 0v-270h330v270H120Zm60-390h210v-270H180v270Zm390 330h210v-270H570v270Zm0-450h210v-150H570v150ZM180-180h210v-150H180v150Zm210-330Zm180-120Zm0 180ZM390-330Z',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class:
|
|
||||||
'mt-2 h-6 w-6 flex-shrink-0 fill-neutral-700 hs-tab-active:fill-orange-400 dark:fill-neutral-300 dark:hs-tab-active:fill-orange-300 md:h-7 md:w-7',
|
|
||||||
width: 48,
|
|
||||||
height: 48,
|
|
||||||
viewBox: '0 -960 960 960',
|
|
||||||
},
|
|
||||||
house: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'M2.25 12l8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class: 'h-4 w-4 flex-shrink-0 md:h-5 md:w-5',
|
|
||||||
width: 24,
|
|
||||||
height: 24,
|
|
||||||
viewBox: '0 0 24 24',
|
|
||||||
fill: 'none',
|
|
||||||
strokeWidth: '2',
|
|
||||||
strokeLinecap: 'round',
|
|
||||||
strokeLinejoin: 'round',
|
|
||||||
stroke: 'currentColor',
|
|
||||||
},
|
|
||||||
home: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'M8.25 21v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21m0 0h4.5V3.545M12.75 21h7.5V10.75M2.25 21h1.5m18 0h-18M2.25 9l4.5-1.636M18.75 3l-1.5.545m0 6.205 3 1m1.5.5-1.5-.5M6.75 7.364V3h-3v18m3-13.636 10.5-3.819',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class:
|
|
||||||
'h-6 w-6 flex-shrink-0 group-hover:text-steel dark:group-hover:text-steel transition-all duration-200 text-neutral-600 dark:text-neutral-300 md:h-7 md:w-7',
|
|
||||||
width: 24,
|
|
||||||
height: 24,
|
|
||||||
viewBox: '0 0 24 24',
|
|
||||||
fill: 'none',
|
|
||||||
strokeWidth: '1.5',
|
|
||||||
strokeLinecap: 'round',
|
|
||||||
strokeLinejoin: 'round',
|
|
||||||
stroke: 'currentColor',
|
|
||||||
},
|
|
||||||
arrowUp: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'm5 12 7-7 7 7',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
d: 'M12 19V5',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class: 'h-5 w-5 flex-shrink-0 text-orange-400 dark:text-orange-300',
|
|
||||||
width: 24,
|
|
||||||
height: 24,
|
|
||||||
viewBox: '0 0 24 24',
|
|
||||||
fill: 'none',
|
|
||||||
strokeWidth: '2',
|
|
||||||
strokeLinecap: 'round',
|
|
||||||
strokeLinejoin: 'round',
|
|
||||||
stroke: 'currentColor',
|
|
||||||
},
|
|
||||||
checkCircle: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'M10 18a8 8 0 100-16 8 8 0 000 16zM13.707 8.293a1 1 0 00-1.414-1.414L9 10.586l-1.293-1.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class: 'h-5 w-5 shrink-0',
|
|
||||||
viewBox: '0 0 20 20',
|
|
||||||
fill: 'currentColor',
|
|
||||||
fillRule: 'evenodd',
|
|
||||||
clipRule: 'evenodd',
|
|
||||||
},
|
|
||||||
bookmark: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12Z',
|
|
||||||
class:
|
|
||||||
'fill-current text-neutral-500 transition duration-300 group-hover:text-red-400 group-hover:dark:text-red-400',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class: 'h-6 w-6 fill-none transition duration-300',
|
|
||||||
width: 24,
|
|
||||||
height: 24,
|
|
||||||
viewBox: '0 0 24 24',
|
|
||||||
fill: 'none',
|
|
||||||
strokeWidth: '1.5',
|
|
||||||
strokeLinecap: 'round',
|
|
||||||
strokeLinejoin: 'round',
|
|
||||||
stroke: 'currentColor',
|
|
||||||
},
|
|
||||||
arrowRight: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'm9 18 6-6-6-6',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class: 'h-4 w-4 flex-shrink-0 transition duration-300 group-hover:translate-x-1',
|
|
||||||
width: 20,
|
|
||||||
height: 20,
|
|
||||||
viewBox: '0 0 22 22',
|
|
||||||
fill: 'none',
|
|
||||||
strokeWidth: '2',
|
|
||||||
strokeLinecap: 'round',
|
|
||||||
strokeLinejoin: 'round',
|
|
||||||
stroke: 'currentColor',
|
|
||||||
},
|
|
||||||
arrowLeft: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'm15 18-6-6 6-6',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class: 'h-4 w-4 flex-shrink-0 transition duration-300 group-hover:-translate-x-1',
|
|
||||||
width: 24,
|
|
||||||
height: 24,
|
|
||||||
viewBox: '0 0 24 24',
|
|
||||||
fill: 'none',
|
|
||||||
strokeWidth: '2',
|
|
||||||
strokeLinecap: 'round',
|
|
||||||
strokeLinejoin: 'round',
|
|
||||||
stroke: 'currentColor',
|
|
||||||
},
|
|
||||||
facebook: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'M9.101 23.691v-7.98H6.627v-3.667h2.474v-1.58c0-4.085 1.848-5.978 5.858-5.978.401 0 .955.042 1.468.103a8.68 8.68 0 0 1 1.141.195v3.325a8.623 8.623 0 0 0-.653-.036 26.805 26.805 0 0 0-.733-.009c-.707 0-1.259.096-1.675.309a1.686 1.686 0 0 0-.679.622c-.258.42-.374.995-.374 1.752v1.297h3.919l-.386 2.103-.287 1.564h-3.246v8.245C19.396 23.238 24 18.179 24 12.044c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.628 3.874 10.35 9.101 11.647Z',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class: 'size-4 flex-shrink-0 fill-current',
|
|
||||||
viewBox: '0 0 24 24',
|
|
||||||
stroke: 'currentColor',
|
|
||||||
},
|
|
||||||
x: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'M18.901 1.153h3.68l-8.04 9.19L24 22.846h-7.406l-5.8-7.584-6.638 7.584H.474l8.6-9.83L0 1.154h7.594l5.243 6.932ZM17.61 20.644h2.039L6.486 3.24H4.298Z',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class: 'size-4 flex-shrink-0 fill-current',
|
|
||||||
viewBox: '0 0 24 24',
|
|
||||||
stroke: 'currentColor',
|
|
||||||
},
|
|
||||||
linkedIn: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class: 'size-4 flex-shrink-0 fill-current',
|
|
||||||
viewBox: '0 0 24 24',
|
|
||||||
stroke: 'currentColor',
|
|
||||||
},
|
|
||||||
share: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'M7.217 10.907a2.25 2.25 0 1 0 0 2.186m0-2.186c.18.324.283.696.283 1.093s-.103.77-.283 1.093m0-2.186 9.566-5.314m-9.566 7.5 9.566 5.314m0 0a2.25 2.25 0 1 0 3.935 2.186 2.25 2.25 0 0 0-3.935-2.186Zm0-12.814a2.25 2.25 0 1 0 3.933-2.185 2.25 2.25 0 0 0-3.933 2.185Z',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class: 'h-4 w-4 group-hover:text-neutral-700',
|
|
||||||
width: 24,
|
|
||||||
height: 24,
|
|
||||||
viewBox: '0 0 24 24',
|
|
||||||
fill: 'none',
|
|
||||||
strokeWidth: '1.5',
|
|
||||||
strokeLinecap: 'round',
|
|
||||||
strokeLinejoin: 'round',
|
|
||||||
stroke: 'currentColor',
|
|
||||||
},
|
|
||||||
github: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.012 8.012 0 0 0 16 8c0-4.42-3.58-8-8-8z',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class: 'w-4.5 h-4.5 transition flex-shrink-0 text-neutral-700 duration-300',
|
|
||||||
width: 16,
|
|
||||||
height: 16,
|
|
||||||
viewBox: '0 0 16 16',
|
|
||||||
fill: 'currentColor',
|
|
||||||
},
|
|
||||||
gitea: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'M4.209 4.603c-.247 0-.525.02-.84.088-.333.07-1.28.283-2.054 1.027C-.403 7.25.035 9.685.089 10.052c.065.446.263 1.687 1.21 2.768 1.749 2.141 5.513 2.092 5.513 2.092s.462 1.103 1.168 2.119c.955 1.263 1.936 2.248 2.89 2.367 2.406 0 7.212-.004 7.212-.004s.458.004 1.08-.394c.535-.324 1.013-.893 1.013-.893s.492-.527 1.18-1.73c.21-.37.385-.729.538-1.068 0 0 2.107-4.471 2.107-8.823-.042-1.318-.367-1.55-.443-1.627-.156-.156-.366-.153-.366-.153s-4.475.252-6.792.306c-.508.011-1.012.023-1.512.027v4.474l-.634-.301c0-1.39-.004-4.17-.004-4.17-1.107.016-3.405-.084-3.405-.084s-5.399-.27-5.987-.324c-.187-.011-.401-.032-.648-.032zm.354 1.832h.111s.271 2.269.6 3.597C5.549 11.147 6.22 13 6.22 13s-.996-.119-1.641-.348c-.99-.324-1.409-.714-1.409-.714s-.73-.511-1.096-1.52C1.444 8.73 2.021 7.7 2.021 7.7s.32-.859 1.47-1.145c.395-.106.863-.12 1.072-.12zm8.33 2.554c.26.003.509.127.509.127l.868.422-.529 1.075a.686.686 0 0 0-.614.359.685.685 0 0 0 .072.756l-.939 1.924a.69.69 0 0 0-.66.527.687.687 0 0 0 .347.763.686.686 0 0 0 .867-.206.688.688 0 0 0-.069-.882l.916-1.874a.667.667 0 0 0 .237-.02.657.657 0 0 0 .271-.137 8.826 8.826 0 0 1 1.016.512.761.761 0 0 1 .286.282c.073.21-.073.569-.073.569-.087.29-.702 1.55-.702 1.55a.692.692 0 0 0-.676.477.681.681 0 1 0 1.157-.252c.073-.141.141-.282.214-.431.19-.397.515-1.16.515-1.16.035-.066.218-.394.103-.814-.095-.435-.48-.638-.48-.638-.467-.301-1.116-.58-1.116-.58s0-.156-.042-.27a.688.688 0 0 0-.148-.241l.516-1.062 2.89 1.401s.48.218.583.619c.073.282-.019.534-.069.657-.24.587-2.1 4.317-2.1 4.317s-.232.554-.748.588a1.065 1.065 0 0 1-.393-.045l-.202-.08-4.31-2.1s-.417-.218-.49-.596c-.083-.31.104-.691.104-.691l2.073-4.272s.183-.37.466-.497a.855.855 0 0 1 .35-.077z',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class: 'w-6 h-6 transition flex-shrink-0 duration-300',
|
|
||||||
width: 24,
|
|
||||||
height: 24,
|
|
||||||
viewBox: '0 0 24 24',
|
|
||||||
fill: 'currentColor',
|
|
||||||
},
|
|
||||||
arrowRightStatic: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'm9 18 6-6-6-6',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class: 'size-4 flex-shrink-0',
|
|
||||||
width: 24,
|
|
||||||
height: 24,
|
|
||||||
viewBox: '0 0 24 24',
|
|
||||||
fill: 'none',
|
|
||||||
strokeWidth: '2',
|
|
||||||
strokeLinecap: 'round',
|
|
||||||
strokeLinejoin: 'round',
|
|
||||||
stroke: 'currentColor',
|
|
||||||
},
|
|
||||||
openInNew: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'm4.5 19.5 15-15m0 0H8.25m11.25 0v11.25',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class: 'ml-0.5 w-3 h-3 md:w-4 md:h-4 inline pb-0.5',
|
|
||||||
width: 24,
|
|
||||||
height: 24,
|
|
||||||
viewBox: '0 0 24 24',
|
|
||||||
fill: 'none',
|
|
||||||
strokeWidth: '3',
|
|
||||||
strokeLinecap: 'round',
|
|
||||||
strokeLinejoin: 'round',
|
|
||||||
stroke: 'currentColor',
|
|
||||||
},
|
|
||||||
accordionNotActive: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'm6 9 6 6 6-6',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class:
|
|
||||||
'block h-5 w-5 flex-shrink-0 text-neutral-600 group-hover:text-neutral-500 hs-accordion-active:hidden dark:text-neutral-400',
|
|
||||||
width: 24,
|
|
||||||
height: 24,
|
|
||||||
viewBox: '0 0 24 24',
|
|
||||||
fill: 'none',
|
|
||||||
strokeWidth: '2',
|
|
||||||
strokeLinecap: 'round',
|
|
||||||
strokeLinejoin: 'round',
|
|
||||||
stroke: 'currentColor',
|
|
||||||
},
|
|
||||||
accordionActive: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'm18 15-6-6-6 6',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class:
|
|
||||||
'hidden h-5 w-5 flex-shrink-0 text-neutral-600 group-hover:text-neutral-500 hs-accordion-active:block dark:text-neutral-400',
|
|
||||||
width: 24,
|
|
||||||
height: 24,
|
|
||||||
viewBox: '0 0 24 24',
|
|
||||||
fill: 'none',
|
|
||||||
strokeWidth: '2',
|
|
||||||
strokeLinecap: 'round',
|
|
||||||
strokeLinejoin: 'round',
|
|
||||||
stroke: 'currentColor',
|
|
||||||
},
|
|
||||||
xFooter: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'M18.901 1.153h3.68l-8.04 9.19L24 22.846h-7.406l-5.8-7.584-6.638 7.584H.474l8.6-9.83L0 1.154h7.594l5.243 6.932ZM17.61 20.644h2.039L6.486 3.24H4.298Z',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class: 'h-4 w-4 flex-shrink-0 fill-current text-neutral-700 dark:text-neutral-400',
|
|
||||||
viewBox: '0 0 24 24',
|
|
||||||
fill: 'currentColor',
|
|
||||||
title: 'Twitter',
|
|
||||||
},
|
|
||||||
facebookFooter: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'M9.101 23.691v-7.98H6.627v-3.667h2.474v-1.58c0-4.085 1.848-5.978 5.858-5.978.401 0 .955.042 1.468.103a8.68 8.68 0 0 1 1.141.195v3.325a8.623 8.623 0 0 0-.653-.036 26.805 26.805 0 0 0-.733-.009c-.707 0-1.259.096-1.675.309a1.686 1.686 0 0 0-.679.622c-.258.42-.374.995-.374 1.752v1.297h3.919l-.386 2.103-.287 1.564h-3.246v8.245C19.396 23.238 24 18.179 24 12.044c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.628 3.874 10.35 9.101 11.647Z',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class: 'h-4 w-4 flex-shrink-0 fill-current text-neutral-700 dark:text-neutral-400',
|
|
||||||
viewBox: '0 0 24 24',
|
|
||||||
fill: 'currentColor',
|
|
||||||
title: 'Facebook',
|
|
||||||
},
|
|
||||||
githubFooter: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class: 'h-4 w-4 flex-shrink-0 fill-current text-neutral-700 dark:text-neutral-400',
|
|
||||||
viewBox: '0 0 24 24',
|
|
||||||
fill: 'currentColor',
|
|
||||||
title: 'GitHub',
|
|
||||||
},
|
|
||||||
googleFooter: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class: 'h-4 w-4 flex-shrink-0 fill-current text-neutral-700 dark:text-neutral-400',
|
|
||||||
viewBox: '0 0 24 24',
|
|
||||||
fill: 'currentColor',
|
|
||||||
title: 'Google',
|
|
||||||
},
|
|
||||||
slackFooter: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52zM6.313 15.165a2.527 2.527 0 0 1 2.521-2.52 2.527 2.527 0 0 1 2.521 2.52v6.313A2.528 2.528 0 0 1 8.834 24a2.528 2.528 0 0 1-2.521-2.522v-6.313zM8.834 5.042a2.528 2.528 0 0 1-2.521-2.52A2.528 2.528 0 0 1 8.834 0a2.528 2.528 0 0 1 2.521 2.522v2.52H8.834zM8.834 6.313a2.528 2.528 0 0 1 2.521 2.521 2.528 2.528 0 0 1-2.521 2.521H2.522A2.528 2.528 0 0 1 0 8.834a2.528 2.528 0 0 1 2.522-2.521h6.312zM18.956 8.834a2.528 2.528 0 0 1 2.522-2.521A2.528 2.528 0 0 1 24 8.834a2.528 2.528 0 0 1-2.522 2.521h-2.522V8.834zM17.688 8.834a2.528 2.528 0 0 1-2.523 2.521 2.527 2.527 0 0 1-2.52-2.521V2.522A2.527 2.527 0 0 1 15.165 0a2.528 2.528 0 0 1 2.523 2.522v6.312zM15.165 18.956a2.528 2.528 0 0 1 2.523 2.522A2.528 2.528 0 0 1 15.165 24a2.527 2.527 0 0 1-2.52-2.522v-2.522h2.52zM15.165 17.688a2.527 2.527 0 0 1-2.52-2.523 2.526 2.526 0 0 1 2.52-2.52h6.313A2.527 2.527 0 0 1 24 15.165a2.528 2.528 0 0 1-2.522 2.523h-6.313z',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class: 'h-4 w-4 flex-shrink-0 fill-current text-neutral-700 dark:text-neutral-400',
|
|
||||||
viewBox: '0 0 24 24',
|
|
||||||
fill: 'currentColor',
|
|
||||||
title: 'Slack',
|
|
||||||
},
|
|
||||||
quotation: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'M7.39762 10.3C7.39762 11.0733 7.14888 11.7 6.6514 12.18C6.15392 12.6333 5.52552 12.86 4.76621 12.86C3.84979 12.86 3.09047 12.5533 2.48825 11.94C1.91222 11.3266 1.62421 10.4467 1.62421 9.29999C1.62421 8.07332 1.96459 6.87332 2.64535 5.69999C3.35231 4.49999 4.33418 3.55332 5.59098 2.85999L6.4943 4.25999C5.81354 4.73999 5.26369 5.27332 4.84476 5.85999C4.45201 6.44666 4.19017 7.12666 4.05926 7.89999C4.29491 7.79332 4.56983 7.73999 4.88403 7.73999C5.61716 7.73999 6.21938 7.97999 6.69067 8.45999C7.16197 8.93999 7.39762 9.55333 7.39762 10.3ZM14.6242 10.3C14.6242 11.0733 14.3755 11.7 13.878 12.18C13.3805 12.6333 12.7521 12.86 11.9928 12.86C11.0764 12.86 10.3171 12.5533 9.71484 11.94C9.13881 11.3266 8.85079 10.4467 8.85079 9.29999C8.85079 8.07332 9.19117 6.87332 9.87194 5.69999C10.5789 4.49999 11.5608 3.55332 12.8176 2.85999L13.7209 4.25999C13.0401 4.73999 12.4903 5.27332 12.0713 5.85999C11.6786 6.44666 11.4168 7.12666 11.2858 7.89999C11.5215 7.79332 11.7964 7.73999 12.1106 7.73999C12.8437 7.73999 13.446 7.97999 13.9173 8.45999C14.3886 8.93999 14.6242 9.55333 14.6242 10.3Z',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class:
|
|
||||||
'absolute start-0 top-0 h-16 w-16 -translate-x-6 -translate-y-8 transform text-neutral-300 dark:text-neutral-700',
|
|
||||||
width: 16,
|
|
||||||
height: 16,
|
|
||||||
viewBox: '0 0 16 16',
|
|
||||||
fill: 'currentColor',
|
|
||||||
},
|
|
||||||
question: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 5.25h.008v.008H12v-.008Z',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class: 'mt-1.5 h-6 w-6 flex-shrink-0 text-neutral-600 dark:text-neutral-400',
|
|
||||||
viewBox: '0 0 24 24',
|
|
||||||
fill: 'none',
|
|
||||||
strokeWidth: '1.5',
|
|
||||||
strokeLinecap: 'round',
|
|
||||||
strokeLinejoin: 'round',
|
|
||||||
stroke: 'currentColor',
|
|
||||||
},
|
|
||||||
chatBubble: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'M20.25 8.511c.884.284 1.5 1.128 1.5 2.097v4.286c0 1.136-.847 2.1-1.98 2.193-.34.027-.68.052-1.02.072v3.091l-3-3c-1.354 0-2.694-.055-4.02-.163a2.115 2.115 0 0 1-.825-.242m9.345-8.334a2.126 2.126 0 0 0-.476-.095 48.64 48.64 0 0 0-8.048 0c-1.131.094-1.976 1.057-1.976 2.192v4.286c0 .837.46 1.58 1.155 1.951m9.345-8.334V6.637c0-1.621-1.152-3.026-2.76-3.235A48.455 48.455 0 0 0 11.25 3c-2.115 0-4.198.137-6.24.402-1.608.209-2.76 1.614-2.76 3.235v6.226c0 1.621 1.152 3.026 2.76 3.235.577.075 1.157.14 1.74.194V21l4.155-4.155',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class: 'mt-1.5 h-6 w-6 flex-shrink-0 text-neutral-600 dark:text-neutral-400',
|
|
||||||
viewBox: '0 0 24 24',
|
|
||||||
fill: 'none',
|
|
||||||
strokeWidth: '1.5',
|
|
||||||
strokeLinecap: 'round',
|
|
||||||
strokeLinejoin: 'round',
|
|
||||||
stroke: 'currentColor',
|
|
||||||
},
|
|
||||||
mapPin: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'M15 10.5a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
d: 'M19.5 10.5c0 7.142-7.5 11.25-7.5 11.25S4.5 17.642 4.5 10.5a7.5 7.5 0 1 1 15 0Z',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class: 'mt-1.5 h-6 w-6 flex-shrink-0 text-neutral-600 dark:text-neutral-400',
|
|
||||||
viewBox: '0 0 24 24',
|
|
||||||
fill: 'none',
|
|
||||||
strokeWidth: '1.5',
|
|
||||||
strokeLinecap: 'round',
|
|
||||||
strokeLinejoin: 'round',
|
|
||||||
stroke: 'currentColor',
|
|
||||||
},
|
|
||||||
envelopeOpen: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'M21.75 9v.906a2.25 2.25 0 0 1-1.183 1.981l-6.478 3.488M2.25 9v.906a2.25 2.25 0 0 0 1.183 1.981l6.478 3.488m8.839 2.51-4.66-2.51m0 0-1.023-.55a2.25 2.25 0 0 0-2.134 0l-1.022.55m0 0-4.661 2.51m16.5 1.615a2.25 2.25 0 0 1-2.25 2.25h-15a2.25 2.25 0 0 1-2.25-2.25V8.844a2.25 2.25 0 0 1 1.183-1.981l7.5-4.039a2.25 2.25 0 0 1 2.134 0l7.5 4.039a2.25 2.25 0 0 1 1.183 1.98V19.5Z',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class: 'mt-1.5 h-6 w-6 flex-shrink-0 text-neutral-600 dark:text-neutral-400',
|
|
||||||
viewBox: '0 0 24 24',
|
|
||||||
fill: 'none',
|
|
||||||
strokeWidth: '1.5',
|
|
||||||
strokeLinecap: 'round',
|
|
||||||
strokeLinejoin: 'round',
|
|
||||||
stroke: 'currentColor',
|
|
||||||
},
|
|
||||||
earth: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'm20.893 13.393-1.135-1.135a2.252 2.252 0 0 1-.421-.585l-1.08-2.16a.414.414 0 0 0-.663-.107.827.827 0 0 1-.812.21l-1.273-.363a.89.89 0 0 0-.738 1.595l.587.39c.59.395.674 1.23.172 1.732l-.2.2c-.212.212-.33.498-.33.796v.41c0 .409-.11.809-.32 1.158l-1.315 2.191a2.11 2.11 0 0 1-1.81 1.025 1.055 1.055 0 0 1-1.055-1.055v-1.172c0-.92-.56-1.747-1.414-2.089l-.655-.261a2.25 2.25 0 0 1-1.383-2.46l.007-.042a2.25 2.25 0 0 1 .29-.787l.09-.15a2.25 2.25 0 0 1 2.37-1.048l1.178.236a1.125 1.125 0 0 0 1.302-.795l.208-.73a1.125 1.125 0 0 0-.578-1.315l-.665-.332-.091.091a2.25 2.25 0 0 1-1.591.659h-.18c-.249 0-.487.1-.662.274a.931.931 0 0 1-1.458-1.137l1.411-2.353a2.25 2.25 0 0 0 .286-.76m11.928 9.869A9 9 0 0 0 8.965 3.525m11.928 9.868A9 9 0 1 1 8.965 3.525',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class: 'w-4 h-4 flex-shrink-0',
|
|
||||||
viewBox: '0 0 24 24',
|
|
||||||
fill: 'none',
|
|
||||||
strokeWidth: '1.5',
|
|
||||||
strokeLinecap: 'round',
|
|
||||||
strokeLinejoin: 'round',
|
|
||||||
stroke: 'currentColor',
|
|
||||||
},
|
|
||||||
party: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'M5.8 11.3 2 22l10.7-3.79',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
d: 'M4 3h.01',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
d: 'M22 8h.01',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
d: 'M15 2h.01',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
d: 'M22 20h.01',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
d: 'm22 2-2.24.75a2.9 2.9 0 0 0-1.96 3.12v0c.1.86-.57 1.63-1.45 1.63h-.38c-.86 0-1.6.6-1.76 1.44L14 10',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
d: 'm22 13-.82-.33c-.86-.34-1.82.2-1.98 1.11v0c-.11.7-.72 1.22-1.43 1.22H17',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
d: 'm11 2 .33.82c.34.86-.2 1.82-1.11 1.98v0C9.52 4.9 9 5.52 9 6.23V7',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
d: 'M11 13c1.93 1.93 2.83 4.17 2 5-.83.83-3.07-.07-5-2-1.93-1.93-2.83-4.17-2-5 .83-.83 3.07.07 5 2Z',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class:
|
|
||||||
'w-6 h-6 group-hover:text-steel dark:group-hover:text-steel transition-all duration-200 text-neutral-600 dark:text-neutral-300',
|
|
||||||
width: 24,
|
|
||||||
height: 24,
|
|
||||||
viewBox: '0 0 24 24',
|
|
||||||
fill: 'none',
|
|
||||||
strokeWidth: '2',
|
|
||||||
strokeLinecap: 'round',
|
|
||||||
strokeLinejoin: 'round',
|
|
||||||
stroke: 'currentColor',
|
|
||||||
},
|
|
||||||
email: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class:
|
|
||||||
'w-8 h-8 group-hover:text-steel dark:group-hover:text-steel transition-all duration-200 text-neutral-600 dark:text-neutral-300',
|
|
||||||
width: 24,
|
|
||||||
height: 24,
|
|
||||||
viewBox: '0 0 24 24',
|
|
||||||
fill: 'none',
|
|
||||||
strokeWidth: '2',
|
|
||||||
strokeLinecap: 'round',
|
|
||||||
strokeLinejoin: 'round',
|
|
||||||
stroke: 'currentColor',
|
|
||||||
},
|
|
||||||
sun: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'M12 1v2M12 21v2M4.2 4.2l1.4 1.4M18.4 18.4l1.4 1.4M1 12h2M21 12h2M4.2 19.8l1.4-1.4M18.4 5.6l1.4-1.4',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
circleCx: '12',
|
|
||||||
circleCy: '12',
|
|
||||||
circleR: '5',
|
|
||||||
class:
|
|
||||||
'icon-light absolute h-5 w-5 scale-100 rotate-0 text-neutral-800 transition-all duration-500 dark:scale-0 dark:-rotate-90 dark:text-neutral-200',
|
|
||||||
width: 24,
|
|
||||||
height: 24,
|
|
||||||
viewBox: '0 0 24 24',
|
|
||||||
fill: 'none',
|
|
||||||
strokeWidth: '2',
|
|
||||||
strokeLinecap: 'round',
|
|
||||||
strokeLinejoin: 'round',
|
|
||||||
stroke: 'currentColor',
|
|
||||||
},
|
|
||||||
moon: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class:
|
|
||||||
'icon-dark absolute h-5 w-5 scale-0 rotate-90 text-neutral-800 transition-all duration-500 dark:scale-100 dark:rotate-0 dark:text-neutral-200',
|
|
||||||
width: 24,
|
|
||||||
height: 24,
|
|
||||||
viewBox: '0 0 24 24',
|
|
||||||
fill: 'none',
|
|
||||||
strokeWidth: '2',
|
|
||||||
strokeLinecap: 'round',
|
|
||||||
strokeLinejoin: 'round',
|
|
||||||
stroke: 'currentColor',
|
|
||||||
},
|
|
||||||
arrow: {
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
d: 'M5.22 14.78a.75.75 0 001.06 0l7.22-7.22v5.69a.75.75 0 001.5 0v-7.5a.75.75 0 00-.75-.75h-7.5a.75.75 0 000 1.5h5.69l-7.22 7.22a.75.75 0 000 1.06z',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
class:
|
|
||||||
'icon-dark absolute h-5 w-5 scale-0 rotate-90 text-neutral-800 transition-all duration-500 dark:scale-100 dark:rotate-0 dark:text-neutral-200',
|
|
||||||
width: 16,
|
|
||||||
height: 16,
|
|
||||||
viewBox: '0 0 20 20',
|
|
||||||
fill: 'none',
|
|
||||||
strokeWidth: '2',
|
|
||||||
strokeLinecap: 'round',
|
|
||||||
strokeLinejoin: 'round',
|
|
||||||
stroke: 'currentColor',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
---
|
|
||||||
import { Image } from 'astro:assets';
|
|
||||||
import { ImageMetadata } from 'astro';
|
|
||||||
import { blurStyle } from '@support/image';
|
|
||||||
|
|
||||||
interface FsPathImage extends ImageMetadata {
|
|
||||||
fsPath?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = Astro.props;
|
|
||||||
|
|
||||||
const image = props.src as FsPathImage;
|
|
||||||
const showBlur = !props.disableBlur;
|
|
||||||
const blurCSS = image.fsPath && showBlur ? await blurStyle(image.fsPath) : {};
|
|
||||||
---
|
|
||||||
|
|
||||||
<Image {...props} style={blurCSS} inferSize={true} />
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
---
|
|
||||||
import ImageTheme from '@components/ui/images/ImageTheme.astro';
|
|
||||||
|
|
||||||
const { srcLight, srcDark, alt } = Astro.props;
|
|
||||||
---
|
|
||||||
|
|
||||||
<ImageTheme
|
|
||||||
srcLight={srcLight}
|
|
||||||
srcDark={srcDark}
|
|
||||||
alt={alt}
|
|
||||||
style='color: transparent; width: 48px; height: 48px; object-fit: contain; max-height: 100%; max-width: 100%;'
|
|
||||||
draggable="false"
|
|
||||||
loading="lazy"
|
|
||||||
width="48"
|
|
||||||
height="48"
|
|
||||||
/>
|
|
||||||
@@ -66,21 +66,21 @@ const normalizeTitle = !title ? global.name : `${title} | ${global.name}`;
|
|||||||
data-site-id={global.rybbit_site_id}
|
data-site-id={global.rybbit_site_id}
|
||||||
defer
|
defer
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="bg-background selection:bg-yellow-400">
|
<body class="bg-background selection:bg-yellow-400 m-0 p-0 overflow-x-hidden">
|
||||||
<!-- Disabled texture background for now
|
|
||||||
<div class="fixed inset-0 -z-10">
|
|
||||||
<div class="bg-grid-pattern absolute inset-0 mask-[radial-gradient(white,transparent_85%)] bg-position-[center_top_-1px]"/>
|
|
||||||
</div>
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
<!-- Sliding backgrounds -->
|
||||||
|
<div class="bg"/>
|
||||||
|
<div class="bg bg2"/>
|
||||||
|
<div class="bg bg3"/>
|
||||||
|
|
||||||
|
<!-- Layout -->
|
||||||
<div class="grow w-full max-w-(--breakpoint-2xl) px-4 sm:px-6 lg:px-8 py-20 mx-auto">
|
<div class="grow w-full max-w-(--breakpoint-2xl) px-4 sm:px-6 lg:px-8 py-20 mx-auto">
|
||||||
|
|
||||||
<Header />
|
<Header />
|
||||||
|
|
||||||
<main class="min-h-screen">
|
<main class="has-js scroll-fade-container min-h-screen">
|
||||||
<slot />
|
<slot />
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
@@ -91,14 +91,84 @@ const normalizeTitle = !title ? global.name : `${title} | ${global.name}`;
|
|||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('astro:page-load', () => {
|
||||||
|
const onScroll = () => {
|
||||||
|
document.documentElement.style.setProperty('--scroll-offset', `${window.scrollY}px`);
|
||||||
|
document.documentElement.classList.add('has-js');
|
||||||
|
};
|
||||||
|
|
||||||
|
window.removeEventListener('scroll', onScroll);
|
||||||
|
window.addEventListener('scroll', onScroll, { passive: true });
|
||||||
|
|
||||||
|
onScroll();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.bg-grid-pattern {
|
/* Fade away content below header when scrolling */
|
||||||
background-size: 24px 24px;
|
.has-js .scroll-fade-container {
|
||||||
background-image: radial-gradient(circle, rgba(0, 0, 0, 0.2) 1px, transparent 1px);
|
-webkit-mask-image: linear-gradient(
|
||||||
transition: background-image 0.7s cubic-bezier(0.65, 0, 0.35, 1);
|
to bottom,
|
||||||
|
transparent 0px,
|
||||||
|
transparent 16px,
|
||||||
|
black 80px,
|
||||||
|
black 100%
|
||||||
|
);
|
||||||
|
|
||||||
|
mask-image: linear-gradient(
|
||||||
|
to bottom,
|
||||||
|
transparent 0px,
|
||||||
|
transparent 16px,
|
||||||
|
black 80px,
|
||||||
|
black 100%
|
||||||
|
);
|
||||||
|
|
||||||
|
-webkit-mask-size: 100vw 100vh;
|
||||||
|
-webkit-mask-repeat: no-repeat;
|
||||||
|
|
||||||
|
-webkit-mask-position-y: var(--scroll-offset);
|
||||||
|
mask-position-y: var(--scroll-offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.dark) .bg-grid-pattern {
|
/* Background that creates the "glimmer" effect */
|
||||||
background-image: radial-gradient(circle, rgba(255, 255, 255, 0.25) 1px, transparent 1px);
|
.bg {
|
||||||
|
animation: slide 20s ease-in-out infinite alternate;
|
||||||
|
background-image: linear-gradient(-60deg, var(--bg-primary) 33.3%, var(--bg-secondary) 33.3%, var(--bg-secondary) 66.6%, var(--bg-tertiary) 66.6%);
|
||||||
|
filter: blur(80px);
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: -50%;
|
||||||
|
right: -50%;
|
||||||
|
opacity: .5;
|
||||||
|
position: fixed;
|
||||||
|
z-index: -1;
|
||||||
|
--bg-primary: #e5e5e5;
|
||||||
|
--bg-secondary: #d9d9d9;
|
||||||
|
--bg-tertiary: #ededed;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.dark) .bg {
|
||||||
|
--bg-primary: #292524;
|
||||||
|
--bg-secondary: #44403c;
|
||||||
|
--bg-tertiary: #57534e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg2 {
|
||||||
|
animation-direction: alternate-reverse;
|
||||||
|
animation-duration: 30s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg3 {
|
||||||
|
animation-duration: 25s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slide {
|
||||||
|
0% {
|
||||||
|
transform:translateX(-25%);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform:translateX(25%);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import type {
|
|||||||
Skill,
|
Skill,
|
||||||
} from '@lib/directusTypes';
|
} from '@lib/directusTypes';
|
||||||
|
|
||||||
import { getDirectusURL } from '@lib/directusFunctions';
|
import { getDirectusURL } from '@/support/url';
|
||||||
|
|
||||||
type Schema = {
|
type Schema = {
|
||||||
site_global: Global;
|
site_global: Global;
|
||||||
|
|||||||
@@ -92,7 +92,8 @@ export type Certificate = {
|
|||||||
issuer: string;
|
issuer: string;
|
||||||
issuerDate: string;
|
issuerDate: string;
|
||||||
url: string;
|
url: string;
|
||||||
logoName: string;
|
logo: string;
|
||||||
|
logoDark: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Project = {
|
export type Project = {
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ const global = await directus.request(readSingleton('site_global'));
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<section class="max-w-7xl px-4 sm:px-6 lg:px-8 py-10 lg:py-14 mx-auto">
|
<section class="max-w-7xl px-4 sm:px-6 lg:px-8 py-10 lg:py-14 mx-auto">
|
||||||
<div class="flex flex-col gap-y-24 md:gap-y-32">
|
<div class="flex flex-col gap-y-12 md:gap-y-20">
|
||||||
<ExperienceSection className="smooth-reveal" />
|
<ExperienceSection className="smooth-reveal" />
|
||||||
<EducationSection className="smooth-reveal" />
|
<EducationSection className="smooth-reveal" />
|
||||||
<ProjectSection className="smooth-reveal" />
|
<ProjectSection className="smooth-reveal" />
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
---
|
---
|
||||||
import { type CollectionEntry, getCollection } from 'astro:content';
|
import { type CollectionEntry, getCollection } from 'astro:content';
|
||||||
|
import { Image } from 'astro:assets';
|
||||||
import getReadingTime from 'reading-time';
|
import getReadingTime from 'reading-time';
|
||||||
import { marked } from 'marked';
|
import { marked } from 'marked';
|
||||||
import markedShiki from 'marked-shiki';
|
import markedShiki from 'marked-shiki';
|
||||||
import { createHighlighter } from 'shiki';
|
import { createHighlighter } from 'shiki';
|
||||||
import { readItems, readSingleton } from '@directus/sdk';
|
import { readItems, readSingleton } from '@directus/sdk';
|
||||||
|
|
||||||
import Image from '@components/ui/images/Image.astro';
|
|
||||||
import SocialShareButton from '@components/buttons/SocialShareButton.astro';
|
import SocialShareButton from '@components/buttons/SocialShareButton.astro';
|
||||||
import BaseLayout from '@layouts/BaseLayout.astro';
|
import BaseLayout from '@layouts/BaseLayout.astro';
|
||||||
import directus from '@lib/directus';
|
import directus from '@lib/directus';
|
||||||
import { getDirectusImageURL } from '@lib/directusFunctions';
|
|
||||||
import { formatDate } from '@support/time';
|
import { formatDate } from '@support/time';
|
||||||
|
import { getDirectusImageURL } from '@/support/url';
|
||||||
|
|
||||||
const post = Astro.props;
|
const post = Astro.props;
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
|
|
||||||
/* Object colors */
|
/* Object colors */
|
||||||
--color-background: light-dark(var(--color-neutral-200), var(--color-stone-700));
|
--color-background: light-dark(var(--color-neutral-200), var(--color-stone-700));
|
||||||
--color-background-accent: light-dark(color-mix(in srgb, var(--color-stone-300) 40%, transparent), color-mix(in srgb, var(--color-stone-800) 20%, transparent));
|
--color-background-accent: light-dark(color-mix(in srgb, var(--color-neutral-300) 40%, transparent), color-mix(in srgb, var(--color-stone-800) 20%, transparent));
|
||||||
--color-background-card: light-dark(color-mix(in srgb, var(--color-neutral-100) 80%, transparent), color-mix(in srgb, var(--color-neutral-800) 60%, transparent));
|
--color-background-card: light-dark(color-mix(in srgb, var(--color-neutral-100) 80%, transparent), color-mix(in srgb, var(--color-neutral-800) 60%, transparent));
|
||||||
|
|
||||||
--color-divider: light-dark(color-mix(in srgb, var(--color-neutral-400) 50%, transparent), color-mix(in srgb, var(--color-neutral-500) 50%, transparent));
|
--color-divider: light-dark(color-mix(in srgb, var(--color-neutral-400) 50%, transparent), color-mix(in srgb, var(--color-neutral-500) 50%, transparent));
|
||||||
@@ -50,8 +50,9 @@
|
|||||||
:root {
|
:root {
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
|
||||||
--theme-transition: 0.3s ease;
|
--theme-transition: 0.3s ease;
|
||||||
color-scheme: light;
|
--scroll-offset: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:root:where(.dark, .dark *) {
|
:root:where(.dark, .dark *) {
|
||||||
@@ -73,9 +74,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
overflow-x: hidden;
|
|
||||||
--swup-fade-theme-duration: 0.2s;
|
--swup-fade-theme-duration: 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
@utility button-base-hidden {
|
@utility button-base-hidden {
|
||||||
@apply transition-all duration-300
|
@apply transition-all duration-300
|
||||||
border border-transparent
|
border border-transparent
|
||||||
hover:bg-neutral-100 dark:hover:bg-neutral-700
|
hover:bg-neutral-200 dark:hover:bg-neutral-700
|
||||||
p-2
|
p-2
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,9 +74,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@utility card-hover-icon-scale {
|
@utility card-hover-icon-scale {
|
||||||
@apply transition-all duration-300
|
@apply transition-transform duration-300 will-change-transform
|
||||||
drop-shadow-sm
|
drop-shadow-md dark:drop-shadow-xl dark:drop-shadow-neutral-500/60
|
||||||
group-hover:scale-110
|
group-hover:scale-3d group-hover:scale-110
|
||||||
}
|
}
|
||||||
|
|
||||||
@utility card-text-header {
|
@utility card-text-header {
|
||||||
|
|||||||
@@ -1,68 +0,0 @@
|
|||||||
import fs from 'node:fs/promises';
|
|
||||||
|
|
||||||
interface BlurImageMetadata {
|
|
||||||
/**
|
|
||||||
* The width of the origin image
|
|
||||||
*/
|
|
||||||
width: number;
|
|
||||||
/**
|
|
||||||
* The height of the origin image
|
|
||||||
*/
|
|
||||||
height: number;
|
|
||||||
/**
|
|
||||||
* blurDataURL of the image
|
|
||||||
*/
|
|
||||||
blurDataURL: string;
|
|
||||||
/**
|
|
||||||
* blur image width
|
|
||||||
*/
|
|
||||||
blurWidth: number;
|
|
||||||
/**
|
|
||||||
* blur image height
|
|
||||||
*/
|
|
||||||
blurHeight: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function blurStyle(filePath: string) {
|
|
||||||
const image = await blurImageMetadata(filePath);
|
|
||||||
const svg = blurImageSVG(image);
|
|
||||||
return {
|
|
||||||
backgroundSize: 'cover',
|
|
||||||
backgroundPosition: '50% 50%',
|
|
||||||
backgroundRepeat: 'no-repeat',
|
|
||||||
backgroundImage: `url("data:image/svg+xml;charset=utf-8,${svg}")`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function blurImageSVG(image: BlurImageMetadata): string {
|
|
||||||
const { blurDataURL, blurWidth, blurHeight, width, height } = image;
|
|
||||||
|
|
||||||
const std = 20;
|
|
||||||
const svgWidth = blurWidth ? blurWidth * 40 : width;
|
|
||||||
const svgHeight = blurHeight ? blurHeight * 40 : height;
|
|
||||||
|
|
||||||
const viewBox = svgWidth && svgHeight ? `viewBox='0 0 ${svgWidth} ${svgHeight}'` : '';
|
|
||||||
|
|
||||||
return `%3Csvg xmlns='http://www.w3.org/2000/svg' ${viewBox}%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='${std}'/%3E%3CfeColorMatrix values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 100 -1' result='s'/%3E%3CfeFlood x='0' y='0' width='100%25' height='100%25'/%3E%3CfeComposite operator='out' in='s'/%3E%3CfeComposite in2='SourceGraphic'/%3E%3CfeGaussianBlur stdDeviation='${std}'/%3E%3C/filter%3E%3Cimage width='100%25' height='100%25' x='0' y='0' preserveAspectRatio='xMidYMid slice' style='filter: url(%23b);' href='${blurDataURL}'/%3E%3C/svg%3E`;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function blurImageMetadata(filepath: string): Promise<BlurImageMetadata> {
|
|
||||||
const { default: sharp } = await import('sharp');
|
|
||||||
const buffer = await fs.readFile(filepath);
|
|
||||||
|
|
||||||
const img = sharp(buffer);
|
|
||||||
const { width, height } = await img.metadata();
|
|
||||||
if (width == null || height == null) {
|
|
||||||
throw new Error(`Invalid image path: ${filepath}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const aspectRatio = width / height;
|
|
||||||
const blurWidth = 8;
|
|
||||||
const blurHeight = Math.round(blurWidth / aspectRatio);
|
|
||||||
const blurImage = await img.resize(blurWidth, blurHeight).webp({ quality: 10 }).toBuffer();
|
|
||||||
const blurDataURL = `data:image/webp;base64,${blurImage.toString('base64')}`;
|
|
||||||
|
|
||||||
return { blurDataURL, blurHeight, blurWidth, width, height };
|
|
||||||
}
|
|
||||||
|
|
||||||
export { blurStyle };
|
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
const getDirectusURL = () => {
|
const getDirectusURL = () => {
|
||||||
if (process.env.DIRECTUS_URL) {
|
|
||||||
return `https://${process.env.DIRECTUS_URL}`;
|
|
||||||
}
|
|
||||||
return 'https://directus.alexlebens.net';
|
return 'https://directus.alexlebens.net';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getSiteURL = () => {
|
||||||
|
return 'https://www.alexlebens.dev';
|
||||||
|
};
|
||||||
|
|
||||||
async function getDirectusImageURL(image: string) {
|
async function getDirectusImageURL(image: string) {
|
||||||
return `${getDirectusURL()}/assets/${image}`;
|
return `${getDirectusURL()}/assets/${image}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export { getDirectusURL, getDirectusImageURL };
|
export { getDirectusURL, getSiteURL, getDirectusImageURL };
|
||||||
Reference in New Issue
Block a user