想搞个写真站

Noontwo 2026-09-20 11:19 1

效果大概这样的,但是总觉得会有些臃肿,个人收藏倒还行?




<!DOCTYPE html>
<html lang="zh-CN" class="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>LUMINA - 电影级人像写真画廊与贝叶斯美学评分体系</title>

<!-- Tailwind CSS & FontAwesome CDN -->
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">

<!-- Google Fonts: Inter & Noto Serif SC -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=Noto+Serif+SC:wght@400;600;700;900&display=swap" rel="stylesheet">

<script>
tailwind.config = {
darkMode: 'class',
theme: {
extend: {
fontFamily: {
sans: ['Inter', '-apple-system', 'BlinkMacSystemFont', 'sans-serif'],
serif: ['"Noto Serif SC"', 'serif'],
},
colors: {
noir: {
950: '#06070A',
900: '#0C0E15',
850: '#11141F',
800: '#171B2A',
750: '#1E2336',
700: '#272E44'
},
accent: {
gold: '#F59E0B',
amber: '#D97706',
rose: '#F43F5E',
cyan: '#06B6D4',
violet: '#8B5CF6'
}
},
boxShadow: {
'glow-gold': '0 0 30px -5px rgba(245, 158, 11, 0.28)',
'glow-rose': '0 0 30px -5px rgba(244, 63, 94, 0.28)',
'glow-cyan': '0 0 30px -5px rgba(6, 182, 212, 0.28)',
'glass': '0 8px 32px 0 rgba(0, 0, 0, 0.55)'
}
}
}
}
</script>

<style>
/* Custom scrollbars */
::-webkit-scrollbar {
width: 6px;
height: 6px;
}
::-webkit-scrollbar-track {
background: #08090E;
}
::-webkit-scrollbar-thumb {
background: #252B3E;
border-radius: 9999px;
}
::-webkit-scrollbar-thumb:hover {
background: #3B4461;
}

/* Glassmorphism primitives */
.glass-nav {
background: rgba(12, 14, 21, 0.78);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-bottom: 1px solid rgba(255, 255, 255, 0.07);
}
.glass-panel {
background: rgba(17, 20, 31, 0.75);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
border: 1px solid rgba(255, 255, 255, 0.08);
}
.glass-card {
background: rgba(14, 17, 26, 0.85);
backdrop-filter: blur(12px);
border: 1px solid rgba(255, 255, 255, 0.06);
transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}
.glass-card:hover {
border-color: rgba(245, 158, 11, 0.4);
transform: translateY(-5px);
box-shadow: 0 16px 36px -8px rgba(0, 0, 0, 0.7), 0 0 24px -6px rgba(245, 158, 11, 0.2);
}

/* Multi-column Pinterest-like masonry layout */
.masonry-container {
column-count: 1;
column-gap: 1.5rem;
}
@media (min-width: 640px) {
.masonry-container { column-count: 2; }
}
@media (min-width: 1024px) {
.masonry-container { column-count: 3; }
}
@media (min-width: 1440px) {
.masonry-container { column-count: 4; }
}
.masonry-brick {
break-inside: avoid;
margin-bottom: 1.5rem;
}

