<!DOCTYPE html>

<html lang="zh-CN">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">

<title>我们的星星瓶</title>

<link href="https://fonts.googleapis.com/css2?family=Zhi+Mang+Xing&display=swap" rel="stylesheet">

<script src="https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2"></script>

<style>

* { margin:0; padding:0; box-sizing:border-box; -webkit-tap-highlight-color:transparent; }

html, body { height:100%; overflow:hidden; }


body {

  font-family: -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif;

  background: #1a3a5c;

  background-image:

    radial-gradient(ellipse at 20% 30%, rgba(70,130,180,0.55) 0%, transparent 50%),

    radial-gradient(ellipse at 80% 20%, rgba(40,90,140,0.6) 0%, transparent 45%),

    radial-gradient(ellipse at 50% 80%, rgba(30,70,110,0.7) 0%, transparent 55%),

    radial-gradient(ellipse at 90% 70%, rgba(60,110,160,0.4) 0%, transparent 40%),

    linear-gradient(160deg, #1e4266 0%, #153252 40%, #0f2440 70%, #1a3a5c 100%);

  background-attachment: fixed;

  color:#fff;

  user-select:none;

  position:relative;

}

body::before {

  content:''; position:fixed; inset:0; pointer-events:none;

  background:

    radial-gradient(circle at 15% 25%, rgba(120,170,220,0.12) 0%, transparent 30%),

    radial-gradient(circle at 75% 65%, rgba(80,140,200,0.1) 0%, transparent 35%);

  animation: drift 20s ease-in-out infinite alternate;

}

@keyframes drift { from { transform:translate(0,0) scale(1); } to { transform:translate(2%,1%) scale(1.05); } }


.screen { position:fixed; inset:0; display:flex; flex-direction:column; align-items:center; justify-content:center; padding:24px; transition:opacity .4s, visibility .4s; }

.screen.hidden { opacity:0; visibility:hidden; pointer-events:none; }


/* 入场 */

.entry-box { width:100%; max-width:340px; text-align:center; }

.entry-title { font-size:26px; font-weight:600; margin-bottom:8px; letter-spacing:2px; text-shadow:0 2px 12px rgba(0,0,0,0.4); }

.entry-sub { font-size:13px; opacity:.65; margin-bottom:32px; letter-spacing:1px; }

.input-field {

  width:100%; padding:15px 18px; border-radius:14px;

  border:1px solid rgba(180,210,240,0.3);

  background:rgba(255,255,255,0.08);

  backdrop-filter:blur(10px);

  color:#fff; font-size:17px; text-align:center; letter-spacing:6px;

  outline:none; transition:.3s;

}

.input-field::placeholder { letter-spacing:2px; color:rgba(255,255,255,0.35); font-size:14px; }

.input-field:focus { border-color:rgba(160,210,255,0.6); background:rgba(255,255,255,0.13); }

.btn-primary {

  width:100%; margin-top:18px; padding:15px; border:none; border-radius:14px;

  background:linear-gradient(135deg, rgba(120,180,240,0.85), rgba(80,140,210,0.85));

  color:#fff; font-size:16px; font-weight:600; letter-spacing:2px;

  cursor:pointer; transition:.25s; box-shadow:0 6px 20px rgba(0,0,0,0.25);

}

.btn-primary:active { transform:scale(0.97); }

.btn-primary:disabled { opacity:.4; cursor:not-allowed; }

.error-msg { color:#ff9a9a; font-size:13px; margin-top:12px; min-height:18px; }


.identity-btns { display:flex; gap:16px; width:100%; max-width:340px; }

.identity-btn {

  flex:1; padding:28px 12px; border-radius:18px;

  border:1px solid rgba(180,210,240,0.25);

  background:rgba(255,255,255,0.07);

  backdrop-filter:blur(10px);

  color:#fff; font-size:17px; font-weight:600; letter-spacing:1px;

  cursor:pointer; transition:.25s;

}

.identity-btn:active { transform:scale(0.96); }

.identity-btn:hover { background:rgba(255,255,255,0.14); border-color:rgba(180,210,240,0.5); }


/* 主页面 */

#mainScreen { justify-content:flex-start; padding-top:20px; }

.top-bar {

  position:fixed; top:16px; right:16px; z-index:30;

  display:flex; gap:10px;

}

.btn-add-star {

  padding:11px 18px; border-radius:12px; border:1px solid rgba(180,210,240,0.3);

  background:rgba(255,255,255,0.12); backdrop-filter:blur(12px);

  color:#fff; font-size:13px; font-weight:600; letter-spacing:1px;

  cursor:pointer; transition:.25s;

}

.btn-add-star:active { transform:scale(0.95); }


.current-user { position:fixed; top:16px; left:16px; font-size:12px; opacity:.6; letter-spacing:1px; z-index:30; }


.bottles-wrap {

  display:flex; gap:clamp(20px, 6vw, 70px);

  align-items:flex-end; justify-content:center;

  margin-top:auto; margin-bottom:auto;

  width:100%; max-width:820px;

  padding:0 10px;

}

.bottle-col { display:flex; flex-direction:column; align-items:center; gap:14px; flex:1; max-width:300px; }

.bottle-label { font-size:14px; letter-spacing:2px; opacity:.8; font-weight:600; text-shadow:0 2px 8px rgba(0,0,0,0.4); }


/* 玻璃杯伪3D */

.glass {

  position:relative;

  width:clamp(120px, 30vw, 200px);

  height:clamp(180px, 44vw, 290px);

  cursor:pointer;

  transition:transform .3s;

  perspective:800px;

}

.glass:active { transform:scale(0.96); }


.glass-body {

  position:absolute; inset:0;

  border-radius:12% 12% 22% 22% / 8% 8% 18% 18%;

  background:

    linear-gradient(100deg, rgba(255,255,255,0.28) 0%, rgba(255,255,255,0.05) 18%, rgba(255,255,255,0.02) 45%, rgba(255,255,255,0.1) 78%, rgba(255,255,255,0.3) 100%),

    linear-gradient(to top, rgba(150,200,240,0.22) 0%, rgba(180,220,250,0.14) 40%, rgba(200,230,255,0.06) 100%);

  border:1px solid rgba(220,240,255,0.35);

  box-shadow:

    inset 0 0 30px rgba(200,230,255,0.18),

    inset -8px 0 20px rgba(150,200,240,0.15),

    inset 8px 0 20px rgba(255,255,255,0.12),

    0 10px 30px rgba(0,0,0,0.3);

  overflow:hidden;

  backdrop-filter:blur(2px);

}


/* 浮雕纹路 */

.glass-body::before {

  content:''; position:absolute; inset:12% 18% 28% 18%;

  border-radius:8px;

  background:

    repeating-linear-gradient(90deg, transparent 0 10px, rgba(255,255,255,0.055) 10px 12px),

    radial-gradient(ellipse at 50% 35%, rgba(255,255,255,0.07) 0%, transparent 65%);

  box-shadow: inset 0 0 20px rgba(200,230,255,0.08);

  pointer-events:none;

}

/* 高光 */

.glass-body::after {

  content:''; position:absolute; top:6%; left:12%; width:16%; height:60%;

  border-radius:50%;

  background:linear-gradient(to bottom, rgba(255,255,255,0.5), rgba(255,255,255,0.05));

  filter:blur(2px); opacity:.7; pointer-events:none;

}


/* 杯口 */

.glass-rim {

  position:absolute; top:-3px; left:6%; right:6%; height:14px;

  border-radius:50%;

  border:1.5px solid rgba(230,245,255,0.55);

  background:linear-gradient(to bottom, rgba(255,255,255,0.2), rgba(255,255,255,0.02));

  box-shadow:0 2px 8px rgba(0,0,0,0.15), inset 0 1px 3px rgba(255,255,255,0.4);

  z-index:3;

}


/* 把手 */

.glass-handle {

  position:absolute; top:22%; right:-30%; width:42%; height:44%;

  border:clamp(6px,1.6vw,10px) solid rgba(200,230,255,0.32);

  border-left:none;

  border-radius:0 50% 50% 0 / 0 50% 50% 0;

  box-shadow:

    0 0 0 1px rgba(255,255,255,0.12),

    inset 0 0 0 1px rgba(255,255,255,0.18),

    4px 4px 14px rgba(0,0,0,0.2);

  background:linear-gradient(120deg, rgba(255,255,255,0.12), rgba(255,255,255,0.02));

  z-index:-1;

}


/* 底部厚度 */

.glass-base {

  position:absolute; bottom:0; left:5%; right:5%; height:12px;

  border-radius:50%;

  background:linear-gradient(to top, rgba(180,220,250,0.35), transparent);

  filter:blur(1px);

}


/* 星星 */

.stars-container { position:absolute; bottom:8%; left:8%; right:8%; height:55%; z-index:2; }


.star {

  position:absolute; width:22px; height:22px;

  cursor:pointer;

  transition:transform .2s, filter .2s;

  filter:drop-shadow(0 2px 4px rgba(0,0,0,0.3));

}

.star:hover { transform:scale(1.25) rotate(8deg); filter:drop-shadow(0 3px 8px rgba(255,255,255,0.4)); }

.star:active { transform:scale(1.1); }

.star svg { width:100%; height:100%; display:block; }


/* 弹窗 */

.modal-overlay {

  position:fixed; inset:0; z-index:100;

  background:rgba(8,20,38,0.75);

  backdrop-filter:blur(8px);

  display:flex; align-items:center; justify-content:center;

  padding:20px;

  opacity:0; visibility:hidden; transition:.3s;

}

.modal-overlay.show { opacity:1; visibility:visible; }


.letter {

  width:100%; max-width:380px; max-height:78vh;

  background:linear-gradient(160deg, #fdf8ee 0%, #f5efe0 100%);

  color:#3a3226;

  border-radius:6px;

  padding:32px 26px;

  box-shadow:0 20px 60px rgba(0,0,0,0.5);

  overflow-y:auto;

  position:relative;

  transform:scale(0.9); transition:.3s;

  background-image:

    repeating-linear-gradient(0deg, transparent, transparent 27px, rgba(180,160,120,0.12) 27px, rgba(180,160,120,0.12) 28px);

}

.modal-overlay.show .letter { transform:scale(1); }


.letter-from { font-size:12px; opacity:.55; margin-bottom:16px; letter-spacing:1px; }

.letter-content {

  font-family:'Zhi Mang Xing', cursive;

  font-size:22px; line-height:28px; white-space:pre-wrap;

  word-break:break-word; min-height:60px;

}

.letter-actions { display:flex; gap:12px; margin-top:24px; }

.letter-actions button {

  flex:1; padding:12px; border-radius:10px; border:none; font-size:14px; cursor:pointer; transition:.2s;

}

.btn-close { background:#e0d5c0; color:#5a4a30; }

.btn-close:active { transform:scale(0.97); }

.btn-danger { background:#f0c8c0; color:#8a3a2a; }

.btn-danger:active { transform:scale(0.97); }

.btn-edit { background:#c8dce8; color:#2a4a5a; }

.btn-edit:active { transform:scale(0.97); }


/* 写星星弹窗 */

.write-panel {

  width:100%; max-width:380px;

  background:rgba(30,55,85,0.95);

  backdrop-filter:blur(20px);

  border:1px solid rgba(180,210,240,0.25);

  border-radius:20px; padding:26px;

  box-shadow:0 20px 60px rgba(0,0,0,0.5);

  transform:scale(0.9); transition:.3s;

}

.modal-overlay.show .write-panel { transform:scale(1); }

.write-title { font-size:17px; font-weight:600; margin-bottom:18px; text-align:center; letter-spacing:1px; }

.write-textarea {

  width:100%; min-height:150px; padding:14px; border-radius:12px;

  border:1px solid rgba(180,210,240,0.3);

  background:rgba(255,255,255,0.08);

  color:#fff; font-size:15px; line-height:1.6; resize:vertical;

  outline:none; font-family:inherit;

}

.write-textarea::placeholder { color:rgba(255,255,255,0.3); }

.color-picker { display:flex; gap:12px; justify-content:center; margin:18px 0; }

.color-dot {

  width:36px; height:36px; border-radius:50%; cursor:pointer;

  border:2px solid transparent; transition:.2s;

  box-shadow:0 2px 8px rgba(0,0,0,0.2);

}

.color-dot.selected { border-color:#fff; transform:scale(1.15); box-shadow:0 0 0 3px rgba(255,255,255,0.25); }


/* 空瓶提示 */

.empty-hint { position:absolute; bottom:30%; left:0; right:0; text-align:center; font-size:11px; opacity:.4; letter-spacing:1px; }


/* 加载 */

.loading { position:fixed; inset:0; display:flex; align-items:center; justify-content:center; z-index:200; background:rgba(26,58,92,0.9); }

.loading.hidden { display:none; }

.spinner { width:36px; height:36px; border:3px solid rgba(255,255,255,0.2); border-top-color:#fff; border-radius:50%; animation:spin .8s linear infinite; }

@keyframes spin { to { transform:rotate(360deg); } }


/* 小屏优化 */

@media (max-width:400px) {

  .glass-handle { right:-26%; }

  .top-bar { top:12px; right:12px; }

  .btn-add-star { padding:9px 13px; font-size:12px; }

}

</style>

</head>

<body>


<div class="loading" id="loading"><div class="spinner"></div></div>


<!-- 密码 -->

<div class="screen" id="passwordScreen">

  <div class="entry-box">

    <div class="entry-title">我们的星星瓶</div>

    <div class="entry-sub">请输入房间密码</div>

    <input class="input-field" id="passwordInput" type="password" inputmode="numeric" placeholder="····" maxlength="8" autocomplete="off">

    <button class="btn-primary" id="passwordBtn">进入</button>

    <div class="error-msg" id="passwordError"></div>

  </div>

</div>


<!-- 选身份 -->

<div class="screen hidden" id="identityScreen">

  <div class="entry-box">

    <div class="entry-title">你是?</div>

    <div class="entry-sub" style="margin-bottom:28px;">选择你的身份</div>

    <div class="identity-btns">

      <button class="identity-btn" data-user="Steven">Steven</button>

      <button class="identity-btn" data-user="Holly">Holly</button>

    </div>

  </div>

</div>


<!-- 主页 -->

<div class="screen hidden" id="mainScreen">

  <div class="current-user" id="currentUser"></div>

  <div class="top-bar">

    <button class="btn-add-star" id="addStarBtn">✦ 折一颗新星星</button>

  </div>

  <div class="bottles-wrap">

    <div class="bottle-col">

      <div class="bottle-label">to Steven</div>

      <div class="glass" data-bottle="to Steven">

        <div class="glass-handle"></div>

        <div class="glass-body">

          <div class="stars-container" id="starsToSteven"></div>

        </div>

        <div class="glass-rim"></div>

        <div class="glass-base"></div>

      </div>

    </div>

    <div class="bottle-col">

      <div class="bottle-label">to Holly</div>

      <div class="glass" data-bottle="to Holly">

        <div class="glass-handle"></div>

        <div class="glass-body">

          <div class="stars-container" id="starsToHolly"></div>

        </div>

        <div class="glass-rim"></div>

        <div class="glass-base"></div>

      </div>

    </div>

  </div>

</div>


<!-- 读信弹窗 -->

<div class="modal-overlay" id="letterModal">

  <div class="letter">

    <div class="letter-from" id="letterFrom"></div>

    <div class="letter-content" id="letterContent"></div>

    <div class="letter-actions">

      <button class="btn-edit" id="editStarBtn">修改</button>

      <button class="btn-danger" id="deleteStarBtn">删除</button>

      <button class="btn-close" id="closeLetterBtn">折回去</button>

    </div>

  </div>

</div>


<!-- 写星星弹窗 -->

<div class="modal-overlay" id="writeModal">

  <div class="write-panel">

    <div class="write-title" id="writeTitle">折一颗新星星</div>

    <textarea class="write-textarea" id="writeText" placeholder="写点什么..."></textarea>

    <div class="color-picker" id="colorPicker"></div>

    <div class="letter-actions">

      <button class="btn-close" id="cancelWriteBtn">取消</button>

      <button class="btn-primary" style="margin:0; flex:1;" id="saveStarBtn">放进瓶子</button>

    </div>

  </div>

</div>


<script>

const SUPABASE_URL = 'https://hknlfxuwjwxturfbdbkg.supabase.co';

const SUPABASE_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImhrbmxmeHV3and4dHVyZmJkYmtnIiwicm9sZSI6ImFub24iLCJpYXQiOjE3OTIyMDgzNjYsImV4cCI6MjEwNzc4NDM2Nn0.sHvNHL0VZ1wIdT6oMaTNfYlBUItwhZ6i0FSpBXpCXQc';


const supabase = window.supabase.createClient(SUPABASE_URL, SUPABASE_KEY);


const PASSWORDS = ['1215', '1124'];

const COLORS = [

  { name:'淡蓝', value:'#a8d4f0' },

  { name:'淡粉', value:'#f5b8d0' },

  { name:'淡紫', value:'#c8b8e8' },

  { name:'淡黄', value:'#f5e0a0' },

  { name:'淡绿', value:'#b0e0b8' },

];


let currentUser = null;

let allStars = [];

let activeStarId = null;

let editingStarId = null;

let selectedColor = COLORS[0].value;


const $ = id => document.getElementById(id);


// ===== 入口流程 =====

$('passwordBtn').onclick = () => {

  const pw = $('passwordInput').value.trim();

  if (PASSWORDS.includes(pw)) {

    $('passwordError').textContent = '';

    $('passwordScreen').classList.add('hidden');

    $('identityScreen').classList.remove('hidden');

  } else {

    $('passwordError').textContent = '密码不对,再想想~';

    $('passwordInput').value = '';

  }

};

$('passwordInput').onkeydown = e => { if (e.key === 'Enter') $('passwordBtn').click(); };


document.querySelectorAll('.identity-btn').forEach(btn => {

  btn.onclick = () => {

    currentUser = btn.dataset.user;

    $('identityScreen').classList.add('hidden');

    $('mainScreen').classList.remove('hidden');

    $('currentUser').textContent = '你好,' + currentUser;

    loadStars();

    subscribeRealtime();

  };

});


// ===== 数据 =====

async function loadStars() {

  $('loading').classList.remove('hidden');

  const { data, error } = await supabase.from('stars').select('*').order('created_at', { ascending: true });

  $('loading').classList.add('hidden');

  if (error) { console.error(error); alert('加载失败:' + error.message); return; }

  allStars = data || [];

  renderStars();

}


function subscribeRealtime() {

  supabase.channel('stars-channel')

    .on('postgres_changes', { event: '*', schema: 'public', table: 'stars' }, () => {

      loadStars();

    })

    .subscribe();

}


// ===== 渲染星星 =====

function starSvg(color) {

  return `<svg viewBox="0 0 24 24"><path d="M12 2 L14.5 9 L22 9.5 L16 14 L18 21.5 L12 17.5 L6 21.5 L8 14 L2 9.5 L9.5 9 Z" fill="${color}" stroke="rgba(255,255,255,0.5)" stroke-width="0.8"/></svg>`;

}


function renderStars() {

  const toSteven = allStars.filter(s => s.bottle === 'to Steven');

  const toHolly = allStars.filter(s => s.bottle === 'to Holly');

  paintBottle('starsToSteven', toSteven);

  paintBottle('starsToHolly', toHolly);

}


function paintBottle(containerId, stars) {

  const box = $(containerId);

  box.innerHTML = '';

  if (stars.length === 0) {

    const hint = document.createElement('div');

    hint.className = 'empty-hint';

    hint.textContent = '还空着…';

    box.appendChild(hint);

    return;

  }

  stars.forEach((star, i) => {

    const el = document.createElement('div');

    el.className = 'star';

    el.innerHTML = starSvg(star.color);

    // 堆叠布局:底部密集,随机微散

    const total = stars.length;

    const perRow = 4;

    const row = Math.floor(i / perRow);

    const col = i % perRow;

    const xBase = 8 + col * 22 + (row % 2 ? 10 : 0);

    const yBase = 88 - row * 18;

    const jitterX = (Math.random() - 0.5) * 10;

    const jitterY = (Math.random() - 0.5) * 8;

    el.style.left = Math.min(Math.max(xBase + jitterX, 0), 82) + '%';

    el.style.bottom = Math.min(Math.max(yBase + jitterY, 0), 88) + '%';

    el.style.transform = `rotate(${(Math.random()-0.5)*60}deg)`;

    el.onclick = (e) => { e.stopPropagation(); openStar(star); };

    box.appendChild(el);

  });

}


// ===== 读星星 =====

function openStar(star) {

  activeStarId = star.id;

  $('letterFrom').textContent = star.author + ' 写于 ' + formatDate(star.created_at);

  $('letterContent').textContent = star.content;

  $('editStarBtn').style.display = star.author === currentUser ? 'block' : 'none';

  $('deleteStarBtn').style.display = star.author === currentUser ? 'block' : 'none';

  $('letterModal').classList.add('show');

}


function formatDate(ts) {

  const d = new Date(ts);

  return `${d.getFullYear()}.${String(d.getMonth()+1).padStart(2,'0')}.${String(d.getDate()).padStart(2,'0')} ${String(d.getHours()).padStart(2,'0')}:${String(d.getMinutes()).padStart(2,'0')}`;

}


$('closeLetterBtn').onclick = () => { $('letterModal').classList.remove('show'); activeStarId = null; };


$('deleteStarBtn').onclick = async () => {

  if (!activeStarId) return;

  if (!confirm('确定要撕掉这颗星星吗?')) return;

  const { error } = await supabase.from('stars').delete().eq('id', activeStarId);

  if (error) { alert('删除失败:' + error.message); return; }

  $('letterModal').classList.remove('show');

  activeStarId = null;

  loadStars();

};


$('editStarBtn').onclick = () => {

  const star = allStars.find(s => s.id === activeStarId);

  if (!star) return;

  $('letterModal').classList.remove('show');

  openWritePanel(star);

};


// ===== 写星星 =====

$('addStarBtn').onclick = () => openWritePanel(null);


function openWritePanel(star) {

  editingStarId = star ? star.id : null;

  $('writeTitle').textContent = star ? '修改这颗星星' : '折一颗新星星';

  $('writeText').value = star ? star.content : '';

  selectedColor = star ? star.color : COLORS[0].value;

  renderColorPicker();

  $('writeModal').classList.add('show');

}


function renderColorPicker() {

  const picker = $('colorPicker');

  picker.innerHTML = '';

  COLORS.forEach(c => {

    const dot = document.createElement('div');

    dot.className = 'color-dot' + (c.value === selectedColor ? ' selected' : '');

    dot.style.background = c.value;

    dot.title = c.name;

    dot.onclick = () => { selectedColor = c.value; renderColorPicker(); };

    picker.appendChild(dot);

  });

}


$('cancelWriteBtn').onclick = () => {

  $('writeModal').classList.remove('show');

  editingStarId = null;

};


$('saveStarBtn').onclick = async () => {

  const content = $('writeText').value.trim();

  if (!content) { alert('写点什么再放进去吧~'); return; }


  if (editingStarId) {

    const { error } = await supabase.from('stars')

      .update({ content, color: selectedColor })

      .eq('id', editingStarId);

    if (error) { alert('保存失败:' + error.message); return; }

  } else {

    // 检查上限

    const targetBottle = currentUser === 'Holly' ? 'to Steven' : 'to Holly';

    const count = allStars.filter(s => s.bottle === targetBottle).length;

    if (count >= 30) { alert('这个瓶子已经装满 30 颗星星啦~'); return; }


    const { error } = await supabase.from('stars').insert({

      bottle: targetBottle,

      author: currentUser,

      content,

      color: selectedColor,

    });

    if (error) { alert('保存失败:' + error.message); return; }

  }


  $('writeModal').classList.remove('show');

  editingStarId = null;

  loadStars();

};


// 点遮罩关闭

$('letterModal').onclick = e => { if (e.target === $('letterModal')) $('closeLetterBtn').click(); };

$('writeModal').onclick = e => { if (e.target === $('writeModal')) $('cancelWriteBtn').click(); };


// 瓶子点击放大(可选交互:点瓶身打开最近一颗)

document.querySelectorAll('.glass').forEach(g => {

  g.onclick = () => {

    const bottleName = g.dataset.bottle;

    const stars = allStars.filter(s => s.bottle === bottleName);

    if (stars.length === 0) return;

    // 随机打开一颗

    const random = stars[Math.floor(Math.random() * stars.length)];

    openStar(random);

  };

});

</script>

</body>

</html>