Skip to content

Commit 2c8d89e

Browse files
committed
Add astro src directory.
1 parent 40b72a6 commit 2c8d89e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+2724
-0
lines changed
169 KB
Loading
158 KB
Loading

src/assets/socialIcons.ts

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
const socialIcons = {
2+
Github: `<svg
3+
xmlns="http://www.w3.org/2000/svg"
4+
class="icon-tabler"
5+
stroke-linecap="round"
6+
stroke-linejoin="round"
7+
>
8+
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
9+
<path
10+
d="M9 19c-4.3 1.4 -4.3 -2.5 -6 -3m12 5v-3.5c0 -1 .1 -1.4 -.5 -2c2.8 -.3 5.5 -1.4 5.5 -6a4.6 4.6 0 0 0 -1.3 -3.2a4.2 4.2 0 0 0 -.1 -3.2s-1.1 -.3 -3.5 1.3a12.3 12.3 0 0 0 -6.2 0c-2.4 -1.6 -3.5 -1.3 -3.5 -1.3a4.2 4.2 0 0 0 -.1 3.2a4.6 4.6 0 0 0 -1.3 3.2c0 4.6 2.7 5.7 5.5 6c-.6 .6 -.6 1.2 -.5 2v3.5"
11+
></path>
12+
</svg>`,
13+
Facebook: `<svg
14+
xmlns="http://www.w3.org/2000/svg"
15+
class="icon-tabler"
16+
stroke-linecap="round"
17+
stroke-linejoin="round"
18+
>
19+
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
20+
<path
21+
d="M7 10v4h3v7h4v-7h3l1 -4h-4v-2a1 1 0 0 1 1 -1h3v-4h-3a5 5 0 0 0 -5 5v2h-3"
22+
></path>
23+
</svg>`,
24+
Instagram: `<svg
25+
xmlns="http://www.w3.org/2000/svg"
26+
class="icon-tabler"
27+
stroke-linecap="round"
28+
stroke-linejoin="round"
29+
>
30+
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
31+
<rect x="4" y="4" width="16" height="16" rx="4"></rect>
32+
<circle cx="12" cy="12" r="3"></circle>
33+
<line x1="16.5" y1="7.5" x2="16.5" y2="7.501"></line>
34+
</svg>`,
35+
LinkedIn: `<svg
36+
xmlns="http://www.w3.org/2000/svg"
37+
class="icon-tabler"
38+
stroke-linecap="round"
39+
stroke-linejoin="round"
40+
>
41+
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
42+
<rect x="4" y="4" width="16" height="16" rx="2"></rect>
43+
<line x1="8" y1="11" x2="8" y2="16"></line>
44+
<line x1="8" y1="8" x2="8" y2="8.01"></line>
45+
<line x1="12" y1="16" x2="12" y2="11"></line>
46+
<path d="M16 16v-3a2 2 0 0 0 -4 0"></path>
47+
</svg>`,
48+
Mail: `<svg
49+
xmlns="http://www.w3.org/2000/svg"
50+
class="icon-tabler"
51+
stroke-linecap="round"
52+
stroke-linejoin="round"
53+
>
54+
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
55+
<rect x="3" y="5" width="18" height="14" rx="2"></rect>
56+
<polyline points="3 7 12 13 21 7"></polyline>
57+
</svg>`,
58+
Twitter: `<svg
59+
xmlns="http://www.w3.org/2000/svg"
60+
class="icon-tabler"
61+
stroke-linecap="round"
62+
stroke-linejoin="round"
63+
>
64+
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
65+
<path d="M22 4.01c-1 .49 -1.98 .689 -3 .99c-1.121 -1.265 -2.783 -1.335 -4.38 -.737s-2.643 2.06 -2.62 3.737v1c-3.245 .083 -6.135 -1.395 -8 -4c0 0 -4.182 7.433 4 11c-1.872 1.247 -3.739 2.088 -6 2c3.308 1.803 6.913 2.423 10.034 1.517c3.58 -1.04 6.522 -3.723 7.651 -7.742a13.84 13.84 0 0 0 .497 -3.753c-.002 -.249 1.51 -2.772 1.818 -4.013z"></path>
66+
</svg>`,
67+
Twitch: `<svg
68+
xmlns="http://www.w3.org/2000/svg"
69+
class="icon-tabler"
70+
stroke-linecap="round"
71+
stroke-linejoin="round"
72+
>
73+
<path d="M21 2H3v16h5v4l4-4h5l4-4V2zm-10 9V7m5 4V7"></path>
74+
</svg>`,
75+
YouTube: `<svg
76+
xmlns="http://www.w3.org/2000/svg"
77+
class="icon-tabler"
78+
stroke-linecap="round"
79+
stroke-linejoin="round"
80+
>
81+
<path d="M22.54 6.42a2.78 2.78 0 0 0-1.94-2C18.88 4 12 4 12 4s-6.88 0-8.6.46a2.78 2.78 0 0 0-1.94 2A29 29 0 0 0 1 11.75a29 29 0 0 0 .46 5.33A2.78 2.78 0 0 0 3.4 19c1.72.46 8.6.46 8.6.46s6.88 0 8.6-.46a2.78 2.78 0 0 0 1.94-2 29 29 0 0 0 .46-5.25 29 29 0 0 0-.46-5.33z"></path>
82+
<polygon points="9.75 15.02 15.5 11.75 9.75 8.48 9.75 15.02"></polygon>
83+
</svg>`,
84+
WhatsApp: `<svg
85+
xmlns="http://www.w3.org/2000/svg"
86+
class="icon-tabler"
87+
stroke-linecap="round"
88+
stroke-linejoin="round"
89+
>
90+
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
91+
<path d="M3 21l1.65 -3.8a9 9 0 1 1 3.4 2.9l-5.05 .9"></path>
92+
<path d="M9 10a0.5 .5 0 0 0 1 0v-1a0.5 .5 0 0 0 -1 0v1a5 5 0 0 0 5 5h1a0.5 .5 0 0 0 0 -1h-1a0.5 .5 0 0 0 0 1"></path>
93+
</svg>`,
94+
Snapchat: `<svg
95+
xmlns="http://www.w3.org/2000/svg"
96+
class="icon-tabler"
97+
stroke-linecap="round"
98+
stroke-linejoin="round"
99+
>
100+
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
101+
<path d="M16.882 7.842a4.882 4.882 0 0 0 -9.764 0c0 4.273 -.213 6.409 -4.118 8.118c2 .882 2 .882 3 3c3 0 4 2 6 2s3 -2 6 -2c1 -2.118 1 -2.118 3 -3c-3.906 -1.709 -4.118 -3.845 -4.118 -8.118zm-13.882 8.119c4 -2.118 4 -4.118 1 -7.118m17 7.118c-4 -2.118 -4 -4.118 -1 -7.118"></path>
102+
</svg>`,
103+
Pinterest: `<svg
104+
xmlns="http://www.w3.org/2000/svg"
105+
class="icon-tabler"
106+
stroke-linecap="round"
107+
stroke-linejoin="round"
108+
>
109+
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
110+
<line x1="8" y1="20" x2="12" y2="11"></line>
111+
<path d="M10.7 14c.437 1.263 1.43 2 2.55 2c2.071 0 3.75 -1.554 3.75 -4a5 5 0 1 0 -9.7 1.7"></path>
112+
<circle cx="12" cy="12" r="9"></circle>
113+
</svg>`,
114+
TikTok: `<svg
115+
xmlns="http://www.w3.org/2000/svg"
116+
class="icon-tabler"
117+
stroke-linecap="round"
118+
stroke-linejoin="round"
119+
>
120+
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
121+
<path d="M9 12a4 4 0 1 0 4 4v-12a5 5 0 0 0 5 5"></path>
122+
</svg>`,
123+
CodePen: `<svg
124+
xmlns="http://www.w3.org/2000/svg"
125+
class="icon-tabler"
126+
stroke-linecap="round"
127+
stroke-linejoin="round"
128+
>
129+
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
130+
<path d="M3 15l9 6l9 -6l-9 -6l-9 6"></path>
131+
<path d="M3 9l9 6l9 -6l-9 -6l-9 6"></path>
132+
<line x1="3" y1="9" x2="3" y2="15"></line>
133+
<line x1="21" y1="9" x2="21" y2="15"></line>
134+
<line x1="12" y1="3" x2="12" y2="9"></line>
135+
<line x1="12" y1="15" x2="12" y2="21"></line>
136+
</svg>`,
137+
Discord: `<svg
138+
xmlns="http://www.w3.org/2000/svg"
139+
class="icon-tabler"
140+
stroke-linecap="round"
141+
stroke-linejoin="round"
142+
>
143+
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
144+
<circle cx="9" cy="12" r="1"></circle>
145+
<circle cx="15" cy="12" r="1"></circle>
146+
<path d="M7.5 7.5c3.5 -1 5.5 -1 9 0"></path>
147+
<path d="M7 16.5c3.5 1 6.5 1 10 0"></path>
148+
<path d="M15.5 17c0 1 1.5 3 2 3c1.5 0 2.833 -1.667 3.5 -3c.667 -1.667 .5 -5.833 -1.5 -11.5c-1.457 -1.015 -3 -1.34 -4.5 -1.5l-1 2.5"></path>
149+
<path d="M8.5 17c0 1 -1.356 3 -1.832 3c-1.429 0 -2.698 -1.667 -3.333 -3c-.635 -1.667 -.476 -5.833 1.428 -11.5c1.388 -1.015 2.782 -1.34 4.237 -1.5l1 2.5"></path>
150+
</svg>`,
151+
GitLab: `<svg
152+
xmlns="http://www.w3.org/2000/svg"
153+
class="icon-tabler"
154+
stroke-linecap="round"
155+
stroke-linejoin="round"
156+
>
157+
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
158+
<path d="M21 14l-9 7l-9 -7l3 -11l3 7h6l3 -7z"></path>
159+
</svg>`,
160+
Reddit: `<svg
161+
xmlns="http://www.w3.org/2000/svg"
162+
class="icon-tabler"
163+
stroke-linecap="round"
164+
stroke-linejoin="round"
165+
>
166+
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
167+
<path d="M12 8c2.648 0 5.028 .826 6.675 2.14a2.5 2.5 0 0 1 2.326 4.36c0 3.59 -4.03 6.5 -9 6.5c-4.875 0 -8.845 -2.8 -9 -6.294l-1 -.206a2.5 2.5 0 0 1 2.326 -4.36c1.646 -1.313 4.026 -2.14 6.674 -2.14z"></path>
168+
<path d="M12 8l1 -5l6 1"></path>
169+
<circle cx="19" cy="4" r="1"></circle>
170+
<circle cx="9" cy="13" r=".5" fill="currentColor"></circle>
171+
<circle cx="15" cy="13" r=".5" fill="currentColor"></circle>
172+
<path d="M10 17c.667 .333 1.333 .5 2 .5s1.333 -.167 2 -.5"></path>
173+
</svg>`,
174+
Skype: `<svg
175+
xmlns="http://www.w3.org/2000/svg"
176+
class="icon-tabler"
177+
stroke-linecap="round"
178+
stroke-linejoin="round"
179+
>
180+
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
181+
<path d="M12 3a9 9 0 0 1 8.603 11.65a4.5 4.5 0 0 1 -5.953 5.953a9 9 0 0 1 -11.253 -11.253a4.5 4.5 0 0 1 5.953 -5.954a8.987 8.987 0 0 1 2.65 -.396z"></path>
182+
<path d="M8 14.5c.5 2 2.358 2.5 4 2.5c2.905 0 4 -1.187 4 -2.5c0 -1.503 -1.927 -2.5 -4 -2.5s-4 -.997 -4 -2.5c0 -1.313 1.095 -2.5 4 -2.5c1.642 0 3.5 .5 4 2.5"></path>
183+
</svg>`,
184+
Steam: `<svg
185+
xmlns="http://www.w3.org/2000/svg"
186+
class="icon-tabler"
187+
stroke-linecap="round"
188+
stroke-linejoin="round"
189+
>
190+
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
191+
<path d="M16.5 5a4.5 4.5 0 1 1 -.653 8.953l-4.347 3.009l0 .038a3 3 0 0 1 -2.824 2.995l-.176 .005a3 3 0 0 1 -2.94 -2.402l-2.56 -1.098v-3.5l3.51 1.755a2.989 2.989 0 0 1 2.834 -.635l2.727 -3.818a4.5 4.5 0 0 1 4.429 -5.302z"></path>
192+
<circle fill="currentColor" cx="16.5" cy="9.5" r="1"></circle>
193+
</svg>`,
194+
Telegram: `<svg
195+
xmlns="http://www.w3.org/2000/svg"
196+
class="icon-tabler"
197+
stroke-linecap="round"
198+
stroke-linejoin="round"
199+
>
200+
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
201+
<path d="M15 10l-4 4l6 6l4 -16l-18 7l4 2l2 6l3 -4"></path>
202+
</svg>`,
203+
Mastodon: `<svg class="icon-tabler" viewBox="-10 -5 1034 1034" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
204+
<path fill="currentColor"
205+
d="M499 112q-93 1 -166 11q-81 11 -128 33l-14 8q-16 10 -32 25q-22 21 -38 47q-21 33 -32 73q-14 47 -14 103v37q0 77 1 119q3 113 18 188q19 95 62 154q50 67 134 89q109 29 210 24q46 -3 88 -12q30 -7 55 -17l19 -8l-4 -75l-22 6q-28 6 -57 10q-41 6 -78 4q-53 -1 -80 -7
206+
q-43 -8 -67 -30q-29 -25 -35 -72q-2 -14 -2 -29l25 6q31 6 65 10q48 7 93 9q42 2 92 -2q32 -2 88 -9t107 -30q49 -23 81.5 -54.5t38.5 -63.5q9 -45 13 -109q4 -46 5 -97v-41q0 -56 -14 -103q-11 -40 -32 -73q-16 -26 -38 -47q-15 -15 -32 -25q-12 -8 -14 -8
207+
q-46 -22 -127 -33q-74 -10 -166 -11h-3zM367 267q73 0 109 56l24 39l24 -39q36 -56 109 -56q63 0 101 43t38 117v239h-95v-232q0 -74 -61 -74q-69 0 -69 88v127h-94v-127q0 -88 -69 -88q-61 0 -61 74v232h-95v-239q0 -74 38 -117t101 -43z" />
208+
</svg>`,
209+
};
210+
211+
export default socialIcons;

