Enhance styling and functionality: add scrollbar styles, update iframe source, adjust project section width, implement MagicalGirl toggle, and create ASCII art HTML page.

This commit is contained in:
암냥 2025-11-20 00:02:08 +09:00
commit deca6506a9
No known key found for this signature in database
8 changed files with 178 additions and 22 deletions

99
public/ascii-art.html Normal file
View file

@ -0,0 +1,99 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<meta name="theme-color" content="#0C0C0C">
<meta name="date" content="2025-10-21T13:11:07.098Z">
<link href="https://fonts.cdnfonts.com/css/cascadia-code" rel="stylesheet">
<title>imnyang</title>
<style>
:root {
--color-primary-light: #FFD7D7;
--color-secondary-light: #EEEEEE;
--color-tertiary-light: #FFFFFF;
--color-quaternary-light: #E4E4E4;
--color-quinary-light: #DADADA;
--color-senary-light: #D7D7D7;
--color-septenary-light: #D0D0D0;
--color-text: #fcf8f9;
--background: #191017;
}
@media (prefers-color-scheme: light) {
:root {
--color-primary-light: #FFD7D7;
--color-secondary-light: #EEEEEE;
--color-tertiary-light: #FFFFFF;
--color-quaternary-light: #E4E4E4;
--color-quinary-light: #DADADA;
--color-senary-light: #D7D7D7;
--color-septenary-light: #D0D0D0;
--color-text: #fcf8f9;
--background: #191017;
}
}
* {
font-variant-ligatures: none;
font-feature-settings: 'liga' 0, 'clig' 0;
}
html, body {
background: var(--background);
color: var(--color-text);
margin: 0;
}
pre {
font-family: 'Cascadia Code', sans-serif;
font-size: 6pt;
line-height: 1.2;
margin: 0px 0;
}
</style>
</head>
<body><pre><span style="color: var(--color-primary-light);"> @@@@@@@@ @@@@@@@@@
@@ @@ @@@ @@
@@ @@@ @ @@ @@
@@ @@ @@ @ @@ @@ @@
@@ @@ @ @@ @@ @@ @
@ @@@ @ @@ @@@ @ @
@@ @@ @ @ @@ @@ @@
@@ @@ @ @@ @@ @@
@ @@ @ @@@@@ @@ @@
@ @@ @@@@ @@ @@ @@@@@@ @@
@ @@ @@@ @@@ @@ @@
@@ @@@ @ @@@ @ @@ @@ @@
@@@ @@@@@ @@@@ @@@ @@ @@ @@@@ @@
@@ @ @@ @@@@@ @@@ @ @
@@ @@@@ @ @ @
@@ @@ @ @ @ @@ @@
@@ @@ @ @ @@ @@ @@
@@ @@@@@ @ @ @@ @
@ @@@ @ @@ @ @@ @
@@ @@@ @ @ @ @@ @@ @
@@@ @@ @@ @@ @@
@@ @ @ @ @ @
@ @ @ @ @@
@@ @@ @ @@ @ @
@ @@@@@@ @@@ @@ @ @@
@ @ @ @@ @ @@ @@ @ @@ @@
@@@ @ @ @@@@@@ @ @ @@
@ @ @ @ @@@ @@ @@@@ @@
@@ @@@@@@@@@@@@@ @@@@ @@@ @@ @@@@@ @
@@ @ @ @ @@@ @@@@@@@@@@@ @ @@ @
@@ @ @ @ @@ @ @ @@@@ @@ @@
@@ @@ @ @@ @ @ @@ @@ @@ @@
@@ @ @@ @@@ @ @@ @ @@@@@ @@ @@
@@ @@ @@@ @ @@ @@@ @@ @
@@ @ @@@ @@ @ @@
@ @ @@@ @ @ @@
@ @@ @ @ @
@@ @@ @ @ @@
@ @@ @@ @@@@@@@@
@@ @@ @@@@@@@@@@@@@@@@@@@ @@@@@@@@
@@ @@@@ @@@@@ @@@ @ @@
@@@ @ @@@@ @ @ @@@ @@
@@@ @@ @@@ @ @@ @ @@@@@@@@@@@@@@@ @@
@@ @@ @@@ @ @@ @ @@@@@@ @@
</span></pre></body>
</html>