/* Gradient typography */
.text-gold-gradient {
background: linear-gradient(135deg, #FDE68A 0%, #F59E0B 50%, #D97706 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.text-rose-gradient {
background: linear-gradient(135deg, #FECDD3 0%, #F43F5E 50%, #BE123C 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
</style>
</head>

<body class="bg-noir-950 text-slate-100 font-sans min-h-screen selection:bg-amber-500/30 selection:text-amber-200 antialiased overflow-x-hidden">

<!-- Top Sticky Navigation Bar -->
<header class="sticky top-0 z-40 w-full glass-nav transition-all duration-300">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 h-18 flex items-center justify-between gap-4 py-3">

<!-- Brand Logo -->
<div class="flex items-center gap-7">
<a href="#" class="flex items-center gap-3.5 group">
<div class="w-10 h-10 rounded-xl bg-gradient-to-tr from-amber-600 via-rose-500 to-amber-300 flex items-center justify-center shadow-glow-gold group-hover:scale-105 transition-transform duration-300">
<i class="fa-solid fa-camera-retro text-noir-950 text-lg"></i>
</div>
<div>
<span class="text-xl font-bold tracking-wider font-serif text-gold-gradient">LUMINA</span>
<span class="block text-[10px] tracking-widest text-slate-400 uppercase -mt-1 font-mono">PORTRAIT VAULT</span>
</div>
</a>

<!-- Main Categories (Desktop) -->
<nav class="hidden lg:flex items-center gap-1.5 text-xs font-semibold text-slate-300">
<button onclick="setGlobalCategory('全部')" id="cat-nav-all" class="cat-link px-3 py-1.5 rounded-lg text-amber-400 bg-amber-500/10 transition">
全库探索
</button>
<button onclick="setGlobalCategory('胶片写真')" id="cat-nav-film" class="cat-link px-3 py-1.5 rounded-lg hover:text-white hover:bg-white/5 transition">
🎞️ 胶片写真
</button>
<button onclick="setGlobalCategory('商业棚拍')" id="cat-nav-studio" class="cat-link px-3 py-1.5 rounded-lg hover:text-white hover:bg-white/5 transition">
👠 商业棚拍
</button>
<button onclick="setGlobalCategory('情绪胶片')" id="cat-nav-moody" class="cat-link px-3 py-1.5 rounded-lg hover:text-white hover:bg-white/5 transition">
🏮 情绪胶片
</button>
<button onclick="setGlobalCategory('手机人像')" id="cat-nav-mobile" class="cat-link px-3 py-1.5 rounded-lg hover:text-white hover:bg-white/5 transition">
📱 手机人像
</button>
<button onclick="setGlobalCategory('AI写真')" id="cat-nav-ai" class="cat-link px-3 py-1.5 rounded-lg hover:text-white hover:bg-white/5 transition">
✨ AI写真
</button>
</nav>
</div>

<!-- Search Box with instant filtering -->
<div class="flex-1 max-w-md mx-2 hidden md:block">
<div class="relative group">
<i class="fa-solid fa-magnifying-glass absolute left-3.5 top-1/2 -translate-y-1/2 text-slate-400 group-focus-within:text-amber-400 transition text-xs"></i>
<input
type="text"
id="searchInput"
placeholder="搜索写真主题、相机镜头、胶卷型号、模特艺名..."
class="w-full bg-noir-900 text-xs text-slate-200 placeholder-slate-500 pl-9 pr-9 py-2.5 rounded-xl border border-white/10 focus:border-amber-500/60 focus:outline-none focus:ring-2 focus:ring-amber-500/20 transition shadow-inner"
oninput="handleSearchInput(this.value)"
>
<button onclick="clearSearchInput()" id="searchClearBtn" class="hidden absolute right-3 top-1/2 -translate-y-1/2 text-slate-500 hover:text-slate-300 text-xs">
<i class="fa-solid fa-circle-xmark"></i>
</button>
</div>
</div>

<!-- User Actions & Favorites Drawer Trigger -->
<div class="flex items-center gap-3">
<!-- Bookmark Collection Trigger -->
<button
onclick="toggleFavoritesDrawer()"
title="我的私享收藏夹"
class="relative p-2.5 rounded-xl bg-white/5 hover:bg-white/10 border border-white/5 text-slate-300 hover:text-rose-400 transition">
<i class="fa-regular fa-bookmark"></i>
<span id="favCountBadge" class="absolute -top-1 -right-1 w-4 h-4 bg-rose-500 text-white text-[10px] font-bold rounded-full flex items-center justify-center">2</span>
</button>

<!-- Quick Algorithm Modal Helper -->
<button
onclick="showAlgorithmExplainToast()"
title="查看贝叶斯平滑算法说明"
class="hidden sm:inline-flex items-center gap-1.5 px-3 py-2 rounded-xl bg-noir-900 hover:bg-noir-850 border border-white/10 text-xs text-amber-400 hover:text-amber-300 transition">
<i class="fa-solid fa-calculator"></i>
<span class="font-mono">Bayes S</span>
</button>

<!-- User Profile Avatar -->
<div class="flex items-center pl-2 border-l border-white/10">
<div class="w-9 h-9 rounded-xl overflow-hidden border border-amber-500/40 cursor-pointer hover:ring-2 hover:ring-amber-400/50 transition" onclick="showToast('当前登录身份:特邀评审委员 (Level 4 · 权重加成 2.5x)')">
<img src="https://images.unsplash.com/photo-1534528741775-53994a69daeb?auto=format&fit=crop&w=140&q=80" alt="Reviewer Avatar" class="w-full h-full object-cover">
</div>
</div>
</div>

</div>

<!-- Category Mobile Bar -->
<div class="lg:hidden max-w-7xl mx-auto px-4 py-2 flex items-center gap-2 overflow-x-auto text-xs no-scrollbar border-t border-white/[0.04]">
<button onclick="setGlobalCategory('全部')" class="cat-pill-mobile active px-3 py-1 rounded-full bg-amber-500 text-noir-950 font-bold whitespace-nowrap">全部</button>
<button onclick="setGlobalCategory('胶片写真')" class="cat-pill-mobile px-3 py-1 rounded-full bg-noir-900 text-slate-300 border border-white/10 whitespace-nowrap">胶片写真</button>
<button onclick="setGlobalCategory('商业棚拍')" class="cat-pill-mobile px-3 py-1 rounded-full bg-noir-900 text-slate-300 border border-white/10 whitespace-nowrap">商业棚拍</button>
<button onclick="setGlobalCategory('情绪胶片')" class="cat-pill-mobile px-3 py-1 rounded-full bg-noir-900 text-slate-300 border border-white/10 whitespace-nowrap">情绪胶片</button>
<button onclick="setGlobalCategory('手机人像')" class="cat-pill-mobile px-3 py-1 rounded-full bg-noir-900 text-slate-300 border border-white/10 whitespace-nowrap">手机人像</button>
<button onclick="setGlobalCategory('AI写真')" class="cat-pill-mobile px-3 py-1 rounded-full bg-noir-900 text-slate-300 border border-white/10 whitespace-nowrap">AI写真</button>
</div>
</header>

<!-- Hero Section & Refined Multi-tier Filter Dock -->
<section class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pt-7 pb-4">

<!-- Hero Header -->
<div class="flex flex-col md:flex-row md:items-end justify-between gap-5 pb-6 border-b border-white/5">
<div>
<div class="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-amber-500/10 border border-amber-500/20 text-amber-400 text-xs font-semibold mb-2.5">
<span class="w-2 h-2 rounded-full bg-amber-400 animate-pulse"></span>
双层贝叶斯平滑算法 (Bayesian Score Weighted) · 解耦表现力体系
</div>
<h1 class="text-2xl sm:text-3xl lg:text-4xl font-extrabold font-serif tracking-tight text-white">
严选光影与情绪的 <span class="text-gold-gradient">沉浸式人像写真画廊</span>
</h1>
<p class="text-slate-400 text-xs sm:text-sm mt-1.5 max-w-3xl leading-relaxed">
倡导健康的美学鉴赏:将<span class="text-amber-300 font-medium">作品艺术质量</span>与<span class="text-rose-300 font-medium">模特出镜表现力档案</span>完全解耦,提供自适应五重元数据面板(数码、胶片、布光、手机、AI),杜绝外貌低质恶评。
</p>
</div>

<!-- Algorithmic Stats Pill -->
<div class="flex items-center gap-4 text-xs text-slate-400 bg-noir-900/80 p-3.5 rounded-2xl border border-white/10 shrink-0">
<div>
<span class="block text-base font-extrabold text-slate-100 font-mono">1,940</span>
<span>已核验写真</span>
</div>
<div class="w-px h-8 bg-white/10"></div>
<div>
<span class="block text-base font-extrabold text-amber-400 font-mono">C=50 · m=8.5</span>
<span>贝叶斯置信先验</span>
</div>
<div class="w-px h-8 bg-white/10"></div>
<div>
<span class="block text-base font-extrabold text-emerald-400 font-mono">100%</span>
<span>肖像协议公示</span>
</div>
</div>
</div>

<!-- Filter Control Dock -->
<div class="pt-5 space-y-4">

<!-- Primary Row: Sort & Meta Type Filter -->
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-3 text-xs">

<!-- Meta Type Quick Switcher -->
<div class="flex items-center gap-2 overflow-x-auto pb-1 no-scrollbar">
<span class="text-slate-400 font-medium whitespace-nowrap">元数据模式:</span>
<button onclick="setMetaTypeFilter('all')" class="meta-type-btn active px-3 py-1.5 rounded-xl bg-amber-500 text-noir-950 font-bold transition whitespace-nowrap">全部模式</button>
<button onclick="setMetaTypeFilter('digital')" class="meta-type-btn px-3 py-1.5 rounded-xl bg-noir-900 text-slate-300 border border-white/5 hover:bg-white/10 transition whitespace-nowrap">📷 数码相机EXIF</button>
<button onclick="setMetaTypeFilter('film')" class="meta-type-btn px-3 py-1.5 rounded-xl bg-noir-900 text-slate-300 border border-white/5 hover:bg-white/10 transition whitespace-nowrap">🎞️ 胶片冲扫参数</button>
<button onclick="setMetaTypeFilter('bts')" class="meta-type-btn px-3 py-1.5 rounded-xl bg-noir-900 text-slate-300 border border-white/5 hover:bg-white/10 transition whitespace-nowrap">💡 影棚布光BTS</button>
<button onclick="setMetaTypeFilter('mobile')" class="meta-type-btn px-3 py-1.5 rounded-xl bg-noir-900 text-slate-300 border border-white/5 hover:bg-white/10 transition whitespace-nowrap">📱 移动计算摄影</button>
<button onclick="setMetaTypeFilter('ai')" class="meta-type-btn px-3 py-1.5 rounded-xl bg-noir-900 text-slate-300 border border-white/5 hover:bg-white/10 transition whitespace-nowrap">✨ AI生图参数</button>
</div>

<!-- Sorting Selector -->
<div class="flex items-center gap-2 self-end sm:self-auto">
<div class="flex items-center gap-1.5 bg-noir-900 px-3 py-1.5 rounded-xl border border-white/10 text-slate-300">
<span class="text-slate-400"><i class="fa-solid fa-arrow-down-wide-short text-[11px]"></i> 排序:</span>
<select id="sortSelect" onchange="handleSortChange(this.value)" class="bg-transparent text-slate-200 focus:outline-none cursor-pointer font-medium">
<option value="bayesian" class="bg-noir-900">贝叶斯最高分榜 (平滑权重)</option>
<option value="presence" class="bg-noir-900">模特出镜表现力榜 (神态高分)</option>
<option value="trending" class="bg-noir-900">24小时互动飙升</option>
<option value="newest" class="bg-noir-900">最新收录归档</option>
</select>
</div>
</div>
</div>

<!-- Secondary Row: Dominant Tone Swatches & Count Display -->
<div class="flex items-center justify-between gap-4 text-xs pt-1 border-t border-white/[0.04]">
<div class="flex items-center gap-2 overflow-x-auto no-scrollbar py-1">
<span class="text-slate-400 font-medium whitespace-nowrap">色相倾向:</span>
<button onclick="setColorFilter('all')" class="px-2.5 py-1 rounded-lg bg-white/10 text-slate-200 border border-white/10 hover:bg-white/20 transition">全色谱</button>
<button onclick="setColorFilter('#E11D48')" class="w-6 h-6 rounded-full bg-[#E11D48] border border-white/20 hover:scale-110 transition shadow" title="港风绯红"></button>
<button onclick="setColorFilter('#D97706')" class="w-6 h-6 rounded-full bg-[#D97706] border border-white/20 hover:scale-110 transition shadow" title="暖金黄昏"></button>
<button onclick="setColorFilter('#0891B2')" class="w-6 h-6 rounded-full bg-[#0891B2] border border-white/20 hover:scale-110 transition shadow" title="青蓝冷夜"></button>
<button onclick="setColorFilter('#16A34A')" class="w-6 h-6 rounded-full bg-[#16A34A] border border-white/20 hover:scale-110 transition shadow" title="森系柔绿"></button>
<button onclick="setColorFilter('#2A2D34')" class="w-6 h-6 rounded-full bg-[#2A2D34] border border-white/20 hover:scale-110 transition shadow" title="极简黑白"></button>
<button onclick="setColorFilter('#8B5CF6')" class="w-6 h-6 rounded-full bg-[#8B5CF6] border border-white/20 hover:scale-110 transition shadow" title="赛博紫光"></button>
</div>

<div class="text-slate-400 hidden sm:block">
呈现 <span id="itemCountDisplay" class="text-slate-100 font-semibold font-mono">0</span> 件写真杰作
</div>
</div>

</div>
</section>

<!-- Main Masonry Photo Gallery Grid -->
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
<div id="masonryGallery" class="masonry-container">
<!-- Injected via JavaScript -->
</div>

<!-- Empty State -->
<div id="emptyGalleryNotice" class="hidden text-center py-24">
<div class="w-16 h-16 rounded-2xl bg-noir-900 border border-white/10 text-slate-500 flex items-center justify-center mx-auto mb-4 text-2xl shadow-inner">
<i class="fa-solid fa-camera-rotate"></i>
</div>
<h3 class="text-lg font-bold text-slate-200 font-serif">未检索到符合条件的人像写真</h3>
<p class="text-xs text-slate-500 mt-1.5 max-w-sm mx-auto">请尝试重置筛选维度、切换元数据模式或清空搜索关键词。</p>
<button onclick="resetAllFilters()" class="mt-4 px-4 py-2 rounded-xl bg-amber-500/10 hover:bg-amber-500/20 text-amber-400 text-xs font-semibold border border-amber-500/20 transition">
重置所有筛选
</button>
</div>
</main>

<!-- Refactored Detail Lightbox Modal -->
<div id="photoDetailModal" class="fixed inset-0 z-50 hidden flex items-center justify-center p-2 sm:p-4 md:p-6 bg-black/92 backdrop-blur-2xl transition-opacity duration-300 opacity-0 pointer-events-none">

<!-- Modal Frame Container -->
<div id="modalDialogBox" class="relative w-full max-w-6xl max-h-[94vh] bg-noir-900 border border-white/10 rounded-2xl sm:rounded-3xl shadow-2xl overflow-hidden flex flex-col lg:flex-row transform scale-95 transition-all duration-300">

<!-- Top-right Close Button -->
<button onclick="closeDetailLightbox()" class="absolute top-4 right-4 z-30 w-10 h-10 rounded-full bg-black/70 hover:bg-black border border-white/20 text-slate-300 hover:text-white flex items-center justify-center transition shadow-lg">
<i class="fa-solid fa-xmark text-lg"></i>
</button>

<!-- ================= LEFT COLUMN: Visual Presentation ================= -->
<div class="lg:w-[56%] xl:w-[60%] bg-noir-950 flex flex-col justify-between relative group select-none min-h-[380px] lg:min-h-[660px] overflow-hidden">

<!-- Floating Meta Type Badges -->
<div class="absolute top-4 left-4 z-20 flex items-center gap-2">
<span id="modalMetaTypePill" class="px-3 py-1 rounded-full bg-black/70 backdrop-blur-md text-amber-300 text-xs font-semibold border border-amber-500/30 flex items-center gap-1.5">
<i class="fa-solid fa-camera"></i> 数码原画
</span>
<span id="modalAspectPill" class="px-2.5 py-1 rounded-full bg-black/70 backdrop-blur-md text-slate-300 text-xs border border-white/10">
3:4 竖构图
</span>
</div>

<!-- High-Res Photo Display Area -->
<div class="flex-1 flex items-center justify-center p-4 sm:p-8 relative overflow-hidden">
<img
id="modalPhotoImage"
src=""
alt="Lumina Portrait"
class="max-h-[66vh] w-auto max-w-full object-contain rounded-xl shadow-2xl transition-transform duration-300 cursor-zoom-in"
onclick="toggleImageZoom()"
>
</div>

<!-- Bottom Image Toolbar: Palette & Co-credits -->
<div class="px-6 py-4 bg-gradient-to-t from-black/90 via-black/50 to-transparent border-t border-white/5 space-y-2.5">
<!-- Dominant Color Swatches with HEX click-to-copy -->
<div class="flex items-center justify-between text-xs">
<span class="text-slate-400 font-medium flex items-center gap-1.5">
<i class="fa-solid fa-palette text-amber-400"></i> 主色调光谱 (点击复制HEX):
</span>
<div id="modalPaletteRow" class="flex items-center gap-1.5">
<!-- Swatches generated here -->
</div>
</div>

<!-- Photographer & Studio Attribution -->
<div class="flex items-center justify-between text-xs text-slate-400 pt-1">
<div class="flex items-center gap-2">
<img id="modalPhotographerAvatar" src="" class="w-6 h-6 rounded-full object-cover border border-white/20">
<span>摄影师: <strong id="modalPhotographerName" class="text-slate-200 font-medium">--</strong></span>
<span id="modalPhotographerBadge" class="text-[10px] px-1.5 py-0.5 rounded bg-amber-500/20 text-amber-300 border border-amber-500/30">PGC</span>
</div>
<button onclick="toggleImageZoom()" class="text-slate-400 hover:text-white flex items-center gap-1">
<i class="fa-solid fa-expand"></i> <span id="zoomLabelText">缩放原图</span>
</button>
</div>
</div>

</div>

<!-- ================= RIGHT COLUMN: Decoupled Model, Adaptive Meta & Scoring ================= -->
<div class="lg:w-[44%] xl:w-[40%] flex flex-col bg-noir-900 border-t lg:border-t-0 lg:border-l border-white/10 overflow-y-auto p-6 sm:p-7 space-y-5">

<!-- 1. Work Title & Model Release Status -->
<div>
<div class="flex items-center justify-between gap-3">
<h2 id="modalWorkTitle" class="text-xl sm:text-2xl font-serif font-bold text-white tracking-tight leading-snug">
写真作品标题
</h2>
<button id="modalBookmarkBtn" onclick="handleModalBookmarkToggle()" class="p-2.5 rounded-xl border border-white/10 bg-white/5 hover:bg-rose-500/20 text-slate-300 hover:text-rose-400 transition shrink-0" title="收藏至私享画板">
<i class="fa-regular fa-bookmark"></i>
</button>
</div>
<!-- Model Release Certification Badge -->
<div class="mt-2 flex items-center gap-2">
<span id="modalReleaseBadge" class="inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-md text-[11px] font-semibold bg-emerald-500/10 text-emerald-400 border border-emerald-500/20">
<i class="fa-solid fa-shield-check"></i> 已签署 Model Release 肖像权协议 (商用授权)
</span>
</div>
</div>

<!-- 2. Decoupled Model Profile Card (出镜模特档案卡 - 艺术表现力解耦) -->
<div class="p-4 rounded-2xl bg-noir-850 border border-white/10 space-y-3">
<div class="flex items-center justify-between">
<span class="text-[11px] font-bold text-slate-400 uppercase tracking-wider flex items-center gap-1.5">
<i class="fa-solid fa-user-tag text-rose-400"></i> 出镜模特合作档案 (Profile)
</span>
<span class="text-[10px] text-slate-400">解耦机制 · 非外貌打分</span>
</div>

<div class="flex items-center gap-3.5">
<img id="modelAvatar" src="" class="w-12 h-12 rounded-2xl object-cover border border-white/15 shadow-md">
<div class="flex-1 min-w-0">
<div class="flex items-center gap-2">
<h4 id="modelName" class="font-bold text-sm text-slate-100 truncate">模特艺名</h4>
<span class="text-[9px] px-1.5 py-0.2 rounded bg-rose-500/20 text-rose-300 border border-rose-500/30 font-semibold">认证模特</span>
</div>
<p id="modelBio" class="text-[11px] text-slate-400 truncate mt-0.5">擅长风格:情绪暗调、复古胶片、先锋高定</p>
</div>
<!-- Aggregated Presence Score -->
<div class="text-right pl-2 border-l border-white/10">
<div class="text-[10px] text-slate-400">生涯出镜表现力</div>
<div class="text-base font-extrabold text-rose-400 font-mono" id="modelAggregateScore">9.55</div>
<div class="text-[9px] text-slate-400" id="modelTotalShoots">28 组作品聚合</div>
</div>
</div>

<!-- Professional boundary notice -->
<div class="text-[10px] text-slate-400 bg-noir-900/80 px-2.5 py-1.5 rounded-lg border border-white/5 flex items-start gap-1.5">
<i class="fa-solid fa-circle-info text-slate-400 mt-0.5"></i>
<span>本平台表现力指数基于姿态神态、主题契合度与张力评分,严禁对创作者与模特做任何外貌及身材侮辱性评价。</span>
</div>
</div>

<!-- 3. Adaptive Contextual Metadata Panel (自适应元数据面板 - 5种专属形态 + 交互演示器) -->
<div class="rounded-2xl bg-noir-850 p-4 border border-white/10 space-y-3">
<div class="flex items-center justify-between">
<h4 class="text-xs font-bold uppercase tracking-wider text-slate-300 flex items-center gap-1.5">
<i class="fa-solid fa-sliders text-amber-400"></i> 自适应创作元数据 (Contextual Meta)
</h4>
<span id="currentMetaTypeName" class="text-[10px] text-amber-400 font-mono font-semibold">📷 数码相机EXIF</span>
</div>

<!-- Quick interactive demonstrator tabs to switch styles in real time -->
<div class="flex items-center gap-1 bg-noir-900 p-1 rounded-xl border border-white/5 text-[10px] overflow-x-auto no-scrollbar">
<button onclick="switchModalMetaPreview('digital')" id="tab-meta-digital" class="meta-preview-tab active flex-1 py-1 px-2 rounded-lg font-medium text-amber-400 bg-white/10 whitespace-nowrap">数码EXIF</button>
<button onclick="switchModalMetaPreview('film')" id="tab-meta-film" class="meta-preview-tab flex-1 py-1 px-2 rounded-lg font-medium text-slate-400 hover:text-white whitespace-nowrap">胶片冲扫</button>
<button onclick="switchModalMetaPreview('bts')" id="tab-meta-bts" class="meta-preview-tab flex-1 py-1 px-2 rounded-lg font-medium text-slate-400 hover:text-white whitespace-nowrap">布光幕后</button>
<button onclick="switchModalMetaPreview('mobile')" id="tab-meta-mobile" class="meta-preview-tab flex-1 py-1 px-2 rounded-lg font-medium text-slate-400 hover:text-white whitespace-nowrap">手机计算</button>
<button onclick="switchModalMetaPreview('ai')" id="tab-meta-ai" class="meta-preview-tab flex-1 py-1 px-2 rounded-lg font-medium text-slate-400 hover:text-white whitespace-nowrap">AI参数</button>
</div>

<!-- Dynamic Panel Content Container -->
<div id="dynamicMetaPanelBody" class="text-xs">
<!-- Dynamic content injected by JavaScript based on active type -->
</div>
</div>

<!-- 4. Refactored Two-tier Bayesian Scoring System (双层贝叶斯表现力评分引擎) -->
<div class="rounded-2xl bg-noir-850 p-4 border border-white/10 space-y-4">

<!-- Bayesian Composite Header -->
<div class="flex items-start justify-between">
<div>
<div class="flex items-center gap-1.5">
<span class="text-xs text-slate-300 font-semibold">贝叶斯加权综合评分</span>
<span title="公式: S = (C*m + ∑w*r) / (C + ∑w)" class="cursor-help text-amber-400 text-[11px]">
<i class="fa-solid fa-circle-question"></i>
</span>
</div>
<div class="flex items-baseline gap-2 mt-1">
<span id="modalBayesianScoreText" class="text-3xl font-extrabold text-gold-gradient font-serif">9.45</span>
<span class="text-xs text-slate-500 font-mono">/ 10.0</span>
<span id="modalGradeBadge" class="text-[10px] font-bold px-2 py-0.5 rounded-full bg-amber-500/20 text-amber-300 border border-amber-500/30">
殿堂级写真
</span>
</div>
</div>
<div class="text-right">
<span class="text-[10px] text-slate-400 block font-mono" id="modalRawRatingText">样本均值: 9.60</span>
<span class="text-[11px] text-slate-300 font-medium" id="modalVotersCountText">基于 1,480 人加权鉴赏</span>
</div>
</div>

<!-- Ordinary User: Fast 1-10 Slider Rating -->
<div class="pt-3 border-t border-white/5">
<div class="flex items-center justify-between text-xs mb-1.5">
<span class="font-medium text-slate-200">鉴赏家即时评分 (1.0 - 10.0):</span>
<span id="quickSliderValue" class="font-bold text-amber-400 font-mono text-sm">9.0 分</span>
</div>
<div class="flex items-center gap-3">
<input
type="range"
id="casualRatingSlider"
min="1.0"
max="10.0"
step="0.1"
value="9.0"
class="flex-1 accent-amber-500 cursor-pointer h-1.5 bg-white/10 rounded-lg"
oninput="handleQuickSliderChange(this.value)"
>
<button
onclick="submitQuickRating()"
class="px-3.5 py-1.5 rounded-xl bg-amber-500 hover:bg-amber-400 text-noir-950 font-bold text-xs transition shadow-glow-gold active:scale-95 shrink-0">
提交评分
</button>
</div>
</div>

<!-- Professional 4-Axis Deep Review (Expandable Accordion) -->
<div class="pt-2 border-t border-white/5">
<button onclick="toggleProReviewDrawer()" class="w-full flex items-center justify-between text-xs font-semibold text-slate-300 hover:text-white py-1">
<span class="flex items-center gap-1.5 text-amber-300">
<i class="fa-solid fa-feather-pointed"></i> 展开专业四维细分评审 (带权重评审)
</span>
<i id="proDrawerIcon" class="fa-solid fa-chevron-down text-[10px] text-slate-400 transition-transform"></i>
</button>

<!-- 4-Axis Drawer Body -->
<div id="proDrawerContent" class="hidden pt-3 space-y-3">

<!-- 1. Composition -->
<div class="space-y-1 text-xs">
<div class="flex justify-between text-[11px]">
<span class="text-slate-300">1. 构图视角美感 (25%)</span>
<span id="proScoreComp" class="font-mono text-amber-300">9.4</span>
</div>
<input type="range" min="1" max="10" step="0.1" value="9.4" class="w-full accent-amber-500 h-1 bg-white/10 rounded" oninput="updateProAxis('comp', this.value)">
</div>

<!-- 2. Lighting & Shadow -->
<div class="space-y-1 text-xs">
<div class="flex justify-between text-[11px]">
<span class="text-slate-300">2. 用光质感与影调 (25%)</span>
<span id="proScoreLight" class="font-mono text-rose-300">9.6</span>
</div>
<input type="range" min="1" max="10" step="0.1" value="9.6" class="w-full accent-rose-500 h-1 bg-white/10 rounded" oninput="updateProAxis('light', this.value)">
</div>

<!-- 3. Color & Grading -->
<div class="space-y-1 text-xs">
<div class="flex justify-between text-[11px]">
<span class="text-slate-300">3. 色彩层次与质感 (25%)</span>
<span id="proScoreColor" class="font-mono text-cyan-300">9.3</span>
</div>
<input type="range" min="1" max="10" step="0.1" value="9.3" class="w-full accent-cyan-500 h-1 bg-white/10 rounded" oninput="updateProAxis('color', this.value)">
</div>

<!-- 4. Model Presence (Decoupled disclaimer) -->
<div class="space-y-1 text-xs">
<div class="flex justify-between text-[11px]">
<span class="text-slate-300 flex items-center gap-1">
4. 出镜表现张力与姿态 (25%)
<i class="fa-solid fa-circle-check text-rose-400 text-[10px]" title="评价神态与肢体艺术表现,严禁外貌评价"></i>
</span>
<span id="proScoreExp" class="font-mono text-purple-300">9.5</span>
</div>
<input type="range" min="1" max="10" step="0.1" value="9.5" class="w-full accent-purple-500 h-1 bg-white/10 rounded" oninput="updateProAxis('exp', this.value)">
<div class="text-[9px] text-slate-400 italic mt-0.5">
注:第 4 项评分将计入该模特档案的「生涯出镜表现力」加权聚合。
</div>
</div>

<button onclick="submitProFourAxisRating()" class="w-full mt-2 py-2 rounded-xl bg-gradient-to-r from-amber-500 via-rose-500 to-amber-600 text-noir-950 font-bold text-xs shadow-glow-gold hover:opacity-90 transition">
提交四维专家级评审 (2.5x 置信加权)
</button>
</div>
</div>

</div>

<!-- 5. Download & Archival Licensing Actions -->
<div class="pt-2 border-t border-white/10 flex items-center gap-3">
<button
onclick="triggerDownloadAction('4k')"
class="flex-1 py-3 px-4 rounded-xl bg-gradient-to-r from-amber-500 to-amber-600 hover:from-amber-400 hover:to-amber-500 text-noir-950 font-bold text-xs sm:text-sm flex items-center justify-center gap-2 shadow-glow-gold transition active:scale-95">
<i class="fa-solid fa-arrow-down-to-line"></i>
<span>无损高清原图下载</span>
</button>
<button
onclick="triggerDownloadAction('wallpaper')"
class="py-3 px-3.5 rounded-xl bg-white/5 hover:bg-white/10 border border-white/10 text-slate-200 text-xs font-medium transition" title="下载手机 9:16 壁纸版">
<i class="fa-solid fa-mobile-screen"></i> 手机壁纸
</button>
</div>

</div>

</div>
</div>

<!-- Favorites Slide Drawer -->
<div id="favoritesSlideDrawer" class="fixed top-0 right-0 bottom-0 w-84 max-w-[85vw] bg-noir-900/98 backdrop-blur-2xl border-l border-white/10 z-50 p-6 transform translate-x-full transition-transform duration-300 flex flex-col justify-between shadow-2xl">
<div>
<div class="flex items-center justify-between pb-4 border-b border-white/10">
<h3 class="font-serif font-bold text-base flex items-center gap-2 text-white">
<i class="fa-solid fa-bookmark text-rose-500"></i> 私享写真收藏集
</h3>
<button onclick="toggleFavoritesDrawer()" class="text-slate-400 hover:text-white">
<i class="fa-solid fa-xmark"></i>
</button>
</div>
<div id="favoritesContainer" class="py-4 space-y-3 overflow-y-auto max-h-[72vh]">
<!-- Rendered dynamically -->
</div>
</div>
<button onclick="showToast('已复制收藏画板分享链接!')" class="w-full py-2.5 rounded-xl bg-white/10 hover:bg-white/20 text-xs font-semibold transition">
分享我的鉴赏画板
</button>
</div>

<!-- Global Toast Notification Element -->
<div id="appToast" class="fixed bottom-6 right-6 z-50 transform translate-y-16 opacity-0 pointer-events-none transition-all duration-300 flex items-center gap-3 px-4 py-3 rounded-2xl glass-panel shadow-2xl border border-white/15 text-slate-100 text-xs">
<div id="toastIconContainer" class="w-6 h-6 rounded-lg bg-amber-500/20 text-amber-400 flex items-center justify-center">
<i class="fa-solid fa-check"></i>
</div>
<span id="toastMessageText" class="font-medium">通知信息</span>
</div>

<script>
// 6 Typical High-Quality Portrait Data Scenarios
const PORTRAIT_DATABASE = [
{
id: 'lum-01',
title: '夜幕低语·霓虹雨夜下的迷离回眸',
category: '情绪胶片',
metaType: 'digital', // Digital Camera
photographer: {
name: '林深见鹿 (Vincent)',
avatar: 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?auto=format&fit=crop&w=120&q=80',
badge: 'PGC Pick'
},
model: {
name: '苏夏 (Xia)',
avatar: 'https://images.unsplash.com/photo-1524504388940-b1c1722653e1?auto=format&fit=crop&w=120&q=80',
bio: '擅长风格:情绪暗调、夜景霓虹、法式复古',
aggregateScore: 9.62,
shootsCount: 34
},
release: '已签署商业 Model Release 授权书',
aspect: '3:4 竖幅写真',
imgUrl: 'https://images.unsplash.com/photo-1509967419530-da38b4704bc6?auto=format&fit=crop&w=1000&q=80',
rawRating: 9.60,
votes: 1480,
scores: {
comp: 9.5,
light: 9.7,
color: 9.5,
exp: 9.7 // Subject Expression
},
toneHex: '#E11D48',
palette: ['#E11D48', '#0F172A', '#FBBF24', '#3B82F6', '#1E293B'],
views: 28400,
isFavorited: true,
// Detailed 5-type data
metaData: {
digital: {
camera: 'Sony α7R V',
lens: 'FE 85mm F1.4 GM II',
focalAperture: '85mm · f/1.4',
shutterIso: '1/320s · ISO 400'
},
film: {
filmStock: 'Kodak Portra 800 (135mm)',
formatProcess: '36张标准装 · C-41 冲洗工艺',
scannerLab: 'Fuji Frontier SP-3000 · 富士魔术手冲扫',
pushPull: '盒速拍摄 · 无增感'
},
bts: {
keyLight: '神牛 AD600 Pro + 90cm 抛物线柔光箱 (右侧 45°)',
fillLight: '街边霓虹牌作为自然环境轮廓光 + 银色反光板',
modifierPreset: '达芬奇 Cineon 柯达2383 胶片模拟LUT',
locationSetup: '重庆白象居连廊夜景 · 人工雾化水雾机'
},
mobile: {
device: 'iPhone 16 Pro Max 5x 潜望长焦',
sensor: '48MP 四合一融合镜头',
engine: '原生人像引擎 + 景深模拟 f/1.6',
toneProfile: '冷调高对比度摄影风格'
},
ai: {
baseModel: 'Flux.1 Dev 采样生成',
promptTokens: 'cinematic portrait, wet neon street, moody expression, 85mm bokeh, realistic skin texture',
params: 'Steps: 28 · CFG: 3.5 · Seed: 948102',
loraSpec: 'HongKong_Vintage_v2 (Weight 0.65)'
}
}
},
{
id: 'lum-02',
title: '银盐记忆·东京暮色与风衣衣角',
category: '胶片写真',
metaType: 'film', // Analog Film
photographer: {
name: '荒木哲 (Tetsu)',
avatar: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?auto=format&fit=crop&w=120&q=80',
badge: 'PRO'
},
model: {
name: '知念里奈 (Rina)',
avatar: 'https://images.unsplash.com/photo-1517841905240-472988babdf9?auto=format&fit=crop&w=120&q=80',
bio: '擅长风格:日系微风、生活纪实、极简胶片',
aggregateScore: 9.48,
shootsCount: 22
},
release: '已签署非商用艺术交流协议 (CC BY-NC)',
aspect: '3:2 胶片画幅',
imgUrl: 'https://images.unsplash.com/photo-1517841905240-472988babdf9?auto=format&fit=crop&w=1000&q=80',
rawRating: 9.45,
votes: 920,
scores: {
comp: 9.4,
light: 9.6,
color: 9.5,
exp: 9.3
},
toneHex: '#D97706',
palette: ['#D97706', '#FEF3C7', '#451A03', '#78350F', '#1F2937'],
views: 19800,
isFavorited: false,
metaData: {
digital: {
camera: 'Leica M11',
lens: 'Summilux-M 50mm f/1.4 ASPH',
focalAperture: '50mm · f/1.4',
shutterIso: '1/1000s · ISO 100'
},
film: {
filmStock: 'Kodak Portra 400 (120 中画幅)',
formatProcess: '6x7 比例底片 · 标准 C-41 冲洗',
scannerLab: 'Noritsu HS-1800 诺日士高清扫描',
pushPull: '曝光过曝 1 档拍摄 · 色彩细腻浓郁'
},
bts: {
keyLight: '自然黄昏逆光 (太阳落山前 30 分钟)',
fillLight: '白色泡沫反光板正面柔和漫反射',
modifierPreset: '富士胶片原色扫描直出 · 未过度数码干预',
locationSetup: '东京下北泽街角天桥'
},
mobile: {
device: 'Xiaomi 14 Ultra (徕卡光学)',
sensor: '1英寸 LYT-900 传感器',
engine: '徕卡生动人像画质风格',
toneProfile: '暖调胶片颗粒模拟'
},
ai: {
baseModel: 'Midjourney v6.1 PhotoReal',
promptTokens: 'analog 35mm film photography, natural golden hour, Japanese girl trench coat, soft grain',
params: 'Stylize: 250 · Aspect: 3:2 · Version: 6.1',
loraSpec: 'None (Pure MJ Core Prompting)'
}
}
},
{
id: 'lum-03',
title: '黑白雕塑·光与影的棱角分界',
category: '商业棚拍',
metaType: 'bts', // Studio Lighting BTS
photographer: {
name: 'Studio Nova',
avatar: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?auto=format&fit=crop&w=120&q=80',
badge: 'PGC Pick'
},
model: {
name: 'Elena Rostova',
avatar: 'https://images.unsplash.com/photo-1508214751196-bcfd4ca60f91?auto=format&fit=crop&w=120&q=80',
bio: '擅长风格:先锋高定、商业珠宝、雕塑感硬光',
aggregateScore: 9.75,
shootsCount: 48
},
release: '已签署商业 Model Release 肖像授权',
aspect: '3:4 竖构图',
imgUrl: 'https://images.unsplash.com/photo-1508214751196-bcfd4ca60f91?auto=format&fit=crop&w=1000&q=80',
rawRating: 9.72,
votes: 2180,
scores: {
comp: 9.8,
light: 9.9,
color: 9.2,
exp: 9.8
},
toneHex: '#2A2D34',
palette: ['#0A0A0B', '#27272A', '#52525B', '#A1A1AA', '#FAFAFA'],
views: 38200,
isFavorited: true,
metaData: {
digital: {
camera: 'Hasselblad H6D-100c',
lens: 'HC 100mm f/2.2',
focalAperture: '100mm · f/8.0',
shutterIso: '1/250s · ISO 64'
},
film: {
filmStock: 'Ilford HP5 Plus 400 黑白胶片',
formatProcess: '120 中画幅 · D-76 药水手工冲洗',
scannerLab: '哈苏 X5 虚拟滚筒扫描仪',
pushPull: '增感至 ISO 800 · 强化黑白反差'
},
bts: {
keyLight: '布朗 Broncolor 3200J + 美人碟 (Beauty Dish + 蜂巢网格)',
fillLight: '两侧黑色吸光板 (Negative Fill) 极度收窄下颌光比',
modifierPreset: 'Capture One 高对比度黑白灰阶曲线',
locationSetup: '上海西岸商业暗房影棚'
},
mobile: {
device: 'Vivo X100 Ultra 蔡司长焦',
sensor: '2亿像素潜望长焦传感器',
engine: '蔡司黑白人像色彩科学',
toneProfile: '经典高反差单色'
},
ai: {
baseModel: 'Flux.1 Dev High-Fashion Edition',
promptTokens: 'black and white studio portrait, high contrast beauty dish, intense gaze, sculpted jawline',
params: 'Steps: 35 · CFG: 4.0 · Seed: 492019',
loraSpec: 'MonochromeMaster_v1 (0.8)'
}
}
},
{
id: 'lum-04',
title: '微风温室·青绿日系柔光人像',
category: '手机人像',
metaType: 'mobile', // Mobile Optics
photographer: {
name: '浅野晴 (Haru)',
avatar: 'https://images.unsplash.com/photo-1492562080023-ab3db95bfbce?auto=format&fit=crop&w=120&q=80',
badge: 'UGC'
},
model: {
name: '温禾 (He)',
avatar: 'https://images.unsplash.com/photo-1529626455594-4ff0802cfb7e?auto=format&fit=crop&w=120&q=80',
bio: '擅长风格:森系自然光、清冷氧气感、胶片生活',
aggregateScore: 9.32,
shootsCount: 16
},
release: '已签署完整肖像权协议',
aspect: '3:4 竖幅写真',
imgUrl: 'https://images.unsplash.com/photo-1529626455594-4ff0802cfb7e?auto=format&fit=crop&w=1000&q=80',
rawRating: 9.22,
votes: 760,
scores: {
comp: 9.2,
light: 9.3,
color: 9.4,
exp: 9.1
},
toneHex: '#16A34A',
palette: ['#16A34A', '#FAF5EF', '#4ADE80', '#064E3B', '#D1FAE5'],
views: 14200,
isFavorited: false,
metaData: {
digital: {
camera: 'Fujifilm X-T5',
lens: 'XF 56mm F1.2 R WR',
focalAperture: '56mm · f/1.2',
shutterIso: '1/800s · ISO 160'
},
film: {
filmStock: 'Fujifilm Pro 400H 经典负片',
formatProcess: '135 胶卷 · 富士原厂药水精冲',
scannerLab: '富士 SP-3000 扫描 · 清新绿调',
pushPull: '标准曝光 · 偏向柔和低反差'
},
bts: {
keyLight: '温室漫反射自然散射光 (多云阴天环境)',
fillLight: '绿色植物边缘自然漫射光',
modifierPreset: 'Lightroom 日系低反差青绿预设',
locationSetup: '杭州植物园玻璃暖房'
},
mobile: {
device: 'iPhone 16 Pro Max 5x 潜望长焦 (120mm 等效)',
sensor: '4800万融合计算影像单元',
engine: '原生计算人像模式 · 模拟 f/1.8 景深虚化',
toneProfile: '摄影风格设置:色调 -25 / 暖色 -10 清透氧气感'
},
ai: {
baseModel: 'Midjourney v6.1 SoftLighting',
promptTokens: 'greenhouse portrait, soft ambient light, green foliage bokeh, relaxed posture',
params: 'Stylize: 150 · Seed: 284910',
loraSpec: 'None'
}
}
},
{
id: 'lum-05',
title: '虚实纪元·赛博霓光与数字仿生',
category: 'AI写真',
metaType: 'ai', // AI Generation
photographer: {
name: 'CyberMuse Lab',
avatar: 'https://images.unsplash.com/photo-1519085360753-af0119f7cbe7?auto=format&fit=crop&w=120&q=80',
badge: 'AI Creator'
},
model: {
name: 'Nova-07 (虚拟仿生数字人)',
avatar: 'https://images.unsplash.com/photo-1531746020798-e6953c6e8e04?auto=format&fit=crop&w=120&q=80',
bio: '擅长风格:赛博未来、数码超现实、机械古典主义',
aggregateScore: 9.38,
shootsCount: 52
},
release: 'AI 数字生成人像 · 无真人肖像权冲突',
aspect: '3:4 沉浸画幅',
imgUrl: 'https://images.unsplash.com/photo-1531746020798-e6953c6e8e04?auto=format&fit=crop&w=1000&q=80',
rawRating: 9.30,
votes: 840,
scores: {
comp: 9.4,
light: 9.6,
color: 9.5,
exp: 9.0
},
toneHex: '#8B5CF6',
palette: ['#8B5CF6', '#3B82F6', '#EC4899', '#0F172A', '#E0E7FF'],
views: 16800,
isFavorited: false,
metaData: {
digital: {
camera: 'Sony α1 全画幅旗舰',
lens: 'FE 50mm F1.2 GM',
focalAperture: '50mm · f/1.2',
shutterIso: '1/500s · ISO 200'
},
film: {
filmStock: 'Cinestill 800T 电影胶片',
formatProcess: 'ECN-2 电影工艺手工除碳水冲',
scannerLab: '哈苏柔光数码扫描',
pushPull: '高光红晕卤化银特效'
},
bts: {
keyLight: '青蓝色 LED 光棒作为面部主光 (45°)',
fillLight: '紫色 LED 泛光灯背部轮廓逆光',
modifierPreset: 'Cyberpunk 赛博霓虹双色调调色',
locationSetup: '虚拟 3D 摄影棚渲染模拟'
},
mobile: {
device: 'Samsung Galaxy S24 Ultra',
sensor: '200MP 超级传感器',
engine: '夜景人像 AI 计算多帧合成',
toneProfile: '超清数码锐化风格'
},
ai: {
baseModel: 'Flux.1 Dev 旗舰底模 (fp8)',
promptTokens: 'futuristic cyborg portrait, delicate synthetic skin, neon cyan and magenta reflections, photorealistic 8k, bokeh',
params: 'Steps: 30 · CFG Scale: 3.5 · Sampler: Euler',
loraSpec: 'CyberpunkGlow_v1.safetensors (Weight 0.7)'
}
}
},
{
id: 'lum-06',
title: '幽蓝夜色·港风雨巷的情绪呼吸',
category: '情绪胶片',
metaType: 'digital',
photographer: {
name: '阿澈 (Che)',
avatar: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?auto=format&fit=crop&w=120&q=80',
badge: 'PRO'
},
model: {
name: '林小雨 (Rain)',
avatar: 'https://images.unsplash.com/photo-1544005313-94ddf0286df2?auto=format&fit=crop&w=120&q=80',
bio: '擅长风格:港风忧郁、街头纪实、冷暖对比',
aggregateScore: 9.42,
shootsCount: 20
},
release: '已签署商业 Model Release 肖像授权',
aspect: '9:16 竖屏',
imgUrl: 'https://images.unsplash.com/photo-1544005313-94ddf0286df2?auto=format&fit=crop&w=1000&q=80',
rawRating: 9.40,
votes: 1120,
scores: {
comp: 9.3,
light: 9.5,
color: 9.6,
exp: 9.3
},
toneHex: '#0891B2',
palette: ['#0891B2', '#1E293B', '#F43F5E', '#0F172A', '#94A3B8'],
views: 21300,
isFavorited: false,
metaData: {
digital: {
camera: 'Canon EOS R5',
lens: 'RF 50mm F1.2 L USM',
focalAperture: '50mm · f/1.2',
shutterIso: '1/200s · ISO 800'
},
film: {
filmStock: 'Cinestill 800T 电影负片',
formatProcess: '标准 135 画幅 · ECN-2 专业电影冲洗',
scannerLab: 'Noritsu HS-1800 诺日士冲扫',
pushPull: '原速拍摄 · 呈现暗部幽蓝'
},
bts: {
keyLight: '暖黄路灯作为顶光 + 蓝色手持补光棒打面光',
fillLight: '湿漉地面天然漫反射雨水镜面光',
modifierPreset: '冷暖对比港风高饱和色温分割',
locationSetup: '香港深水埗旧街雨夜'
},
mobile: {
device: 'iPhone 15 Pro Max',
sensor: '48MP 计算影像传感器',
engine: '夜景长曝光人像引擎',
toneProfile: '电影冷暖色彩预设'
},
ai: {
baseModel: 'Flux.1 Dev HongKong Moody',
promptTokens: 'drenching rain, neon signs reflection, melancholic eyes, 50mm lens shot',
params: 'Steps: 28 · CFG: 3.2',
loraSpec: 'HongKongCinema_v2 (0.75)'
}
}
}
];

// Global Application State Variables
let activeCategory = '全部';
let activeMetaType = 'all';
let activeSortMode = 'bayesian';
let activeColor = 'all';
let searchQueryStr = '';
let currentPhotoItem = null;
let currentModalMetaTab = 'digital'; // Active preview tab in the modal

// Mathematical Bayesian Smoothing Parameters
// Formula: S = (C * m + sum(w_i * r_i)) / (C + sum(w_i))
const BAYES_PRIOR_M = 8.5; // Prior mean rating across the platform
const BAYES_CONF_C = 50; // Confidence threshold constant (samples needed to shift)

function calculateBayesianScore(votes, rawRating) {
const weightedScore = (BAYES_CONF_C * BAYES_PRIOR_M + votes * rawRating) / (BAYES_CONF_C + votes);
return Number(weightedScore.toFixed(2));
}

function getGradeTitle(bayesianScore) {
if (bayesianScore >= 9.5) return '殿堂级神作';
if (bayesianScore >= 9.2) return '卓越级写真';
if (bayesianScore >= 8.8) return '优选级佳作';
return '探索级新作';
}

function getMetaTypeIconAndName(typeKey) {
switch (typeKey) {
case 'digital': return { icon: 'fa-camera', label: '数码相机EXIF' };
case 'film': return { icon: 'fa-film', label: '胶片冲扫参数' };
case 'bts': return { icon: 'fa-lightbulb', label: '影棚布光BTS' };
case 'mobile': return { icon: 'fa-mobile-screen', label: '移动计算摄影' };
case 'ai': return { icon: 'fa-wand-magic-sparkles', label: 'AI生图参数' };
default: return { icon: 'fa-image', label: '专业视觉资产' };
}
}

// Initialize gallery on page load
window.addEventListener('DOMContentLoaded', () => {
renderGalleryBricks();
updateFavoriteCounterBadge();
});

// Render Masonry Bricks
function renderGalleryBricks() {
const container = document.getElementById('masonryGallery');
const emptyNotice = document.getElementById('emptyGalleryNotice');

// Filter dataset
let filtered = PORTRAIT_DATABASE.filter(item => {
// Category
if (activeCategory !== '全部' && item.category !== activeCategory) return false;

// Meta Type
if (activeMetaType !== 'all' && item.metaType !== activeMetaType) return false;

// Color
if (activeColor !== 'all' && item.toneHex !== activeColor) return false;

// Search Query
if (searchQueryStr.trim()) {
const q = searchQueryStr.toLowerCase();
const matchTitle = item.title.toLowerCase().includes(q);
const matchPhotographer = item.photographer.name.toLowerCase().includes(q);
const matchModel = item.model.name.toLowerCase().includes(q);
const matchCategory = item.category.toLowerCase().includes(q);
if (!matchTitle && !matchPhotographer && !matchModel && !matchCategory) return false;
}

return true;
});

// Sorting
filtered.sort((a, b) => {
if (activeSortMode === 'bayesian') {
return calculateBayesianScore(b.votes, b.rawRating) - calculateBayesianScore(a.votes, a.rawRating);
} else if (activeSortMode === 'presence') {
return b.scores.exp - a.scores.exp;
} else if (activeSortMode === 'trending') {
return b.views - a.views;
} else if (activeSortMode === 'newest') {
return b.id.localeCompare(a.id);
}
return 0;
});

document.getElementById('itemCountDisplay').textContent = filtered.length;

if (filtered.length === 0) {
container.innerHTML = '';
emptyNotice.classList.remove('hidden');
return;
} else {
emptyNotice.classList.add('hidden');
}

container.innerHTML = filtered.map(item => {
const bayesian = calculateBayesianScore(item.votes, item.rawRating);
const metaInfo = getMetaTypeIconAndName(item.metaType);

return `
<div class="masonry-brick">
<div class="glass-card rounded-2xl overflow-hidden relative group cursor-pointer" onclick="openDetailLightbox('${item.id}')">

<!-- Floating Top Badges (Metadata mode + Category) -->
<div class="absolute top-3 left-3 z-10 flex items-center gap-1.5 pointer-events-none">
<span class="px-2.5 py-0.5 rounded-lg text-[10px] font-bold tracking-wide shadow-md bg-noir-900/80 backdrop-blur-md text-amber-300 border border-amber-500/30 flex items-center gap-1">
<i class="fa-solid ${metaInfo.icon} text-[9px]"></i> ${metaInfo.label.split(' ')[0]}
</span>
<span class="px-2 py-0.5 rounded-lg text-[10px] bg-black/60 backdrop-blur-md text-slate-300 border border-white/10">
${item.category}
</span>
</div>

<!-- Top-Right Bayesian Rating Pill -->
<div class="absolute top-3 right-3 z-10 flex items-center gap-1 px-2.5 py-1 rounded-xl bg-black/75 backdrop-blur-md border border-amber-500/40 shadow-glow-gold pointer-events-none">
<i class="fa-solid fa-star text-amber-400 text-[11px]"></i>
<span class="text-xs font-black text-amber-300 font-mono">${bayesian}</span>
<span class="text-[9px] text-slate-400">(${item.votes})</span>
</div>

<!-- Photograph Frame -->
<div class="w-full bg-noir-950 overflow-hidden relative">
<img
src="${item.imgUrl}"
alt="${item.title}"
loading="lazy"
class="w-full h-auto object-cover group-hover:scale-105 transition-transform duration-700 ease-out"
>
<div class="absolute inset-0 bg-gradient-to-t from-black/90 via-black/20 to-transparent opacity-40 group-hover:opacity-85 transition-opacity duration-300"></div>
</div>

<!-- Bottom Content & Attribution -->
<div class="absolute inset-x-0 bottom-0 p-4 flex flex-col justify-end transform translate-y-2 group-hover:translate-y-0 opacity-90 group-hover:opacity-100 transition-all duration-300">
<h3 class="font-serif font-bold text-sm text-white drop-shadow truncate group-hover:text-amber-200 transition">
${item.title}
</h3>

<!-- Joint Attribution & Presence Score -->
<div class="flex items-center justify-between mt-2 pt-2 border-t border-white/10 text-xs">
<div class="flex items-center gap-2 truncate">
<img src="${item.model.avatar}" alt="${item.model.name}" class="w-5 h-5 rounded-full object-cover border border-rose-500/40" title="出镜模特: ${item.model.name}">
<span class="text-slate-300 text-[11px] truncate">
模特: <strong class="text-rose-300">${item.model.name}</strong> · 表现力 <span class="font-mono text-amber-300 font-bold">${item.scores.exp}</span>
</span>
</div>

<!-- Quick Action Icons -->
<div class="flex items-center gap-1.5" onclick="event.stopPropagation()">
<button
onclick="toggleFavoritePhoto('${item.id}')"
class="w-7 h-7 rounded-lg bg-black/60 hover:bg-rose-500/20 text-slate-300 hover:text-rose-400 border border-white/10 flex items-center justify-center transition"
title="收藏写真">
<i class="${item.isFavorited ? 'fa-solid fa-bookmark text-rose-500' : 'fa-regular fa-bookmark'} text-xs"></i>
</button>
<button
onclick="openDetailLightbox('${item.id}'); document.getElementById('casualRatingSlider').focus();"
class="w-7 h-7 rounded-lg bg-black/60 hover:bg-amber-500/20 text-slate-300 hover:text-amber-400 border border-white/10 flex items-center justify-center transition"
title="即刻评分">
<i class="fa-solid fa-sliders text-xs"></i>
</button>
</div>
</div>

</div>

</div>
</div>
`;
}).join('');
}

// Render dynamic contextual metadata body inside the detail lightbox
function renderAdaptiveMetaPanel(typeKey) {
if (!currentPhotoItem) return;
const data = currentPhotoItem.metaData[typeKey];
const panel = document.getElementById('dynamicMetaPanelBody');
const titleLabel = document.getElementById('currentMetaTypeName');

// Update switcher active tab button styling
document.querySelectorAll('.meta-preview-tab').forEach(t => {
t.classList.remove('text-amber-400', 'bg-white/10');
t.classList.add('text-slate-400');
});
const activeBtn = document.getElementById(`tab-meta-${typeKey}`);
if (activeBtn) {
activeBtn.classList.add('text-amber-400', 'bg-white/10');
activeBtn.classList.remove('text-slate-400');
}

// Update text indicator
const info = getMetaTypeIconAndName(typeKey);
titleLabel.innerHTML = `<i class="fa-solid ${info.icon} mr-1"></i> ${info.label}`;

if (typeKey === 'digital') {
panel.innerHTML = `
<div class="grid grid-cols-2 gap-2">
<div class="p-2.5 rounded-xl bg-noir-900 border border-white/5">
<span class="text-[10px] text-slate-400 block">机身 / Camera Body</span>
<span class="font-medium text-slate-200 block truncate">${data.camera}</span>
</div>
<div class="p-2.5 rounded-xl bg-noir-900 border border-white/5">
<span class="text-[10px] text-slate-400 block">镜头 / Prime Lens</span>
<span class="font-medium text-slate-200 block truncate">${data.lens}</span>
</div>
<div class="p-2.5 rounded-xl bg-noir-900 border border-white/5">
<span class="text-[10px] text-slate-400 block">焦段与光圈</span>
<span class="font-medium text-amber-300 font-mono">${data.focalAperture}</span>
</div>
<div class="p-2.5 rounded-xl bg-noir-900 border border-white/5">
<span class="text-[10px] text-slate-400 block">快门速度与感光度</span>
<span class="font-medium text-slate-200 font-mono">${data.shutterIso}</span>
</div>
</div>
`;
} else if (typeKey === 'film') {
panel.innerHTML = `
<div class="grid grid-cols-2 gap-2">
<div class="p-2.5 rounded-xl bg-noir-900 border border-white/5">
<span class="text-[10px] text-amber-400/90 block">🎞️ 胶卷型号 / Film Stock</span>
<span class="font-medium text-slate-100 block truncate font-serif">${data.filmStock}</span>
</div>
<div class="p-2.5 rounded-xl bg-noir-900 border border-white/5">
<span class="text-[10px] text-slate-400 block">画幅规格与冲洗工艺</span>
<span class="font-medium text-slate-200 block truncate">${data.formatProcess}</span>
</div>
<div class="p-2.5 rounded-xl bg-noir-900 border border-white/5">
<span class="text-[10px] text-slate-400 block">冲扫实验室与底扫设备</span>
<span class="font-medium text-slate-200 block truncate">${data.scannerLab}</span>
</div>
<div class="p-2.5 rounded-xl bg-noir-900 border border-white/5">
<span class="text-[10px] text-slate-400 block">增感/减感策略 (Push/Pull)</span>
<span class="font-medium text-amber-300 font-mono">${data.pushPull}</span>
</div>
</div>
`;
} else if (typeKey === 'bts') {
panel.innerHTML = `
<div class="space-y-2">
<div class="p-2.5 rounded-xl bg-noir-900 border border-white/5">
<span class="text-[10px] text-amber-400/90 block">💡 核心主光与控光附件 (Key Light)</span>
<span class="font-medium text-slate-100 block text-[11px]">${data.keyLight}</span>
</div>
<div class="p-2.5 rounded-xl bg-noir-900 border border-white/5">
<span class="text-[10px] text-slate-400 block">副光、轮廓与环境补光 (Fill & Rim)</span>
<span class="font-medium text-slate-200 block text-[11px]">${data.fillLight}</span>
</div>
<div class="grid grid-cols-2 gap-2">
<div class="p-2 rounded-xl bg-noir-900 border border-white/5">
<span class="text-[9px] text-slate-400 block">后期色彩科学 / LUT</span>
<span class="font-medium text-slate-200 block text-[10px] truncate">${data.modifierPreset}</span>
</div>
<div class="p-2 rounded-xl bg-noir-900 border border-white/5">
<span class="text-[9px] text-slate-400 block">拍摄场景与置景细节</span>
<span class="font-medium text-slate-200 block text-[10px] truncate">${data.locationSetup}</span>
</div>
</div>
</div>
`;
} else if (typeKey === 'mobile') {
panel.innerHTML = `
<div class="grid grid-cols-2 gap-2">
<div class="p-2.5 rounded-xl bg-noir-900 border border-white/5">
<span class="text-[10px] text-cyan-400 block">📱 移动智能设备</span>
<span class="font-medium text-slate-100 block truncate">${data.device}</span>
</div>
<div class="p-2.5 rounded-xl bg-noir-900 border border-white/5">
<span class="text-[10px] text-slate-400 block">感光元件与多合一像素</span>
<span class="font-medium text-slate-200 block truncate">${data.sensor}</span>
</div>
<div class="p-2.5 rounded-xl bg-noir-900 border border-white/5">
<span class="text-[10px] text-slate-400 block">计算摄影人像引擎</span>
<span class="font-medium text-slate-200 block truncate font-mono">${data.engine}</span>
</div>
<div class="p-2.5 rounded-xl bg-noir-900 border border-white/5">
<span class="text-[10px] text-slate-400 block">原生摄影风格 / 影调预设</span>
<span class="font-medium text-amber-300 block truncate">${data.toneProfile}</span>
</div>
</div>
`;
} else if (typeKey === 'ai') {
panel.innerHTML = `
<div class="space-y-2">
<div class="grid grid-cols-2 gap-2">
<div class="p-2.5 rounded-xl bg-noir-900 border border-white/5">
<span class="text-[10px] text-purple-400 block">✨ 生成底模 / Model</span>
<span class="font-medium text-slate-100 block truncate font-mono">${data.baseModel}</span>
</div>
<div class="p-2.5 rounded-xl bg-noir-900 border border-white/5">
<span class="text-[10px] text-slate-400 block">采样超参数 (Steps / CFG)</span>
<span class="font-medium text-slate-200 block truncate font-mono">${data.params}</span>
</div>
</div>
<div class="p-2.5 rounded-xl bg-noir-900 border border-white/5">
<span class="text-[10px] text-slate-400 block">核心艺术提示词 (Prompt Tokens)</span>
<p class="font-mono text-slate-300 text-[10px] break-all leading-tight mt-0.5">${data.promptTokens}</p>
</div>
<div class="p-2 rounded-xl bg-noir-900 border border-white/5 flex items-center justify-between text-[11px]">
<span class="text-slate-400">LoRA 微调模型:</span>
<span class="text-purple-300 font-mono font-medium">${data.loraSpec}</span>
</div>
</div>
`;
}
}

function switchModalMetaPreview(typeKey) {
currentModalMetaTab = typeKey;
renderAdaptiveMetaPanel(typeKey);
const info = getMetaTypeIconAndName(typeKey);
showToast(`已切换至【${info.label}】展示模板`);
}

// Open Detail Lightbox
function openDetailLightbox(id) {
const item = PORTRAIT_DATABASE.find(p => p.id === id);
if (!item) return;
currentPhotoItem = item;
currentModalMetaTab = item.metaType; // Default to photograph's true type

// Left Column Visuals
document.getElementById('modalPhotoImage').src = item.imgUrl;
document.getElementById('modalPhotoImage').classList.remove('scale-125');
document.getElementById('zoomLabelText').textContent = '缩放原图';

const metaInfo = getMetaTypeIconAndName(item.metaType);
document.getElementById('modalMetaTypePill').innerHTML = `<i class="fa-solid ${metaInfo.icon}"></i> ${metaInfo.label}`;
document.getElementById('modalAspectPill').textContent = item.aspect;

document.getElementById('modalPhotographerAvatar').src = item.photographer.avatar;
document.getElementById('modalPhotographerName').textContent = item.photographer.name;
document.getElementById('modalPhotographerBadge').textContent = item.photographer.badge;

// Color Palette Swatches
const palContainer = document.getElementById('modalPaletteRow');
palContainer.innerHTML = item.palette.map(hex => `
<button
onclick="copyPaletteColor('${hex}')"
title="点击复制色值 ${hex}"
class="w-5 h-5 rounded-md transition-transform hover:scale-125 border border-white/20 shadow"
style="background-color: ${hex}">
</button>
`).join('');

// Right Column: Title & Release
document.getElementById('modalWorkTitle').textContent = item.title;
document.getElementById('modalReleaseBadge').innerHTML = `<i class="fa-solid fa-shield-check"></i> ${item.release}`;

// Right Column: Decoupled Model Profile Card
document.getElementById('modelAvatar').src = item.model.avatar;
document.getElementById('modelName').textContent = item.model.name;
document.getElementById('modelBio').textContent = item.model.bio;
document.getElementById('modelAggregateScore').textContent = item.model.aggregateScore.toFixed(2);
document.getElementById('modelTotalShoots').textContent = `${item.model.shootsCount} 组作品聚合`;

// Adaptive Contextual Meta Panel
renderAdaptiveMetaPanel(item.metaType);

// Bayesian Composite Scoring
updateModalBayesianUI();

// Bookmark button state
updateModalBookmarkState();

// Reset casual slider
document.getElementById('casualRatingSlider').value = "9.0";
document.getElementById('quickSliderValue').textContent = "9.0 分";

// Reset Pro sliders
document.getElementById('proScoreComp').textContent = item.scores.comp;
document.getElementById('proScoreLight').textContent = item.scores.light;
document.getElementById('proScoreColor').textContent = item.scores.color;
document.getElementById('proScoreExp').textContent = item.scores.exp;

// Show Modal with smooth animation
const modal = document.getElementById('photoDetailModal');
const dialog = document.getElementById('modalDialogBox');
modal.classList.remove('hidden');
setTimeout(() => {
modal.classList.remove('opacity-0', 'pointer-events-none');
dialog.classList.remove('scale-95');
dialog.classList.add('scale-100');
}, 10);
document.body.style.overflow = 'hidden';
}

function closeDetailLightbox() {
const modal = document.getElementById('photoDetailModal');
const dialog = document.getElementById('modalDialogBox');
modal.classList.add('opacity-0', 'pointer-events-none');
dialog.classList.remove('scale-100');
dialog.classList.add('scale-95');
setTimeout(() => {
modal.classList.add('hidden');
document.body.style.overflow = '';
}, 300);
currentPhotoItem = null;
}

function updateModalBayesianUI() {
if (!currentPhotoItem) return;
const bayesian = calculateBayesianScore(currentPhotoItem.votes, currentPhotoItem.rawRating);
const grade = getGradeTitle(bayesian);

document.getElementById('modalBayesianScoreText').textContent = bayesian;
document.getElementById('modalGradeBadge').textContent = grade;
document.getElementById('modalRawRatingText').textContent = `样本均值: ${currentPhotoItem.rawRating.toFixed(2)}`;
document.getElementById('modalVotersCountText').textContent = `基于 ${currentPhotoItem.votes.toLocaleString()} 人加权鉴赏`;
}

// Quick Rating Slider
function handleQuickSliderChange(val) {
document.getElementById('quickSliderValue').textContent = `${Number(val).toFixed(1)} 分`;
}

function submitQuickRating() {
if (!currentPhotoItem) return;
const userRating = parseFloat(document.getElementById('casualRatingSlider').value);

// Update item with casual weight (1.0)
const oldSum = currentPhotoItem.rawRating * currentPhotoItem.votes;
currentPhotoItem.votes += 1;
currentPhotoItem.rawRating = Number(((oldSum + userRating) / currentPhotoItem.votes).toFixed(3));

// Recalculate & update UI
updateModalBayesianUI();
renderGalleryBricks();
showToast(`✨ 您的评分 ${userRating.toFixed(1)} 分已入库,贝叶斯平滑均值已实时重新拟合!`);
}

// Pro 4-Axis Drawer Accordion
function toggleProReviewDrawer() {
const drawer = document.getElementById('proDrawerContent');
const icon = document.getElementById('proDrawerIcon');
if (drawer.classList.contains('hidden')) {
drawer.classList.remove('hidden');
icon.classList.add('rotate-180');
} else {
drawer.classList.add('hidden');
icon.classList.remove('rotate-180');
}
}

function updateProAxis(axis, val) {
const num = Number(val).toFixed(1);
if (axis === 'comp') document.getElementById('proScoreComp').textContent = num;
if (axis === 'light') document.getElementById('proScoreLight').textContent = num;
if (axis === 'color') document.getElementById('proScoreColor').textContent = num;
if (axis === 'exp') document.getElementById('proScoreExp').textContent = num;
}

function submitProFourAxisRating() {
if (!currentPhotoItem) return;
const c = parseFloat(document.getElementById('proScoreComp').textContent);
const l = parseFloat(document.getElementById('proScoreLight').textContent);
const co = parseFloat(document.getElementById('proScoreColor').textContent);
const e = parseFloat(document.getElementById('proScoreExp').textContent);

const proComposite = Number(((c + l + co + e) / 4).toFixed(2));
const proWeight = 2.5; // Professional reviewer weight constant

// Apply weighted addition
const oldWeightedSum = currentPhotoItem.rawRating * currentPhotoItem.votes;
currentPhotoItem.votes += Math.round(proWeight);
currentPhotoItem.rawRating = Number(((oldWeightedSum + (proComposite * proWeight)) / currentPhotoItem.votes).toFixed(3));

// Update model aggregated presence score slightly
const oldModelTotal = currentPhotoItem.model.aggregateScore * currentPhotoItem.model.shootsCount;
currentPhotoItem.model.aggregateScore = Number(((oldModelTotal + e) / (currentPhotoItem.model.shootsCount + 1)).toFixed(2));
document.getElementById('modelAggregateScore').textContent = currentPhotoItem.model.aggregateScore.toFixed(2);

updateModalBayesianUI();
renderGalleryBricks();
toggleProReviewDrawer();
showToast(`🏆 专业四维评审已提交 (综合 ${proComposite}分 · 2.5x权重),出镜表现力已同步入库!`);
}

// Zoom Image in modal
function toggleImageZoom() {
const img = document.getElementById('modalPhotoImage');
const label = document.getElementById('zoomLabelText');
if (img.classList.contains('scale-125')) {
img.classList.remove('scale-125', 'cursor-zoom-out');
img.classList.add('cursor-zoom-in');
label.textContent = '缩放原图';
} else {
img.classList.add('scale-125', 'cursor-zoom-out');
img.classList.remove('cursor-zoom-in');
label.textContent = '适屏比例';
}
}

// Copying Palette HEX Code
function copyPaletteColor(hex) {
const temp = document.createElement('input');
temp.value = hex;
document.body.appendChild(temp);
temp.select();
try {
document.execCommand('copy');
showToast(`🎨 已复制色相 HEX 编码: ${hex}`);
} catch (err) {
showToast(`提取色值: ${hex}`);
}
document.body.removeChild(temp);
}

// Modal Bookmarking
function handleModalBookmarkToggle() {
if (!currentPhotoItem) return;
currentPhotoItem.isFavorited = !currentPhotoItem.isFavorited;
updateModalBookmarkState();
renderGalleryBricks();
updateFavoriteCounterBadge();
showToast(currentPhotoItem.isFavorited ? '❤️ 已将写真收录至您的私享画板' : '已从收藏夹中移除');
}

function updateModalBookmarkState() {
const btn = document.getElementById('modalBookmarkBtn');
if (currentPhotoItem && currentPhotoItem.isFavorited) {
btn.innerHTML = '<i class="fa-solid fa-bookmark text-rose-500"></i>';
btn.classList.add('bg-rose-500/20', 'border-rose-500/40');
} else {
btn.innerHTML = '<i class="fa-regular fa-bookmark text-slate-300"></i>';
btn.classList.remove('bg-rose-500/20', 'border-rose-500/40');
}
}

// Favorites Slide Drawer Management
function toggleFavoritePhoto(id) {
const item = PORTRAIT_DATABASE.find(p => p.id === id);
if (!item) return;
item.isFavorited = !item.isFavorited;
renderGalleryBricks();
updateFavoriteCounterBadge();
showToast(item.isFavorited ? '❤️ 已将写真收录至您的私享画板' : '已从收藏夹中移除');
}

function updateFavoriteCounterBadge() {
const count = PORTRAIT_DATABASE.filter(p => p.isFavorited).length;
document.getElementById('favCountBadge').textContent = count;
renderFavoritesList();
}

function toggleFavoritesDrawer() {
const drawer = document.getElementById('favoritesSlideDrawer');
if (drawer.classList.contains('translate-x-full')) {
drawer.classList.remove('translate-x-full');
} else {
drawer.classList.add('translate-x-full');
}
}

function renderFavoritesList() {
const container = document.getElementById('favoritesContainer');
const favs = PORTRAIT_DATABASE.filter(p => p.isFavorited);
if (favs.length === 0) {
container.innerHTML = '<div class="text-xs text-slate-500 text-center py-10 font-sans">暂无收藏写真,快去探索画廊吧</div>';
return;
}
container.innerHTML = favs.map(item => `
<div class="flex items-center gap-3 p-2.5 rounded-xl bg-noir-850 hover:bg-noir-800 transition cursor-pointer border border-white/5" onclick="openDetailLightbox('${item.id}'); toggleFavoritesDrawer();">
<img src="${item.imgUrl}" class="w-12 h-12 rounded-lg object-cover">
<div class="flex-1 min-w-0">
<h5 class="text-xs font-bold text-slate-200 truncate">${item.title}</h5>
<p class="text-[10px] text-amber-400 font-mono mt-0.5">★ ${calculateBayesianScore(item.votes, item.rawRating)} · ${item.category}</p>
</div>
</div>
`).join('');
}

// Global Filter Handlers
function setGlobalCategory(cat) {
activeCategory = cat;
// Desktop Nav Links
document.querySelectorAll('.cat-link').forEach(btn => {
btn.classList.remove('text-amber-400', 'bg-amber-500/10');
btn.classList.add('hover:text-white', 'hover:bg-white/5');
});
// Mobile Nav Pills
document.querySelectorAll('.cat-pill-mobile').forEach(btn => {
btn.classList.remove('bg-amber-500', 'text-noir-950', 'font-bold');
btn.classList.add('bg-noir-900', 'text-slate-300');
if (btn.textContent.trim() === cat) {
btn.classList.remove('bg-noir-900', 'text-slate-300');
btn.classList.add('bg-amber-500', 'text-noir-950', 'font-bold');
}
});
renderGalleryBricks();
}

function setMetaTypeFilter(metaTypeKey) {
activeMetaType = metaTypeKey;
document.querySelectorAll('.meta-type-btn').forEach(btn => {
btn.classList.remove('bg-amber-500', 'text-noir-950', 'font-bold');
btn.classList.add('bg-noir-900', 'text-slate-300');
});
event.currentTarget.classList.remove('bg-noir-900', 'text-slate-300');
event.currentTarget.classList.add('bg-amber-500', 'text-noir-950', 'font-bold');
renderGalleryBricks();
}

function handleSortChange(sortVal) {
activeSortMode = sortVal;
renderGalleryBricks();
}

function setColorFilter(colorHex) {
activeColor = colorHex;
renderGalleryBricks();
showToast(colorHex === 'all' ? '已展示全色谱写真' : `已筛选主色调为 ${colorHex} 的写真`);
}

function handleSearchInput(val) {
searchQueryStr = val;
const clearBtn = document.getElementById('searchClearBtn');
if (val.trim()) {
clearBtn.classList.remove('hidden');
} else {
clearBtn.classList.add('hidden');
}
renderGalleryBricks();
}

function clearSearchInput() {
document.getElementById('searchInput').value = '';
searchQueryStr = '';
document.getElementById('searchClearBtn').classList.add('hidden');
renderGalleryBricks();
}

function resetAllFilters() {
activeCategory = '全部';
activeMetaType = 'all';
activeSortMode = 'bayesian';
activeColor = 'all';
clearSearchInput();
setGlobalCategory('全部');
}

function triggerDownloadAction(format) {
const title = currentPhotoItem ? currentPhotoItem.title : 'Lumina_Photo';
showToast(`📥 正在为您打包下载「${title}」${format === 'wallpaper' ? '9:16 壁纸版' : '无损 4K 原画'}`);
}

function showAlgorithmExplainToast() {
showToast('🧮 贝叶斯平滑公式 S=(C*m + ∑w*r)/(C+∑w),有效平抑小号刷分并保障冷启动公平!');
}

// Global Toast Notification Helper
let toastTimeout = null;
function showToast(msg) {
const toast = document.getElementById('appToast');
const text = document.getElementById('toastMessageText');
text.textContent = msg;

toast.classList.remove('translate-y-16', 'opacity-0', 'pointer-events-none');
toast.classList.add('translate-y-0', 'opacity-100');

if (toastTimeout) clearTimeout(toastTimeout);
toastTimeout = setTimeout(() => {
toast.classList.add('translate-y-16', 'opacity-0', 'pointer-events-none');
toast.classList.remove('translate-y-0', 'opacity-100');
}, 3500);
}

// Keyboard and background click handlers
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
closeDetailLightbox();
const drawer = document.getElementById('favoritesSlideDrawer');
if (!drawer.classList.contains('translate-x-full')) {
drawer.classList.add('translate-x-full');
}
}
});