src/components/Breadcrumbs.astro

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
---
2+
// Remove current url path and remove trailing slash if exists
3+
const currentUrlPath = Astro.url.pathname.replace(/\/+$/, "");
4+
5+
// Get url array from path
6+
// eg: /tags/tailwindcss => ['tags', 'tailwindcss']
7+
const breadcrumbList = currentUrlPath.split("/").slice(1);
8+
9+
// if breadcrumb is Home > Posts > 1 <etc>
10+
// replace Posts with Posts (page number)
11+
breadcrumbList[0] === "posts" &&
12+
breadcrumbList.splice(0, 2, `Posts (page ${breadcrumbList[1] || 1})`);
13+
14+
// if breadcrumb is Home > Tags > [tag] > [page] <etc>
15+
// replace [tag] > [page] with [tag] (page number)
16+
breadcrumbList[0] === "tags" &&
17+
!isNaN(Number(breadcrumbList[2])) &&
18+
breadcrumbList.splice(
19+
1,
20+
3,
21+
`${breadcrumbList[1]} ${
22+
Number(breadcrumbList[2]) === 1 ? "" : "(page " + breadcrumbList[2] + ")"
23+
}`
24+
);
25+
---
26+
27+
<nav class="breadcrumb" aria-label="breadcrumb">
28+
<ul>
29+
<li>
30+
<a href="/">Home</a>
31+
<span aria-hidden="true">&raquo;</span>
32+
</li>
33+
{
34+
breadcrumbList.map((breadcrumb, index) =>
35+
index + 1 === breadcrumbList.length ? (
36+
<li>
37+
<span
38+
class={`${index > 0 ? "lowercase" : "capitalize"}`}
39+
aria-current="page"
40+
>
41+
{/* make the last part lowercase in Home > Tags > some-tag */}
42+
{decodeURIComponent(breadcrumb)}
43+
</span>
44+
</li>
45+
) : (
46+
<li>
47+
<a href={`/${breadcrumb}/`}>{breadcrumb}</a>
48+
<span aria-hidden="true">&raquo;</span>
49+
</li>
50+
)
51+
)
52+
}
53+
</ul>
54+
</nav>
55+
56+
<style>
57+
.breadcrumb {
58+
@apply mx-auto mb-1 mt-8 w-full max-w-3xl px-4;
59+
}
60+
.breadcrumb ul li {
61+
@apply inline;
62+
}
63+
.breadcrumb ul li a {
64+
@apply capitalize opacity-70;
65+
}
66+
.breadcrumb ul li span {
67+
@apply opacity-70;
68+
}
69+
.breadcrumb ul li:not(:last-child) a {
70+
@apply hover:opacity-100;
71+
}
72+
</style>

