parent
0d5c3f88a8
commit
bcd4fa87b2
11 changed files with 679 additions and 34 deletions
|
|
@ -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>
|
||||
|
|
|
|||
583
src/components/ContactSection.astro
Normal file
583
src/components/ContactSection.astro
Normal 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>
|
||||
|
|
@ -1,27 +1,31 @@
|
|||
---
|
||||
export interface Props {
|
||||
targetDate: string;
|
||||
label: string;
|
||||
targetDate: string;
|
||||
label?: string;
|
||||
}
|
||||
|
||||
const { targetDate, label } = Astro.props;
|
||||
---
|
||||
|
||||
<div class="flex flex-col items-end text-right text-sm">
|
||||
<span id="dday-label">D-Day</span>
|
||||
<span class="text-muted-foreground">{label} | {new Date(targetDate).toDateString()}</span>
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<script define:vars={{ targetDate }}>
|
||||
const today = new Date();
|
||||
const target = new Date(targetDate);
|
||||
const diffTime = target.getTime() - today.getTime();
|
||||
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
|
||||
|
||||
let label = "D-Day";
|
||||
if (diffDays > 0) label = `D-${diffDays}`;
|
||||
else if (diffDays < 0) label = `D+${Math.abs(diffDays)}`;
|
||||
|
||||
const el = document.getElementById('dday-label');
|
||||
if (el) el.textContent = label;
|
||||
const today = new Date();
|
||||
const target = new Date(targetDate);
|
||||
const diffTime = target.getTime() - today.getTime();
|
||||
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
|
||||
|
||||
let label = "D-Day";
|
||||
if (diffDays > 0) label = `D-${diffDays}`;
|
||||
else if (diffDays < 0) label = `D+${Math.abs(diffDays)}`;
|
||||
|
||||
const el = document.getElementById("dday-label");
|
||||
if (el) el.textContent = label;
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Reference in a new issue