document.getElementById('photoDetailModal').addEventListener('click', (e) => {
if (e.target.id === 'photoDetailModal') {
closeDetailLightbox();
}
});
</script>
</body>
</html>
最新回复 (27)
  • hardware 09-20 11:19
    1

    支持搞 ^-^

  • DayDayWait 09-20 11:19
    2

    预定SSSSVIP

  • Noontwo 楼主 09-20 11:20
    3

    ^-^ ^-^ ^-^ 得提意见先呀。

  • Lemonadeccc 09-20 11:21
    4

    能不能爬一下 beautyleg ^-^ ,一个鸡腿预订 VIP

  • 老衲推车 09-20 11:22
    5

    厉害

  • Tulescu 09-20 11:22
    6

    这么长,差点没翻到评论框 ^-^

  • tubu 09-20 11:23
    7

    正经的写真站吗? ^-^

  • Noontwo 楼主 09-20 11:26
    8

    ^-^ @Lemonadeccc #4 我想做没那么色的。

  • Lemonadeccc 09-20 11:28
    9

    @Noontwo #8 我相信你 ^-^

  • Pole 09-20 11:30
    10

    不懂帮顶

  • cxj13800 09-20 11:31
    11

    ^-^ 这个好

  • markslee 09-20 11:33
    12

    之前也想整,但是在个人收藏和分享两个方向犹豫了,就没弄了,加油,期待你的成果

  • ggee 09-20 11:35
    13

    裸体的比较棒

  • 一粒小尘埃 09-20 11:36
    14

    好长

  • Noontwo 楼主 09-20 11:43
    15

    @Lemonadeccc #9 吼吼吼吼吼吼吼吼吼吼吼,只保留不漏,有漏的就放网盘?

  • Noontwo 楼主 09-20 11:44
    16

    @一粒小尘埃 #14 因为放了前端

  • Fate 09-20 11:45
    17

    有里站吗

  • tryfree666 09-20 11:45
    18

    我不管你排版,给我写真集

  • chenbz 09-20 11:54
    19

    bd支持一下

  • 服务器老王 09-20 11:55
    20

    直接拿ai搞呢这是

  • vhxubo 09-20 14:34
    21

    前排支持!不重视展示形式,资源足够多就行。

  • byfly 09-20 14:54
    22

    送会员不

  • waytogo 09-20 14:55
    23

    写真站 怎么挣钱?

  • Noontwo 楼主 09-20 15:22
    24

    @waytogo #23 不知道,自慰(自我安慰)整理图库用

  • Lisi 09-20 15:28
    25

    帮顶,学习一下

  • treasureu 09-20 15:29
    26

    这么长,我差点没下来

  • 1-eason 09-20 15:30
    27

    用的什么方案,我也有点想拿来给大家看

* 帖子来源NodeSeek
返回