View file

@ -48,6 +48,9 @@
--sidebar-accent-foreground: hsl(240 5.9% 10%);
--sidebar-border: hsl(340 20% 90%);
--sidebar-ring: hsl(217.2 91.2% 59.8%);
--scrollbar: hsla(340 10% 60% / 0.5);
--scrollbar-hover: hsla(340 10% 60% / 0.8);
}
.dark {
@ -84,6 +87,9 @@
--sidebar-border: hsl(296, 18%, 15%);
--sidebar-ring: hsl(217.2 91.2% 59.8%);
--sidebar: hsl(240 5.9% 10%);
--scrollbar: hsla(340 10% 60% / 0.5);
--scrollbar-hover: hsla(340 10% 60% / 0.8);
}
@theme inline {

View file

@ -4,13 +4,13 @@
}
::-webkit-scrollbar-thumb {
background: var(--muted-foreground);
background: var(--scrollbar);
border: 5px solid var(--background);
border-radius: 16px;
}
::-webkit-scrollbar-thumb:hover {
background: var(--foreground);
background: var(--scrollbar-hover);
}
/* ::-webkit-scrollbar:not(.highlighttable, .highlight table, .gist .highlight) {

View file

@ -11,7 +11,7 @@ export default function NeoFetch() {
<div className="w-full bg-[#191017] text-[#fcf8f9] font-[Google Sans Code] rounded-b-4xl">
<div className="flex flex-col md:flex-row">
<iframe
src="/art.html"
src="/ascii-art.html"
className="border-0 min-w-[430px] min-h-[430px] scale-75"
></iframe>
<div className="px-12 md:py-12 text-lg">

View file

@ -22,7 +22,7 @@ const projects = [
export default function Projects() {
return (
<section className="break-keep break-words w-full md:w-1/2">
<section className="break-keep break-words w-full lg:w-1/2">
<div className="space-y-8">
{projects.map((project, idx) => (
<div className="space-y-2" key={idx}>

View file

@ -78,7 +78,14 @@ export default function SUPERCOMMAND() {
</DialogDescription>
<DialogFooter className="px-6 py-6 sm:justify-start fixed bottom-0 left-0 w-full bg-background/80 backdrop-blur-sm">
<Button type="button" onClick={() => {
document.cookie = "MagicalGirl=true; path=/";
const existingCookie = document.cookie.split('; ').find(row => row.startsWith('MagicalGirl='));
if (existingCookie) {
document.cookie = "MagicalGirl=; path=/; expires=Thu, 01 Jan 1970 00:00:00 UTC";
window.location.reload();
} else {
document.cookie = "MagicalGirl=true; path=/; expires=Fri, 31 Dec 9999 23:59:59 GMT";
window.location.reload();
}
setShowDialog(false);
}}>Okay</Button>
</DialogFooter>

View file

@ -1,14 +1,21 @@
"use client";
import Sidebar from "@/components/sidebar";
import Image from "next/image";
import { useEffect, useRef, useState } from "react";
import Sidebar from "@/components/sidebar";
import { useIsMobile } from "@/hooks/use-mobile";
export default function Top() {
const containerRef = useRef<HTMLDivElement>(null);
const [randomBg, setRandomBg] = useState(1);
const isMobile = useIsMobile();
const [clickCount, setClickCount] = useState(0);
const clickTimeoutRef = useRef<NodeJS.Timeout | null>(null);
const [isMagicalGirlEnabled, setIsMagicalGirlEnabled] = useState(false);
const REQUIRED_CLICKS = 6;
useEffect(() => {
setRandomBg(Math.floor(Math.random() * 14) + 1);
setIsMagicalGirlEnabled(document.cookie.includes('MagicalGirl=true'));
}, []);
const requestPermission = async () => {
@ -18,8 +25,8 @@ export default function Top() {
window.addEventListener("deviceorientation", handleDeviceOrientation);
try {
const res = await (DeviceOrientationEvent as any).requestPermission();
if (res === "granted") {
const permission = await (DeviceOrientationEvent as unknown as { requestPermission: () => Promise<string> }).requestPermission();
if (permission === "granted") {
window.addEventListener("devicemotion", handleDeviceMotion);
window.addEventListener("deviceorientation", handleDeviceOrientation);
}
@ -51,6 +58,36 @@ export default function Top() {
bg.style.backgroundPosition = `${50 - x * 3}% ${50 - y * 3}%`;
};
const handleBackgroundTouchClick = () => {
if (!isMobile) return;
setClickCount((prev) => {
const newCount = prev + 1;
// Clear existing timeout
if (clickTimeoutRef.current) {
clearTimeout(clickTimeoutRef.current);
}
// Check if required clicks reached
if (newCount >= REQUIRED_CLICKS) {
const newValue = !isMagicalGirlEnabled;
setIsMagicalGirlEnabled(newValue);
document.cookie = `MagicalGirl=${newValue}; path=/; max-age=${60 * 60 * 24 * 365}`;
window.location.reload();
return 0;
}
// Reset click count after 1 second if not enough clicks
clickTimeoutRef.current = setTimeout(() => {
setClickCount(0);
}, 1000);
return newCount;
});
};
useEffect(() => {
return () => {
window.removeEventListener("deviceorientation", handleDeviceOrientation);
@ -62,10 +99,10 @@ export default function Top() {
<section
id="top"
className="snap-start h-screen w-full relative"
// onWheel={(e) => {
// e.preventDefault();
// window.scrollBy(0, window.innerHeight * (e.deltaY > 0 ? 1 : -1));
// }}
// onWheel={(e) => {
// e.preventDefault();
// window.scrollBy(0, window.innerHeight * (e.deltaY > 0 ? 1 : -1));
// }}
>
<Sidebar />
<div
@ -74,6 +111,10 @@ export default function Top() {
style={{
backgroundImage: `url('/background/${randomBg}.avif')`,
}}
role="button"
tabIndex={0}
aria-label="Toggle MagicalGirl mode on mobile"
onClick={handleBackgroundTouchClick}
onMouseMove={(e) => {
const { clientX, clientY } = e;
const { innerWidth, innerHeight } = window;
@ -90,15 +131,17 @@ export default function Top() {
}
}}
>
{/* <Image
src={"/char.avif"}
alt="character"
width={4096}
height={4096}
className="w-[50vh] lg:w-[30vw] translate-y-[10%] transition-transform duration-100 ease-out"
unoptimized
onClick={requestPermission}
/> */} {/* 이제 그런 애는 없어 */}
{isMagicalGirlEnabled && (
<Image
src={"/char.avif"}
alt="character"
width={4740}
height={7584}
className="w-[50vh] lg:w-[30vw] translate-y-[10%] transition-transform duration-100 ease-out"
unoptimized
onClick={requestPermission}
/>
)}
</div>
</section>
);

View file

@ -25,7 +25,7 @@ export default function TimelineComponent() {
return (
<div
id="timeline"
className="w-full md:w-1/2 flex flex-col items-center justify-center px-12 mt-8"
className="w-full lg:w-1/2 flex flex-col items-center justify-center px-12 mt-8"
>
<div className="w-full">
<h1 className="text-2xl font-bold mb-4 w-full">🌠 </h1>
@ -36,6 +36,7 @@ export default function TimelineComponent() {
{years.map((year) => (
<button
key={year}
type="button"
onClick={() => setSelectedYear(year)}
className={`px-4 py-2 rounded-lg font-semibold transition-all text-sm ${
selectedYear === year