diff --git a/app/pages/[slug]/page.tsx b/app/pages/[slug]/page.tsx index cdf8c45..acb73d7 100644 --- a/app/pages/[slug]/page.tsx +++ b/app/pages/[slug]/page.tsx @@ -10,6 +10,7 @@ import { PostLayout } from '@/components/post-layout'; import { ScrollReveal } from '@/components/scroll-reveal'; import { SectionDivider } from '@/components/section-divider'; import { JsonLd } from '@/components/json-ld'; +import { DevEnvDeviceHero } from '@/components/dev-env-device-hero'; export function generateStaticParams() { const params = allPages.map((page) => ({ @@ -115,18 +116,22 @@ export default async function StaticPage({ params }: Props) { data-toc-content={slug} className="prose prose-lg prose-slate mx-auto max-w-none dark:prose-invert" > - {page.feature_image && ( -
- {page.title} -
+ {slug === 'dev-env' ? ( + + ) : ( + page.feature_image && ( +
+ {page.title} +
+ ) )}
diff --git a/components/dev-env-device-hero.tsx b/components/dev-env-device-hero.tsx new file mode 100644 index 0000000..09eb48f --- /dev/null +++ b/components/dev-env-device-hero.tsx @@ -0,0 +1,97 @@ +'use client'; + +import { SiArchlinux, SiUbuntu, SiLinux } from 'react-icons/si'; + +/** + * Mac mini + 螢幕 3D 裝置展示 + * 使用純 CSS 3D transforms,取代開發工作環境頁的 feature_image + */ +export function DevEnvDeviceHero() { + return ( +
+
+ {/* Monitor */} +
+ {/* Bezel */} +
+ {/* Screen */} +
+ {/* macOS Desktop mockup */} +
+ {/* macOS Menu bar - 半透明毛玻璃 */} +
+ {'\uF8FF'} + Terminal + + + + + + 14:30 + +
+ {/* Window - Terminal 顯示 Arch / Ubuntu / Tux 三個 Logo */} +
+
+ + + +
+
+
+ $ neofetch --ascii_distro arch,ubuntu,tux +
+
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+
+ {/* Monitor stand */} +
+
+ + {/* Desk surface - Mac mini 與鍵盤均勻放置 */} +
+ {/* 鍵盤 - Magic Keyboard 風格,鍵帽網格 */} +
+
+
+ {[14, 14, 13, 12].map((keyCount, row) => ( +
+ {Array.from({ length: keyCount }).map((_, col) => ( +
+ ))} +
+ ))} +
+
+
+
+
+
+ {/* Mac mini M4 2024 - 頂視,避免 3D 偽影 */} +
+
+ {'\uF8FF'} +
+
+
+
+
+ ); +} diff --git a/styles/globals.css b/styles/globals.css index b09d785..bad9d3d 100644 --- a/styles/globals.css +++ b/styles/globals.css @@ -56,6 +56,460 @@ 100% { transform: translate3d(0,0,0) scale(1); } } +/* Dev env device hero - Mac mini + 螢幕 3D mockup */ +@keyframes device-float { + 0% { transform: perspective(800px) rotateY(-4deg) rotateX(2deg) translate3d(0, 0, 0); } + 50% { transform: perspective(800px) rotateY(-4deg) rotateX(2deg) translate3d(0, -8px, 0); } + 100% { transform: perspective(800px) rotateY(-4deg) rotateX(2deg) translate3d(0, 0, 0); } +} + +@media (prefers-reduced-motion: reduce) { + .dev-env-device-hero .dev-env-device-scene { + animation: none; + } +} + +.dev-env-device-hero { + min-height: 320px; +} + +.dev-env-device-scene { + display: flex; + flex-direction: column; + align-items: center; + perspective: 800px; + transform-style: preserve-3d; + animation: device-float 8s ease-in-out infinite; +} + +.dev-env-monitor { + position: relative; + width: min(340px, 88vw); + padding-bottom: 75%; /* 4:3 較高,讓 terminal 內容完整顯示 */ + transform-style: preserve-3d; +} + +.dev-env-monitor + .dev-env-desk { + margin-top: 40px; +} + +.dev-env-bezel { + position: absolute; + inset: 0; + background: linear-gradient(145deg, #2d2d2d 0%, #1a1a1a 100%); + border-radius: 12px; + padding: 8px; + box-shadow: + 0 25px 50px -12px rgba(0, 0, 0, 0.4), + 0 0 0 1px rgba(255, 255, 255, 0.05) inset, + -2px -2px 8px rgba(0, 0, 0, 0.3); +} + +.dark .dev-env-bezel { + background: linear-gradient(145deg, #1a1a1a 0%, #0d0d0d 100%); +} + +.dev-env-screen { + position: absolute; + inset: 8px; + border-radius: 6px; + overflow: hidden; + background: linear-gradient(165deg, #e8ecf0 0%, #dde2e8 50%, #e2e6ec 100%); + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.4) inset; +} + +.dark .dev-env-screen { + background: linear-gradient(165deg, #1a1d21 0%, #15181c 50%, #1c1f24 100%); +} + +/* macOS desktop mockup */ +.dev-env-desktop { + position: absolute; + inset: 0; + display: flex; + flex-direction: column; +} + +/* macOS Menu bar - 毛玻璃效果 */ +.dev-env-menubar { + display: flex; + align-items: center; + gap: 10px; + height: 26px; + padding: 0 14px; + background: rgba(255, 255, 255, 0.72); + backdrop-filter: blur(20px) saturate(180%); + -webkit-backdrop-filter: blur(20px) saturate(180%); + border-bottom: 1px solid rgba(0, 0, 0, 0.08); + font-size: 13px; + font-weight: 500; + color: rgba(0, 0, 0, 0.88); +} + +.dark .dev-env-menubar { + background: rgba(50, 50, 50, 0.72); + border-bottom-color: rgba(255, 255, 255, 0.06); + color: rgba(255, 255, 255, 0.9); +} + +.dev-env-apple { + font-size: 17px; + font-weight: 400; + margin-right: 6px; + font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", sans-serif; +} + +.dev-env-app-name { + opacity: 0.95; +} + +.dev-env-spacer { + flex: 1; +} + +.dev-env-menubar-right { + display: flex; + align-items: center; + gap: 14px; +} + +.dev-env-menubar-icon { + width: 16px; + height: 16px; + border-radius: 50%; + background: rgba(0, 0, 0, 0.25); +} + +.dark .dev-env-menubar-icon { + background: rgba(255, 255, 255, 0.2); +} + +.dev-env-time { + font-size: 12px; + opacity: 0.9; +} + +.dev-env-window { + flex: 1; + min-height: 80px; + margin: 12px 16px; + background: rgba(255, 255, 255, 0.98); + border-radius: 10px; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12); + overflow: hidden; + border: 1px solid rgba(0, 0, 0, 0.06); + display: flex; + flex-direction: column; +} + +.dark .dev-env-window { + background: rgba(30, 30, 30, 0.98); + border-color: rgba(255, 255, 255, 0.06); +} + +/* macOS 紅黃綠三色按鈕 */ +.dev-env-window-titlebar { + display: flex; + align-items: center; + gap: 8px; + height: 32px; + padding: 0 12px; + background: rgba(0, 0, 0, 0.04); + border-bottom: 1px solid rgba(0, 0, 0, 0.06); +} + +.dark .dev-env-window-titlebar { + background: rgba(255, 255, 255, 0.03); + border-bottom-color: rgba(255, 255, 255, 0.06); +} + +.dev-env-traffic-light { + width: 12px; + height: 12px; + border-radius: 50%; + flex-shrink: 0; +} + +.dev-env-traffic-red { + background: #ff5f57; + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1); +} + +.dev-env-traffic-yellow { + background: #febc2e; + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1); +} + +.dev-env-traffic-green { + background: #28c840; + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1); +} + +.dev-env-window-content { + padding: 10px 14px; + font-family: ui-monospace, "SF Mono", "Monaco", "Consolas", monospace; + font-size: 9px; + line-height: 1.2; + overflow: visible; + flex: 1; + min-height: 52px; + display: flex; + flex-direction: column; +} + +.dev-env-terminal-prompt { + margin-bottom: 8px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + flex-shrink: 0; +} + +.dev-env-terminal-logos { + display: flex; + gap: 12px; + justify-content: center; + align-items: center; + flex-wrap: wrap; + flex: 1 0 auto; + min-height: 36px; + padding: 4px 0; +} + +.dev-env-logo-svg { + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; +} + +.dev-env-logo-svg svg { + flex-shrink: 0; + display: block; +} + +.dev-env-svg-arch { + color: #1793d1; +} + +.dark .dev-env-svg-arch { + color: #38bdf8; +} + +.dev-env-svg-ubuntu { + color: #e95420; +} + +.dark .dev-env-svg-ubuntu { + color: #f97316; +} + +.dev-env-svg-tux { + color: #334155; +} + +.dark .dev-env-svg-tux { + color: #cbd5e1; +} + +.dev-env-terminal-line { + height: 8px; + margin-bottom: 6px; + background: rgba(0, 0, 0, 0.08); + border-radius: 2px; +} + +.dev-env-terminal-line.short { + width: 60%; +} + +.dark .dev-env-terminal-line { + background: rgba(255, 255, 255, 0.05); +} + +.dev-env-prompt { + color: #22c55e; +} + +.dark .dev-env-prompt { + color: #4ade80; +} + +.dev-env-stand { + position: absolute; + bottom: -12px; + left: 50%; + transform: translateX(-50%); + width: 60px; + height: 24px; + background: linear-gradient(180deg, #8a8a8a 0%, #6e6e6e 100%); + border-radius: 12px 12px 0 0; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15); +} + +.dark .dev-env-stand { + background: linear-gradient(180deg, #2d2d2d 0%, #1a1a1a 100%); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); +} + +.dev-env-desk { + position: relative; + width: min(360px, 90vw); + height: 56px; + margin: 0 auto; + padding: 0 12px; + display: flex; + align-items: flex-end; + justify-content: space-evenly; + gap: 12px; + background: linear-gradient(180deg, #b8b8b8 0%, #9a9a9a 50%, #888888 100%); + border-radius: 4px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12); +} + +.dark .dev-env-desk { + background: linear-gradient(180deg, #3d3d3d 0%, #2a2a2a 100%); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); +} + +/* 鍵盤 - Magic Keyboard 風格,鍵帽網格 */ +.dev-env-keyboard { + width: 110px; + height: 36px; + display: flex; + align-items: flex-end; + justify-content: center; +} + +.dev-env-keyboard-body { + width: 100%; + padding: 4px 6px; + background: linear-gradient( + 180deg, + #e8e8ed 0%, + #d1d1d6 25%, + #c8c8cd 60%, + #b8b8bd 100% + ); + border-radius: 6px; + box-shadow: + 0 2px 8px rgba(0, 0, 0, 0.2), + inset 0 1px 0 rgba(255, 255, 255, 0.6); +} + +.dark .dev-env-keyboard-body { + background: linear-gradient( + 180deg, + #4a4a4f 0%, + #3d3d42 40%, + #2d2d32 100% + ); + box-shadow: + 0 2px 8px rgba(0, 0, 0, 0.4), + inset 0 1px 0 rgba(255, 255, 255, 0.06); +} + +.dev-env-keyboard-keys { + display: flex; + flex-direction: column; + gap: 2px; +} + +.dev-env-keyboard-row { + display: flex; + justify-content: center; + gap: 1px; +} + +.dev-env-keyboard-row:nth-child(2) { padding-left: 4px; } +.dev-env-keyboard-row:nth-child(3) { padding-left: 8px; } +.dev-env-keyboard-row:nth-child(4) { padding-left: 12px; } +.dev-env-keyboard-row:nth-child(5) { padding-left: 20px; } + +.dev-env-keyboard-row-space { + padding-left: 24px !important; +} + +.dev-env-key-space { + width: 36px; +} + +.dev-env-key { + width: 5px; + height: 4px; + background: linear-gradient( + 180deg, + rgba(255, 255, 255, 0.9) 0%, + rgba(0, 0, 0, 0.08) 100% + ); + border-radius: 1px; + flex-shrink: 0; +} + +.dark .dev-env-key { + background: linear-gradient( + 180deg, + rgba(255, 255, 255, 0.08) 0%, + rgba(0, 0, 0, 0.4) 100% + ); +} + +/* Mac mini - 頂視,無 3D 旋轉,避免偽影 */ +.dev-env-macmini { + display: flex; + align-items: flex-end; + justify-content: center; + height: 44px; +} + +.dev-env-macmini-top { + width: 64px; + height: 64px; + display: flex; + align-items: center; + justify-content: center; + background: linear-gradient( + 145deg, + #eaeaf0 0%, + #d4d4d9 25%, + #c4c4c9 55%, + #b4b4b9 85%, + #a8a8ad 100% + ); + border-radius: 14px; + box-shadow: + 0 4px 12px rgba(0, 0, 0, 0.15), + inset 0 2px 4px rgba(255, 255, 255, 0.6), + inset 0 -1px 2px rgba(0, 0, 0, 0.06); +} + +.dark .dev-env-macmini-top { + background: linear-gradient( + 145deg, + #7a7a7f 0%, + #5e5e63 25%, + #4e4e53 55%, + #3e3e43 85%, + #323237 100% + ); + box-shadow: + 0 4px 12px rgba(0, 0, 0, 0.35), + inset 0 2px 4px rgba(255, 255, 255, 0.08), + inset 0 -1px 2px rgba(0, 0, 0, 0.3); +} + +.dev-env-macmini-apple { + font-size: 24px; + font-weight: 400; + color: rgba(0, 0, 0, 0.5); + font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", sans-serif; +} + +.dark .dev-env-macmini-apple { + color: rgba(255, 255, 255, 0.4); +} + + @keyframes mastodon-shimmer { 0% { background-position: -200% 0; } 100% { background-position: 200% 0; }