Better slugs, improvements to projects, some fixes
All checks were successful
Build and Deploy to Web Server / deploy (push) Successful in 14m57s
All checks were successful
Build and Deploy to Web Server / deploy (push) Successful in 14m57s
This commit is contained in:
@@ -23,19 +23,23 @@ const languageIcons: Record<string, string> = {
|
||||
const languageIcon = languageIcons[props["data-language"]];
|
||||
|
||||
const title = meta.title;
|
||||
|
||||
const copyID = Math.random().toString(36);
|
||||
---
|
||||
|
||||
<figure class="my-4 rounded-b">
|
||||
{
|
||||
title && (
|
||||
<figcaption>
|
||||
<div class="bg-primary w-full rounded-t-md border-1 border-black px-4 py-2 text-white">
|
||||
<div class="bg-primary w-full rounded-t-md border-1 border-gray-600 px-4 py-2 text-white">
|
||||
<div class="flex justify-between">
|
||||
<div class="flex items-center justify-between gap-2 font-bold">
|
||||
{languageIcon && <Icon name={languageIcon} />}
|
||||
<p>{title}</p>
|
||||
</div>
|
||||
<button id="copy__code">Copy Code</button>
|
||||
<button class="font-bold" id=`copy-${copyID}`>
|
||||
Copy <Icon name="mdi:content-copy" class="ml-0.5 inline-block" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</figcaption>
|
||||
@@ -44,8 +48,7 @@ const title = meta.title;
|
||||
|
||||
<pre
|
||||
class:list={[
|
||||
"py-2",
|
||||
"border-x border-b",
|
||||
"border-x border-b border-gray-600",
|
||||
"rounded-b",
|
||||
!title ? "rounded-t border-t" : "",
|
||||
className
|
||||
@@ -53,59 +56,11 @@ const title = meta.title;
|
||||
{...props}><slot /></pre>
|
||||
</figure>
|
||||
|
||||
<style is:global>
|
||||
.astro-code {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.astro-code code {
|
||||
/* Define a counter for each <code> inside .astro-code */
|
||||
counter-reset: step;
|
||||
/* Start from zero, increment the counter */
|
||||
counter-increment: step 0;
|
||||
|
||||
font-size: 14px;
|
||||
|
||||
width: fit-content;
|
||||
min-width: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.astro-code code .line {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
padding-right: 2rem;
|
||||
}
|
||||
|
||||
.astro-code code .line::before {
|
||||
content: counter(step);
|
||||
counter-increment: step;
|
||||
width: 2rem;
|
||||
margin-right: 1.25rem;
|
||||
display: inline-block;
|
||||
margin-left: auto;
|
||||
text-align: right;
|
||||
|
||||
/* Fix element position during horizontal scroll */
|
||||
position: sticky;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
|
||||
/* Give a bit of space to counter on horizontal scroll */
|
||||
padding-right: 0.25rem;
|
||||
|
||||
/* Illustrative purpose, please extract the value from the theme instead */
|
||||
background-color: white;
|
||||
color: hsla(0, 0%, 0%, 0.5);
|
||||
}
|
||||
</style>
|
||||
|
||||
<script define:vars={{ dataCode }}>
|
||||
<script define:vars={{ dataCode, copyID }}>
|
||||
if (typeof navigator.clipboard !== undefined) {
|
||||
const trigger = document.querySelector("#copy__code");
|
||||
const trigger = document.getElementById(`copy-${copyID}`);
|
||||
|
||||
trigger.addEventListener("click", () => {
|
||||
// Write the code to clipboard
|
||||
navigator.clipboard.writeText(dataCode);
|
||||
});
|
||||
}
|
||||
|
@@ -1 +1 @@
|
||||
<h5 class="font-base text-base font-bold"><slot /></h5>
|
||||
<h5 class="text-lg font-bold"><slot /></h5>
|
||||
|
@@ -1 +1 @@
|
||||
<h6 class="font-base text-base underline"><slot /></h6>
|
||||
<h6 class="text-base font-bold"><slot /></h6>
|
||||
|
10
src/components/MDX/IMG.astro
Normal file
10
src/components/MDX/IMG.astro
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
import Image from "astro/components/Image.astro";
|
||||
const { src, alt } = Astro.props;
|
||||
|
||||
import { getImageByPath } from "@lib/utils";
|
||||
|
||||
const imageSRC = getImageByPath(src)!;
|
||||
---
|
||||
|
||||
<Image src={imageSRC} alt={alt} />
|
@@ -112,10 +112,18 @@ const { navbarDisplay = "normal" } = Astro.props as Props;
|
||||
</script>
|
||||
|
||||
<script>
|
||||
let nav: HTMLElement;
|
||||
let toggle: HTMLElement;
|
||||
let nav: HTMLElement | null;
|
||||
let toggle: HTMLElement | null;
|
||||
|
||||
const checkScroll = () => {
|
||||
if (!nav) {
|
||||
nav = document.getElementById("nav");
|
||||
}
|
||||
|
||||
if (!nav) {
|
||||
return;
|
||||
}
|
||||
|
||||
nav.setAttribute(
|
||||
"data-transparency",
|
||||
window.scrollY === 0 && window.navbarDisplay === "transparent"
|
||||
@@ -125,14 +133,19 @@ const { navbarDisplay = "normal" } = Astro.props as Props;
|
||||
};
|
||||
|
||||
document.addEventListener("astro:page-load", () => {
|
||||
nav = document.getElementById("nav")!;
|
||||
toggle = document.getElementById("menu-toggle")!;
|
||||
nav = document.getElementById("nav");
|
||||
toggle = document.getElementById("menu-toggle");
|
||||
|
||||
toggle.addEventListener("click", () => {
|
||||
const visible = nav.getAttribute("data-mobile-menu") === "visible";
|
||||
nav.setAttribute("data-mobile-menu", visible ? "hidden" : "visible");
|
||||
checkScroll();
|
||||
});
|
||||
if (toggle) {
|
||||
toggle.addEventListener("click", () => {
|
||||
if (nav) {
|
||||
const visible = nav.getAttribute("data-mobile-menu") === "visible";
|
||||
nav.setAttribute("data-mobile-menu", visible ? "hidden" : "visible");
|
||||
}
|
||||
|
||||
checkScroll();
|
||||
});
|
||||
}
|
||||
|
||||
checkScroll();
|
||||
});
|
||||
|
@@ -8,6 +8,8 @@ import { Icon } from "astro-icon/components";
|
||||
import { Image } from "astro:assets";
|
||||
import type { CollectionEntry } from "astro:content";
|
||||
|
||||
import { slugify } from '@lib/utils';
|
||||
|
||||
interface Props {
|
||||
project: CollectionEntry<"projects">;
|
||||
textOn?: "left" | "right";
|
||||
@@ -130,7 +132,7 @@ const projectHasBody = project.body && project.body.trim().length > 0;
|
||||
>
|
||||
<span
|
||||
><h2 class="font-header-alt inline-block text-lg font-semibold">
|
||||
{projectHasBody && <TextLink href=`/projects/${project.id}/`>{project.data.title}</TextLink>}{!projectHasBody && project.data.title }{!project.data.ongoing && <span class="italic text-sm font-light"> ({project.data.date.getFullYear()})</span>}</h2></span
|
||||
{projectHasBody && <TextLink href=`/projects/${slugify(project.data.type)}/${slugify(project.data.slug)}/`>{project.data.title}</TextLink>}{!projectHasBody && project.data.title }{!project.data.ongoing && <span class="italic text-sm font-light"> ({project.data.date.getFullYear()})</span>}</h2></span
|
||||
>
|
||||
<h3 class="font-header-alt font-base font-medium">
|
||||
{project.data.role}
|
||||
|
@@ -9,6 +9,7 @@ const projects = defineCollection({
|
||||
type: z.string(),
|
||||
date: z.date(),
|
||||
description: z.string(),
|
||||
slug: z.string(),
|
||||
ongoing: z.boolean().optional().default(false),
|
||||
frontPage: z
|
||||
.object({
|
||||
|
@@ -14,6 +14,23 @@ const allProjectHeros = import.meta.glob<{ default: ImageMetadata }>(
|
||||
{ eager: true }
|
||||
);
|
||||
|
||||
const allImages = import.meta.glob<{ default: ImageMetadata }>(
|
||||
"/**/*.{jpeg,jpg,png,gif}",
|
||||
{
|
||||
eager: true
|
||||
}
|
||||
);
|
||||
|
||||
export function getImageByPath(path: string): ImageMetadata | null {
|
||||
for (const [imagePath, mod] of Object.entries(allImages)) {
|
||||
if (imagePath.includes(path)) {
|
||||
return mod.default;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function getProjectHero(project: Project): ImageMetadata {
|
||||
let image: ImageMetadata = Object.values(allProjectHeros)[0].default;
|
||||
for (const [path, mod] of Object.entries(allProjectHeros)) {
|
||||
@@ -110,3 +127,13 @@ export async function getFullExternalURLOfImage(
|
||||
return new URL((await getImage({ src: image })).src, import.meta.env.SITE)
|
||||
.href;
|
||||
}
|
||||
|
||||
export function slugify(input: string): string {
|
||||
if (!input) return "";
|
||||
let slug = input.toLowerCase().trim();
|
||||
slug = slug.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
|
||||
slug = slug.replace(/[^a-z0-9\s-]/g, " ");
|
||||
slug = slug.replace(/[\s-]+/g, "-");
|
||||
slug = slug.replace(/^-+|-+$/g, "");
|
||||
return slug;
|
||||
}
|
||||
|
@@ -7,7 +7,8 @@ import { getCollection, render } from "astro:content";
|
||||
import {
|
||||
getAllProjectImages,
|
||||
getFullExternalURLOfImage,
|
||||
getProjectHero
|
||||
getProjectHero,
|
||||
slugify
|
||||
} from "@/lib/utils";
|
||||
|
||||
export async function getStaticPaths() {
|
||||
@@ -16,7 +17,9 @@ export async function getStaticPaths() {
|
||||
});
|
||||
|
||||
return projects.map((project) => ({
|
||||
params: { slug: project.id },
|
||||
params: {
|
||||
slug: `${slugify(project.data.type)}/${slugify(project.data.slug)}`
|
||||
},
|
||||
props: { project }
|
||||
}));
|
||||
}
|
||||
@@ -44,6 +47,7 @@ import H3 from "@components/MDX/H3.astro";
|
||||
import H4 from "@components/MDX/H4.astro";
|
||||
import H5 from "@components/MDX/H5.astro";
|
||||
import H6 from "@components/MDX/H6.astro";
|
||||
import IMG from "@components/MDX/IMG.astro";
|
||||
import P from "@components/MDX/P.astro";
|
||||
---
|
||||
|
||||
@@ -83,7 +87,8 @@ import P from "@components/MDX/P.astro";
|
||||
h5: H5,
|
||||
h6: H6,
|
||||
blockquote: Blockquote,
|
||||
pre: CodeSnippet
|
||||
pre: CodeSnippet,
|
||||
img: IMG
|
||||
}}
|
||||
/>
|
||||
</div>
|
@@ -78,4 +78,41 @@
|
||||
font-family: "Roboto", sans-serif;
|
||||
@apply text-gray-600 dark:text-white;
|
||||
}
|
||||
|
||||
.astro-code {
|
||||
@apply overflow-auto;
|
||||
}
|
||||
|
||||
.astro-code code {
|
||||
counter-reset: step;
|
||||
counter-increment: step 0;
|
||||
|
||||
@apply text-sm;
|
||||
@apply block;
|
||||
@apply w-fit min-w-full;
|
||||
}
|
||||
|
||||
.astro-code code .line {
|
||||
@apply inline-block;
|
||||
@apply w-full;
|
||||
@apply pr-8;
|
||||
@apply first:pt-2 last:pb-2;
|
||||
@apply bg-white dark:bg-gray-100;
|
||||
}
|
||||
|
||||
.astro-code code .line::before {
|
||||
content: counter(step);
|
||||
counter-increment: step;
|
||||
|
||||
@apply w-10;
|
||||
@apply mr-5 ml-auto pr-2;
|
||||
@apply inline-block;
|
||||
@apply text-right;
|
||||
|
||||
@apply sticky;
|
||||
@apply left-0;
|
||||
@apply z-10;
|
||||
|
||||
@apply bg-gray-200;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user