Skip to content

Commit

Permalink
Merge pull request #41 from yossydev/update-blog
Browse files Browse the repository at this point in the history
update blog
  • Loading branch information
Yuto Yoshino authored Jul 20, 2024
2 parents 9618985 + 3ab2028 commit 95daf60
Show file tree
Hide file tree
Showing 14 changed files with 281 additions and 41 deletions.
1 change: 1 addition & 0 deletions app/constants/link/link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ export const LINK = {
ZENN: "https://zenn.dev/yuto76",
AMAZON: "https://www.amazon.jp/hz/wishlist/ls/XSPLZ7OVMR3M?ref_=wl_share",
YOUTUBE: "https://www.youtube.com/@yossydev",
SPEAKERDECK: "https://speakerdeck.com/yossydev",
};
9 changes: 8 additions & 1 deletion app/libs/posts/rss-parser.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ const parser = new Parser();

(async () => {
let jsonFeed = {};
const [feed1, feed2] = await Promise.all([
const [feed1, feed2, feed3] = await Promise.all([
parser.parseURL("https://zenn.dev/yuto76/feed"),
parser.parseURL(
"https://www.youtube.com/feeds/videos.xml?channel_id=UCu6ckjaLjqCKY-c01fEqUqw",
),
parser.parseURL("https://speakerdeck.com/yossydev.rss"),
]);
const items = feed1.items.map((data) => {
return data;
Expand All @@ -21,4 +22,10 @@ const parser = new Parser();
});
jsonFeed = items2;
writeFileSync("app/libs/rss/youtube.json", JSON.stringify(jsonFeed));

const items3 = feed3.items.map((data) => {
return data;
});
jsonFeed = items3;
writeFileSync("app/libs/rss/speakerdeck.json", JSON.stringify(jsonFeed));
})();
10 changes: 10 additions & 0 deletions app/libs/rss/rss.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import zennRss from "./data.json";
import speakerdeckRss from "./speakerdeck.json";
import youtubeRss from "./youtube.json";

function formatDate(utcDate: string) {
Expand Down Expand Up @@ -27,4 +28,13 @@ export const rssClient = {
link: item.link,
}));
},

findSpeakerdeck() {
return speakerdeckRss.map((item) => ({
id: item.guid,
title: item.title,
date: formatDate(item.isoDate),
link: item.link,
}));
},
};
43 changes: 43 additions & 0 deletions app/libs/rss/speakerdeck.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
[
{
"title": "Fast JSX: Don't clone props object #28768",
"link": "https://speakerdeck.com/yossydev/fast-jsx-dont-clone-props-object-number-28768",
"pubDate": "Wed, 24 Apr 2024 00:00:00 -0400",
"content:encoded": "",
"content": "",
"contentSnippet": "",
"guid": "https://speakerdeck.com/yossydev/fast-jsx-dont-clone-props-object-number-28768",
"isoDate": "2024-04-24T04:00:00.000Z"
},
{
"title": "2023 Spindle Review",
"link": "https://speakerdeck.com/yossydev/2023-spindle-review",
"pubDate": "Fri, 12 Jan 2024 00:00:00 -0500",
"content:encoded": "2023年度にSpindleに対して自分が取り組んだこと、学んだことの話です。",
"content:encodedSnippet": "2023年度にSpindleに対して自分が取り組んだこと、学んだことの話です。",
"content": "2023年度にSpindleに対して自分が取り組んだこと、学んだことの話です。",
"contentSnippet": "2023年度にSpindleに対して自分が取り組んだこと、学んだことの話です。",
"guid": "https://speakerdeck.com/yossydev/2023-spindle-review",
"isoDate": "2024-01-12T05:00:00.000Z"
},
{
"title": "Core Web Vitalsについて",
"link": "https://speakerdeck.com/yossydev/core-web-vitalsnituite",
"pubDate": "Sat, 01 Jul 2023 00:00:00 -0400",
"content:encoded": "",
"content": "",
"contentSnippet": "",
"guid": "https://speakerdeck.com/yossydev/core-web-vitalsnituite",
"isoDate": "2023-07-01T04:00:00.000Z"
},
{
"title": "React の色々な スタイリング方法",
"link": "https://speakerdeck.com/yossydev/react-nose-na-sutairingufang-fa",
"pubDate": "Fri, 03 Jun 2022 00:00:00 -0400",
"content:encoded": "",
"content": "",
"contentSnippet": "",
"guid": "https://speakerdeck.com/yossydev/react-nose-na-sutairingufang-fa",
"isoDate": "2022-06-03T04:00:00.000Z"
}
]
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import type { Element, Root, Text } from "hast";
import { visit } from "unist-util-visit";