src/components/Card.tsx

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { slugifyStr } from "@utils/slugify";
2+
import Datetime from "./Datetime";
3+
import type { CollectionEntry } from "astro:content";
4+
5+
export interface Props {
6+
href?: string;
7+
frontmatter: CollectionEntry<"blog">["data"];
8+
secHeading?: boolean;
9+
}
10+
11+
export default function Card({ href, frontmatter, secHeading = true }: Props) {
12+
const { title, pubDatetime, modDatetime, description } = frontmatter;
13+
14+
const headerProps = {
15+
style: { viewTransitionName: slugifyStr(title) },
16+
className: "text-lg font-medium decoration-dashed hover:underline",
17+
};
18+
19+
return (
20+
<li className="my-6">
21+
<a
22+
href={href}
23+
className="inline-block text-lg font-medium text-skin-accent decoration-dashed underline-offset-4 focus-visible:no-underline focus-visible:underline-offset-0"
24+
>
25+
{secHeading ? (
26+
<h2 {...headerProps}>{title}</h2>
27+
) : (
28+
<h3 {...headerProps}>{title}</h3>
29+
)}
30+
</a>
31+
<Datetime pubDatetime={pubDatetime} modDatetime={modDatetime} />
32+
<p>{description}</p>
33+
</li>
34+
);
35+
}

