Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions content/publications/ss2026_27.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ news:
title:
ja: "SIGSS 2026年7月研究会で研究発表を行いました."
en: "Presented our work at the July 2026 SIGSS meeting."
url: "https://www.ipsj.or.jp/kenkyukai/event/se223.html"
type: "talk"
14 changes: 14 additions & 0 deletions src/components/about_section.astro
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
import type { Lang } from "@i18n/ui";
import { useTranslations, pickLocale } from "@i18n/utils";
import { education } from "@data/education";
import { profile } from "@data/profile";
import Section from "./section.astro";
import TagList from "./tag_list.astro";

interface Props {
lang: Lang;
Expand All @@ -13,6 +15,10 @@ const t = useTranslations(lang);
---

<Section id="about" title={t("section.about")}>
<p class="introduction">{pickLocale(profile.introduction, lang)}</p>
<div class="skills">
<TagList tags={profile.skills} />
</div>
<h3 class="sub-heading">{t("about.education")}</h3>
<ul class="timeline">
{
Expand All @@ -30,6 +36,14 @@ const t = useTranslations(lang);
</Section>

<style>
.introduction {
margin-bottom: 1rem;
}

.skills {
margin-bottom: 2.5rem;
}

.sub-heading {
font-size: 1.125rem;
font-weight: 600;
Expand Down
39 changes: 0 additions & 39 deletions src/components/news_section.astro

This file was deleted.

19 changes: 18 additions & 1 deletion src/components/publications_section.astro
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
---
import type { Lang } from "@i18n/ui";
import { useTranslations } from "@i18n/utils";
import { getNews } from "@data/news";
import { getPublications } from "@data/publications";
import Section from "./section.astro";
import NewsEntry from "./news_entry.astro";
import PublicationEntry from "./publication_entry.astro";

interface Props {
Expand All @@ -12,6 +14,7 @@ interface Props {
const { lang } = Astro.props;
const t = useTranslations(lang);
const publications = await getPublications(lang);
const news = await getNews();
---

<Section id="publications" title={t("section.publications")}>
Expand All @@ -26,13 +29,27 @@ const publications = await getPublications(lang);
<p class="empty">{t("publications.empty")}</p>
)
}
{
news.length > 0 && (
<ul class="news-list">
{news.map((item) => (
<NewsEntry item={item} lang={lang} />
))}
</ul>
)
}
</Section>

<style>
.pub-list {
.pub-list,
.news-list {
list-style: none;
}

.news-list {
margin-top: 1.5rem;
}

.empty {
color: var(--color-text-secondary);
}
Expand Down
7 changes: 7 additions & 0 deletions src/data/profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ interface Profile {
department: LocalizedText;
university: LocalizedText;
email: string;
introduction: LocalizedText;
skills: string[];
socialLinks: SocialLink[];
}

Expand All @@ -30,6 +32,11 @@ export const profile: Profile = {
},
university: { ja: "九州大学", en: "Kyushu University" },
email: "shigyo@posl.ait.kyushu-u.ac.jp",
introduction: {
ja: "AI Coding Agent と開発基盤に関心のある,ソフトウェアエンジニア志望の修士学生です.",
en: "I'm a master's student aspiring to be a software engineer, interested in AI coding agents and developer infrastructure.",
},
skills: ["Python", "Rust", "TypeScript", "Bash", "Nix", "Docker", "GitHub Actions"],
socialLinks: [
{ platform: "GitHub", url: "https://github.com/furedea", icon: "github" },
{ platform: "X", url: "https://x.com/furedea596", icon: "x" },
Expand Down
3 changes: 1 addition & 2 deletions src/data/sections.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
export const HOME_SECTIONS = [
"about",
"research",
"works",
"research",
"publications",
"news",
"blog",
"contact",
] as const;
Expand Down
4 changes: 1 addition & 3 deletions src/data/site_record_schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ export const newsSchema = z
})
.strict();

const publicationNewsSchema = newsSchema.omit({ url: true }).strict();

export const publicationSchema = z
.object({
title: localizedTextSchema,
Expand All @@ -31,7 +29,7 @@ export const publicationSchema = z
pdfUrl: z.url().optional(),
slidesUrl: z.url().optional(),
bibtex: z.string().min(1).optional(),
news: publicationNewsSchema.optional(),
news: newsSchema.optional(),
})
.strict();

Expand Down
16 changes: 16 additions & 0 deletions src/data/site_records.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,22 @@ test("projects a publication announcement into news with the publication URL", (
]);
});

test("links a publication announcement to its own event page when given", () => {
const items = toNewsItems([
publication({
url: "https://example.com/publication",
news: {
date: "2026-07-24",
title: { ja: "研究発表を行いました.", en: "Presented our work." },
url: "https://example.com/event",
type: "talk",
},
}),
]);

expect(items[0]?.url).toBe("https://example.com/event");
});

test("orders projected and standalone news from newest to oldest", () => {
const items = toNewsItems([
publication({
Expand Down
2 changes: 1 addition & 1 deletion src/data/site_records.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export function toNewsItems(records: readonly SiteRecord[]): NewsItem[] {
const publications = records.filter(isPublicationRecord);
const standaloneItems = records.filter(isNewsRecord);
const publicationItems = publications.flatMap(({ news, url }) =>
news ? [{ ...news, ...(url ? { url } : {}) }] : [],
news ? [{ ...(url ? { url } : {}), ...news }] : [],
);

return [...standaloneItems, ...publicationItems].sort((left, right) =>
Expand Down
47 changes: 46 additions & 1 deletion src/data/works.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,51 @@ export const works: Work[] = [
en: "Same choice, different luck: 100 versions of you live one job-hunting year. A browser game.",
},
url: "https://furedea.com/effort-or-luck/",
tags: ["Astro", "React", "TypeScript"],
tags: ["TypeScript", "React", "Astro"],
},
{
title: { ja: "agent-harness", en: "agent-harness" },
description: {
ja: "Claude Code や Codex の hooks,skills,権限ルールを1つの Nix 設定で管理するエージェントハーネス.",
en: "One Nix configuration for the hooks, skills, and permission rules of Claude Code, Codex, and other coding agents.",
},
url: "https://github.com/furedea/agent-harness",
tags: ["Rust", "Nix", "CLI"],
},
{
title: { ja: "apple-mail-cli", en: "apple-mail-cli" },
description: {
ja: "macOS の Apple Mail を安全に自動操作する JSON CLI.",
en: "A safe JSON CLI for Apple Mail automation on macOS.",
},
url: "https://github.com/furedea/apple-mail-cli",
tags: ["Rust", "CLI"],
},
{
title: { ja: "reflex-state", en: "reflex-state" },
description: {
ja: "Pi coding agent の変更・検証・ブロッカーといった実行状態を,メインの LLM の外で追跡する.",
en: "Tracks execution state for Pi coding agents, such as changes, checks, and blockers, outside the main LLM.",
},
url: "https://github.com/furedea/reflex-state",
tags: ["TypeScript", "Pi"],
},
{
title: { ja: "book-agent", en: "book-agent" },
description: {
ja: "技術書のメモを Sub Agent 定義に変換する Claude Code コマンド.",
en: "A Claude Code command that turns notes from technical books into sub-agent definitions.",
},
url: "https://github.com/furedea/book-agent",
tags: ["Claude Code", "Obsidian"],
},
{
title: { ja: "LLM-chatbot", en: "LLM-chatbot" },
description: {
ja: "LINE の対話からスマートフォンを推薦し,PDF カタログを生成するサービス.福岡未踏でチーム開発し,商品データの整備・統合,検索と推薦文の生成,実行環境の整備,発表の約半分を担当.",
en: "A LINE service that recommends smartphones through conversation and generates PDF catalogs. Built as a team in Fukuoka Mitou; I handled product data integration, search and recommendation text generation, the runtime environment, and about half of the presentation.",
},
url: "https://mitou-fukuoka.org/works/genius_catalog.html",
tags: ["Python", "LangChain", "LINE"],
},
];
14 changes: 4 additions & 10 deletions src/i18n/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,13 @@ export const ui = {
"nav.about": "概要",
"nav.research": "研究",
"nav.works": "作品",
"nav.publications": "業績",
"nav.news": "ニュース",
"nav.publications": "発表・論文",
"nav.blog": "ブログ",
"nav.contact": "連絡先",
"section.about": "About",
"section.research": "Research",
"section.works": "Works",
"section.publications": "Publications",
"section.news": "News",
"section.publications": "Publications & Talks",
"section.blog": "Blog",
"section.contact": "Contact",
"about.education": "学歴",
Expand All @@ -36,7 +34,6 @@ export const ui = {
"common.skipToContent": "Skip to content",
"contact.email": "Email",
"footer.copyright": "All rights reserved.",
"news.empty": "ニュースはまだありません",
"publications.empty": "準備中",
"publications.nonPeerReviewed": "査読なし",
},
Expand All @@ -45,15 +42,13 @@ export const ui = {
"nav.about": "About",
"nav.research": "Research",
"nav.works": "Works",
"nav.publications": "Publications",
"nav.news": "News",
"nav.publications": "Publications & Talks",
"nav.blog": "Blog",
"nav.contact": "Contact",
"section.about": "About",
"section.research": "Research",
"section.works": "Works",
"section.publications": "Publications",
"section.news": "News",
"section.publications": "Publications & Talks",
"section.blog": "Blog",
"section.contact": "Contact",
"about.education": "Education",
Expand All @@ -66,7 +61,6 @@ export const ui = {
"common.skipToContent": "Skip to content",
"contact.email": "Email",
"footer.copyright": "All rights reserved.",
"news.empty": "No news yet",
"publications.empty": "Coming soon",
"publications.nonPeerReviewed": "Non-peer-reviewed",
},
Expand Down
4 changes: 1 addition & 3 deletions src/pages/[lang]/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import AboutSection from "@components/about_section.astro";
import ResearchSection from "@components/research_section.astro";
import WorksSection from "@components/works_section.astro";
import PublicationsSection from "@components/publications_section.astro";
import NewsSection from "@components/news_section.astro";
import BlogSection from "@components/blog_section.astro";
import ContactSection from "@components/contact_section.astro";
import { HOME_SECTIONS, type HomeSectionId } from "@data/sections";
Expand All @@ -19,10 +18,9 @@ type SectionComponent = (typeof sectionComponents)[HomeSectionId];

const sectionComponents = {
about: AboutSection,
research: ResearchSection,
works: WorksSection,
research: ResearchSection,
publications: PublicationsSection,
news: NewsSection,
blog: BlogSection,
contact: ContactSection,
} as const satisfies Record<HomeSectionId, unknown>;
Expand Down
Loading
Loading