interface Heading extends Element {
id: string;
}

function rehypeTOC() {
return (tree) => {
const headings = [];
visit(tree, "element", (node) => {
return (tree: Root) => {
const headings: Heading[] = [];
visit(tree, "element", (node: Element) => {
if (node.tagName === "h2" || node.tagName === "h3") {
const id = createId(node);
headings.push({ id, ...node });
Expand All @@ -18,15 +23,15 @@ function rehypeTOC() {
};
}

function createId(node) {
function createId(node: Element): string {
return node.children
.filter((child) => child.type === "text")
.filter((child): child is Text => child.type === "text")
.map((child) => child.value.replace(/\s+/g, "-").toLowerCase())
.join("");
}

function buildTOC(headings) {
const listItems = headings.map((heading) => {
function buildTOC(headings: Heading[]): Element {
const listItems: Element[] = headings.map((heading) => {
const levelClass = getLevelClass(heading.tagName);
return {
type: "element",
Expand All @@ -51,18 +56,20 @@ function buildTOC(headings) {
{
type: "element",
tagName: "summary",
properties: {},
children: [{ type: "text", value: "目次" }],
},
{
type: "element",
tagName: "ul",
properties: {},
children: listItems,
},
],
};
}

function getLevelClass(tagName) {
function getLevelClass(tagName: string): string {
switch (tagName) {
case "h2":
return "toc-level-2";
Expand Down
23 changes: 15 additions & 8 deletions app/routes/_renderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,25 @@ export default jsxRenderer(({ children, title, description }) => {
Yuto Blog
</a>
<div class="flex items-center gap-4">
<a href={"/slides"}>
<img
src="/static/speaker-deck-logo.png"
alt="speaker-deck-icon"
class="w-8 h-5"
/>
</a>
<a href={"/youtube"}>
<img
src="/static/youtube-svgrepo-com.svg"
alt="youtube-icon"
class="w-9 h-9"
/>
</a>
<a href={LINK.RSS} target={"_blank"} rel={"noreferrer"}>
<img
src="/static/rss-svgrepo-com.svg"
alt="rss-icon"
class="w-9 h-9"
class="w-8 h-8"
/>
</a>
<a href={LINK.X} target={"_blank"} rel={"noreferrer"}>
Expand All @@ -59,13 +73,6 @@ export default jsxRenderer(({ children, title, description }) => {
class="w-7 h-7 text-white"
/>
</a>
<a href={LINK.YOUTUBE} target={"_blank"} rel={"noreferrer"}>
<img
src="/static/youtube-svgrepo-com.svg"
alt="youtube-icon"
class="w-9 h-9"
/>
</a>
</div>
</div>
</header>
Expand Down
16 changes: 3 additions & 13 deletions app/routes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ export default function Top() {
<Heading title="Hi! I'm Yuto" />
<div class="mt-5">
<p class="font-medium">
都内在住の技術好きなエンジニアです。Web / OSS開発 / developer
experienceの向上に興味があります
都内在住の技術好きなエンジニアです。Rust / OSS / Developer
Experienceの向上に興味があります
<span class="ml-1">
<a
href="/profile"
Expand Down Expand Up @@ -86,17 +86,7 @@ const Posts: FC = () => {
link: post.link,
postedIn: "zenn",
}));
const youtubePosts = rssClient
.findYoutube()
.filter((post) => {
const postYear = new Date(post.date).getFullYear();
return postYear === year;
})
.map((post) => ({
...post,
postedIn: "youtube",
}));
const posts = [...arrBlog, ...zennPosts, ...youtubePosts];
const posts = [...arrBlog, ...zennPosts];

blogData.push({
year: year,
Expand Down
47 changes: 38 additions & 9 deletions app/routes/profile/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { FC } from "hono/jsx";
import { createRoute } from "honox/factory";
import { Link } from "honox/server";
import { Heading } from "../../components/Heading";
import { LINK } from "../../constants";
import { getAge } from "../../libs/date";

const SnsList: {
id: number;
Expand Down Expand Up @@ -44,6 +44,11 @@ const SnsList: {
title: "Youtube",
href: LINK.YOUTUBE,
},
{
id: 9,
title: "Speakerdeck",
href: LINK.SPEAKERDECK,
},
];

const Text: FC<{ text: string }> = ({ text }) => {
Expand All @@ -54,20 +59,44 @@ export default createRoute((c) => {
return c.render(
<>
<Heading title="About Me" />
<Text text="都内在住の技術好きなエンジニアです。出身は日本です。🇯🇵🏯" />
<Text text="TypeScriptを主に扱っており、最近ではパフォーマンス改善 / Rust / Webブラウザ / Developer Experience / OSS開発に興味があります。" />
<Text text="2022年からフルタイムでエンジニアとして働き始め、スピード感のある開発をしていく中で、フロントエンドとバックエンド両方の経験をさせていただけたのはとてもいい経験でした。そして2023年、新しい会社にジョインし、Webフロントエンド領域の様々なことに挑戦し、開発者としてレベルアップすることに注力しています。" />
<Text text="空いた時間で、技術のキャッチアップをし、それを実際に自分の手で動かしてみたりすること。理解が足りない部分や、新しく学んだことを記事にすることも好きです。あとは勉強会に行って発表したりすることも好きです。" />

<Text text="都内在住の技術好きなエンジニアです。出身は日本です。TypeScriptを主に扱っており、最近ではRust / Developer Experience / OSS開発に興味があります。" />
<br />
自分のアウトプットに関しては、
<a href={"/"} class="underline-offset-2 underline mr-1 text-blue-600">
Blog
</a>
<a
href={"/slides"}
class="underline-offset-2 underline mr-1 text-blue-600"
>
Slides
</a>
<a
href={"/youtube"}
class="underline-offset-2 underline mr-1 text-blue-600"
>
Youtube
</a>
<a
href={LINK.GITHUB}
class="underline-offset-2 underline mr-1 text-blue-600"
>
GitHub
</a>
でチェックできます。
<Heading title="Sponsor" />
<Text text="GitHub Sponsorで応援していただけるとモチベーションにつながります🔥" />
<Text text="GitHub Sponcerで応援してくださる方を募集しています🙏" />
<br />
<iframe
src="https://github.com/sponsors/yossydev/card"
title="Sponsor yossydev"
class="md:w-[600px] w-full md:h-auto h-40"
/>

<ul class="text-lg mt-6 pt-6 border-t border-black">
<Heading title="Contact" />
<Text text="お仕事や登壇のご依頼などはXのDMもしくは[email protected]までご連絡ください。" />
<br />
<Heading title="Link" />
<ul class="text-lg mt-6">
{SnsList.map(({ id, title, href }) => (
<li key={id} class="flex items-center py-1">
<div class="w-2 h-2 rounded bg-black mr-2" />
Expand Down
72 changes: 72 additions & 0 deletions app/routes/slides/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { Fragment } from "hono/jsx";
import { Heading } from "../../components/Heading";
import { rssClient } from "../../libs/rss/rss";

const FIRST_SPEAKERDECK_YEAR = 2022;

export default function Slide() {
const yearlyBlogs = () => {
const data = [];
const thisYear = new Date().getFullYear();
for (let year = FIRST_SPEAKERDECK_YEAR; year <= thisYear; year++) {
const speakerdeck = rssClient
.findSpeakerdeck()
.filter((post) => {
const postYear = new Date(post.date).getFullYear();
return postYear === year;
})
.map((post) => ({
id: post.id,
date: post.date,
title: post.title,
link: post.link,
postedIn: "speakerdeck",
}));

data.push({
year: year,
posts: speakerdeck.sort((a, b) => {
const dateA = new Date(a.date).getTime();
const dateB = new Date(b.date).getTime();
return dateB - dateA;
}),
});
}
return data;
};

return (
<div class="mt-16">
<Heading title="Slides" />
<ul class="mt-10">
{yearlyBlogs()
.reverse()
.map((res, index) => {
return (
// biome-ignore lint/suspicious/noArrayIndexKey: enable index
<Fragment key={`${index}`}>
<h3 class="text-xl my-5 font-bold">{res.year}</h3>
{res.posts.map(({ id, title, date, link }) => {
return (
<li key={id} class="text-lg mt-2 md:mt-1">
<time class="tabular-nums tnum date pr-3">{date}</time>
<br class="block md:hidden" />
<a class="text-blue-600 underline" href={link}>
{title}
</a>

<img
src="/static/speaker_deck_logo.webp"
alt="zenn-logo"
class="ml-2 w-5 h-5 inline"
/>
</li>
);
})}
</Fragment>
);
})}
</ul>
</div>
);
}
Loading

0 comments on commit 95daf60

Please sign in to comment.