更新页面效果
This commit is contained in:
@@ -0,0 +1 @@
|
||||
.admin-tabs[data-v-8b21252d] .ant-tabs-tab.ant-tabs-tab-active .ant-tabs-tab-btn{color:#a88c6b}.admin-tabs[data-v-8b21252d] .ant-tabs-ink-bar{background:#a88c6b}.admin-tabs[data-v-8b21252d] .ant-tabs-tab:hover .ant-tabs-tab-btn{color:#967b5c}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
import{y as k,d as y,e as t,x as a,z as o,A as n,B as z,C as A,b as q,k as c,q as B,r as C,D as p}from"./index-HKNS6H1K.js";const N={class:"min-h-screen w-full flex items-center justify-center bg-[#Fdfbf7] relative overflow-hidden"},S={class:"relative z-10 w-[360px] bg-white/80 backdrop-blur-xl border border-[#a88c6b]/15 rounded-3xl shadow-2xl p-9 animate-fade-up"},V={class:"mt-6 text-center"},U={__name:"AdminLogin",setup(F){const m=z(),b=A(),f=k(),i=C(!1),r=B({account:"",password:""}),x=async()=>{var u,e;i.value=!0;try{await f.login(r),p.success("登录成功"),m.replace(b.query.redirect||"/admin")}catch(s){const l=((e=(u=s==null?void 0:s.response)==null?void 0:u.data)==null?void 0:e.error)||(s==null?void 0:s.message)||"登录失败";p.error(l)}finally{i.value=!1}};return(u,e)=>{const s=n("a-input"),l=n("a-form-item"),g=n("a-input-password"),v=n("a-button"),_=n("a-form"),w=n("router-link");return q(),y("div",N,[e[7]||(e[7]=t("div",{class:"absolute -top-24 -right-24 w-80 h-80 rounded-full bg-[#a88c6b]/10 blur-3xl"},null,-1)),e[8]||(e[8]=t("div",{class:"absolute -bottom-24 -left-24 w-80 h-80 rounded-full bg-[#e8a5b2]/10 blur-3xl"},null,-1)),e[9]||(e[9]=t("div",{class:"absolute inset-0 pointer-events-none opacity-[0.04]",style:{"background-image":"radial-gradient(#a88c6b 1px, transparent 1px)","background-size":"22px 22px"}},null,-1)),t("div",S,[e[6]||(e[6]=t("div",{class:"text-center mb-8"},[t("div",{class:"text-3xl mb-3 text-[#a88c6b] font-serif"},"❀"),t("h1",{class:"text-xl tracking-[0.3em] text-[#2c2c2c] font-light"},"婚礼纪 · 后台"),t("p",{class:"text-[11px] text-[#8A8680] tracking-[0.3em] mt-2 uppercase"},"Admin Console")],-1)),a(_,{model:r,layout:"vertical",onFinish:x},{default:o(()=>[a(l,{name:"account",rules:[{required:!0,message:"请输入账号"}]},{default:o(()=>[a(s,{value:r.account,"onUpdate:value":e[0]||(e[0]=d=>r.account=d),size:"large",placeholder:"管理员账号"},{prefix:o(()=>[...e[2]||(e[2]=[t("i",{class:"fa-solid fa-user text-[#a88c6b]"},null,-1)])]),_:1},8,["value"])]),_:1}),a(l,{name:"password",rules:[{required:!0,message:"请输入密码"}]},{default:o(()=>[a(g,{value:r.password,"onUpdate:value":e[1]||(e[1]=d=>r.password=d),size:"large",placeholder:"密码"},{prefix:o(()=>[...e[3]||(e[3]=[t("i",{class:"fa-solid fa-lock text-[#a88c6b]"},null,-1)])]),_:1},8,["value"])]),_:1}),a(v,{type:"primary","html-type":"submit",size:"large",block:"",loading:i.value,class:"!bg-[#a88c6b] hover:!bg-[#967b5c] !border-[#a88c6b] !rounded-xl !tracking-[0.2em]"},{default:o(()=>[...e[4]||(e[4]=[c(" 登 录 ",-1)])]),_:1},8,["loading"])]),_:1},8,["model"]),t("div",V,[a(w,{to:"/",class:"text-[12px] text-[#a88c6b] hover:underline"},{default:o(()=>[...e[5]||(e[5]=[c("返回请柬预览",-1)])]),_:1})])])])}}};export{U as default};
|
||||
@@ -0,0 +1 @@
|
||||
const n=[{value:"none",label:"无边框"},{value:"thin",label:"细金线"},{value:"mat",label:"白卡纸"},{value:"rounded",label:"柔圆角"},{value:"double",label:"双线框"},{value:"gold",label:"古典金框"}];function r(e){return"gf-frame gf-"+(n.some(a=>a.value===e)?e:"mat")}const u=(e,l)=>{const a=e.__vccOpts||e;for(const[o,t]of l)a[o]=t;return a};export{n as B,u as _,r as b};
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
514
vite-tailwindcss/dist-chk-1785462736/assets/index-HKNS6H1K.js
Normal file
514
vite-tailwindcss/dist-chk-1785462736/assets/index-HKNS6H1K.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
14
vite-tailwindcss/dist-chk-1785462736/index.html
Normal file
14
vite-tailwindcss/dist-chk-1785462736/index.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>婚礼请柬 · Wedding Invitation</title>
|
||||
<script type="module" crossorigin src="/assets/index-HKNS6H1K.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-DjNxM5ZE.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
</body>
|
||||
1
vite-tailwindcss/dist-chk-1785462736/vite.svg
Normal file
1
vite-tailwindcss/dist-chk-1785462736/vite.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
.admin-tabs[data-v-8b21252d] .ant-tabs-tab.ant-tabs-tab-active .ant-tabs-tab-btn{color:#a88c6b}.admin-tabs[data-v-8b21252d] .ant-tabs-ink-bar{background:#a88c6b}.admin-tabs[data-v-8b21252d] .ant-tabs-tab:hover .ant-tabs-tab-btn{color:#967b5c}
|
||||
@@ -0,0 +1 @@
|
||||
import{y as k,d as y,e as t,x as a,z as o,A as n,B as z,C as A,b as q,k as c,q as B,r as C,D as p}from"./index-Cy2RptFJ.js";const N={class:"min-h-screen w-full flex items-center justify-center bg-[#Fdfbf7] relative overflow-hidden"},S={class:"relative z-10 w-[360px] bg-white/80 backdrop-blur-xl border border-[#a88c6b]/15 rounded-3xl shadow-2xl p-9 animate-fade-up"},V={class:"mt-6 text-center"},U={__name:"AdminLogin",setup(F){const m=z(),b=A(),f=k(),i=C(!1),r=B({account:"",password:""}),x=async()=>{var u,e;i.value=!0;try{await f.login(r),p.success("登录成功"),m.replace(b.query.redirect||"/admin")}catch(s){const l=((e=(u=s==null?void 0:s.response)==null?void 0:u.data)==null?void 0:e.error)||(s==null?void 0:s.message)||"登录失败";p.error(l)}finally{i.value=!1}};return(u,e)=>{const s=n("a-input"),l=n("a-form-item"),g=n("a-input-password"),v=n("a-button"),_=n("a-form"),w=n("router-link");return q(),y("div",N,[e[7]||(e[7]=t("div",{class:"absolute -top-24 -right-24 w-80 h-80 rounded-full bg-[#a88c6b]/10 blur-3xl"},null,-1)),e[8]||(e[8]=t("div",{class:"absolute -bottom-24 -left-24 w-80 h-80 rounded-full bg-[#e8a5b2]/10 blur-3xl"},null,-1)),e[9]||(e[9]=t("div",{class:"absolute inset-0 pointer-events-none opacity-[0.04]",style:{"background-image":"radial-gradient(#a88c6b 1px, transparent 1px)","background-size":"22px 22px"}},null,-1)),t("div",S,[e[6]||(e[6]=t("div",{class:"text-center mb-8"},[t("div",{class:"text-3xl mb-3 text-[#a88c6b] font-serif"},"❀"),t("h1",{class:"text-xl tracking-[0.3em] text-[#2c2c2c] font-light"},"婚礼纪 · 后台"),t("p",{class:"text-[11px] text-[#8A8680] tracking-[0.3em] mt-2 uppercase"},"Admin Console")],-1)),a(_,{model:r,layout:"vertical",onFinish:x},{default:o(()=>[a(l,{name:"account",rules:[{required:!0,message:"请输入账号"}]},{default:o(()=>[a(s,{value:r.account,"onUpdate:value":e[0]||(e[0]=d=>r.account=d),size:"large",placeholder:"管理员账号"},{prefix:o(()=>[...e[2]||(e[2]=[t("i",{class:"fa-solid fa-user text-[#a88c6b]"},null,-1)])]),_:1},8,["value"])]),_:1}),a(l,{name:"password",rules:[{required:!0,message:"请输入密码"}]},{default:o(()=>[a(g,{value:r.password,"onUpdate:value":e[1]||(e[1]=d=>r.password=d),size:"large",placeholder:"密码"},{prefix:o(()=>[...e[3]||(e[3]=[t("i",{class:"fa-solid fa-lock text-[#a88c6b]"},null,-1)])]),_:1},8,["value"])]),_:1}),a(v,{type:"primary","html-type":"submit",size:"large",block:"",loading:i.value,class:"!bg-[#a88c6b] hover:!bg-[#967b5c] !border-[#a88c6b] !rounded-xl !tracking-[0.2em]"},{default:o(()=>[...e[4]||(e[4]=[c(" 登 录 ",-1)])]),_:1},8,["loading"])]),_:1},8,["model"]),t("div",V,[a(w,{to:"/",class:"text-[12px] text-[#a88c6b] hover:underline"},{default:o(()=>[...e[5]||(e[5]=[c("返回请柬预览",-1)])]),_:1})])])])}}};export{U as default};
|
||||
@@ -0,0 +1 @@
|
||||
const n=[{value:"none",label:"无边框"},{value:"thin",label:"细金线"},{value:"mat",label:"白卡纸"},{value:"rounded",label:"柔圆角"},{value:"double",label:"双线框"},{value:"gold",label:"古典金框"}];function r(e){return"gf-frame gf-"+(n.some(a=>a.value===e)?e:"mat")}const u=(e,l)=>{const a=e.__vccOpts||e;for(const[o,t]of l)a[o]=t;return a};export{n as B,u as _,r as b};
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
514
vite-tailwindcss/dist-chk-1785463334/assets/index-Cy2RptFJ.js
Normal file
514
vite-tailwindcss/dist-chk-1785463334/assets/index-Cy2RptFJ.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
14
vite-tailwindcss/dist-chk-1785463334/index.html
Normal file
14
vite-tailwindcss/dist-chk-1785463334/index.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>婚礼请柬 · Wedding Invitation</title>
|
||||
<script type="module" crossorigin src="/assets/index-Cy2RptFJ.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-B8bH8RjL.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
</body>
|
||||
1
vite-tailwindcss/dist-chk-1785463334/vite.svg
Normal file
1
vite-tailwindcss/dist-chk-1785463334/vite.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1 @@
|
||||
.admin-tabs[data-v-8b21252d] .ant-tabs-tab.ant-tabs-tab-active .ant-tabs-tab-btn{color:#a88c6b}.admin-tabs[data-v-8b21252d] .ant-tabs-ink-bar{background:#a88c6b}.admin-tabs[data-v-8b21252d] .ant-tabs-tab:hover .ant-tabs-tab-btn{color:#967b5c}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
import{x as k,d as y,e as t,q as a,y as o,z as n,A as z,B as A,b as q,k as c,p as B,r as C,C as p}from"./index-J-2DY0cU.js";const N={class:"min-h-screen w-full flex items-center justify-center bg-[#Fdfbf7] relative overflow-hidden"},S={class:"relative z-10 w-[360px] bg-white/80 backdrop-blur-xl border border-[#a88c6b]/15 rounded-3xl shadow-2xl p-9 animate-fade-up"},V={class:"mt-6 text-center"},U={__name:"AdminLogin",setup(F){const m=z(),b=A(),f=k(),i=C(!1),r=B({account:"",password:""}),x=async()=>{var u,e;i.value=!0;try{await f.login(r),p.success("登录成功"),m.replace(b.query.redirect||"/admin")}catch(s){const l=((e=(u=s==null?void 0:s.response)==null?void 0:u.data)==null?void 0:e.error)||(s==null?void 0:s.message)||"登录失败";p.error(l)}finally{i.value=!1}};return(u,e)=>{const s=n("a-input"),l=n("a-form-item"),g=n("a-input-password"),v=n("a-button"),_=n("a-form"),w=n("router-link");return q(),y("div",N,[e[7]||(e[7]=t("div",{class:"absolute -top-24 -right-24 w-80 h-80 rounded-full bg-[#a88c6b]/10 blur-3xl"},null,-1)),e[8]||(e[8]=t("div",{class:"absolute -bottom-24 -left-24 w-80 h-80 rounded-full bg-[#e8a5b2]/10 blur-3xl"},null,-1)),e[9]||(e[9]=t("div",{class:"absolute inset-0 pointer-events-none opacity-[0.04]",style:{"background-image":"radial-gradient(#a88c6b 1px, transparent 1px)","background-size":"22px 22px"}},null,-1)),t("div",S,[e[6]||(e[6]=t("div",{class:"text-center mb-8"},[t("div",{class:"text-3xl mb-3 text-[#a88c6b] font-serif"},"❀"),t("h1",{class:"text-xl tracking-[0.3em] text-[#2c2c2c] font-light"},"婚礼纪 · 后台"),t("p",{class:"text-[11px] text-[#8A8680] tracking-[0.3em] mt-2 uppercase"},"Admin Console")],-1)),a(_,{model:r,layout:"vertical",onFinish:x},{default:o(()=>[a(l,{name:"account",rules:[{required:!0,message:"请输入账号"}]},{default:o(()=>[a(s,{value:r.account,"onUpdate:value":e[0]||(e[0]=d=>r.account=d),size:"large",placeholder:"管理员账号"},{prefix:o(()=>[...e[2]||(e[2]=[t("i",{class:"fa-solid fa-user text-[#a88c6b]"},null,-1)])]),_:1},8,["value"])]),_:1}),a(l,{name:"password",rules:[{required:!0,message:"请输入密码"}]},{default:o(()=>[a(g,{value:r.password,"onUpdate:value":e[1]||(e[1]=d=>r.password=d),size:"large",placeholder:"密码"},{prefix:o(()=>[...e[3]||(e[3]=[t("i",{class:"fa-solid fa-lock text-[#a88c6b]"},null,-1)])]),_:1},8,["value"])]),_:1}),a(v,{type:"primary","html-type":"submit",size:"large",block:"",loading:i.value,class:"!bg-[#a88c6b] hover:!bg-[#967b5c] !border-[#a88c6b] !rounded-xl !tracking-[0.2em]"},{default:o(()=>[...e[4]||(e[4]=[c(" 登 录 ",-1)])]),_:1},8,["loading"])]),_:1},8,["model"]),t("div",V,[a(w,{to:"/",class:"text-[12px] text-[#a88c6b] hover:underline"},{default:o(()=>[...e[5]||(e[5]=[c("返回请柬预览",-1)])]),_:1})])])])}}};export{U as default};
|
||||
@@ -0,0 +1 @@
|
||||
const n=[{value:"none",label:"无边框"},{value:"thin",label:"细金线"},{value:"mat",label:"白卡纸"},{value:"rounded",label:"柔圆角"},{value:"double",label:"双线框"},{value:"gold",label:"古典金框"}];function r(e){return"gf-frame gf-"+(n.some(a=>a.value===e)?e:"mat")}const u=(e,l)=>{const a=e.__vccOpts||e;for(const[o,t]of l)a[o]=t;return a};export{n as B,u as _,r as b};
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
14
vite-tailwindcss/dist-chk-1785464315/index.html
Normal file
14
vite-tailwindcss/dist-chk-1785464315/index.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>婚礼请柬 · Wedding Invitation</title>
|
||||
<script type="module" crossorigin src="/assets/index-J-2DY0cU.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-B8bH8RjL.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
</body>
|
||||
1
vite-tailwindcss/dist-chk-1785464315/vite.svg
Normal file
1
vite-tailwindcss/dist-chk-1785464315/vite.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
.admin-tabs[data-v-0b99ae25] .ant-tabs-tab.ant-tabs-tab-active .ant-tabs-tab-btn{color:#a88c6b}.admin-tabs[data-v-0b99ae25] .ant-tabs-ink-bar{background:#a88c6b}.admin-tabs[data-v-0b99ae25] .ant-tabs-tab:hover .ant-tabs-tab-btn{color:#967b5c}
|
||||
@@ -1 +0,0 @@
|
||||
import{y as k,d as y,e as t,l as a,m as o,q as n,z,A,b as q,j as c,s as B,r as C,B as p}from"./index-BLDegpD4.js";const N={class:"min-h-screen w-full flex items-center justify-center bg-[#Fdfbf7] relative overflow-hidden"},S={class:"relative z-10 w-[360px] bg-white/80 backdrop-blur-xl border border-[#a88c6b]/15 rounded-3xl shadow-2xl p-9 animate-fade-up"},V={class:"mt-6 text-center"},R={__name:"AdminLogin",setup(j){const m=z(),b=A(),f=k(),i=C(!1),r=B({account:"",password:""}),x=async()=>{var u,e;i.value=!0;try{await f.login(r),p.success("登录成功"),m.replace(b.query.redirect||"/admin")}catch(s){const l=((e=(u=s==null?void 0:s.response)==null?void 0:u.data)==null?void 0:e.error)||(s==null?void 0:s.message)||"登录失败";p.error(l)}finally{i.value=!1}};return(u,e)=>{const s=n("a-input"),l=n("a-form-item"),g=n("a-input-password"),v=n("a-button"),_=n("a-form"),w=n("router-link");return q(),y("div",N,[e[7]||(e[7]=t("div",{class:"absolute -top-24 -right-24 w-80 h-80 rounded-full bg-[#a88c6b]/10 blur-3xl"},null,-1)),e[8]||(e[8]=t("div",{class:"absolute -bottom-24 -left-24 w-80 h-80 rounded-full bg-[#e8a5b2]/10 blur-3xl"},null,-1)),e[9]||(e[9]=t("div",{class:"absolute inset-0 pointer-events-none opacity-[0.04]",style:{"background-image":"radial-gradient(#a88c6b 1px, transparent 1px)","background-size":"22px 22px"}},null,-1)),t("div",S,[e[6]||(e[6]=t("div",{class:"text-center mb-8"},[t("div",{class:"text-3xl mb-3 text-[#a88c6b] font-serif"},"❀"),t("h1",{class:"text-xl tracking-[0.3em] text-[#2c2c2c] font-light"},"婚礼纪 · 后台"),t("p",{class:"text-[11px] text-[#8A8680] tracking-[0.3em] mt-2 uppercase"},"Admin Console")],-1)),a(_,{model:r,layout:"vertical",onFinish:x},{default:o(()=>[a(l,{name:"account",rules:[{required:!0,message:"请输入账号"}]},{default:o(()=>[a(s,{value:r.account,"onUpdate:value":e[0]||(e[0]=d=>r.account=d),size:"large",placeholder:"管理员账号"},{prefix:o(()=>[...e[2]||(e[2]=[t("i",{class:"fa-solid fa-user text-[#a88c6b]"},null,-1)])]),_:1},8,["value"])]),_:1}),a(l,{name:"password",rules:[{required:!0,message:"请输入密码"}]},{default:o(()=>[a(g,{value:r.password,"onUpdate:value":e[1]||(e[1]=d=>r.password=d),size:"large",placeholder:"密码"},{prefix:o(()=>[...e[3]||(e[3]=[t("i",{class:"fa-solid fa-lock text-[#a88c6b]"},null,-1)])]),_:1},8,["value"])]),_:1}),a(v,{type:"primary","html-type":"submit",size:"large",block:"",loading:i.value,class:"!bg-[#a88c6b] hover:!bg-[#967b5c] !border-[#a88c6b] !rounded-xl !tracking-[0.2em]"},{default:o(()=>[...e[4]||(e[4]=[c(" 登 录 ",-1)])]),_:1},8,["loading"])]),_:1},8,["model"]),t("div",V,[a(w,{to:"/",class:"text-[12px] text-[#a88c6b] hover:underline"},{default:o(()=>[...e[5]||(e[5]=[c("返回请柬预览",-1)])]),_:1})])])])}}};export{R as default};
|
||||
@@ -1 +0,0 @@
|
||||
const s=(t,r)=>{const o=t.__vccOpts||t;for(const[c,e]of r)o[c]=e;return o};export{s as _};
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -9,51 +9,52 @@
|
||||
|
||||
<!-- 单图(满幅带留白卡纸) -->
|
||||
<div v-if="page.type === 'single'" v-reveal="{ variant: 'scale', delay: 100 }"
|
||||
class="w-full max-w-[300px] mx-auto aspect-[4/5] bg-white p-2 shadow-sm border-[0.5px] border-[#a88c6b]/20 relative mt-6">
|
||||
<img :src="page.img1" class="w-full h-full object-cover" />
|
||||
class="w-full max-w-[300px] mx-auto aspect-[4/5] mt-6">
|
||||
<div :class="frameClass"><img :src="page.img1" /></div>
|
||||
</div>
|
||||
|
||||
<!-- 错落双图 -->
|
||||
<div v-else-if="page.type === 'overlap'" class="relative w-full h-[50vh] mt-4">
|
||||
<div v-reveal="{ variant: 'left', delay: 100 }" class="absolute top-0 right-4 w-[70%] h-[65%] shadow-md bg-white p-1 z-10 border border-[#a88c6b]/10">
|
||||
<img :src="page.img1" class="w-full h-full object-cover" />
|
||||
<div v-reveal="{ variant: 'left', delay: 100 }" class="absolute top-0 right-4 w-[70%] h-[65%] z-10" :class="frameClass">
|
||||
<img :src="page.img1" />
|
||||
</div>
|
||||
<div v-reveal="{ variant: 'right', delay: 300 }" class="absolute bottom-4 left-4 w-[60%] h-[60%] shadow-lg bg-white p-1 z-20 border border-[#a88c6b]/10">
|
||||
<img :src="page.img2" class="w-full h-full object-cover" />
|
||||
<div v-reveal="{ variant: 'right', delay: 300 }" class="absolute bottom-4 left-4 w-[60%] h-[60%] z-20" :class="frameClass">
|
||||
<img :src="page.img2" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 一大五小 -->
|
||||
<div v-else-if="page.type === 'one-large-five-small'"
|
||||
class="relative w-full aspect-square mt-6 grid grid-cols-3 grid-rows-3 gap-1.5 z-20">
|
||||
<div v-reveal="{ variant: 'scale', delay: 100 }" class="col-span-2 row-span-2 relative overflow-hidden bg-[#Fdfbf7] shadow-sm">
|
||||
<img :src="page.images[0]" class="w-full h-full object-cover hover:scale-105 transition-transform duration-1000" />
|
||||
<div v-reveal="{ variant: 'scale', delay: 100 }" class="col-span-2 row-span-2 relative" :class="frameClass">
|
||||
<img :src="page.images[0]" class="hover:scale-105 transition-transform duration-1000" />
|
||||
</div>
|
||||
<div v-for="i in [1,2,3,4,5]" :key="i" v-reveal="{ variant: 'up', delay: i * 80 }" class="relative bg-[#Fdfbf7]">
|
||||
<img :src="page.images[i]" class="w-full h-full object-cover" />
|
||||
<div v-for="i in [1,2,3,4,5]" :key="i" v-reveal="{ variant: 'up', delay: i * 80 }" class="relative" :class="frameClass">
|
||||
<img :src="page.images[i]" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 九宫格 -->
|
||||
<div v-else-if="page.type === 'nine-grid'" class="grid grid-cols-3 gap-1.5 px-4 mt-6">
|
||||
<div v-for="(img, imgIdx) in page.images" :key="imgIdx" v-reveal="{ variant: 'scale', delay: imgIdx * 60 }"
|
||||
class="aspect-square bg-[#Fdfbf7] relative rounded-sm overflow-hidden">
|
||||
<img :src="img" class="w-full h-full object-cover hover:scale-105 transition-transform duration-700" />
|
||||
class="aspect-square relative" :class="frameClass">
|
||||
<img :src="img" class="hover:scale-105 transition-transform duration-700" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 瀑布流(错落多列) -->
|
||||
<div v-else-if="page.type === 'masonry'" class="g-masonry mt-6 px-1">
|
||||
<div v-for="(img, imgIdx) in page.images" :key="imgIdx" v-reveal="{ variant: 'up', delay: imgIdx * 50 }" class="g-masonry-item">
|
||||
<img :src="img" class="w-full block" />
|
||||
<div v-for="(img, imgIdx) in page.images" :key="imgIdx" v-reveal="{ variant: 'up', delay: imgIdx * 50 }"
|
||||
class="g-masonry-item" :class="frameClass">
|
||||
<img :src="img" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 轮播滑动 -->
|
||||
<div v-else-if="page.type === 'carousel'" class="relative mt-6">
|
||||
<div ref="trackRef" class="g-carousel-track no-scrollbar" @scroll="onScroll">
|
||||
<div v-for="(img, imgIdx) in page.images" :key="imgIdx" class="g-carousel-slide">
|
||||
<img :src="img" class="w-full h-full object-cover" />
|
||||
<div v-for="(img, imgIdx) in page.images" :key="imgIdx" class="g-carousel-slide" :class="frameClass">
|
||||
<img :src="img" />
|
||||
</div>
|
||||
</div>
|
||||
<button class="g-arrow g-prev" @click="goTo(index - 1)" aria-label="上一张">‹</button>
|
||||
@@ -64,7 +65,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 拍立得拼贴 -->
|
||||
<!-- 拍立得拼贴(自带边框,不受 borderStyle 影响) -->
|
||||
<div v-else-if="page.type === 'polaroid'" class="g-polaroid mt-6">
|
||||
<div v-for="(img, imgIdx) in page.images" :key="imgIdx" v-reveal="{ variant: 'scale', delay: imgIdx * 70 }"
|
||||
class="g-polaroid-item" :style="{ transform: polaroidTransform(imgIdx) }">
|
||||
@@ -78,12 +79,16 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { ref, computed } from 'vue'
|
||||
import { borderClass } from '@/composables/borderStyles'
|
||||
|
||||
const props = defineProps({
|
||||
page: { type: Object, required: true },
|
||||
})
|
||||
|
||||
// 边框样式:前台按 page.borderStyle 套用全局 gf-* 类
|
||||
const frameClass = computed(() => borderClass(props.page.borderStyle))
|
||||
|
||||
/* ---------- 轮播状态 ---------- */
|
||||
const index = ref(0)
|
||||
const trackRef = ref(null)
|
||||
@@ -117,8 +122,7 @@ function polaroidTransform(i) {
|
||||
|
||||
/* 瀑布流 */
|
||||
.g-masonry { column-count: 2; column-gap: 10px; }
|
||||
.g-masonry-item { break-inside: avoid; margin-bottom: 10px; border-radius: 6px; overflow: hidden; background: #Fdfbf7; box-shadow: 0 1px 4px rgba(0,0,0,0.05); }
|
||||
.g-masonry-item img { display: block; }
|
||||
.g-masonry-item { break-inside: avoid; margin-bottom: 10px; border-radius: 6px; }
|
||||
|
||||
/* 轮播 */
|
||||
.g-carousel-track {
|
||||
|
||||
14
vite-tailwindcss/src/composables/borderStyles.js
Normal file
14
vite-tailwindcss/src/composables/borderStyles.js
Normal file
@@ -0,0 +1,14 @@
|
||||
// 相册边框样式定义:供前台 PhotoGallery 渲染与后台 AdminEditor 配置/预览共用
|
||||
export const BORDER_STYLES = [
|
||||
{ value: 'none', label: '无边框' },
|
||||
{ value: 'thin', label: '细金线' },
|
||||
{ value: 'mat', label: '白卡纸' },
|
||||
{ value: 'rounded', label: '柔圆角' },
|
||||
{ value: 'double', label: '双线框' },
|
||||
{ value: 'gold', label: '古典金框' },
|
||||
]
|
||||
|
||||
export function borderClass(style) {
|
||||
const v = BORDER_STYLES.some((b) => b.value === style) ? style : 'mat'
|
||||
return 'gf-frame gf-' + v
|
||||
}
|
||||
@@ -62,6 +62,18 @@ export function useAudio() {
|
||||
}
|
||||
|
||||
const play = () => playUrl(activeUrl.value)
|
||||
|
||||
// 尝试自动播放,返回是否成功(被浏览器拦截则返回 false,由调用方决定是否弹授权框)
|
||||
const attemptAutoplay = async () => {
|
||||
if (!activeUrl.value) return false
|
||||
try {
|
||||
await playUrl(activeUrl.value)
|
||||
return isPlaying.value
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
const pause = () => {
|
||||
if (audio) audio.pause()
|
||||
isPlaying.value = false
|
||||
@@ -98,5 +110,5 @@ export function useAudio() {
|
||||
}
|
||||
})
|
||||
|
||||
return { isPlaying, isReady, tracks, activeUrl, currentName, setTracks, setActive, play, pause, toggle, armAutoplay }
|
||||
return { isPlaying, isReady, tracks, activeUrl, currentName, setTracks, setActive, play, pause, toggle, attemptAutoplay, armAutoplay }
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { createPinia } from 'pinia'
|
||||
import Antd from 'ant-design-vue'
|
||||
import './style.css'
|
||||
import './styles/animations.css'
|
||||
import './styles/frames.css'
|
||||
import App from './App.vue'
|
||||
import '@fortawesome/fontawesome-free/css/all.css' // 引入所有样式
|
||||
// 注册路由
|
||||
|
||||
@@ -25,36 +25,41 @@
|
||||
.reveal { opacity: 1 !important; transform: none !important; filter: none !important; transition: none; }
|
||||
}
|
||||
|
||||
/* ---------- 飘落花瓣 ---------- */
|
||||
/* ---------- 飘落花瓣(优雅:柔和渐变 + 轻微摇曳) ---------- */
|
||||
@keyframes petalFall {
|
||||
0% { transform: translate3d(0, -12vh, 0) rotate(0deg); opacity: 0; }
|
||||
8% { opacity: 0.9; }
|
||||
90% { opacity: 0.85; }
|
||||
100% { transform: translate3d(8vw, 112vh, 0) rotate(420deg); opacity: 0; }
|
||||
10% { opacity: 0.85; }
|
||||
90% { opacity: 0.7; }
|
||||
100% { transform: translate3d(6vw, 112vh, 0) rotate(360deg); opacity: 0; }
|
||||
}
|
||||
@keyframes petalDrift {
|
||||
0%, 100% { margin-left: -14px; }
|
||||
50% { margin-left: 14px; }
|
||||
}
|
||||
.petal {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
pointer-events: none;
|
||||
will-change: transform, opacity;
|
||||
animation: petalFall linear infinite;
|
||||
animation:
|
||||
petalFall var(--p-dur, 12s) linear infinite,
|
||||
petalDrift var(--p-sway, 6s) ease-in-out infinite alternate;
|
||||
}
|
||||
|
||||
/* ---------- 漂浮爱心 ---------- */
|
||||
/* ---------- 漂浮爱心(全屏自然上升,随机分布) ---------- */
|
||||
@keyframes heartFloat {
|
||||
0% { transform: translateY(110%) translateX(0) scale(0.8); opacity: 0; }
|
||||
10% { opacity: 0.85; }
|
||||
50% { transform: translateY(45%) translateX(14px) scale(1); }
|
||||
90% { opacity: 0.7; }
|
||||
100% { transform: translateY(-15%) translateX(-10px) scale(1.1); opacity: 0; }
|
||||
0% { transform: translateY(20px) translateX(0) scale(0.7); opacity: 0; }
|
||||
12% { opacity: 0.8; }
|
||||
85% { opacity: 0.6; }
|
||||
100% { transform: translateY(-118vh) translateX(24px) scale(1.1); opacity: 0; }
|
||||
}
|
||||
@keyframes heartSway {
|
||||
0% { margin-left: -18px; }
|
||||
100% { margin-left: 18px; }
|
||||
0%, 100% { margin-left: -16px; }
|
||||
50% { margin-left: 16px; }
|
||||
}
|
||||
.heart-bubble {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
will-change: transform, opacity;
|
||||
animation:
|
||||
heartFloat var(--float-duration, 18s) linear infinite,
|
||||
heartSway var(--sway-duration, 5s) ease-in-out infinite alternate;
|
||||
|
||||
71
vite-tailwindcss/src/styles/frames.css
Normal file
71
vite-tailwindcss/src/styles/frames.css
Normal file
@@ -0,0 +1,71 @@
|
||||
/* ============================================================
|
||||
相册边框样式(全局)
|
||||
- 前台 PhotoGallery 按 page.borderStyle 套用
|
||||
- 后台 AdminEditor 预览复用同一套类
|
||||
结构约定:<div class="gf-frame gf-xxx"><img/></div>
|
||||
gf-frame 负责定位与裁切,gf-xxx 负责边框/卡纸/投影
|
||||
============================================================ */
|
||||
.gf-frame {
|
||||
position: relative;
|
||||
background: #fff;
|
||||
overflow: hidden;
|
||||
}
|
||||
.gf-frame > img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
/* 无边框 */
|
||||
.gf-none {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* 细金线 */
|
||||
.gf-thin {
|
||||
padding: 0;
|
||||
border: 1px solid #cdb89c;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 10px rgba(120, 90, 60, 0.08);
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
/* 白卡纸(经典裱框) */
|
||||
.gf-mat {
|
||||
padding: 8px;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 6px 20px rgba(120, 90, 60, 0.12);
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
/* 柔圆角 */
|
||||
.gf-rounded {
|
||||
padding: 0;
|
||||
border: 1px solid rgba(168, 140, 107, 0.4);
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 8px 24px rgba(120, 90, 60, 0.1);
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
/* 双线框 */
|
||||
.gf-double {
|
||||
padding: 6px;
|
||||
border: 3px double #b89a78;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 4px 16px rgba(120, 90, 60, 0.1);
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
/* 古典金框(外白 + 金线双层) */
|
||||
.gf-gold {
|
||||
padding: 7px;
|
||||
border: 2px solid #c9a978;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 0 0 4px #fff, 0 0 0 5px #e7d6bb, 0 8px 22px rgba(120, 90, 60, 0.12);
|
||||
background: #fff;
|
||||
}
|
||||
@@ -170,6 +170,21 @@
|
||||
</div>
|
||||
</a-form-item>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-6 items-start">
|
||||
<a-form-item label="边框样式">
|
||||
<a-select v-model:value="page.borderStyle">
|
||||
<a-select-option v-for="b in BORDER_STYLES" :key="b.value" :value="b.value">{{ b.label }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="text-[11px] text-[#a88c6b]">预览</span>
|
||||
<div class="w-[70px] h-[88px] shrink-0">
|
||||
<div :class="borderClass(page.borderStyle)" style="width:100%;height:100%">
|
||||
<img src="https://images.unsplash.com/photo-1519741497674-611481863552?auto=format&fit=crop&w=200&q=80" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-6">
|
||||
<a-form-item label="小标题 (英文)">
|
||||
<a-input v-model:value="page.subtitle" />
|
||||
@@ -258,6 +273,7 @@ import { message } from 'ant-design-vue'
|
||||
import { getConfig, saveConfig, uploadImage, getRsvpList } from '@/api/wedding'
|
||||
import { useAdminStore } from '@/stores/admin'
|
||||
import ImageField from '@/components/ImageField.vue'
|
||||
import { BORDER_STYLES, borderClass } from '@/composables/borderStyles'
|
||||
|
||||
const router = useRouter()
|
||||
const adminStore = useAdminStore()
|
||||
@@ -280,10 +296,10 @@ function defaultConfig() {
|
||||
activeMusicUrl: 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3',
|
||||
scrollMode: 'snap', petalEnabled: true, bubbleEnabled: true, introEnabled: true,
|
||||
photoPages: [
|
||||
{ type: 'single', title: '初遇', subtitle: 'FIRST MET', desc: '世界那么大,还是遇见了你。\n于千万人之中,没有早一步也没有晚一步。', img1: 'https://images.unsplash.com/photo-1606800052052-a08af7148866?auto=format&fit=crop&w=600&q=80', height: '100vh' },
|
||||
{ type: 'overlap', title: '相知', subtitle: 'FALL IN LOVE', desc: '纵然万劫不复,纵然相思入骨。\n我也待你眉眼如初,岁月如故。', img1: 'https://images.unsplash.com/photo-1532712938310-34cb3982ef74?auto=format&fit=crop&w=600&q=80', img2: 'https://images.unsplash.com/photo-1511285560929-80b456fea0bc?auto=format&fit=crop&w=600&q=80', height: '100vh' },
|
||||
{ type: 'one-large-five-small', title: '相恋', subtitle: 'ROMANCE', desc: '星光坠入眼眸,晚风轻抚过裙摆。\n浪漫不止于此,还有无数个明天。', images: fill(6), height: '100vh' },
|
||||
{ type: 'nine-grid', title: '相守', subtitle: 'FOREVER', desc: '往后余生,风雪是你,平淡是你。', images: fill(9), height: '100vh' },
|
||||
{ type: 'single', title: '初遇', subtitle: 'FIRST MET', desc: '世界那么大,还是遇见了你。\n于千万人之中,没有早一步也没有晚一步。', img1: 'https://images.unsplash.com/photo-1606800052052-a08af7148866?auto=format&fit=crop&w=600&q=80', height: '100vh', borderStyle: 'mat' },
|
||||
{ type: 'overlap', title: '相知', subtitle: 'FALL IN LOVE', desc: '纵然万劫不复,纵然相思入骨。\n我也待你眉眼如初,岁月如故。', img1: 'https://images.unsplash.com/photo-1532712938310-34cb3982ef74?auto=format&fit=crop&w=600&q=80', img2: 'https://images.unsplash.com/photo-1511285560929-80b456fea0bc?auto=format&fit=crop&w=600&q=80', height: '100vh', borderStyle: 'mat' },
|
||||
{ type: 'one-large-five-small', title: '相恋', subtitle: 'ROMANCE', desc: '星光坠入眼眸,晚风轻抚过裙摆。\n浪漫不止于此,还有无数个明天。', images: fill(6), height: '100vh', borderStyle: 'mat' },
|
||||
{ type: 'nine-grid', title: '相守', subtitle: 'FOREVER', desc: '往后余生,风雪是你,平淡是你。', images: fill(9), height: '100vh', borderStyle: 'mat' },
|
||||
],
|
||||
schedule: [
|
||||
{ time: '16:00', event: '签到迎宾', desc: 'Welcome' },
|
||||
@@ -337,6 +353,7 @@ function ensurePageShape(p) {
|
||||
}
|
||||
p.title = p.title || ''; p.subtitle = p.subtitle || ''; p.desc = p.desc || ''
|
||||
p.height = p.height || '100vh'
|
||||
p.borderStyle = p.borderStyle || 'mat'
|
||||
return p
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
<template>
|
||||
<div class="wrapper relative w-full h-[100vh] bg-[#Fdfbf7] overflow-hidden text-[#2c2c2c]">
|
||||
|
||||
<!-- 入场揭幕帘幕(双开门 + 印章徽标) -->
|
||||
<!-- 入场揭幕帘幕(雅致双开门 + 徽标) -->
|
||||
<div v-show="showIntro" class="curtain-root" :class="{ 'is-opening': introOpening }" @click="openInvitation">
|
||||
<div class="curtain-bg" :style="curtainBg"></div>
|
||||
<div class="curtain-veil"></div>
|
||||
<div class="curtain-door curtain-door-left"></div>
|
||||
<div class="curtain-door curtain-door-right"></div>
|
||||
<div class="curtain-door curtain-door-left"><span class="door-sheen"></span></div>
|
||||
<div class="curtain-door curtain-door-right"><span class="door-sheen"></span></div>
|
||||
<div class="curtain-emblem">
|
||||
<div class="emblem-card">
|
||||
<span class="emblem-label">WEDDING INVITATION</span>
|
||||
<div class="emblem-seal">❀</div>
|
||||
<div class="emblem-names">{{ data.groom }} <span class="amp">&</span> {{ data.bride }}</div>
|
||||
<div class="emblem-inner">
|
||||
<span class="emblem-floral">❀</span>
|
||||
<span class="emblem-kicker">WEDDING INVITATION</span>
|
||||
<div class="emblem-names">{{ data.groom }}<span class="amp">&</span>{{ data.bride }}</div>
|
||||
<div class="emblem-rule"></div>
|
||||
<div class="emblem-date">{{ data.date }}</div>
|
||||
<div class="emblem-hint"><span class="dot"></span> 点击开启请柬</div>
|
||||
<div class="emblem-hint"><span class="dot"></span>轻触开启请柬</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -21,14 +22,19 @@
|
||||
<!-- 飘落花瓣层 -->
|
||||
<div v-if="data.petalEnabled" class="absolute inset-0 pointer-events-none overflow-hidden z-[1]">
|
||||
<div v-for="p in petals" :key="'p'+p.id" class="petal"
|
||||
:style="{ left: p.left, width: p.size+'px', height: p.size+'px', opacity: p.opacity, background: p.color, animationDuration: p.duration, animationDelay: p.delay, transform: `rotate(${p.rotate}deg)` }"></div>
|
||||
:style="{ left: p.left, width: p.size+'px', height: p.size+'px', opacity: p.opacity, animationDelay: p.delay, '--p-dur': p.duration, '--p-sway': p.sway }">
|
||||
<svg viewBox="0 0 100 100" class="w-full h-full" :style="{ filter: 'drop-shadow(0 2px 3px rgba(150,110,90,0.12))' }">
|
||||
<path d="M50 3 C28 26 20 62 50 97 C80 62 72 26 50 3 Z" :fill="p.color" opacity="0.9" />
|
||||
<path d="M50 9 C50 36 50 70 50 91" stroke="rgba(255,255,255,0.55)" stroke-width="1.4" fill="none" opacity="0.5" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 漂浮爱心层 -->
|
||||
<div v-if="data.bubbleEnabled" class="absolute inset-0 pointer-events-none overflow-hidden z-[1]">
|
||||
<div v-for="b in bubbles" :key="'b'+b.id"
|
||||
class="heart-bubble flex items-center justify-center"
|
||||
:style="{ left: b.left, color: b.color, fontSize: b.size+'px', opacity: b.opacity, '--float-duration': b.floatDuration, '--sway-duration': b.swayDuration }">♥</div>
|
||||
:style="{ left: b.left, top: b.top, color: b.color, fontSize: b.size+'px', opacity: b.opacity, animationDelay: b.delay, '--float-duration': b.floatDuration, '--sway-duration': b.swayDuration }">♥</div>
|
||||
</div>
|
||||
|
||||
<!-- 顶部滚动进度条 -->
|
||||
@@ -66,9 +72,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 低调管理入口 -->
|
||||
<router-link to="/login" class="absolute bottom-4 right-4 z-50 text-[10px] text-[#a88c6b]/50 hover:text-[#a88c6b] tracking-widest">管理后台</router-link>
|
||||
|
||||
<!-- 主滚动区域 -->
|
||||
<div ref="scrollContainerRef"
|
||||
class="w-full h-full overflow-y-auto no-scrollbar relative scroll-smooth"
|
||||
@@ -165,10 +168,11 @@
|
||||
<span class="text-[11px] text-[#8A8680] font-light tracking-[0.1em] leading-loose block max-w-[240px] mx-auto whitespace-pre-wrap">{{ data.address }}</span>
|
||||
</div>
|
||||
<div v-reveal="{ variant: 'up', delay: 300 }" class="flex flex-col gap-4 w-full px-8 max-w-[280px]">
|
||||
<div @click="isDrawerOpen = true" class="w-full bg-[#a88c6b] text-white py-4 text-[11px] tracking-[0.2em] flex items-center justify-center gap-3 shadow-md uppercase rounded-full cursor-pointer hover:bg-[#967b5c] transition-all">
|
||||
<img src="https://api.iconify.design/lucide:send.svg?color=%23ffffff" class="w-3.5 h-3.5" />
|
||||
<span>填写出席回执</span>
|
||||
</div>
|
||||
<button class="rsvp-cta" @click="isDrawerOpen = true">
|
||||
<span class="rsvp-cta-deco">❀</span>
|
||||
<span class="rsvp-cta-text">填写出席回执</span>
|
||||
<span class="rsvp-cta-line"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -178,26 +182,24 @@
|
||||
<div v-if="isDrawerOpen" class="absolute inset-0 z-[60] bg-black/40 backdrop-blur-sm transition-opacity duration-500" @click="closeDrawer"></div>
|
||||
<div class="absolute bottom-0 left-0 w-full bg-white rounded-t-[2.5rem] shadow-2xl transition-transform duration-500 z-[70] p-10 flex flex-col" :style="{ transform: isDrawerOpen ? 'translateY(0)' : 'translateY(100%)' }">
|
||||
<div @click="closeDrawer" class="absolute top-6 right-6 p-2 text-[#a88c6b] cursor-pointer hover:text-[#2c2c2c] transition-colors text-xl">✕</div>
|
||||
<span class="text-xl text-center text-[#a88c6b] mb-1 tracking-[0.3em] font-light mt-2 uppercase">Guest RSVP</span>
|
||||
<span class="text-center text-[10px] text-[#8A8680] mb-10 uppercase tracking-[0.4em]">R . S . V . P</span>
|
||||
<span class="text-xl text-center text-[#a88c6b] mb-1 tracking-[0.3em] font-light mt-2">出席回执</span>
|
||||
<span class="text-center text-[10px] text-[#8A8680] mb-10 tracking-[0.4em]">敬 请 回 复</span>
|
||||
|
||||
<div v-if="!isSubmitted" class="space-y-6">
|
||||
<div>
|
||||
<span class="block text-[10px] text-[#a88c6b] mb-1.5 tracking-widest uppercase pl-1">Name</span>
|
||||
<span class="block text-[10px] text-[#a88c6b] mb-1.5 tracking-widest pl-1">姓名</span>
|
||||
<input v-model="rsvpForm.name" placeholder="您的姓名" class="w-full bg-[#Fdfbf7] border-[0.5px] border-[#a88c6b]/30 rounded-xl px-5 py-4 text-[13px] focus:outline-none focus:border-[#a88c6b] shadow-[inset_0_2px_4px_rgba(0,0,0,0.02)]" />
|
||||
</div>
|
||||
<div>
|
||||
<span class="block text-[10px] text-[#a88c6b] mb-1.5 tracking-widest uppercase pl-1">Attendance</span>
|
||||
<div @click="isSelectOpen = !isSelectOpen" class="w-full bg-[#Fdfbf7] border-[0.5px] border-[#a88c6b]/30 rounded-xl px-5 py-4 text-[13px] flex items-center justify-between cursor-pointer">
|
||||
<span>{{ rsvpOptions.find(o => o.value === rsvpForm.guest_count)?.label || '请选择出席人数' }}</span>
|
||||
<span class="text-[#a88c6b] transition-transform" :style="{ transform: isSelectOpen ? 'rotate(180deg)' : '' }">▼</span>
|
||||
</div>
|
||||
<div v-show="isSelectOpen" class="absolute left-10 right-10 bottom-full mb-3 bg-white border border-[#a88c6b]/20 rounded-2xl shadow-2xl overflow-hidden z-[80]">
|
||||
<div v-for="opt in rsvpOptions" :key="opt.value" @click="selectRsvpCount(opt.value)" class="px-5 py-4 text-[13px] hover:bg-[#Fdfbf7] cursor-pointer" :class="rsvpForm.guest_count === opt.value ? 'text-[#a88c6b] bg-[#Fdfbf7]/50' : ''">{{ opt.label }}</div>
|
||||
<span class="block text-[10px] text-[#a88c6b] mb-2 tracking-widest pl-1">出席情况</span>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<button v-for="opt in rsvpOptions" :key="opt.value" type="button"
|
||||
class="rsvp-tag" :class="{ active: rsvpForm.guest_count === opt.value }"
|
||||
@click="rsvpForm.guest_count = opt.value">{{ opt.label }}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span class="block text-[10px] text-[#a88c6b] mb-1.5 tracking-widest uppercase pl-1">Wishes</span>
|
||||
<span class="block text-[10px] text-[#a88c6b] mb-1.5 tracking-widest pl-1">祝福语</span>
|
||||
<textarea v-model="rsvpForm.wishes" placeholder="写下您的祝福..." class="w-full bg-[#Fdfbf7] border-[0.5px] border-[#a88c6b]/30 rounded-xl px-5 py-4 text-[13px] h-24 focus:outline-none resize-none shadow-[inset_0_2px_4px_rgba(0,0,0,0.02)]"></textarea>
|
||||
</div>
|
||||
<div @click="handleSubmitRsvp" class="w-full bg-[#a88c6b] text-white py-4 rounded-full text-center tracking-[0.3em] text-[12px] cursor-pointer hover:bg-[#967b5c] transition-all shadow-md">确认发送</div>
|
||||
@@ -208,6 +210,7 @@
|
||||
<span class="text-[13px] text-[#8A8680] leading-loose tracking-widest font-light">回执已妥投,期待与您共享喜悦</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -228,19 +231,19 @@ const data = ref({
|
||||
formalText1: '两姓联姻 一堂缔约', formalText2: '良缘永结 匹配同称',
|
||||
heroImg: 'https://images.unsplash.com/photo-1583939003579-730e3918a45a?auto=format&fit=crop&w=800&q=80',
|
||||
photoPages: [
|
||||
{ type: 'single', title: '初遇', subtitle: 'FIRST MET', desc: '世界那么大,还是遇见了你。\n于千万人之中,没有早一步也没有晚一步。', img1: 'https://images.unsplash.com/photo-1606800052052-a08af7148866?auto=format&fit=crop&w=600&q=80' },
|
||||
{ type: 'overlap', title: '相知', subtitle: 'FALL IN LOVE', desc: '纵然万劫不复,纵然相思入骨。\n我也待你眉眼如初,岁月如故。', img1: 'https://images.unsplash.com/photo-1532712938310-34cb3982ef74?auto=format&fit=crop&w=600&q=80', img2: 'https://images.unsplash.com/photo-1511285560929-80b456fea0bc?auto=format&fit=crop&w=600&q=80' },
|
||||
{ type: 'one-large-five-small', title: '相恋', subtitle: 'ROMANCE', desc: '星光坠入眼眸,晚风轻抚过裙摆。\n浪漫不止于此,还有无数个明天。', images: Array.from({ length: 6 }, () => 'https://images.unsplash.com/photo-1519741497674-611481863552?auto=format&fit=crop&w=600&q=80') },
|
||||
{ type: 'nine-grid', title: '相守', subtitle: 'FOREVER', desc: '往后余生,风雪是你,平淡是你。', images: Array.from({ length: 9 }, () => 'https://images.unsplash.com/photo-1511285560929-80b456fea0bc?auto=format&fit=crop&w=400&q=80') },
|
||||
{ type: 'single', title: '初遇', subtitle: 'FIRST MET', desc: '世界那么大,还是遇见了你。\n于千万人之中,没有早一步也没有晚一步。', img1: 'https://images.unsplash.com/photo-1606800052052-a08af7148866?auto=format&fit=crop&w=600&q=80', borderStyle: 'mat' },
|
||||
{ type: 'overlap', title: '相知', subtitle: 'FALL IN LOVE', desc: '纵然万劫不复,纵然相思入骨。\n我也待你眉眼如初,岁月如故。', img1: 'https://images.unsplash.com/photo-1532712938310-34cb3982ef74?auto=format&fit=crop&w=600&q=80', img2: 'https://images.unsplash.com/photo-1511285560929-80b456fea0bc?auto=format&fit=crop&w=600&q=80', borderStyle: 'mat' },
|
||||
{ type: 'one-large-five-small', title: '相恋', subtitle: 'ROMANCE', desc: '星光坠入眼眸,晚风轻抚过裙摆。\n浪漫不止于此,还有无数个明天。', images: Array.from({ length: 6 }, () => 'https://images.unsplash.com/photo-1519741497674-611481863552?auto=format&fit=crop&w=600&q=80'), borderStyle: 'mat' },
|
||||
{ type: 'nine-grid', title: '相守', subtitle: 'FOREVER', desc: '往后余生,风雪是你,平淡是你。', images: Array.from({ length: 9 }, () => 'https://images.unsplash.com/photo-1511285560929-80b456fea0bc?auto=format&fit=crop&w=400&q=80'), borderStyle: 'mat' },
|
||||
],
|
||||
schedule: [ { time: '16:00', event: '签到迎宾', desc: 'Welcome' }, { time: '17:08', event: '仪式开始', desc: 'Ceremony' }, { time: '18:00', event: '敬备喜宴', desc: 'Banquet' } ],
|
||||
...DEFAULTS,
|
||||
})
|
||||
|
||||
const audio = useAudio()
|
||||
const isAutoScroll = ref(true), isDrawerOpen = ref(false), isSelectOpen = ref(false), isSubmitted = ref(false)
|
||||
const isAutoScroll = ref(true), isDrawerOpen = ref(false), isSubmitted = ref(false)
|
||||
const isInteracting = ref(false), scrollContainerRef = ref(null), progress = ref(0), parallax = ref(0)
|
||||
const showIntro = ref(false), introOpening = ref(false), showTrackList = ref(false)
|
||||
const showIntro = ref(false), introOpening = ref(false), showTrackList = ref(false), showMusicAuth = ref(false)
|
||||
const rsvpForm = reactive({ name: '', guest_count: '1', wishes: '' })
|
||||
const rsvpOptions = [ { value: '1', label: '1 人出席' }, { value: '2', label: '2 人出席' }, { value: '3', label: '3 人及以上' }, { value: '0', label: '遗憾缺席' } ]
|
||||
|
||||
@@ -248,8 +251,18 @@ let rafId = null, snapTimer = null, pauseTimer = null, introTimer = null
|
||||
|
||||
const loveColors = ['#a88c6b', '#e8a5b2', '#f4c2c2', '#d4af37']
|
||||
const petalColors = ['#f7d9e0', '#fbeee3', '#f3c6d3', '#efd9c4', '#f9e7d6']
|
||||
const bubbles = Array.from({ length: 15 }).map((_, i) => ({ id: i, left: Math.random() * 100 + '%', color: loveColors[i % 4], size: 14 + Math.random() * 10, opacity: 0.2, floatDuration: 14 + Math.random() * 10 + 's', swayDuration: 4 + Math.random() * 2 + 's' }))
|
||||
const petals = Array.from({ length: 18 }).map((_, i) => ({ id: i, left: Math.random() * 100 + '%', size: 10 + Math.random() * 14, opacity: 0.4 + Math.random() * 0.4, color: petalColors[i % petalColors.length], duration: 9 + Math.random() * 8 + 's', delay: Math.random() * 10 + 's', rotate: Math.random() * 360 }))
|
||||
const bubbles = Array.from({ length: 15 }).map((_, i) => ({
|
||||
id: i, left: Math.random() * 100 + '%', top: Math.random() * 100 + '%',
|
||||
color: loveColors[i % 4], size: 13 + Math.random() * 10, opacity: 0.25 + Math.random() * 0.15,
|
||||
floatDuration: (14 + Math.random() * 10) + 's', swayDuration: (4 + Math.random() * 2) + 's',
|
||||
delay: '-' + (Math.random() * 18).toFixed(1) + 's',
|
||||
}))
|
||||
const petals = Array.from({ length: 18 }).map((_, i) => ({
|
||||
id: i, left: Math.random() * 100 + '%', size: 10 + Math.random() * 14,
|
||||
opacity: 0.4 + Math.random() * 0.4, color: petalColors[i % petalColors.length],
|
||||
duration: (9 + Math.random() * 8) + 's', delay: (Math.random() * 10) + 's',
|
||||
sway: (4 + Math.random() * 4) + 's',
|
||||
}))
|
||||
|
||||
const curtainBg = computed(() => ({ backgroundImage: `url(${data.value.heroImg})` }))
|
||||
|
||||
@@ -259,8 +272,8 @@ const pageHeightStyle = (page) => {
|
||||
return h === 'auto' ? { minHeight: 'auto' } : { minHeight: h }
|
||||
}
|
||||
|
||||
const selectRsvpCount = (val) => { rsvpForm.guest_count = val; isSelectOpen.value = false }
|
||||
const closeDrawer = () => { isDrawerOpen.value = false; isSelectOpen.value = false }
|
||||
const closeDrawer = () => { isDrawerOpen.value = false }
|
||||
const authorizeMusic = () => { audio.play(); showMusicAuth.value = false }
|
||||
|
||||
const handleScroll = () => {
|
||||
const el = scrollContainerRef.value
|
||||
@@ -315,6 +328,13 @@ const openInvitation = () => {
|
||||
if (introOpening.value) return
|
||||
introOpening.value = true
|
||||
introTimer = setTimeout(() => { showIntro.value = false }, 1000)
|
||||
// 点击揭幕是明确的用户手势:直接尝试播放背景音乐(最可靠的自动播放路径)
|
||||
if (data.value.musicList.length) audio.play()
|
||||
}
|
||||
const onMusicAuthSkip = () => {
|
||||
showMusicAuth.value = false
|
||||
// 用户暂不开启:挂起首次交互解锁,后续任意点击仍可播放
|
||||
audio.armAutoplay()
|
||||
}
|
||||
const selectTrack = (url) => { audio.setActive(url); showTrackList.value = false }
|
||||
|
||||
@@ -342,10 +362,14 @@ onMounted(async () => {
|
||||
} catch (e) { /* 使用默认配置 */ }
|
||||
|
||||
audio.setTracks(data.value.musicList, data.value.activeMusicUrl)
|
||||
// 先静默尝试自动播放;被浏览器拦截(无用户手势)时,再弹出授权模态框
|
||||
if (data.value.musicList.length) {
|
||||
const autoOk = await audio.attemptAutoplay()
|
||||
if (!autoOk) showMusicAuth.value = true
|
||||
}
|
||||
if (data.value.introEnabled) {
|
||||
showIntro.value = true
|
||||
introTimer = setTimeout(() => openInvitation(), 3600)
|
||||
audio.armAutoplay()
|
||||
}
|
||||
|
||||
startAutoScroll()
|
||||
@@ -369,46 +393,77 @@ onUnmounted(() => {
|
||||
.vertical-text { writing-mode: vertical-rl; letter-spacing: 0.4em; text-orientation: upright; }
|
||||
.page-section { min-height: 100vh; width: 100%; position: relative; overflow: hidden; display: flex; flex-direction: column; justify-content: center; }
|
||||
.no-scrollbar::-webkit-scrollbar { display: none; }
|
||||
/* 花瓣形状 */
|
||||
.petal { border-radius: 0 100% 0 100%; }
|
||||
.heart-bubble { animation: heartFloat var(--float-duration, 18s) linear infinite, heartSway var(--sway-duration, 5s) ease-in-out infinite alternate; position: absolute; bottom: 0; }
|
||||
/* 花瓣形状由 SVG 决定,无需额外形状样式 */
|
||||
|
||||
/* ---------- 入场揭幕 ---------- */
|
||||
.curtain-root { position: fixed; inset: 0; z-index: 100; overflow: hidden; cursor: pointer; font-family: "PingFang SC", sans-serif; }
|
||||
/* ---------- 入场揭幕(雅致象牙金) ---------- */
|
||||
.curtain-root { position: fixed; inset: 0; z-index: 100; overflow: hidden; cursor: pointer; font-family: "PingFang SC", sans-serif; background: #fbf6ef; }
|
||||
.curtain-bg {
|
||||
position: absolute; inset: -24px; background-size: cover; background-position: center;
|
||||
filter: blur(14px) brightness(0.5) saturate(1.1); transform: scale(1.12);
|
||||
filter: blur(16px) brightness(0.7) saturate(1.05); transform: scale(1.12);
|
||||
}
|
||||
.curtain-veil { position: absolute; inset: 0; background: radial-gradient(circle at 50% 42%, rgba(0,0,0,0.15), rgba(0,0,0,0.5)); }
|
||||
.curtain-veil { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(251,246,239,0.35), rgba(232,214,194,0.25)); }
|
||||
.curtain-door {
|
||||
position: absolute; top: 0; bottom: 0; width: 50%; z-index: 2;
|
||||
background: linear-gradient(160deg, #b89a78 0%, #a88c6b 45%, #8a704f 100%);
|
||||
box-shadow: inset 0 0 60px rgba(0,0,0,0.25);
|
||||
transition: transform 1s cubic-bezier(0.76, 0, 0.24, 1);
|
||||
background: linear-gradient(160deg, #fbf6ef 0%, #f5e9dc 45%, #ecd9c4 100%);
|
||||
box-shadow: inset 0 0 50px rgba(184,154,120,0.12);
|
||||
transition: transform 1.4s cubic-bezier(0.76, 0, 0.24, 1);
|
||||
}
|
||||
.curtain-door::after { content: ''; position: absolute; top: 0; bottom: 0; width: 1px; background: rgba(255,255,255,0.18); }
|
||||
.curtain-door::before { content: ''; position: absolute; top: 0; bottom: 0; width: 1px; background: linear-gradient(180deg, transparent, rgba(184,154,120,0.5), transparent); }
|
||||
.curtain-door-left { left: 0; }
|
||||
.curtain-door-right { right: 0; }
|
||||
.curtain-door-right::after { right: 0; }
|
||||
.curtain-door-left::before { right: 0; }
|
||||
.curtain-door-right::before { left: 0; }
|
||||
.door-sheen { position: absolute; inset: 0; background: linear-gradient(115deg, rgba(255,255,255,0.5) 0%, rgba(255,255,255,0) 30%, rgba(255,255,255,0) 70%, rgba(255,255,255,0.25) 100%); }
|
||||
.curtain-root.is-opening .curtain-door-left { transform: translateX(-100%); }
|
||||
.curtain-root.is-opening .curtain-door-right { transform: translateX(100%); }
|
||||
.curtain-emblem {
|
||||
position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; z-index: 3;
|
||||
transition: opacity 0.7s ease, transform 0.9s ease; animation: emblemIn 1s ease both;
|
||||
transition: opacity 0.8s ease, transform 0.9s ease; animation: emblemIn 1.1s ease both;
|
||||
}
|
||||
.curtain-root.is-opening .curtain-emblem { opacity: 0; transform: scale(1.3); }
|
||||
.emblem-card { text-align: center; color: #fff; padding: 30px 34px; border-radius: 18px;
|
||||
background: rgba(255,255,255,0.08); border: 1px solid rgba(255,255,255,0.25); backdrop-filter: blur(8px);
|
||||
box-shadow: 0 20px 60px rgba(0,0,0,0.3); }
|
||||
.emblem-label { display: block; letter-spacing: 0.55em; font-size: 10px; opacity: 0.85; text-transform: uppercase; }
|
||||
.emblem-seal { width: 66px; height: 66px; margin: 16px auto; border: 1px solid rgba(255,255,255,0.6); border-radius: 9999px;
|
||||
display: flex; align-items: center; justify-content: center; font-size: 24px; color: #fff; }
|
||||
.emblem-names { font-family: "Noto Serif SC", serif; font-size: 26px; letter-spacing: 0.15em; font-weight: 300; }
|
||||
.emblem-names .amp { font-style: italic; opacity: 0.85; margin: 0 6px; }
|
||||
.emblem-date { font-size: 11px; letter-spacing: 0.3em; opacity: 0.8; margin-top: 10px; }
|
||||
.emblem-hint { margin-top: 22px; font-size: 11px; letter-spacing: 0.3em; opacity: 0.85;
|
||||
.curtain-root.is-opening .curtain-emblem { opacity: 0; transform: scale(1.25); }
|
||||
.emblem-inner { text-align: center; color: #5b4a36; padding: 10px; }
|
||||
.emblem-floral { display: block; font-size: 22px; color: #b89a78; margin-bottom: 14px; }
|
||||
.emblem-kicker { display: block; letter-spacing: 0.6em; font-size: 9px; color: #b89a78; text-transform: uppercase; margin-bottom: 18px; padding-left: 0.6em; }
|
||||
.emblem-names { font-family: "Noto Serif SC", serif; font-size: 30px; letter-spacing: 0.18em; font-weight: 300; color: #4a3f30; }
|
||||
.emblem-names .amp { font-style: italic; color: #b89a78; margin: 0 8px; }
|
||||
.emblem-rule { width: 46px; height: 1px; background: linear-gradient(90deg, transparent, #b89a78, transparent); margin: 18px auto; }
|
||||
.emblem-date { font-size: 11px; letter-spacing: 0.3em; color: #8a7458; }
|
||||
.emblem-hint { margin-top: 26px; font-size: 11px; letter-spacing: 0.3em; color: #a08a66;
|
||||
display: flex; align-items: center; justify-content: center; gap: 8px; }
|
||||
.emblem-hint .dot { width: 6px; height: 6px; border-radius: 9999px; background: #fff; animation: hintPulse 1.6s infinite; }
|
||||
.emblem-hint .dot { width: 6px; height: 6px; border-radius: 9999px; background: #b89a78; animation: hintPulse 1.6s infinite; }
|
||||
|
||||
/* ---------- 回执 CTA 按钮 ---------- */
|
||||
.rsvp-cta {
|
||||
position: relative; width: 100%; padding: 16px 0; border-radius: 9999px;
|
||||
border: 1px solid #c9a978; background: rgba(255,255,255,0.6);
|
||||
color: #8a704f; font-size: 12px; letter-spacing: 0.28em; cursor: pointer;
|
||||
display: flex; align-items: center; justify-content: center; gap: 10px;
|
||||
backdrop-filter: blur(8px); transition: all .35s ease;
|
||||
box-shadow: 0 6px 18px rgba(184,154,120,0.12);
|
||||
}
|
||||
.rsvp-cta:hover { background: #a88c6b; color: #fff; border-color: #a88c6b; box-shadow: 0 10px 26px rgba(184,154,120,0.28); }
|
||||
.rsvp-cta-deco { font-size: 13px; opacity: .9; }
|
||||
.rsvp-cta-line { width: 18px; height: 1px; background: currentColor; opacity: .6; }
|
||||
|
||||
/* ---------- 出席情况单选标签 ---------- */
|
||||
.rsvp-tag {
|
||||
flex: 1 1 auto; min-width: 72px; padding: 10px 12px; border-radius: 12px;
|
||||
border: 1px solid rgba(168,140,107,0.35); background: #Fdfbf7; color: #6b6863;
|
||||
font-size: 12px; letter-spacing: 0.1em; cursor: pointer; transition: all .25s ease;
|
||||
}
|
||||
.rsvp-tag:hover { border-color: #a88c6b; }
|
||||
.rsvp-tag.active { background: #a88c6b; border-color: #a88c6b; color: #fff; box-shadow: 0 4px 12px rgba(168,140,107,0.25); }
|
||||
|
||||
/* ---------- 音乐授权模态框 ---------- */
|
||||
.music-auth-card { width: 240px; background: #fff; border-radius: 22px; padding: 28px 24px 22px; text-align: center;
|
||||
box-shadow: 0 24px 60px rgba(0,0,0,0.28); border: 1px solid rgba(168,140,107,0.2); }
|
||||
.music-auth-note { font-size: 26px; color: #a88c6b; margin-bottom: 12px; }
|
||||
.music-auth-title { font-size: 16px; color: #4a3f30; letter-spacing: 0.2em; margin-bottom: 6px; }
|
||||
.music-auth-sub { font-size: 11px; color: #8A8680; letter-spacing: 0.15em; margin-bottom: 20px; }
|
||||
.music-auth-btn { width: 100%; padding: 11px 0; border-radius: 9999px; background: #a88c6b; color: #fff;
|
||||
font-size: 12px; letter-spacing: 0.2em; cursor: pointer; border: none; transition: background .3s; }
|
||||
.music-auth-btn:hover { background: #967b5c; }
|
||||
.music-auth-skip { margin-top: 10px; background: none; border: none; color: #b0a99e; font-size: 11px; letter-spacing: 0.1em; cursor: pointer; }
|
||||
|
||||
/* ---------- 音乐曲目弹层 ---------- */
|
||||
.music-wrap { position: relative; }
|
||||
|
||||
Reference in New Issue
Block a user