src/components/Datetime.tsx

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { LOCALE } from "@config";
2+
3+
interface DatetimesProps {
4+
pubDatetime: string | Date;
5+
modDatetime: string | Date | undefined | null;
6+
}
7+
8+
interface Props extends DatetimesProps {
9+
size?: "sm" | "lg";
10+
className?: string;
11+
}
12+
13+
export default function Datetime({
14+
pubDatetime,
15+
modDatetime,
16+
size = "sm",
17+
className,
18+
}: Props) {
19+
return (
20+
<div className={`flex items-center space-x-2 opacity-80 ${className}`}>
21+
<svg
22+
xmlns="http://www.w3.org/2000/svg"
23+
className={`${
24+
size === "sm" ? "scale-90" : "scale-100"
25+
} inline-block h-6 w-6 min-w-[1.375rem] fill-skin-base`}
26+
aria-hidden="true"
27+
>
28+
<path d="M7 11h2v2H7zm0 4h2v2H7zm4-4h2v2h-2zm0 4h2v2h-2zm4-4h2v2h-2zm0 4h2v2h-2z"></path>
29+
<path d="M5 22h14c1.103 0 2-.897 2-2V6c0-1.103-.897-2-2-2h-2V2h-2v2H9V2H7v2H5c-1.103 0-2 .897-2 2v14c0 1.103.897 2 2 2zM19 8l.001 12H5V8h14z"></path>
30+
</svg>
31+
{modDatetime && modDatetime > pubDatetime ? (
32+
<span className={`italic ${size === "sm" ? "text-sm" : "text-base"}`}>
33+
Updated:
34+
</span>
35+
) : (
36+
<span className="sr-only">Published:</span>
37+
)}
38+
<span className={`italic ${size === "sm" ? "text-sm" : "text-base"}`}>
39+
<FormattedDatetime
40+
pubDatetime={pubDatetime}
41+
modDatetime={modDatetime}
42+
/>
43+
</span>
44+
</div>
45+
);
46+
}
47+
48+
const FormattedDatetime = ({ pubDatetime, modDatetime }: DatetimesProps) => {
49+
const myDatetime = new Date(
50+
modDatetime && modDatetime > pubDatetime ? modDatetime : pubDatetime
51+
);
52+
53+
const date = myDatetime.toLocaleDateString(LOCALE.langTag, {
54+
year: "numeric",
55+
month: "short",
56+
day: "numeric",
57+
});
58+
59+
const time = myDatetime.toLocaleTimeString(LOCALE.langTag, {
60+
hour: "2-digit",
61+
minute: "2-digit",
62+
});
63+
64+
return (
65+
<>
66+
<time dateTime={myDatetime.toISOString()}>{date}</time>
67+
<span aria-hidden="true"> | </span>
68+
<span className="sr-only">&nbsp;at&nbsp;</span>
69+
<span className="text-nowrap">{time}</span>
70+
</>
71+
);
72+
};

0 commit comments

Comments
 (0)