wow
Some checks failed
/ print-content (push) Failing after 1m39s

This commit is contained in:
암냥 2026-09-07 00:09:32 +09:00
commit bcd4fa87b2
11 changed files with 679 additions and 34 deletions

16
public/icon/mizuki.svg Normal file
View file

@ -0,0 +1,16 @@
<svg width="114" height="114" viewBox="0 0 114 114" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M111.78 51.8875L62.0349 2.1486C59.1727 -0.7162 54.5267 -0.7162 51.6609 2.1486L41.3319 12.4786L54.4339 25.5806C57.4798 24.5522 60.971 25.2417 63.3978 27.669C65.8372 30.1114 66.5218 33.6324 65.4676 36.6885L78.0956 49.3165C81.1507 48.2637 84.6756 48.9439 87.1151 51.3877C90.5257 54.7973 90.5257 60.3222 87.1151 63.7327C83.704 67.1443 78.1791 67.1443 74.7661 63.7327C72.2016 61.1662 71.5673 57.3982 72.8662 54.2385L61.0892 42.4615L61.0882 73.4525C61.9197 73.8641 62.7044 74.4135 63.3973 75.1034C66.8069 78.5126 66.8069 84.0365 63.3973 87.4514C59.9867 90.8605 54.4593 90.8605 51.0523 87.4514C47.6422 84.0368 47.6422 78.5129 51.0523 75.1034C51.895 74.2622 52.8702 73.6254 53.9107 73.1986V41.9196C52.8697 41.4946 51.8957 40.8626 51.0517 40.0146C48.4687 37.4336 47.8466 33.6426 49.1713 30.4707L36.2553 17.5527L2.14928 51.6577C-0.716425 54.5247 -0.716425 59.1707 2.14928 62.0357L51.8913 111.775C54.7551 114.639 59.3995 114.639 62.2673 111.775L111.779 62.2707C114.644 59.4045 114.644 54.7571 111.779 51.8917" fill="url(#paint0_linear_372_6)"/>
<defs>
<linearGradient id="paint0_linear_372_6" x1="0" y1="0" x2="114" y2="114" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFB5C9"/>
<stop offset="0.125" stop-color="#FFB8C7"/>
<stop offset="0.25" stop-color="#FFBCC4"/>
<stop offset="0.375" stop-color="#FFBFC2"/>
<stop offset="0.5" stop-color="#FFC3BF"/>
<stop offset="0.625" stop-color="#FFC6BD"/>
<stop offset="0.75" stop-color="#FFC9BA"/>
<stop offset="0.875" stop-color="#FFCDB8"/>
<stop offset="1" stop-color="#FFD0B5"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

1
public/icon/steam.svg Normal file
View file

@ -0,0 +1 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Steam</title><path d="M11.979 0C5.678 0 .511 4.86.022 11.037l6.432 2.658c.545-.371 1.203-.59 1.912-.59.063 0 .125.004.188.006l2.861-4.142V8.91c0-2.495 2.028-4.524 4.524-4.524 2.494 0 4.524 2.031 4.524 4.527s-2.03 4.525-4.524 4.525h-.105l-4.076 2.911c0 .052.004.105.004.159 0 1.875-1.515 3.396-3.39 3.396-1.635 0-3.016-1.173-3.331-2.727L.436 15.27C1.862 20.307 6.486 24 11.979 24c6.627 0 11.999-5.373 11.999-12S18.605 0 11.979 0zM7.54 18.21l-1.473-.61c.262.543.714.999 1.314 1.25 1.297.539 2.793-.076 3.332-1.375.263-.63.264-1.319.005-1.949s-.75-1.121-1.377-1.383c-.624-.26-1.29-.249-1.878-.03l1.523.63c.956.4 1.409 1.5 1.009 2.455-.397.957-1.497 1.41-2.454 1.012H7.54zm11.415-9.303c0-1.662-1.353-3.015-3.015-3.015-1.665 0-3.015 1.353-3.015 3.015 0 1.665 1.35 3.015 3.015 3.015 1.663 0 3.015-1.35 3.015-3.015zm-5.273-.005c0-1.252 1.013-2.266 2.265-2.266 1.249 0 2.266 1.014 2.266 2.266 0 1.251-1.017 2.265-2.266 2.265-1.253 0-2.265-1.014-2.265-2.265z"/></svg>

After

Width:  |  Height:  |  Size: 1 KiB

1
public/icon/vrchat.svg Normal file
View file

@ -0,0 +1 @@
<svg fill="#000000" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>VRChat</title><path d="M22.732 6.767H1.268A1.27 1.27 0 0 0 0 8.035v5.296c0 .7.57 1.268 1.268 1.268h18.594l1.725 2.22c.215.275.443.415.68.415.153 0 .296-.06.403-.167.128-.129.193-.308.193-.536l-.002-1.939A1.27 1.27 0 0 0 24 13.331V8.035c0-.7-.569-1.269-1.268-1.269Zm.8 6.564a.8.8 0 0 1-.8.801h-.34v.031l.004 2.371c0 .155-.05.233-.129.233s-.19-.079-.31-.235l-1.866-2.4H1.268a.8.8 0 0 1-.8-.8V8.064a.8.8 0 0 1 .8-.8h21.464a.8.8 0 0 1 .8.8v5.266ZM4.444 8.573c-.127 0-.225.041-.254.15l-.877 3.129-.883-3.128c-.03-.11-.127-.15-.254-.15-.202 0-.473.126-.473.311 0 .012.005.035.011.058l1.114 3.63c.058.173.265.254.485.254s.433-.08.484-.254l1.109-3.63c.005-.023.011-.04.011-.058 0-.179-.27-.312-.473-.312Zm2.925 2.36c.433-.132.757-.49.757-1.153 0-.918-.612-1.207-1.368-1.207H5.614a.234.234 0 0 0-.242.231v3.752c0 .156.184.237.374.237s.376-.081.376-.237V11.05h.484l.82 1.593c.058.115.156.179.26.179.219 0 .467-.203.467-.393a.155.155 0 0 0-.028-.092l-.756-1.403Zm-.61-.473h-.636V9.231h.635c.375 0 .618.162.618.618s-.242.612-.618.612Zm10.056.826h1.004l-.502-1.772-.502 1.772Zm4.684-3.095H9.366a.8.8 0 0 0-.8.8v3.383a.8.8 0 0 0 .8.8h12.132a.8.8 0 0 0 .8-.8V8.992a.8.8 0 0 0-.8-.801Zm-10.946 3.977c.525 0 .571-.374.589-.617.011-.179.173-.236.369-.236.26 0 .38.075.38.369 0 .698-.57 1.142-1.379 1.142-.727 0-1.327-.357-1.327-1.322v-1.61c0-.963.606-1.322 1.333-1.322.802 0 1.374.427 1.374 1.097 0 .3-.121.37-.375.37-.214 0-.37-.064-.375-.238-.012-.178-.052-.57-.6-.57-.387 0-.606.213-.606.663v1.61c0 .45.219.664.617.664Zm4.703.388c0 .156-.19.237-.375.237s-.375-.081-.375-.237V10.9h-1.299v1.656c0 .156-.19.237-.375.237s-.375-.081-.375-.237V8.804c0-.161.185-.23.375-.23s.375.069.375.23v1.507h1.299V8.804c0-.161.185-.23.375-.23s.375.069.375.23v3.752Zm3.198.236c-.127 0-.225-.04-.254-.15l-.22-.768h-1.322l-.219.768c-.029.11-.127.15-.254.15-.202 0-.473-.127-.473-.311 0-.012.006-.035.012-.058l1.114-3.63c.051-.173.265-.254.478-.254s.433.08.485.254l1.114 3.63c.006.023.012.04.012.058 0 .179-.272.311-.473.311Zm2.989-3.543h-.843v3.306c0 .156-.19.237-.375.237s-.375-.081-.375-.237V9.25h-.848c-.15 0-.237-.157-.237-.34 0-.162.075-.336.237-.336h2.44c.162 0 .238.173.238.335 0 .18-.087.34-.237.34Z"/></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View file

@ -1,6 +1,7 @@
---
import { events } from "@/lib/events";
import AboutRow from "@/components/AboutRow.astro";
import DDay from "./DDay.astro";
const sortedEvents = [...events].sort((a, b) => b.date.localeCompare(a.date));
const years = [...new Set(sortedEvents.map((event) => event.date.slice(0, 4)))];
@ -38,6 +39,26 @@ const daysUntilYearEnd = Math.ceil(
안녕하세요, 정보보안과 소프트웨어 엔지니어링을 주로하고 있는
암냥입니다.
</p>
<div class="flex flex-row mt-4 gap-1">
<b>생일 : </b><DDay targetDate="2010-11-08T03:00:00+09:00" />
</div>
<a href="#contact" class="flex flex-row items-center underline">
<span>연락하기</span>
<svg
aria-hidden="true"
class="h-4 text-foreground/40"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M7 17 17 7"></path>
<path d="M7 7h10v10"></path>
</svg>
</a>
<br />
<p>저는...</p>
<section class="mt-[0.75em]">
<div class="mt-[0.5em] flex flex-col gap-[0.34em]">
@ -87,20 +108,40 @@ const daysUntilYearEnd = Math.ceil(
</AboutRow>
</div>
</section>
<p></p>
<div class="flex flex-row">
<a
href="#experience"
class="flex flex-row items-center underline"
><span>등등...</span>
<svg
aria-hidden="true"
class="h-4 text-foreground/40"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M7 17 17 7"></path>
<path d="M7 7h10v10"></path>
</svg></a
>
<p>을 이루어냈어요.</p>
</div>
</div>
<div
class="relative order-first h-[min(150vw,720px)] min-h-[600px] overflow-hidden lg:sticky lg:top-0 lg:order-none lg:h-[calc(100svh-64px)] lg:min-h-0 lg:self-start"
aria-label="활동 사진"
>
<img
<!-- <img
class="absolute inset-0 h-full w-full select-none pointer-events-none object-contain"
src="/side.avif"
alt="활동 사진 콜라주"
width="3840"
height="4320"
/>
/> -->
</div>
</div>
</section>

View file

@ -0,0 +1,583 @@
---
// biome-ignore lint/correctness/noUnusedVariables: Used in the Astro template below.
const groups = [
{
id: "direct",
title: "연락처",
items: [
{
name: "개인 이메일",
value: "me@imnya.ng",
href: "mailto:me@imnya.ng",
icon: "mail",
tone: "pink",
email: true,
},
{
name: "dazzle.st 이메일",
value: "imnyang@dazzle.st",
href: "mailto:imnyang@dazzle.st",
icon: "mail",
tone: "green",
email: true,
},
{
name: "Discord",
value: "@imnyang",
href: "https://discord.com/users/909353223901569035",
icon: "discord",
tone: "purple",
},
],
},
{
id: "social",
title: "소셜",
items: [
{
name: "X (Twitter)",
value: "@imnya_ng",
href: "https://twitter.com/imnya_ng",
icon: "x",
tone: "blue",
},
{
name: "Instagram",
value: "@imnya.ng",
href: "https://instagram.com/imnya.ng",
icon: "instagram",
tone: "pink",
},
{
name: "YouTube",
value: "@imnyang",
href: "https://youtube.com/@imnyang",
icon: "youtube",
tone: "red",
},
],
},
{
id: "work",
title: "코드와 글",
items: [
{
name: "GitHub",
value: "@imnyang",
href: "https://github.com/imnyang",
icon: "github",
tone: "neutral",
},
{
name: "git.mizuki.guru",
value: "@imnyang",
href: "https://git.mizuki.guru/imnyang",
icon: "mizuki",
tone: "orange",
},
{
name: "Blog",
value: "blog.imnya.ng",
href: "https://blog.imnya.ng",
icon: "blog",
tone: "green",
},
],
},
{
id: "game",
title: "Game",
items: [
{
name: "Steam",
value: "@imnyang",
href: "https://steamcommunity.com/id/imnyang/",
icon: "steam",
tone: "blue",
},
{
name: "maimai",
value: "@imnya.ng",
href: "https://mai.sft.sh/imnyang",
icon: "maimai",
tone: "blue",
},
{
name: "Project Sekai KR",
value: "7354623251148069648",
href: "#",
icon: "project-sekai",
tone: "blue",
},
{
name: "Project Sekai JP",
value: "729310364018688008",
href: "#",
icon: "project-sekai",
tone: "blue",
},
{
name: "VRChat",
value: "@imnyang",
href: "https://vrchat.com/home/user/usr_d53ac697-182d-40d0-9fd8-1a7442b0ebfd",
icon: "vrchat",
tone: "blue",
},
],
},
];
// biome-ignore lint/correctness/noUnusedVariables: Used in the Astro template below.
const imageIcons: Record<string, { src: string; monochrome: boolean }> = {
github: { src: "/icon/github.svg", monochrome: true },
discord: { src: "/icon/discord.svg", monochrome: true },
mizuki: { src: "/icon/mizuki.svg", monochrome: false },
// Source: https://github.com/simple-icons/simple-icons/blob/develop/icons/steam.svg
steam: { src: "/icon/steam.svg", monochrome: true },
maimai: { src: "/icon/maimai.webp", monochrome: false },
vrchat: { src: "/icon/vrchat.svg", monochrome: true },
// Source: https://pjsekai.sega.jp/assets/data/webp/icon/icon_app.png.webp
"project-sekai": { src: "/icon/project-sekai.webp", monochrome: false },
};
// biome-ignore lint/correctness/noUnusedVariables: Used in the Astro template below.
const paths: Record<string, string> = {
mail: "M22 12a10 10 0 1 0-4 8 M16 8v5a3 3 0 0 0 6 0v-1 M16 12a4 4 0 1 1-8 0 4 4 0 0 1 8 0",
x: "M4 3h4l12 18h-4L4 3Z M20 3l-7 8 M4 21l7-8",
instagram:
"M7 3h10a4 4 0 0 1 4 4v10a4 4 0 0 1-4 4H7a4 4 0 0 1-4-4V7a4 4 0 0 1 4-4Z M16 12a4 4 0 1 1-8 0 4 4 0 0 1 8 0 M17.5 6.5h.01",
youtube:
"M7 5h10a5 5 0 0 1 5 5v4a5 5 0 0 1-5 5H7a5 5 0 0 1-5-5v-4a5 5 0 0 1 5-5Z M10 9l5 3-5 3V9Z",
blog: "M5 3h11l3 3v15H5V3Z M15 3v4h4 M9 11h6 M9 15h6",
};
---
<section id="contact" class="contact-section" aria-labelledby="contact-title">
<div class="contact-content">
<header class="contact-heading">
<h2 id="contact-title">Contact<span aria-hidden="true">.</span></h2>
<p class="contact-description">
새로운 이야기와 재미있는 만남은 언제나 환영해요.
</p>
</header>
<div class="contact-groups">
{
groups.map((group) => (
<section aria-labelledby={`contact-${group.id}`}>
<h3
id={`contact-${group.id}`}
class="contact-group-title"
>
{group.title}
</h3>
<ul class="contact-list">
{group.items.map((item) => (
<li class="contact-row">
<a
class="contact-link"
href={item.href}
target={
"email" in item
? undefined
: "_blank"
}
rel={
"email" in item
? undefined
: "noopener noreferrer"
}
>
<span
class={`contact-icon tone-${item.tone}`}
aria-hidden="true"
>
{imageIcons[item.icon] ? (
<img
src={
imageIcons[item.icon]
.src
}
width="22"
height="22"
alt=""
class:list={{
"mono-icon":
imageIcons[
item.icon
].monochrome,
}}
/>
) : (
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.7"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d={paths[item.icon]}
/>
</svg>
)}
</span>
<span class="contact-name">
{item.name}
</span>
<span class="contact-value">
{item.value}
</span>
{!("email" in item) && (
<svg
class="contact-arrow"
aria-hidden="true"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M7 17 17 7M7 7h10v10" />
</svg>
)}
</a>
{"email" in item && (
<button
class="contact-copy"
type="button"
data-contact-email={item.value}
aria-label={`${item.value} 복사`}
title="이메일 주소 복사"
>
<svg
class="copy-symbol"
aria-hidden="true"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
>
<rect
x="8"
y="8"
width="12"
height="12"
rx="2"
/>
<path d="M16 8V4a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h4" />
</svg>
<svg
class="copied-symbol"
aria-hidden="true"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.8"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="m5 12 4 4L19 6" />
</svg>
</button>
)}
</li>
))}
</ul>
</section>
))
}
</div>
<div class="contact-footer">
<p>여기까지 와주셔서 고마워요.</p>
<a href="#home">맨 위로 <span aria-hidden="true">↑</span></a>
</div>
<p
class="contact-status"
role="status"
aria-live="polite"
aria-atomic="true"
>
</p>
</div>
</section>
<style>
.contact-section {
--contact-top-spacing: clamp(48px, 7vw, 88px);
min-height: 100%;
/* A viewport-spanning snap area permits free scrolling through the links. */
scroll-snap-align: start;
padding: var(--contact-top-spacing) clamp(24px, 5.208vw, 100px) 32px;
}
.contact-content {
max-width: 1080px;
margin-inline: auto;
}
.contact-heading {
display: flow-root;
/* Keep the snap target smaller than the viewport so entry stops at the title. */
scroll-snap-align: start;
scroll-snap-stop: always;
scroll-margin-top: var(--contact-top-spacing);
padding-bottom: 32px;
border-bottom: 1px solid var(--border);
}
.contact-eyebrow {
font-size: 11px;
font-weight: 700;
letter-spacing: 0.16em;
color: var(--muted-foreground);
}
h2 {
margin-top: 8px;
font-size: clamp(36px, 5vw, 52px);
font-weight: 750;
letter-spacing: -0.045em;
line-height: 1.15;
}
h2 span {
color: #dc6291;
}
.contact-description {
margin-top: 14px;
font-size: 14px;
color: color-mix(in srgb, var(--foreground) 65%, var(--background));
word-break: keep-all;
}
.contact-groups {
display: grid;
gap: 28px;
margin-top: 28px;
}
.contact-group-title {
margin-bottom: 12px;
font-size: 15px;
font-weight: 700;
}
.contact-list {
display: grid;
gap: 8px;
}
.contact-row {
display: flex;
min-width: 0;
border: 1px solid var(--border);
border-radius: 9px;
transition:
background-color 160ms,
border-color 160ms;
}
.contact-row:hover,
.contact-row:focus-within {
background: var(--muted);
border-color: color-mix(
in srgb,
var(--foreground) 22%,
var(--background)
);
}
.contact-link {
display: grid;
grid-template-columns: 22px auto minmax(0, 1fr) 18px;
gap: 12px;
align-items: center;
flex: 1;
min-width: 0;
min-height: 58px;
padding: 12px 18px;
border-radius: 8px;
text-decoration: none;
}
.contact-row:has(.contact-copy) .contact-link {
grid-template-columns: 22px auto minmax(0, 1fr);
padding-right: 0;
}
.contact-icon {
display: flex;
align-items: center;
justify-content: center;
}
.contact-icon svg,
.contact-icon img {
width: 21px;
height: 21px;
object-fit: contain;
}
.mono-icon {
filter: var(--mono-filter);
}
.tone-pink {
color: #ce5484;
}
.tone-green {
color: #46916c;
}
.tone-purple {
color: #8279e2;
}
.tone-blue {
color: #569fc9;
}
.tone-red {
color: #d96570;
}
.tone-orange {
color: #c58055;
}
.contact-name {
font-size: 14px;
font-weight: 650;
}
.contact-value {
text-align: right;
font-size: 14px;
color: color-mix(in srgb, var(--foreground) 65%, var(--background));
overflow-wrap: anywhere;
}
.contact-arrow {
width: 18px;
height: 18px;
color: var(--muted-foreground);
transition:
transform 160ms,
color 160ms;
}
.contact-link:hover .contact-arrow {
transform: translate(2px, -2px);
color: var(--foreground);
}
.contact-copy {
display: grid;
place-items: center;
align-self: center;
width: 44px;
height: 44px;
margin: 0 5px;
flex-shrink: 0;
border-radius: 6px;
color: var(--muted-foreground);
cursor: pointer;
}
.contact-copy:hover {
color: var(--foreground);
background: color-mix(in srgb, var(--foreground) 7%, transparent);
}
.contact-copy svg {
width: 17px;
height: 17px;
}
.copied-symbol,
.contact-copy[data-copied] .copy-symbol {
display: none;
}
.contact-copy[data-copied] .copied-symbol {
display: block;
color: #46916c;
}
.contact-link:focus-visible,
.contact-copy:focus-visible,
.contact-footer a:focus-visible {
outline: 2px solid var(--ring);
outline-offset: 3px;
}
.contact-footer {
display: flex;
justify-content: space-between;
gap: 16px;
margin-top: 40px;
padding-top: 20px;
border-top: 1px solid var(--border);
font-size: 12px;
color: var(--muted-foreground);
}
.contact-footer a {
flex-shrink: 0;
border-radius: 2px;
}
.contact-footer a:hover {
color: var(--foreground);
}
.contact-footer span {
margin-left: 8px;
}
.contact-status {
min-height: 20px;
margin-top: 12px;
font-size: 12px;
color: var(--foreground);
text-align: right;
}
@media (max-width: 540px) {
.contact-link,
.contact-row:has(.contact-copy) .contact-link {
grid-template-columns: 22px minmax(0, 1fr) 18px;
gap: 4px 12px;
padding: 14px;
}
.contact-row:has(.contact-copy) .contact-link {
grid-template-columns: 22px minmax(0, 1fr);
padding-right: 0;
}
.contact-icon {
grid-row: 1 / 3;
}
.contact-name {
grid-column: 2;
font-size: 13px;
}
.contact-value {
grid-column: 2;
grid-row: 2;
text-align: left;
font-size: 12px;
}
.contact-arrow {
grid-column: 3;
grid-row: 1 / 3;
}
}
@media (prefers-reduced-motion: reduce) {
.contact-row,
.contact-arrow {
transition: none;
}
.contact-link:hover .contact-arrow {
transform: none;
}
}
</style>
<script>
const contactStatus =
document.querySelector<HTMLElement>(".contact-status");
document
.querySelectorAll<HTMLButtonElement>("[data-contact-email]")
.forEach((button) => {
let resetTimer: ReturnType<typeof setTimeout>;
button.addEventListener("click", async () => {
const email = button.dataset.contactEmail;
if (!email) return;
try {
await navigator.clipboard.writeText(email);
clearTimeout(resetTimer);
button.dataset.copied = "true";
button.setAttribute("aria-label", `${email} 복사 완료`);
if (contactStatus)
contactStatus.textContent = `${email} 주소를 복사했어요.`;
resetTimer = setTimeout(() => {
delete button.dataset.copied;
button.setAttribute("aria-label", `${email} 복사`);
}, 2000);
} catch {
if (contactStatus)
contactStatus.textContent =
"복사하지 못했어요. 이메일 주소를 직접 선택해 복사해주세요.";
}
});
});
</script>

View file

@ -1,15 +1,19 @@
---
export interface Props {
targetDate: string;
label: string;
label?: string;
}
const { targetDate, label } = Astro.props;
---
<div class="flex flex-col items-end text-right text-sm">
<div class="flex flex-row items-start text-left text-base gap-2">
<span class="text-foreground"
>{label && `${label} | `}{
new Date(targetDate).toLocaleDateString()
}</span
>
<span id="dday-label">D-Day</span>
<span class="text-muted-foreground">{label} | {new Date(targetDate).toDateString()}</span>
</div>
<script define:vars={{ targetDate }}>
@ -22,6 +26,6 @@ const { targetDate, label } = Astro.props;
if (diffDays > 0) label = `D-${diffDays}`;
else if (diffDays < 0) label = `D+${Math.abs(diffDays)}`;
const el = document.getElementById('dday-label');
const el = document.getElementById("dday-label");
if (el) el.textContent = label;
</script>

View file

@ -125,12 +125,12 @@ const roles = ["Broadcast Manager", "ARG Creator", "Developer"];
<button
class="group relative block h-full w-full cursor-pointer border-0 bg-transparent p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-[-5px] focus-visible:outline-[#ff92ad]"
type="button"
aria-label="EPC Finale 결승 방송을 2시간 19분 26초부터 재생"
aria-label="EPC Finale 후기 영상 재생"
>
<img
class="block h-full w-full object-cover"
src="/projects/epc-finale-broadcast.avif"
alt="EPC Finale의 두 선수 경기 화면과 실시간 판정을 보여주는 방송 화면"
src="/projects/epc-finale.avif"
alt="썸네일"
width="655"
height="387"
loading="lazy"
@ -142,11 +142,8 @@ const roles = ["Broadcast Manager", "ARG Creator", "Developer"];
>
<span
class="absolute inset-x-0 bottom-0 flex justify-between gap-2 bg-gradient-to-b from-transparent to-[#000c] px-4 pt-[30px] pb-3 text-left text-[clamp(10px,1vw,14px)] font-semibold"
>Finale 결승 방송 <span
class="font-normal opacity-80"
>02:19:26부터 재생</span
></span
>
>후기 영상
</span>
</button>
</div>
<img
@ -206,9 +203,8 @@ const roles = ["Broadcast Manager", "ARG Creator", "Developer"];
if (!videoFrame) return;
const player = document.createElement("iframe");
player.src =
"https://www.youtube-nocookie.com/embed/5HDW7u3xt6Y?start=8366&autoplay=1&playsinline=1";
player.title =
"EPC Finale Playing Section Tournament Finals — 2:19:26부터 재생";
"https://www.youtube-nocookie.com/embed/3NY8vgxvKaU?autoplay=1&playsinline=1";
player.title = "EPC : Finale 방송화면에 이런 비밀이???";
player.allow =
"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share";
player.allowFullscreen = true;

View file

@ -24,20 +24,19 @@ const daysUntilYearEnd = Math.ceil(
---
<section
id="about"
id="experience"
data-node-id="4:104"
class="min-h-full snap-start snap-always bg-background text-foreground"
aria-labelledby="about-title"
aria-labelledby="experience-title"
>
<div class="grid min-h-full grid-cols-1 lg:grid-cols-2">
<div
class="relative z-10 px-6 py-12 sm:px-10 lg:px-[clamp(52px,5.208vw,100px)] lg:py-[clamp(58px,9.26vh,100px)]"
>
<div
id="experience"
class="max-w-[654px] break-keep text-[24px] leading-[1.2] tracking-[-0.02em] lg:leading-none"
>
<p id="about-title">
<p id="experience-title">
저는 <b>{years.length}년간 {events.length}개</b>의 개성있는
조각들을 모아왔어요.
</p>

View file

@ -1,6 +1,8 @@
---
import About from "@/components/About.astro";
import ContactSection from "@/components/ContactSection.astro";
import EPCProjects from "@/components/EPCProjects.astro";
import Experience from "@/components/Experience.astro";
import Header from "@/components/Header.astro";
import Hero from "@/components/Hero.astro";
import "@/globals.css";
@ -39,6 +41,8 @@ import "@/globals.css";
<Hero />
<About />
<EPCProjects />
<Experience />
<ContactSection />
</main>
</body>
</html>