feat: add ci
This commit is contained in:
parent
93baa3b6b0
commit
e800314589
48
.github/workflows/default.yaml
vendored
Normal file
48
.github/workflows/default.yaml
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
name: Deploy to GitHub Pages
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
build:
|
||||
steps:
|
||||
- name: Checkout your repository using git
|
||||
uses: actions/checkout@v4
|
||||
- name: 🗳️ Setup pnpm cache
|
||||
uses: https://github.com/actions/cache@v3
|
||||
with:
|
||||
path: ${{ env.PNPM_STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ env.PNPM_CACHE_ID }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store
|
||||
- name: Install, build, and upload your site
|
||||
uses: withastro/action@v2
|
||||
# with:
|
||||
# path: . # The root location of your Astro project inside the repository. (optional)
|
||||
# node-version: 20 # The specific version of Node that should be used to build your site. Defaults to 20. (optional)
|
||||
# package-manager: pnpm@latest # The Node package manager that should be used to install dependencies and build your site. Automatically detected based on your lockfile. (optional)
|
||||
|
||||
deploy:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: 🚀 Deploy files via SFTP
|
||||
uses: https://github.com/pressidium/lftp-mirror-action@v1
|
||||
with:
|
||||
host: ${{ secrets.FTP_HOST }}
|
||||
port: ${{ secrets.FTP_PORT || 21 }}
|
||||
user: ${{ secrets.FTP_USERNAME }}
|
||||
pass: ${{ secrets.FTP_PASSWORD }}
|
||||
onlyNewer: true
|
||||
parallel: '4'
|
||||
settings: 'sftp:auto-confirm=yes'
|
||||
localDir: 'public'
|
||||
remoteDir: '/share'
|
||||
options: '--verbose'
|
@ -9,16 +9,21 @@ h3 {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
}
|
||||
|
||||
article h2 {
|
||||
article>h2 {
|
||||
font-size: 24px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
article h3 {
|
||||
article>h3 {
|
||||
font-size: 20px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
article>p>a,
|
||||
article a {
|
||||
color: var(--fill) !important;
|
||||
}
|
||||
|
||||
:root {
|
||||
--neutral-1000: #000000;
|
||||
--neutral-800: #16161E;
|
||||
|
@ -92,8 +92,7 @@
|
||||
<div
|
||||
class="googley-eyes"
|
||||
on:click={() => ($visible = !$visible)}
|
||||
role="button"
|
||||
tabindex="0"
|
||||
role="img"
|
||||
aria-label="Toggle Googley Eyes"
|
||||
aria-hidden="true"
|
||||
on:keydown={(ev) => (ev.key === "Enter" ? ($visible = !$visible) : "")}
|
||||
|
@ -1,7 +1,7 @@
|
||||
---
|
||||
import markdownToText from "@helpers/markdownToText";
|
||||
import { Card } from "./card";
|
||||
import { useTranslatedPath } from "@i18n/utils";
|
||||
import { useTranslatedPath, useTranslations } from "@i18n/utils";
|
||||
import Image from "@components/Image.astro";
|
||||
|
||||
interface Props {
|
||||
@ -25,6 +25,7 @@ const {
|
||||
} = Astro.props.post;
|
||||
|
||||
const translatePath = useTranslatedPath(Astro);
|
||||
const t = useTranslations(Astro);
|
||||
|
||||
const imagePath = `../content/${collection}/${slug.split("/")[0]}/${headerImg}`;
|
||||
|
||||
@ -44,7 +45,7 @@ const link = translatePath(`/${collection}/${slug.split("/")[0]}`);
|
||||
<Card.Description>
|
||||
{markdownToText(body).slice(0, 200)}
|
||||
</Card.Description>
|
||||
<Card.ReadMoreButton link={link} />
|
||||
<Card.ReadMoreButton link={link} text={t("read-more")} />
|
||||
</Card.Content>
|
||||
{
|
||||
image?.format && (
|
||||
|
@ -11,8 +11,6 @@ interface Props {
|
||||
|
||||
const { src: image, alt, maxWidth } = Astro.props;
|
||||
|
||||
console.log({ image, alt, maxWidth });
|
||||
|
||||
const sizes = [
|
||||
{
|
||||
width: 240,
|
||||
|
@ -1,6 +1,7 @@
|
||||
---
|
||||
import { useTranslations, useTranslatedPath } from "../i18n/utils";
|
||||
import Logo from "./Logo.astro";
|
||||
import ToggleTheme from "@components/ThemeToggle.svelte";
|
||||
|
||||
function isActive(path: string) {
|
||||
return Astro.url.pathname === path ? "active" : "";
|
||||
@ -10,10 +11,6 @@ const t = useTranslations(Astro);
|
||||
const translatePath = useTranslatedPath(Astro);
|
||||
|
||||
const paths = [
|
||||
{
|
||||
link: translatePath("/"),
|
||||
component: Logo,
|
||||
},
|
||||
{
|
||||
link: translatePath("/blog"),
|
||||
text: t("nav.blog"),
|
||||
@ -33,16 +30,26 @@ const paths = [
|
||||
];
|
||||
---
|
||||
|
||||
<ul class="flex my-4 divide-x divide-x-1 divide-x-neutral">
|
||||
<ul class="flex my-4 h-12">
|
||||
<li><a href="#main-content" class="skip-link">Skip to main content</a></li>
|
||||
<li
|
||||
class="border-none bg-transparent my-2 mr-4 logo grid place-content-center"
|
||||
>
|
||||
<a
|
||||
href={translatePath("/")}
|
||||
class="text-neutral h-9 flex items-center justify-center lowercase"
|
||||
>
|
||||
<Logo />
|
||||
</a>
|
||||
</li>
|
||||
{
|
||||
paths.map(({ link, text, component }, i) => (
|
||||
paths.map(({ link, text }, i) => (
|
||||
<li
|
||||
class={`
|
||||
flex items-center flex-1 border-t-1 border-b-1 border-neutral
|
||||
${isActive(link) ? "bg-light" : "bg"}
|
||||
${i === 1 ? "rounded-bl-md" : ""}
|
||||
${i === 0 ? "rounded-bl-md border-l-1" : "border-l-1"}
|
||||
${i === paths.length - 1 ? "rounded-tr-md !border-r-1" : ""}
|
||||
${component ? "border-none bg-transparent my-2 mr-4 logo" : ""}
|
||||
`}
|
||||
>
|
||||
<a
|
||||
@ -50,20 +57,40 @@ const paths = [
|
||||
href={link}
|
||||
data-astro-prefetch
|
||||
>
|
||||
{component ? <Logo /> : text}
|
||||
{text}
|
||||
</a>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
<li class="w-8 h-6 flex justify-right items-center h-full">
|
||||
<ToggleTheme client:load />
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<style>
|
||||
ul > li.logo {
|
||||
background: none;
|
||||
flex: 0;
|
||||
height: 34px;
|
||||
margin-left: 0px;
|
||||
--fill: #cb5a5a;
|
||||
--background-fill: none;
|
||||
}
|
||||
/* Visually hide the jump to content button while making it accessible */
|
||||
.skip-link {
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
top: auto;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Make the jump to content button visible when focused */
|
||||
.skip-link:focus {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: auto;
|
||||
height: auto;
|
||||
overflow: visible;
|
||||
}
|
||||
</style>
|
||||
|
59
src/components/ThemeToggle.svelte
Normal file
59
src/components/ThemeToggle.svelte
Normal file
@ -0,0 +1,59 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
let theme = writable("light");
|
||||
|
||||
onMount(() => {
|
||||
theme.set(localStorage.getItem("theme") || "light");
|
||||
});
|
||||
|
||||
$: if ($theme && "document" in globalThis) {
|
||||
document.documentElement.classList.remove("light", "dark");
|
||||
document.documentElement.classList.add($theme);
|
||||
localStorage.setItem("theme", $theme);
|
||||
}
|
||||
|
||||
function toggleTheme() {
|
||||
console.log($theme);
|
||||
theme.update((t) => (t === "light" ? "dark" : "light"));
|
||||
}
|
||||
</script>
|
||||
|
||||
<button class="block w-6 h-6" on:click={toggleTheme} title="toggle dark mode">
|
||||
{#if $theme === "dark"}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="icon icon-tabler icons-tabler-outline icon-tabler-sun"
|
||||
><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path
|
||||
d="M12 12m-4 0a4 4 0 1 0 8 0a4 4 0 1 0 -8 0"
|
||||
/><path
|
||||
d="M3 12h1m8 -9v1m8 8h1m-9 8v1m-6.4 -15.4l.7 .7m12.1 -.7l-.7 .7m0 11.4l.7 .7m-12.1 -.7l-.7 .7"
|
||||
/></svg
|
||||
>
|
||||
{:else}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.25"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="icon icon-tabler icons-tabler-outline icon-tabler-moon"
|
||||
><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path
|
||||
d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"
|
||||
/></svg
|
||||
>
|
||||
{/if}
|
||||
</button>
|
@ -7,22 +7,22 @@ comments: true
|
||||
---
|
||||
|
||||
import Image from "@components/Image.astro";
|
||||
import MAX_7053 from "./images/MAX_7053.jpg";
|
||||
import MAX_7054 from "./images/MAX_7054.jpg";
|
||||
import MAX_7055_Panorama from "./images/MAX_7055-Panorama.jpg";
|
||||
import MAX_7076_Panorama from "./images/MAX_7076-Panorama.jpg";
|
||||
|
||||
Best images from a short trip to liguria in italy
|
||||
|
||||
This image took way to long, had to do several attempts because its really hard to get focus and exposure right when you use self-timer. But i think in the end it payed off :)
|
||||
import MAX_7053 from "./images/MAX_7053.jpg";
|
||||
<Image src={ MAX_7053 }>
|
||||
<Image src={MAX_7053} alt=""/>
|
||||
|
||||
Liminal spaces anyone?
|
||||
import MAX_7054 from "./images/MAX_7054.jpg";
|
||||
<Image src={ MAX_7054 }>
|
||||
<Image src={MAX_7054} alt=""/>
|
||||
|
||||
I had one day with a bit of rain, but that was actually really nice because i never saw this part of the coast in fog.
|
||||
import MAX_7055_Panorama from "./images/MAX_7055-Panorama.jpg";
|
||||
<Image src={ MAX_7055_Panorama }>
|
||||
<Image src={MAX_7055_Panorama} alt=""/>
|
||||
|
||||
Sestri Levante is just nice to look at.
|
||||
import MAX_7076_Panorama from "./images/MAX_7076-Panorama.jpg";
|
||||
<Image src={ MAX_7076_Panorama }>
|
||||
<Image src={MAX_7076_Panorama} alt=""/>
|
||||
|
||||
|
@ -72,7 +72,7 @@ const { title, width = "compact" } = Astro.props;
|
||||
<header>
|
||||
<Nav />
|
||||
</header>
|
||||
<main class="flex flex-col mt-4xl gap-y-2xl">
|
||||
<main id="main-content" class="flex flex-col mt-4xl gap-y-2xl">
|
||||
<slot />
|
||||
</main>
|
||||
<LanguagePicker />
|
||||
|
@ -7,7 +7,9 @@ import HeroCard from "@components/HeroCard.astro";
|
||||
|
||||
const locale = getLocale(Astro.url);
|
||||
const pages = await getCollection("projects");
|
||||
const posts = filterCollection(pages, locale);
|
||||
const posts = filterCollection(pages, locale)
|
||||
.sort((a, b) => b.data.date - a.data.date)
|
||||
.sort((a) => (a.data.featured ? -1 : 1));
|
||||
---
|
||||
|
||||
<Layout title="Dude">
|
||||
|
71
src/pages/tag/[tag].astro
Normal file
71
src/pages/tag/[tag].astro
Normal file
@ -0,0 +1,71 @@
|
||||
---
|
||||
import Layout from "@layouts/Layout.astro";
|
||||
import { getCollection } from "astro:content";
|
||||
import { useTranslatedPath } from "@i18n/utils";
|
||||
|
||||
const collections = ["blog", "photos", "projects"];
|
||||
|
||||
const tp = useTranslatedPath(Astro);
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const collections = ["blog", "photos", "projects"];
|
||||
const posts = await Promise.all(
|
||||
collections.map((collection) => {
|
||||
return getCollection(collection, {
|
||||
fields: ["slug", "title", "date", "tags"],
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
const tags = new Set();
|
||||
|
||||
posts.flat().forEach((post) => {
|
||||
if (!post.data?.tags) return;
|
||||
post.data.tags.forEach((tag) => {
|
||||
tags.add(tag.toLowerCase());
|
||||
});
|
||||
});
|
||||
|
||||
return [...tags.values()].map((tag) => {
|
||||
return {
|
||||
params: {
|
||||
tag,
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
const { tag } = Astro.params;
|
||||
|
||||
|
||||
const allPosts = (await Promise.all(
|
||||
collections.map((collection) => {
|
||||
return getCollection(collection, {
|
||||
fields: ["slug", "title", "date", "tags"],
|
||||
});
|
||||
}),
|
||||
)).flat();
|
||||
|
||||
|
||||
|
||||
const posts = allPosts.filter((post) => {
|
||||
return post.data?.tags?.find(t => t.toLowerCase() === tag);
|
||||
});
|
||||
|
||||
|
||||
---
|
||||
|
||||
<Layout title="Max Richter">
|
||||
<article>
|
||||
<h1>Tags</h1>
|
||||
{posts.length}
|
||||
<div class="flex flex-col gap-2">
|
||||
{
|
||||
posts.map((post) => {
|
||||
return <a href={tp("/"+post.collection+"/" + post.slug)}>{post.slug}</a>;
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</article>
|
||||
</Layout>
|
||||
|
41
src/pages/tag/index.astro
Normal file
41
src/pages/tag/index.astro
Normal file
@ -0,0 +1,41 @@
|
||||
---
|
||||
import Layout from "@layouts/Layout.astro";
|
||||
import { getCollection } from "astro:content";
|
||||
import { useTranslatedPath } from "@i18n/utils";
|
||||
|
||||
const tp = useTranslatedPath(Astro);
|
||||
|
||||
const collections = ["blog", "photos", "projects"];
|
||||
|
||||
const posts = await Promise.all(
|
||||
collections.map((collection) => {
|
||||
return getCollection(collection, {
|
||||
fields: ["slug", "title", "date", "tags"],
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
const tags = new Set();
|
||||
|
||||
posts.flat().forEach((post) => {
|
||||
if (!post.data?.tags) return;
|
||||
post.data.tags.forEach((tag) => {
|
||||
tags.add(tag.toLowerCase());
|
||||
});
|
||||
});
|
||||
|
||||
const _tags = [...tags.values()];
|
||||
---
|
||||
|
||||
<Layout title="Max Richter">
|
||||
<article>
|
||||
<h1>Tags</h1>
|
||||
<div class="flex flex-col gap-2">
|
||||
{
|
||||
_tags.map((t) => {
|
||||
return <a href={tp("/tag/" + t)}>{t}</a>;
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</article>
|
||||
</Layout>
|
@ -15,7 +15,7 @@ export default defineConfig({
|
||||
"border-neutral": "border-neutral-300 dark:border-neutral-1000",
|
||||
"border-light": "border-neutral-100 dark:border-neutral-500",
|
||||
"divide-x-neutral": ['divide-x-neutral-300', "dark:divide-x-neutral-1000"],
|
||||
"gradient": "bg-gradient-to-br from-neutral-000 dark:from-neutral-500 to-neutral-200 dark:to-neutral-800",
|
||||
"gradient": "bg-gradient-to-br from-neutral-000 to-neutral-000 dark:from-neutral-500 dark:to-neutral-800",
|
||||
},
|
||||
theme: {
|
||||
borderRadius: {
|
||||
|
Loading…
Reference in New Issue
Block a user