Spaces:
Running
Running
Upload 101 files
Browse files- 前端页面/auth/找回账号表单组件.js +2 -2
- 前端页面/auth/注册表单组件.js +7 -7
- 前端页面/auth/登录表单组件.js +2 -2
- 前端页面/auth/重置密码表单组件.js +5 -5
- 前端页面/components/互动工具函数.js +6 -2
- 前端页面/components/性能优化工具.js +1 -37
- 前端页面/components/用户体验_国际化.js +14 -6
- 前端页面/core/全局配置.js +9 -1
- 前端页面/core/网络请求_基础设施.js +8 -0
- 前端页面/core/网络请求_缓存管理.js +7 -2
- 前端页面/market/列表卡片组件.js +207 -198
- 前端页面/market/发布内容_UI模板.js +10 -10
- 前端页面/market/发布内容_提交引擎.js +1 -1
- 前端页面/market/资金与钱包_充值组件.js +1 -1
- 前端页面/market/资金与钱包_提现组件.js +5 -5
- 前端页面/post/发布帖子组件.js +5 -5
- 前端页面/prompt/发布提示词组件.js +8 -8
- 前端页面/social/评论数据工具.js +1 -1
- 前端页面/styles/主题基础.css +251 -240
- 前端页面/task/任务详情组件.js +8 -8
- 前端页面/task/发布任务组件.js +6 -6
前端页面/auth/找回账号表单组件.js
CHANGED
|
@@ -22,12 +22,12 @@ export function renderRecoverForm(container, switchView) {
|
|
| 22 |
<p class="auth-form__description">${t('auth.recover_desc')}</p>
|
| 23 |
<fieldset class="auth-form__security">
|
| 24 |
<legend>${t('auth.security_verify')}</legend>
|
| 25 |
-
<label for="recover-email">${t('auth.bound_email')} <span class="auth-form__required" aria-hidden="true">
|
| 26 |
<div class="auth-form__code-row">
|
| 27 |
<input type="email" id="recover-email" name="email" autocomplete="email" required placeholder="${t('auth.enter_bound_email')}" class="auth-form__input">
|
| 28 |
<button type="button" id="btn-recover-send-code" class="auth-form__button">${t('auth.get_code')}</button>
|
| 29 |
</div>
|
| 30 |
-
<label for="recover-code">${t('auth.verification_code')} <span class="auth-form__required" aria-hidden="true">
|
| 31 |
<input type="text" id="recover-code" name="verification-code" autocomplete="one-time-code" inputmode="numeric" required placeholder="${t('auth.enter_6_digit_code')}" maxlength="6" class="auth-form__input">
|
| 32 |
</fieldset>
|
| 33 |
<button type="button" id="btn-submit-recover" class="auth-form__button auth-form__primary">${t('auth.recover_account')}</button>
|
|
|
|
| 22 |
<p class="auth-form__description">${t('auth.recover_desc')}</p>
|
| 23 |
<fieldset class="auth-form__security">
|
| 24 |
<legend>${t('auth.security_verify')}</legend>
|
| 25 |
+
<label for="recover-email">${t('auth.bound_email')} <span class="auth-form__required ranking-required-marker" aria-hidden="true"></span></label>
|
| 26 |
<div class="auth-form__code-row">
|
| 27 |
<input type="email" id="recover-email" name="email" autocomplete="email" required placeholder="${t('auth.enter_bound_email')}" class="auth-form__input">
|
| 28 |
<button type="button" id="btn-recover-send-code" class="auth-form__button">${t('auth.get_code')}</button>
|
| 29 |
</div>
|
| 30 |
+
<label for="recover-code">${t('auth.verification_code')} <span class="auth-form__required ranking-required-marker" aria-hidden="true"></span></label>
|
| 31 |
<input type="text" id="recover-code" name="verification-code" autocomplete="one-time-code" inputmode="numeric" required placeholder="${t('auth.enter_6_digit_code')}" maxlength="6" class="auth-form__input">
|
| 32 |
</fieldset>
|
| 33 |
<button type="button" id="btn-submit-recover" class="auth-form__button auth-form__primary">${t('auth.recover_account')}</button>
|
前端页面/auth/注册表单组件.js
CHANGED
|
@@ -29,21 +29,21 @@ export function renderRegisterForm(container, switchView, onSuccessCallback) {
|
|
| 29 |
container.innerHTML = `
|
| 30 |
<div class="auth-form">
|
| 31 |
<div class="auth-form__grid">
|
| 32 |
-
<div class="auth-form__field"><label for="reg-account">${t('auth.account')} (>5${t('common.chars')}) <span class="auth-form__required" aria-hidden="true">
|
| 33 |
-
<div class="auth-form__field"><label for="reg-name">${t('auth.display_name')} <span class="auth-form__required" aria-hidden="true">
|
| 34 |
</div>
|
| 35 |
<div class="auth-form__grid">
|
| 36 |
-
<div class="auth-form__field"><label for="reg-password">${t('auth.set_password')} (≥6${t('common.chars')}) <span class="auth-form__required" aria-hidden="true">
|
| 37 |
-
<div class="auth-form__field"><label for="reg-password-confirm">${t('auth.confirm_password')} <span class="auth-form__required" aria-hidden="true">
|
| 38 |
</div>
|
| 39 |
<fieldset class="auth-form__security">
|
| 40 |
<legend>${t('auth.security_verify')}</legend>
|
| 41 |
-
<label for="reg-email">${t('auth.security_email')} (${t('auth.security_email_desc')}) <span class="auth-form__required" aria-hidden="true">
|
| 42 |
<div class="auth-form__code-row">
|
| 43 |
<input type="email" id="reg-email" name="email" autocomplete="email" required class="auth-form__input">
|
| 44 |
<button type="button" id="btn-reg-send-code" class="auth-form__button">${t('auth.get_code')}</button>
|
| 45 |
</div>
|
| 46 |
-
<label for="reg-code">${t('auth.verification_code')} <span class="auth-form__required" aria-hidden="true">
|
| 47 |
<input type="text" id="reg-code" name="verification-code" autocomplete="one-time-code" inputmode="numeric" placeholder="6${t('common.digits')}" maxlength="6" required class="auth-form__input">
|
| 48 |
</fieldset>
|
| 49 |
<div class="auth-form__grid auth-form__profile">
|
|
@@ -52,7 +52,7 @@ export function renderRegisterForm(container, switchView, onSuccessCallback) {
|
|
| 52 |
<div class="auth-form__avatar-row"><img id="avatar-preview" src="${DEFAULT_AVATAR}" alt="" class="auth-form__avatar"><input type="file" id="reg-avatar" accept="image/*" class="auth-form__file"></div>
|
| 53 |
<div id="avatar-error" class="auth-form__error" hidden>${t('auth.file_too_large')}</div>
|
| 54 |
</div>
|
| 55 |
-
<div class="auth-form__field"><label for="reg-gender">${t('auth.gender')} <span class="auth-form__required" aria-hidden="true">
|
| 56 |
</div>
|
| 57 |
<div class="auth-form__grid">
|
| 58 |
<div class="auth-form__field">
|
|
|
|
| 29 |
container.innerHTML = `
|
| 30 |
<div class="auth-form">
|
| 31 |
<div class="auth-form__grid">
|
| 32 |
+
<div class="auth-form__field"><label for="reg-account">${t('auth.account')} (>5${t('common.chars')}) <span class="auth-form__required ranking-required-marker" aria-hidden="true"></span></label><input type="text" id="reg-account" class="auth-form__input" name="username" autocomplete="username" required></div>
|
| 33 |
+
<div class="auth-form__field"><label for="reg-name">${t('auth.display_name')} <span class="auth-form__required ranking-required-marker" aria-hidden="true"></span></label><input type="text" id="reg-name" class="auth-form__input" name="nickname" autocomplete="nickname" required></div>
|
| 34 |
</div>
|
| 35 |
<div class="auth-form__grid">
|
| 36 |
+
<div class="auth-form__field"><label for="reg-password">${t('auth.set_password')} (≥6${t('common.chars')}) <span class="auth-form__required ranking-required-marker" aria-hidden="true"></span></label><input type="password" id="reg-password" class="auth-form__input" name="password" autocomplete="new-password" required></div>
|
| 37 |
+
<div class="auth-form__field"><label for="reg-password-confirm">${t('auth.confirm_password')} <span class="auth-form__required ranking-required-marker" aria-hidden="true"></span></label><input type="password" id="reg-password-confirm" class="auth-form__input" name="confirm-password" autocomplete="new-password" required></div>
|
| 38 |
</div>
|
| 39 |
<fieldset class="auth-form__security">
|
| 40 |
<legend>${t('auth.security_verify')}</legend>
|
| 41 |
+
<label for="reg-email">${t('auth.security_email')} (${t('auth.security_email_desc')}) <span class="auth-form__required ranking-required-marker" aria-hidden="true"></span></label>
|
| 42 |
<div class="auth-form__code-row">
|
| 43 |
<input type="email" id="reg-email" name="email" autocomplete="email" required class="auth-form__input">
|
| 44 |
<button type="button" id="btn-reg-send-code" class="auth-form__button">${t('auth.get_code')}</button>
|
| 45 |
</div>
|
| 46 |
+
<label for="reg-code">${t('auth.verification_code')} <span class="auth-form__required ranking-required-marker" aria-hidden="true"></span></label>
|
| 47 |
<input type="text" id="reg-code" name="verification-code" autocomplete="one-time-code" inputmode="numeric" placeholder="6${t('common.digits')}" maxlength="6" required class="auth-form__input">
|
| 48 |
</fieldset>
|
| 49 |
<div class="auth-form__grid auth-form__profile">
|
|
|
|
| 52 |
<div class="auth-form__avatar-row"><img id="avatar-preview" src="${DEFAULT_AVATAR}" alt="" class="auth-form__avatar"><input type="file" id="reg-avatar" accept="image/*" class="auth-form__file"></div>
|
| 53 |
<div id="avatar-error" class="auth-form__error" hidden>${t('auth.file_too_large')}</div>
|
| 54 |
</div>
|
| 55 |
+
<div class="auth-form__field"><label for="reg-gender">${t('auth.gender')} <span class="auth-form__required ranking-required-marker" aria-hidden="true"></span></label><select id="reg-gender" required class="auth-form__input"><option value="male">${t('auth.male')}</option><option value="female">${t('auth.female')}</option></select></div>
|
| 56 |
</div>
|
| 57 |
<div class="auth-form__grid">
|
| 58 |
<div class="auth-form__field">
|
前端页面/auth/登录表单组件.js
CHANGED
|
@@ -4,8 +4,8 @@ import { t } from "../components/用户体验增强.js";
|
|
| 4 |
export function renderLoginForm(container, switchView, onSuccessCallback) {
|
| 5 |
container.innerHTML = `
|
| 6 |
<div class="auth-login">
|
| 7 |
-
<div class="auth-login__field"><label for="login-account">${t('auth.account')} <span class="auth-login__required" aria-hidden="true">
|
| 8 |
-
<div class="auth-login__field"><label for="login-password">${t('auth.password')} <span class="auth-login__required" aria-hidden="true">
|
| 9 |
<div class="auth-login__options">
|
| 10 |
<div class="auth-login__remember">
|
| 11 |
<input type="checkbox" id="login-remember" checked>
|
|
|
|
| 4 |
export function renderLoginForm(container, switchView, onSuccessCallback) {
|
| 5 |
container.innerHTML = `
|
| 6 |
<div class="auth-login">
|
| 7 |
+
<div class="auth-login__field"><label for="login-account">${t('auth.account')} <span class="auth-login__required ranking-required-marker" aria-hidden="true"></span></label><input type="text" id="login-account" name="username" autocomplete="username" required class="auth-login__input"></div>
|
| 8 |
+
<div class="auth-login__field"><label for="login-password">${t('auth.password')} <span class="auth-login__required ranking-required-marker" aria-hidden="true"></span></label><input type="password" id="login-password" name="password" autocomplete="current-password" required class="auth-login__input"></div>
|
| 9 |
<div class="auth-login__options">
|
| 10 |
<div class="auth-login__remember">
|
| 11 |
<input type="checkbox" id="login-remember" checked>
|
前端页面/auth/重置密码表单组件.js
CHANGED
|
@@ -6,20 +6,20 @@ import { t } from "../components/用户体验增强.js";
|
|
| 6 |
export function renderResetForm(container, switchView, onSuccessCallback, prefill = null) {
|
| 7 |
container.innerHTML = `
|
| 8 |
<div class="auth-form">
|
| 9 |
-
<div class="auth-form__field"><label for="reset-account">${t('auth.current_account')} <span class="auth-form__required" aria-hidden="true">
|
| 10 |
<fieldset class="auth-form__security">
|
| 11 |
<legend>${t('auth.security_verify')}</legend>
|
| 12 |
-
<label for="reset-verify">${t('auth.bound_email')} <span class="auth-form__required" aria-hidden="true">
|
| 13 |
<div class="auth-form__code-row">
|
| 14 |
<input type="email" id="reset-verify" name="email" autocomplete="email" required placeholder="${t('auth.enter_bound_email')}" class="auth-form__input">
|
| 15 |
<button type="button" id="btn-send-code" class="auth-form__button">${t('auth.get_code')}</button>
|
| 16 |
</div>
|
| 17 |
-
<label for="reset-code">${t('auth.verification_code')} <span class="auth-form__required" aria-hidden="true">
|
| 18 |
<input type="text" id="reset-code" name="verification-code" autocomplete="one-time-code" inputmode="numeric" required placeholder="${t('auth.enter_6_digit_code')}" maxlength="6" class="auth-form__input">
|
| 19 |
</fieldset>
|
| 20 |
<div class="auth-form__field"><label for="reset-old-password">${t('auth.old_password')} (${t('auth.old_password_tip')})</label><input type="password" id="reset-old-password" class="auth-form__input" name="old-password" autocomplete="current-password" placeholder="${t('auth.old_password_placeholder')}"></div>
|
| 21 |
-
<div class="auth-form__field"><label for="reset-new-password">${t('auth.new_password')} (≥6${t('common.chars')}) <span class="auth-form__required" aria-hidden="true">
|
| 22 |
-
<div class="auth-form__field"><label for="reset-confirm-password">${t('auth.confirm_new_password')} <span class="auth-form__required" aria-hidden="true">
|
| 23 |
<button type="button" id="btn-submit-reset" class="auth-form__button auth-form__primary">${t('auth.change_password')}</button>
|
| 24 |
<div class="auth-form__footer"><button type="button" id="toggle-to-login" class="auth-form__link">${t('auth.back_to_login')}</button></div>
|
| 25 |
</div>
|
|
|
|
| 6 |
export function renderResetForm(container, switchView, onSuccessCallback, prefill = null) {
|
| 7 |
container.innerHTML = `
|
| 8 |
<div class="auth-form">
|
| 9 |
+
<div class="auth-form__field"><label for="reset-account">${t('auth.current_account')} <span class="auth-form__required ranking-required-marker" aria-hidden="true"></span></label><input type="text" id="reset-account" class="auth-form__input" name="username" autocomplete="username" required></div>
|
| 10 |
<fieldset class="auth-form__security">
|
| 11 |
<legend>${t('auth.security_verify')}</legend>
|
| 12 |
+
<label for="reset-verify">${t('auth.bound_email')} <span class="auth-form__required ranking-required-marker" aria-hidden="true"></span></label>
|
| 13 |
<div class="auth-form__code-row">
|
| 14 |
<input type="email" id="reset-verify" name="email" autocomplete="email" required placeholder="${t('auth.enter_bound_email')}" class="auth-form__input">
|
| 15 |
<button type="button" id="btn-send-code" class="auth-form__button">${t('auth.get_code')}</button>
|
| 16 |
</div>
|
| 17 |
+
<label for="reset-code">${t('auth.verification_code')} <span class="auth-form__required ranking-required-marker" aria-hidden="true"></span></label>
|
| 18 |
<input type="text" id="reset-code" name="verification-code" autocomplete="one-time-code" inputmode="numeric" required placeholder="${t('auth.enter_6_digit_code')}" maxlength="6" class="auth-form__input">
|
| 19 |
</fieldset>
|
| 20 |
<div class="auth-form__field"><label for="reset-old-password">${t('auth.old_password')} (${t('auth.old_password_tip')})</label><input type="password" id="reset-old-password" class="auth-form__input" name="old-password" autocomplete="current-password" placeholder="${t('auth.old_password_placeholder')}"></div>
|
| 21 |
+
<div class="auth-form__field"><label for="reset-new-password">${t('auth.new_password')} (≥6${t('common.chars')}) <span class="auth-form__required ranking-required-marker" aria-hidden="true"></span></label><input type="password" id="reset-new-password" class="auth-form__input" name="new-password" autocomplete="new-password" required></div>
|
| 22 |
+
<div class="auth-form__field"><label for="reset-confirm-password">${t('auth.confirm_new_password')} <span class="auth-form__required ranking-required-marker" aria-hidden="true"></span></label><input type="password" id="reset-confirm-password" class="auth-form__input" name="confirm-password" autocomplete="new-password" required></div>
|
| 23 |
<button type="button" id="btn-submit-reset" class="auth-form__button auth-form__primary">${t('auth.change_password')}</button>
|
| 24 |
<div class="auth-form__footer"><button type="button" id="toggle-to-login" class="auth-form__link">${t('auth.back_to_login')}</button></div>
|
| 25 |
</div>
|
前端页面/components/互动工具函数.js
CHANGED
|
@@ -37,9 +37,13 @@ const _pendingActions = new WeakMap();
|
|
| 37 |
*/
|
| 38 |
export async function recordView(apiMethod, contentId, cachePrefix, onSuccess = null) {
|
| 39 |
// 🚀 登录检查:未登录时跳过浏览量记录,避免 401 错误
|
| 40 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
// 🔒 P0同步:旧版 mock_token 已被后端拒绝,仅标准 JWT 格式才记录浏览量
|
| 42 |
-
if (
|
| 43 |
return null;
|
| 44 |
}
|
| 45 |
|
|
|
|
| 37 |
*/
|
| 38 |
export async function recordView(apiMethod, contentId, cachePrefix, onSuccess = null) {
|
| 39 |
// 🚀 登录检查:未登录时跳过浏览量记录,避免 401 错误
|
| 40 |
+
let token = null;
|
| 41 |
+
for (const readStorage of [() => localStorage, () => sessionStorage]) {
|
| 42 |
+
try { token = readStorage()?.getItem("ComfyCommunity_Token"); } catch {}
|
| 43 |
+
if (token) break;
|
| 44 |
+
}
|
| 45 |
// 🔒 P0同步:旧版 mock_token 已被后端拒绝,仅标准 JWT 格式才记录浏览量
|
| 46 |
+
if (typeof token !== "string" || token.split(".").length !== 3) {
|
| 47 |
return null;
|
| 48 |
}
|
| 49 |
|
前端页面/components/性能优化工具.js
CHANGED
|
@@ -671,7 +671,7 @@ export function endTimer(label) {
|
|
| 671 |
// 🎨 骨架屏生成器
|
| 672 |
// ==========================================
|
| 673 |
// 特点:
|
| 674 |
-
// -
|
| 675 |
// - 多种卡片类型
|
| 676 |
// - 流畅的动画效果
|
| 677 |
|
|
@@ -685,42 +685,6 @@ export function createSkeleton(type = "card", count = 1) {
|
|
| 685 |
const container = document.createElement("div");
|
| 686 |
container.className = "skeleton-container";
|
| 687 |
|
| 688 |
-
// 🎨 深色主题骨架屏样式
|
| 689 |
-
const skeletonStyles = `
|
| 690 |
-
.skeleton-container {
|
| 691 |
-
padding: 8px;
|
| 692 |
-
}
|
| 693 |
-
.skeleton-item {
|
| 694 |
-
background: linear-gradient(90deg, #2a2a2a 25%, #3a3a3a 50%, #2a2a2a 75%);
|
| 695 |
-
background-size: 200% 100%;
|
| 696 |
-
animation: skeleton-shimmer 1.5s ease-in-out infinite;
|
| 697 |
-
border-radius: 6px;
|
| 698 |
-
}
|
| 699 |
-
.skeleton-card {
|
| 700 |
-
background: var(--comfy-menu-bg);
|
| 701 |
-
border: 1px solid var(--border-color, #333);
|
| 702 |
-
border-radius: 8px;
|
| 703 |
-
padding: 12px;
|
| 704 |
-
margin-bottom: 12px;
|
| 705 |
-
}
|
| 706 |
-
@keyframes skeleton-shimmer {
|
| 707 |
-
0% { background-position: 200% 0; }
|
| 708 |
-
100% { background-position: -200% 0; }
|
| 709 |
-
}
|
| 710 |
-
@keyframes skeleton-pulse {
|
| 711 |
-
0%, 100% { opacity: 0.4; }
|
| 712 |
-
50% { opacity: 0.8; }
|
| 713 |
-
}
|
| 714 |
-
`;
|
| 715 |
-
|
| 716 |
-
// 注入样式(仅一次)
|
| 717 |
-
if (!document.getElementById("skeleton-styles-v2")) {
|
| 718 |
-
const styleEl = document.createElement("style");
|
| 719 |
-
styleEl.id = "skeleton-styles-v2";
|
| 720 |
-
styleEl.textContent = skeletonStyles;
|
| 721 |
-
document.head.appendChild(styleEl);
|
| 722 |
-
}
|
| 723 |
-
|
| 724 |
for (let i = 0; i < count; i++) {
|
| 725 |
const item = document.createElement("div");
|
| 726 |
|
|
|
|
| 671 |
// 🎨 骨架屏生成器
|
| 672 |
// ==========================================
|
| 673 |
// 特点:
|
| 674 |
+
// - 跟随界面主题
|
| 675 |
// - 多种卡片类型
|
| 676 |
// - 流畅的动画效果
|
| 677 |
|
|
|
|
| 685 |
const container = document.createElement("div");
|
| 686 |
container.className = "skeleton-container";
|
| 687 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 688 |
for (let i = 0; i < count; i++) {
|
| 689 |
const item = document.createElement("div");
|
| 690 |
|
前端页面/components/用户体验_国际化.js
CHANGED
|
@@ -586,6 +586,10 @@ const translations = {
|
|
| 586 |
'feedback.network_unavailable': '网络连接失败,请检查网络',
|
| 587 |
'feedback.http_request_failed': '请求失败(HTTP {status})',
|
| 588 |
'feedback.invalid_request_data': '数据格式不正确,请检查填写内容。',
|
|
|
|
|
|
|
|
|
|
|
|
|
| 589 |
'feedback.response_format_error': '服务器响应格式错误',
|
| 590 |
'feedback.saved': '已保存',
|
| 591 |
'feedback.logged_out': '已退出登录',
|
|
@@ -1786,13 +1790,13 @@ const translations = {
|
|
| 1786 |
'about.warning_account_desc': '可能是你的浏览器自动帮你填入别的网站账号密码,账号是字符(字母、数字、符号)没有中文。',
|
| 1787 |
'about.guide_title': '使用指南',
|
| 1788 |
'about.guide_install_title': '安装插件和Skill',
|
| 1789 |
-
'about.guide_install_desc': '打开
|
| 1790 |
'about.guide_path_title': '文件下载到哪里',
|
| 1791 |
-
'about.guide_path_desc': '插件
|
| 1792 |
'about.guide_update_title': '更新到新版本',
|
| 1793 |
'about.guide_update_desc': '作者发布新版本后,作品详情页会出现「发现新版本」按钮,点一下自动完成更新,不用先卸载旧版本。',
|
| 1794 |
'about.guide_publish_title': '发布自己的作品',
|
| 1795 |
-
'about.guide_publish_desc': '点榜单顶部的「发布」
|
| 1796 |
'about.guide_buy_title': '购买付费作品',
|
| 1797 |
'about.guide_buy_desc': '买付费作品要先让账户里有足够余额:进「个人中心-钱包」用支付宝扫码充值。充好后回详情页点「立即获取使用」即完成购买,一次购买终身有效。',
|
| 1798 |
'about.guide_refund_title': '申请退款',
|
|
@@ -2378,6 +2382,10 @@ const translations = {
|
|
| 2378 |
'feedback.network_unavailable': 'Network connection failed. Check your connection.',
|
| 2379 |
'feedback.http_request_failed': 'Request failed (HTTP {status})',
|
| 2380 |
'feedback.invalid_request_data': 'The submitted data has an invalid format. Check the form.',
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2381 |
'feedback.response_format_error': 'The server response format is invalid',
|
| 2382 |
'feedback.saved': 'Saved',
|
| 2383 |
'feedback.logged_out': 'Logged out',
|
|
@@ -3540,13 +3548,13 @@ const translations = {
|
|
| 3540 |
'about.warning_account_desc': 'Your browser may have auto-filled credentials from another site. Account names only contain letters, numbers, and symbols — no Chinese characters.',
|
| 3541 |
'about.guide_title': 'Usage Guide',
|
| 3542 |
'about.guide_install_title': 'Installing Plugins & Skills',
|
| 3543 |
-
'about.guide_install_desc': 'Open
|
| 3544 |
'about.guide_path_title': 'Where Files Are Downloaded',
|
| 3545 |
-
'about.guide_path_desc': 'Plugins
|
| 3546 |
'about.guide_update_title': 'Updating to New Versions',
|
| 3547 |
'about.guide_update_desc': 'When an author releases a new version, an "Update available" button appears on the item\'s detail page. Click it to update automatically — no need to remove the old version first.',
|
| 3548 |
'about.guide_publish_title': 'Publishing Your Own Work',
|
| 3549 |
-
'about.guide_publish_desc': 'Click
|
| 3550 |
'about.guide_buy_title': 'Buying Paid Items',
|
| 3551 |
'about.guide_buy_desc': 'Paid items need enough balance in your account first: open "Profile - Wallet" and top up by scanning the Alipay QR code. Then return to the detail page and click "Get Now" to finish the purchase — one purchase, yours forever.',
|
| 3552 |
'about.guide_refund_title': 'Requesting a Refund',
|
|
|
|
| 586 |
'feedback.network_unavailable': '网络连接失败,请检查网络',
|
| 587 |
'feedback.http_request_failed': '请求失败(HTTP {status})',
|
| 588 |
'feedback.invalid_request_data': '数据格式不正确,请检查填写内容。',
|
| 589 |
+
'feedback.request_too_large': '提交内容过大,请缩小内容后重试。',
|
| 590 |
+
'feedback.request_receive_timeout': '数据接收超时,本次操作尚未提交,请重试。',
|
| 591 |
+
'feedback.request_busy': '当前请求较多,本次操作尚未提交,请稍后重试。',
|
| 592 |
+
'feedback.request_encoding_unsupported': '暂不支持压缩提交,请取消压缩后重试。',
|
| 593 |
'feedback.response_format_error': '服务器响应格式错误',
|
| 594 |
'feedback.saved': '已保存',
|
| 595 |
'feedback.logged_out': '已退出登录',
|
|
|
|
| 1790 |
'about.warning_account_desc': '可能是你的浏览器自动帮你填入别的网站账号密码,账号是字符(字母、数字、符号)没有中文。',
|
| 1791 |
'about.guide_title': '使用指南',
|
| 1792 |
'about.guide_install_title': '安装插件和Skill',
|
| 1793 |
+
'about.guide_install_desc': '打开作品详情,点「立即获取」并按提示操作;付费作品先完成购买。Skill 需选择接收目录,预览后确认安装。插件装好后重启 ComfyUI。',
|
| 1794 |
'about.guide_path_title': '文件下载到哪里',
|
| 1795 |
+
'about.guide_path_desc': '插件装在 ComfyUI 的 custom_nodes 文件夹。Skill 放在你选择的接收目录下,并保留仓库同名文件夹。工作流获取后会加载到画布。',
|
| 1796 |
'about.guide_update_title': '更新到新版本',
|
| 1797 |
'about.guide_update_desc': '作者发布新版本后,作品详情页会出现「发现新版本」按钮,点一下自动完成更新,不用先卸载旧版本。',
|
| 1798 |
'about.guide_publish_title': '发布自己的作品',
|
| 1799 |
+
'about.guide_publish_desc': '点榜单顶部的「发布」,填写名称和介绍。插件可填写代码仓库地址;Skill 请填写仓库根地址,不支持子目录地址;工作流上传 JSON 文件。',
|
| 1800 |
'about.guide_buy_title': '购买付费作品',
|
| 1801 |
'about.guide_buy_desc': '买付费作品要先让账户里有足够余额:进「个人中心-钱包」用支付宝扫码充值。充好后回详情页点「立即获取使用」即完成购买,一次购买终身有效。',
|
| 1802 |
'about.guide_refund_title': '申请退款',
|
|
|
|
| 2382 |
'feedback.network_unavailable': 'Network connection failed. Check your connection.',
|
| 2383 |
'feedback.http_request_failed': 'Request failed (HTTP {status})',
|
| 2384 |
'feedback.invalid_request_data': 'The submitted data has an invalid format. Check the form.',
|
| 2385 |
+
'feedback.request_too_large': 'The submitted content is too large. Reduce its size and try again.',
|
| 2386 |
+
'feedback.request_receive_timeout': 'Receiving the data timed out. The operation was not submitted. Try again.',
|
| 2387 |
+
'feedback.request_busy': 'Too many requests are active. The operation was not submitted. Try again later.',
|
| 2388 |
+
'feedback.request_encoding_unsupported': 'Compressed submissions are not supported. Submit the data without compression.',
|
| 2389 |
'feedback.response_format_error': 'The server response format is invalid',
|
| 2390 |
'feedback.saved': 'Saved',
|
| 2391 |
'feedback.logged_out': 'Logged out',
|
|
|
|
| 3548 |
'about.warning_account_desc': 'Your browser may have auto-filled credentials from another site. Account names only contain letters, numbers, and symbols — no Chinese characters.',
|
| 3549 |
'about.guide_title': 'Usage Guide',
|
| 3550 |
'about.guide_install_title': 'Installing Plugins & Skills',
|
| 3551 |
+
'about.guide_install_desc': 'Open an item, click "Get Now" and follow the instructions. Paid items require purchase first. For a Skill, choose a destination folder, review the preview and confirm installation. Restart ComfyUI after installing a plugin.',
|
| 3552 |
'about.guide_path_title': 'Where Files Are Downloaded',
|
| 3553 |
+
'about.guide_path_desc': 'Plugins go into the custom_nodes folder inside ComfyUI. A Skill keeps its repository folder inside the destination you choose. Workflows load onto the canvas after download.',
|
| 3554 |
'about.guide_update_title': 'Updating to New Versions',
|
| 3555 |
'about.guide_update_desc': 'When an author releases a new version, an "Update available" button appears on the item\'s detail page. Click it to update automatically — no need to remove the old version first.',
|
| 3556 |
'about.guide_publish_title': 'Publishing Your Own Work',
|
| 3557 |
+
'about.guide_publish_desc': 'Click "Publish" at the top of a board and enter a name and description. Plugins can use a code repository URL. Skills require a repository root URL, not a subfolder URL. Upload a JSON file for a workflow.',
|
| 3558 |
'about.guide_buy_title': 'Buying Paid Items',
|
| 3559 |
'about.guide_buy_desc': 'Paid items need enough balance in your account first: open "Profile - Wallet" and top up by scanning the Alipay QR code. Then return to the detail page and click "Get Now" to finish the purchase — one purchase, yours forever.',
|
| 3560 |
'about.guide_refund_title': 'Requesting a Refund',
|
前端页面/core/全局配置.js
CHANGED
|
@@ -18,12 +18,20 @@
|
|
| 18 |
// 🌐 API 配置
|
| 19 |
// ==========================================
|
| 20 |
|
| 21 |
-
/** @type {{ BASE_URL: string, TIMEOUT: number, VIDEO_UPLOAD_TIMEOUT: number, VIDEO_UPLOAD_RESPONSE_MAX_CHARS: number, LOCAL_CACHE_STATS_TIMEOUT: number, LOCAL_CACHE_CLEAR_TIMEOUT: number, LOCAL_CACHE_RESPONSE_MAX_BYTES: number, SSE_MAX_RESPONSE_BYTES: number, SSE_MAX_LINE_BYTES: number, SSE_MAX_LINES: number, SSE_YIELD_LINES: number, SSE_YIELD_BYTES: number, SSE_YIELD_CHUNKS: number, MAX_RETRIES: number, RETRY_DELAY: number, LIST_RETRIES: number, SEARCH_TIMEOUT: number, SEARCH_RETRIES: number, PROFILE_RESOURCE_TIMEOUT: number, CREATOR_CHART_SCRIPT_URL: string, BACKGROUND_TIMEOUT: number, BANNER_IMAGE_TIMEOUT: number, BACKGROUND_RETRIES: number, WORKFLOW_DOWNLOAD_TIMEOUT: number, CLOUD_DOWN_COOLDOWN: number, SEARCH_COMPONENT_ID: string, IMAGE_PROXY_PATH: string, PROFILE_MEDIA_URL_MAX_BYTES: number, LOCAL_IMAGE_PROXY_PREFIX: string, COMPLETE_IMAGE_QUERY_SUFFIX: string, PRIVATE_GET_PATTERNS: RegExp[], PUBLIC_CONDITIONAL_GET_PATHS: string[], CONDITIONAL_ETAG_PATTERN: RegExp, REQUEST_ID_HEADER: string, REQUEST_ID_PATTERN: RegExp, ENDPOINT_ERROR_SCOPE_HEADER: string, ENDPOINT_ERROR_SCOPE_VALUE: string }} */
|
| 22 |
export const API = {
|
| 23 |
REQUEST_ID_HEADER: "X-Ranking-Request-Id",
|
| 24 |
REQUEST_ID_PATTERN: /^(?:[a-f0-9]{32}|ERR_[0-9]{10,13}_[a-f0-9]{1,8})$/,
|
| 25 |
ENDPOINT_ERROR_SCOPE_HEADER: "X-Ranking-Error-Scope",
|
| 26 |
ENDPOINT_ERROR_SCOPE_VALUE: "endpoint",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
// 仅公开榜单使用由正文派生的条件验证器,私有响应仍禁止留存。
|
| 28 |
PUBLIC_CONDITIONAL_GET_PATHS: ['/api/items', '/api/creators', '/api/creators/search', '/api/posts', '/api/prompts', '/api/tasks'],
|
| 29 |
CONDITIONAL_ETAG_PATTERN: /^W\/"rk-[a-f0-9]{64}"$/,
|
|
|
|
| 18 |
// 🌐 API 配置
|
| 19 |
// ==========================================
|
| 20 |
|
| 21 |
+
/** @type {{ BASE_URL: string, TIMEOUT: number, VIDEO_UPLOAD_TIMEOUT: number, VIDEO_UPLOAD_RESPONSE_MAX_CHARS: number, LOCAL_CACHE_STATS_TIMEOUT: number, LOCAL_CACHE_CLEAR_TIMEOUT: number, LOCAL_CACHE_RESPONSE_MAX_BYTES: number, SSE_MAX_RESPONSE_BYTES: number, SSE_MAX_LINE_BYTES: number, SSE_MAX_LINES: number, SSE_YIELD_LINES: number, SSE_YIELD_BYTES: number, SSE_YIELD_CHUNKS: number, MAX_RETRIES: number, RETRY_DELAY: number, LIST_RETRIES: number, SEARCH_TIMEOUT: number, SEARCH_RETRIES: number, PROFILE_RESOURCE_TIMEOUT: number, CREATOR_CHART_SCRIPT_URL: string, BACKGROUND_TIMEOUT: number, BANNER_IMAGE_TIMEOUT: number, BACKGROUND_RETRIES: number, WORKFLOW_DOWNLOAD_TIMEOUT: number, CLOUD_DOWN_COOLDOWN: number, SEARCH_COMPONENT_ID: string, IMAGE_PROXY_PATH: string, PROFILE_MEDIA_URL_MAX_BYTES: number, LOCAL_IMAGE_PROXY_PREFIX: string, COMPLETE_IMAGE_QUERY_SUFFIX: string, PRIVATE_GET_PATTERNS: RegExp[], PUBLIC_CONDITIONAL_GET_PATHS: string[], CONDITIONAL_ETAG_PATTERN: RegExp, REQUEST_ID_HEADER: string, REQUEST_ID_PATTERN: RegExp, ENDPOINT_ERROR_SCOPE_HEADER: string, ENDPOINT_ERROR_SCOPE_VALUE: string, REQUEST_BODY_ERRORS: Record<string, { status: number, msgKey: string }> }} */
|
| 22 |
export const API = {
|
| 23 |
REQUEST_ID_HEADER: "X-Ranking-Request-Id",
|
| 24 |
REQUEST_ID_PATTERN: /^(?:[a-f0-9]{32}|ERR_[0-9]{10,13}_[a-f0-9]{1,8})$/,
|
| 25 |
ENDPOINT_ERROR_SCOPE_HEADER: "X-Ranking-Error-Scope",
|
| 26 |
ENDPOINT_ERROR_SCOPE_VALUE: "endpoint",
|
| 27 |
+
REQUEST_BODY_ERRORS: {
|
| 28 |
+
request_body_invalid: { status: 400, msgKey: 'feedback.invalid_request_data' },
|
| 29 |
+
request_body_disconnected: { status: 400, msgKey: 'feedback.network_unavailable' },
|
| 30 |
+
request_body_too_large: { status: 413, msgKey: 'feedback.request_too_large' },
|
| 31 |
+
request_body_timeout: { status: 408, msgKey: 'feedback.request_receive_timeout' },
|
| 32 |
+
request_body_busy: { status: 429, msgKey: 'feedback.request_busy' },
|
| 33 |
+
request_body_encoding: { status: 415, msgKey: 'feedback.request_encoding_unsupported' },
|
| 34 |
+
},
|
| 35 |
// 仅公开榜单使用由正文派生的条件验证器,私有响应仍禁止留存。
|
| 36 |
PUBLIC_CONDITIONAL_GET_PATHS: ['/api/items', '/api/creators', '/api/creators/search', '/api/posts', '/api/prompts', '/api/tasks'],
|
| 37 |
CONDITIONAL_ETAG_PATTERN: /^W\/"rk-[a-f0-9]{64}"$/,
|
前端页面/core/网络请求_基础设施.js
CHANGED
|
@@ -47,6 +47,10 @@ function withRequestDiagnostic(error, response, data = null) {
|
|
| 47 |
}
|
| 48 |
|
| 49 |
function httpErrorMessage(data, status) {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
if (Array.isArray(data.detail)) return t('feedback.invalid_request_data');
|
| 51 |
for (const value of [data.detail, data.message, data.error]) {
|
| 52 |
if (typeof value === 'string' && value.trim()) return value;
|
|
@@ -524,6 +528,10 @@ async function request(endpoint, options = {}) {
|
|
| 524 |
const error = withRequestDiagnostic(new Error(errorMsg), response, responseData);
|
| 525 |
error.status = response.status;
|
| 526 |
if (typeof responseData.detail === "string" && /^[a-z][a-z0-9_]{0,79}$/.test(responseData.detail)) error.code = responseData.detail;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 527 |
throw error;
|
| 528 |
}
|
| 529 |
|
|
|
|
| 47 |
}
|
| 48 |
|
| 49 |
function httpErrorMessage(data, status) {
|
| 50 |
+
if (typeof data.detail === 'string' && Object.hasOwn(API.REQUEST_BODY_ERRORS, data.detail)) {
|
| 51 |
+
const rule = API.REQUEST_BODY_ERRORS[data.detail];
|
| 52 |
+
if (rule.status === status) return t(rule.msgKey);
|
| 53 |
+
}
|
| 54 |
if (Array.isArray(data.detail)) return t('feedback.invalid_request_data');
|
| 55 |
for (const value of [data.detail, data.message, data.error]) {
|
| 56 |
if (typeof value === 'string' && value.trim()) return value;
|
|
|
|
| 528 |
const error = withRequestDiagnostic(new Error(errorMsg), response, responseData);
|
| 529 |
error.status = response.status;
|
| 530 |
if (typeof responseData.detail === "string" && /^[a-z][a-z0-9_]{0,79}$/.test(responseData.detail)) error.code = responseData.detail;
|
| 531 |
+
if (result.bodyConfirmed && Object.hasOwn(API.REQUEST_BODY_ERRORS, error.code)
|
| 532 |
+
&& API.REQUEST_BODY_ERRORS[error.code].status === error.status) {
|
| 533 |
+
error.requestBodyRejected = true;
|
| 534 |
+
}
|
| 535 |
throw error;
|
| 536 |
}
|
| 537 |
|
前端页面/core/网络请求_缓存管理.js
CHANGED
|
@@ -302,9 +302,14 @@ function _touchStorageEntry(key, cached) {
|
|
| 302 |
try {
|
| 303 |
const now = Date.now();
|
| 304 |
if (Number.isFinite(cached.lastAccessAt) && now - cached.lastAccessAt < 60_000) return;
|
| 305 |
-
|
|
|
|
|
|
|
|
|
|
| 306 |
cached.lastAccessAt = now;
|
| 307 |
-
|
|
|
|
|
|
|
| 308 |
} catch {}
|
| 309 |
}
|
| 310 |
|
|
|
|
| 302 |
try {
|
| 303 |
const now = Date.now();
|
| 304 |
if (Number.isFinite(cached.lastAccessAt) && now - cached.lastAccessAt < 60_000) return;
|
| 305 |
+
const stored = localStorage.getItem(key);
|
| 306 |
+
if (stored === null) return;
|
| 307 |
+
const persisted = JSON.parse(stored);
|
| 308 |
+
if (!_isValidCacheEntry(persisted)) return;
|
| 309 |
cached.lastAccessAt = now;
|
| 310 |
+
if (Number.isFinite(persisted.lastAccessAt) && now - persisted.lastAccessAt < 60_000) return;
|
| 311 |
+
persisted.lastAccessAt = now;
|
| 312 |
+
localStorage.setItem(key, JSON.stringify(persisted));
|
| 313 |
} catch {}
|
| 314 |
}
|
| 315 |
|
前端页面/market/列表卡片组件.js
CHANGED
|
@@ -173,196 +173,233 @@ export function createItemCard(itemData, currentUser = null, contextType = null)
|
|
| 173 |
detailView.className = "resource-detail";
|
| 174 |
detailView.style.display = "none";
|
| 175 |
|
| 176 |
-
|
| 177 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 178 |
|
| 179 |
-
|
| 180 |
-
|
| 181 |
|
| 182 |
-
|
| 183 |
-
|
| 184 |
|
| 185 |
-
|
| 186 |
|
| 187 |
-
|
| 188 |
-
|
| 189 |
-
|
| 190 |
-
|
| 191 |
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
|
| 201 |
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
|
| 206 |
-
|
| 207 |
-
|
| 208 |
-
|
| 209 |
|
| 210 |
-
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
|
| 214 |
-
|
| 215 |
-
|
| 216 |
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
|
| 220 |
-
|
| 221 |
|
| 222 |
-
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
|
| 232 |
-
|
| 233 |
-
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
actionArea.appendChild(btnLike); actionArea.appendChild(btnFav); actionArea.appendChild(btnUse);
|
| 237 |
-
detailView.appendChild(actionArea);
|
| 238 |
|
| 239 |
-
|
| 240 |
-
|
| 241 |
-
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
|
| 245 |
-
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
|
| 255 |
-
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
|
| 266 |
-
|
| 267 |
-
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
|
| 274 |
-
|
| 275 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 276 |
}
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
|
| 280 |
-
|
| 281 |
-
|
| 282 |
-
detailView.appendChild(ratingSection);
|
| 283 |
|
| 284 |
-
|
| 285 |
-
|
| 286 |
|
| 287 |
-
|
| 288 |
-
|
| 289 |
-
|
| 290 |
-
|
| 291 |
-
|
| 292 |
-
|
| 293 |
-
|
| 294 |
-
|
| 295 |
-
|
| 296 |
-
|
| 297 |
-
|
| 298 |
-
|
| 299 |
-
|
| 300 |
-
|
| 301 |
-
|
| 302 |
-
|
| 303 |
-
|
| 304 |
-
|
| 305 |
-
|
| 306 |
|
| 307 |
-
|
| 308 |
-
|
| 309 |
|
| 310 |
-
|
| 311 |
-
|
| 312 |
-
|
| 313 |
-
|
| 314 |
-
|
| 315 |
|
| 316 |
-
|
| 317 |
-
|
| 318 |
-
|
| 319 |
|
| 320 |
-
|
| 321 |
-
|
| 322 |
-
|
| 323 |
-
|
| 324 |
-
|
| 325 |
-
|
| 326 |
-
|
| 327 |
|
| 328 |
-
|
| 329 |
-
|
| 330 |
-
|
| 331 |
|
| 332 |
-
|
| 333 |
-
|
| 334 |
-
|
| 335 |
-
|
| 336 |
-
|
| 337 |
|
| 338 |
-
|
| 339 |
-
|
| 340 |
-
|
| 341 |
-
|
| 342 |
-
|
| 343 |
-
|
| 344 |
-
|
| 345 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 346 |
|
| 347 |
-
|
| 348 |
-
|
| 349 |
-
|
| 350 |
-
|
| 351 |
-
|
| 352 |
-
|
| 353 |
-
|
| 354 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 355 |
}
|
| 356 |
-
openTipModal(currentUser, { account: itemData.author }, undefined, itemData.id,
|
| 357 |
-
{ isCurrent: () => card.isConnected });
|
| 358 |
-
};
|
| 359 |
|
| 360 |
-
|
| 361 |
-
|
| 362 |
-
refundArea.id = `refund-area-${itemData.id}`;
|
| 363 |
-
refundArea.className = "resource-detail__refund";
|
| 364 |
-
refundArea.style.display = "none";
|
| 365 |
-
detailView.appendChild(refundArea);
|
| 366 |
|
| 367 |
let isRendered = false;
|
| 368 |
let commentUI = null;
|
|
@@ -370,7 +407,9 @@ export function createItemCard(itemData, currentUser = null, contextType = null)
|
|
| 370 |
let trendChartStopped = false;
|
| 371 |
const toggleButton = summaryView.querySelector('.card-summary__toggle');
|
| 372 |
const setExpanded = (expanded) => {
|
|
|
|
| 373 |
if (expanded) {
|
|
|
|
| 374 |
mountComments();
|
| 375 |
if (isRendered) setupImageSandboxEvents(detailView);
|
| 376 |
} else cleanupImageSandbox(detailView);
|
|
@@ -383,6 +422,7 @@ export function createItemCard(itemData, currentUser = null, contextType = null)
|
|
| 383 |
trendChart?.setActive(expanded);
|
| 384 |
};
|
| 385 |
summaryView.onclick = (event) => {
|
|
|
|
| 386 |
// 摘要中的作者、评分等独立控件不触发折叠;标题按钮使用浏览器原生键盘行为。
|
| 387 |
const control = event.target.closest('button, a, input, select, textarea, [role="button"]');
|
| 388 |
if (control && control !== toggleButton) return;
|
|
@@ -418,11 +458,6 @@ export function createItemCard(itemData, currentUser = null, contextType = null)
|
|
| 418 |
toggleButton.focus();
|
| 419 |
});
|
| 420 |
|
| 421 |
-
const commentsContainer = document.createElement("div");
|
| 422 |
-
commentsContainer.className = "resource-detail__comments";
|
| 423 |
-
|
| 424 |
-
// 🚀 核心修改:传入一个回调函数,当组件内部发送/删除留言时,外部的数字能实时响应刷新!
|
| 425 |
-
// 🚀 P0安全修复:传递 itemData.author 作为 contentAuthor,使内容作者可以删除其内容下的评论
|
| 426 |
function mountComments() {
|
| 427 |
if (commentUI) return;
|
| 428 |
commentUI = createCommentSection(itemData.id, itemData.commentsData || [], currentUser, (newCount) => {
|
|
@@ -431,32 +466,6 @@ export function createItemCard(itemData, currentUser = null, contextType = null)
|
|
| 431 |
}, itemData.author);
|
| 432 |
commentsContainer.appendChild(commentUI);
|
| 433 |
}
|
| 434 |
-
detailView.appendChild(commentsContainer);
|
| 435 |
-
|
| 436 |
-
if (currentUser && currentUser.account === itemData.author) {
|
| 437 |
-
const authorActionArea = document.createElement("div");
|
| 438 |
-
authorActionArea.className = "resource-detail__manage";
|
| 439 |
-
|
| 440 |
-
authorActionArea.innerHTML = `
|
| 441 |
-
<div class="resource-detail__manage-title">👑 ${t('market.creator_manage')}</div>
|
| 442 |
-
${IS_WEB_MODE ? '' : `<button type="button" id="btn-edit-item" class="resource-detail__button resource-detail__button--primary">✏️ ${t('market.edit_content')}</button>`}
|
| 443 |
-
<button type="button" id="btn-del-item" class="resource-detail__button resource-detail__button--danger">🗑️ ${t('market.delete_permanently')}</button>
|
| 444 |
-
`;
|
| 445 |
-
|
| 446 |
-
// 📱 Web 模式不渲染编辑按钮,此处需空值保护
|
| 447 |
-
const btnEditItem = authorActionArea.querySelector("#btn-edit-item");
|
| 448 |
-
if (btnEditItem) btnEditItem.onclick = (e) => {
|
| 449 |
-
e.stopPropagation();
|
| 450 |
-
window.dispatchEvent(new CustomEvent("comfy-route-edit-publish", { detail: { itemData, currentUser } }));
|
| 451 |
-
};
|
| 452 |
-
|
| 453 |
-
authorActionArea.querySelector("#btn-del-item").onclick = async (e) => {
|
| 454 |
-
e.stopPropagation();
|
| 455 |
-
await showResourceDeleteDialog({ itemData, currentUser, isCurrent: () => card.isConnected,
|
| 456 |
-
onDeleted: () => window.dispatchEvent(new CustomEvent("comfy-trigger-sidebar-reload")) });
|
| 457 |
-
};
|
| 458 |
-
detailView.appendChild(authorActionArea);
|
| 459 |
-
}
|
| 460 |
|
| 461 |
// 🖼️ 启用图片懒加载(跳过 data URL 和已处理的)
|
| 462 |
lazyLoadImages(card);
|
|
|
|
| 173 |
detailView.className = "resource-detail";
|
| 174 |
detailView.style.display = "none";
|
| 175 |
|
| 176 |
+
let commentsContainer, refundArea, chartContainerId;
|
| 177 |
+
let detailsMounted = false;
|
| 178 |
+
function mountDetails() {
|
| 179 |
+
if (detailsMounted) return;
|
| 180 |
+
const authorInfo = document.createElement("div");
|
| 181 |
+
authorInfo.className = "resource-detail__author";
|
| 182 |
|
| 183 |
+
// 🔄 P7后悔模式:检查是否有待生效价格
|
| 184 |
+
const priceHtml = _generatePriceHTML(itemData, t);
|
| 185 |
|
| 186 |
+
authorInfo.innerHTML = `${t('market.author')}: <button type="button" class="author-name-link card-author-link" ${itemData.author ? '' : 'disabled'}>${t('common.loading')}...</button> ${priceHtml}`;
|
| 187 |
+
detailView.appendChild(authorInfo);
|
| 188 |
|
| 189 |
+
const nameDOM = authorInfo.querySelector('.author-name-link');
|
| 190 |
|
| 191 |
+
// 使用统一辅助函数加载作者名称
|
| 192 |
+
_loadAuthorProfile(itemData.author, {
|
| 193 |
+
onName: (name) => { nameDOM.textContent = name; }
|
| 194 |
+
});
|
| 195 |
|
| 196 |
+
nameDOM.onclick = (e) => { e.stopPropagation(); openOtherUserProfileModal(itemData.author, currentUser); };
|
| 197 |
+
|
| 198 |
+
// 原创内容标识
|
| 199 |
+
if (itemData.is_original) {
|
| 200 |
+
const originalBadge = document.createElement("div");
|
| 201 |
+
originalBadge.className = "resource-detail__badge resource-detail__badge--original";
|
| 202 |
+
originalBadge.textContent = "🎨 " + t('publish.mark_original');
|
| 203 |
+
detailView.appendChild(originalBadge);
|
| 204 |
+
}
|
| 205 |
|
| 206 |
+
// 支持退款标识(仅工具、Skill和应用类型显示,且允许退款时)
|
| 207 |
+
if (itemData.allow_refund !== false && (itemData.type === 'tool' || itemData.type === 'skill' || itemData.type === 'app')) {
|
| 208 |
+
const refundBadge = document.createElement("div");
|
| 209 |
+
refundBadge.className = "resource-detail__badge resource-detail__badge--refundable";
|
| 210 |
+
refundBadge.textContent = `🛡️ ${t('item.refundable')}`;
|
| 211 |
+
detailView.appendChild(refundBadge);
|
| 212 |
+
}
|
| 213 |
|
| 214 |
+
const actionArea = document.createElement("div");
|
| 215 |
+
actionArea.className = "resource-detail__actions";
|
| 216 |
+
const btnLike = document.createElement("button");
|
| 217 |
+
btnLike.type = "button";
|
| 218 |
+
const btnFav = document.createElement("button");
|
| 219 |
+
btnFav.type = "button";
|
| 220 |
|
| 221 |
+
// 🚀 根据安装状态显示不同的按钮样式(installStatus 已在上方声明)
|
| 222 |
+
const btnUse = document.createElement("button");
|
| 223 |
+
btnUse.type = "button";
|
| 224 |
+
btnUse.className = "resource-detail__button resource-detail__use";
|
| 225 |
|
| 226 |
+
if (installStatus.hasUpdate) {
|
| 227 |
+
// 有更新可用
|
| 228 |
+
btnUse.classList.add("resource-detail__button--warning");
|
| 229 |
+
btnUse.innerHTML = `♻️ ${t('market.update_available')}`;
|
| 230 |
+
} else if (installStatus.installed) {
|
| 231 |
+
// 已安装
|
| 232 |
+
btnUse.classList.add("resource-detail__button--success");
|
| 233 |
+
btnUse.innerHTML = `✅ ${t('market.installed')}`;
|
| 234 |
+
} else {
|
| 235 |
+
// 未安装
|
| 236 |
+
btnUse.classList.add("resource-detail__button--primary");
|
| 237 |
+
btnUse.textContent = `🚀 ${t('market.get_now')} ${itemData.uses ? '(' + itemData.uses + ')' : ''}`;
|
| 238 |
+
}
|
|
|
|
|
|
|
|
|
|
| 239 |
|
| 240 |
+
actionArea.appendChild(btnLike); actionArea.appendChild(btnFav); actionArea.appendChild(btnUse);
|
| 241 |
+
detailView.appendChild(actionArea);
|
| 242 |
+
|
| 243 |
+
// ⭐ 展开详情区完整评分组件(互动按钮栏下方、打赏榜单上方)
|
| 244 |
+
const ratingSection = createRatingStars({
|
| 245 |
+
ratingData: {
|
| 246 |
+
rating_avg: itemData.rating_avg || 0,
|
| 247 |
+
rating_count: itemData.rating_count || 0,
|
| 248 |
+
rating_dist: itemData.rating_dist || {"1":0,"2":0,"3":0,"4":0,"5":0},
|
| 249 |
+
rated_by: itemData.rated_by || {}
|
| 250 |
+
},
|
| 251 |
+
currentUser: currentUser,
|
| 252 |
+
authorAccount: itemData.author,
|
| 253 |
+
isCurrent: ratingCurrent,
|
| 254 |
+
onRate: async (score, requestContext) => {
|
| 255 |
+
const current = () => ratingCurrent() && (!requestContext || requestContext.isCurrent());
|
| 256 |
+
if (!current()) return null;
|
| 257 |
+
const res = await api.rateItem(itemData.id, score);
|
| 258 |
+
if (!current()) return null;
|
| 259 |
+
if (isValidRatingResponse(res, score)) {
|
| 260 |
+
itemData.rating_avg = res.rating_avg;
|
| 261 |
+
itemData.rating_count = res.rating_count;
|
| 262 |
+
itemData.rating_dist = res.rating_dist;
|
| 263 |
+
if (!itemData.rated_by) itemData.rated_by = {};
|
| 264 |
+
itemData.rated_by[currentUser.account] = { score: res.user_score, time: Date.now() / 1000 };
|
| 265 |
+
|
| 266 |
+
// 同步更新摘要区紧凑评分
|
| 267 |
+
const oldCompact = summaryView.querySelector(".card-rating-compact");
|
| 268 |
+
if (oldCompact) {
|
| 269 |
+
const newCompact = createRatingStars({
|
| 270 |
+
ratingData: {
|
| 271 |
+
rating_avg: itemData.rating_avg,
|
| 272 |
+
rating_count: itemData.rating_count,
|
| 273 |
+
rating_dist: itemData.rating_dist,
|
| 274 |
+
rated_by: itemData.rated_by
|
| 275 |
+
},
|
| 276 |
+
compact: true
|
| 277 |
+
});
|
| 278 |
+
newCompact.classList.add("card-rating-compact");
|
| 279 |
+
oldCompact.parentNode.replaceChild(newCompact, oldCompact);
|
| 280 |
+
}
|
| 281 |
}
|
| 282 |
+
return res;
|
| 283 |
+
},
|
| 284 |
+
compact: false
|
| 285 |
+
});
|
| 286 |
+
detailView.appendChild(ratingSection);
|
|
|
|
| 287 |
|
| 288 |
+
const isLiked = currentUser && Array.isArray(itemData.liked_by) && itemData.liked_by.includes(currentUser.account);
|
| 289 |
+
const isFav = currentUser && Array.isArray(itemData.favorited_by) && itemData.favorited_by.includes(currentUser.account);
|
| 290 |
|
| 291 |
+
const handleInteraction = async (type, isActive) => {
|
| 292 |
+
if (!currentUser?.account) {
|
| 293 |
+
showToast(t('feedback.login_required'), "warning");
|
| 294 |
+
return { status: "cancelled" };
|
| 295 |
+
}
|
| 296 |
+
const response = await api.toggleInteraction(itemData.id, currentUser.account, type, isActive);
|
| 297 |
+
if (response?.status === "success" && Number.isSafeInteger(response.new_count) && response.new_count >= 0) {
|
| 298 |
+
const membershipKey = type === "like" ? "liked_by" : "favorited_by";
|
| 299 |
+
const countKey = type === "like" ? "likes" : "favorites";
|
| 300 |
+
const previousMembers = Array.isArray(itemData[membershipKey]) ? itemData[membershipKey] : [];
|
| 301 |
+
const members = previousMembers.filter(account => account !== currentUser.account);
|
| 302 |
+
if (isActive) members.push(currentUser.account);
|
| 303 |
+
itemData[membershipKey] = members;
|
| 304 |
+
itemData[countKey] = response.new_count;
|
| 305 |
+
const summaryCount = summaryView.querySelector(type === "like" ? '[data-stat="likes"]' : '[data-stat="favorites"]');
|
| 306 |
+
if (summaryCount) summaryCount.textContent = `${type === "like" ? "👍" : "🔖"} ${response.new_count}`;
|
| 307 |
+
}
|
| 308 |
+
return response ?? { status: "error" };
|
| 309 |
+
};
|
| 310 |
|
| 311 |
+
setupToggleButton(btnLike, isLiked, itemData.likes || 0, `👍 ${t('market.liked')}`, `👍 ${t('market.like')}`, "#FF5722", (isActive) => handleInteraction("like", isActive));
|
| 312 |
+
setupToggleButton(btnFav, isFav, itemData.favorites || 0, `🔖 ${t('market.favorited')}`, `🔖 ${t('market.favorite')}`, "#FFC107", (isActive) => handleInteraction("favorite", isActive));
|
| 313 |
|
| 314 |
+
const inlineStatusBox = document.createElement("div");
|
| 315 |
+
inlineStatusBox.className = "resource-detail__status";
|
| 316 |
+
inlineStatusBox.style.display = "none";
|
| 317 |
+
detailView.appendChild(inlineStatusBox);
|
| 318 |
+
setupResourceInstall(btnUse, itemData, currentUser, inlineStatusBox);
|
| 319 |
|
| 320 |
+
const mediaArea = document.createElement("div");
|
| 321 |
+
chartContainerId = `chart-${Math.random().toString(36).substr(2, 9)}`;
|
| 322 |
+
const chartHtml = `<div class="resource-detail__heading">📈 ${t('market.usage_trend')}</div><div id="${chartContainerId}" class="resource-detail__chart"></div>`;
|
| 323 |
|
| 324 |
+
mediaArea.innerHTML = `
|
| 325 |
+
${chartHtml}
|
| 326 |
+
${getCoverSandboxHTML(itemData.imageUrls?.length > 0 ? itemData.imageUrls : itemData.coverUrl)}
|
| 327 |
+
<div class="resource-detail__heading">📝 ${t('market.full_description')}</div>
|
| 328 |
+
<div class="resource-detail__description">${escapeHtml(itemData.fullDesc)}</div>
|
| 329 |
+
`;
|
| 330 |
+
detailView.appendChild(mediaArea);
|
| 331 |
|
| 332 |
+
// 🚀 新增:赞赏贡献榜单与打赏按钮(带等级显示)
|
| 333 |
+
const tipArea = document.createElement("div");
|
| 334 |
+
tipArea.className = "resource-detail__tips";
|
| 335 |
|
| 336 |
+
// 使用统一的打赏榜单渲染工具(带星星/月亮/太阳等级)
|
| 337 |
+
const boardData = Array.isArray(itemData.tip_board)
|
| 338 |
+
? itemData.tip_board.filter(entry => entry && typeof entry === "object" && !Array.isArray(entry))
|
| 339 |
+
: [];
|
| 340 |
+
const boardHtml = renderTipBoardHTML(boardData, 5, t('market.no_tips_yet'), "small");
|
| 341 |
|
| 342 |
+
tipArea.innerHTML = `
|
| 343 |
+
<div class="resource-detail__tip-header">
|
| 344 |
+
<div class="resource-detail__heading resource-detail__tip-heading">💖 ${t('market.tip_board')} (TOP 5)</div>
|
| 345 |
+
<button type="button" class="btn-tip-item resource-detail__button resource-detail__button--tip">💰 ${t('market.tip')}</button>
|
| 346 |
+
</div>
|
| 347 |
+
${boardHtml}
|
| 348 |
+
`;
|
| 349 |
+
detailView.appendChild(tipArea);
|
| 350 |
+
|
| 351 |
+
// 🚀 绑定打赏按钮事件
|
| 352 |
+
tipArea.querySelector('.btn-tip-item').onclick = (e) => {
|
| 353 |
+
e.stopPropagation();
|
| 354 |
+
if (!currentUser) return showToast(t('feedback.login_required'), "warning");
|
| 355 |
+
// 🐛 Bug修复:防御性校验,防止 itemId 为空
|
| 356 |
+
if (!itemData.id) {
|
| 357 |
+
console.warn('⚠️ 列表卡片: itemData.id 为空,已拦截无效打赏请求');
|
| 358 |
+
return showToast(t('item.invalid_id_tip'), "error");
|
| 359 |
+
}
|
| 360 |
+
openTipModal(currentUser, { account: itemData.author }, undefined, itemData.id,
|
| 361 |
+
{ isCurrent: () => card.isConnected });
|
| 362 |
+
};
|
| 363 |
+
|
| 364 |
+
// 🔄 P7后悔模式:退款区域(仅在"我购买的"列表中显示)
|
| 365 |
+
refundArea = document.createElement("div");
|
| 366 |
+
refundArea.id = `refund-area-${itemData.id}`;
|
| 367 |
+
refundArea.className = "resource-detail__refund";
|
| 368 |
+
refundArea.style.display = "none";
|
| 369 |
+
detailView.appendChild(refundArea);
|
| 370 |
+
|
| 371 |
+
commentsContainer = document.createElement("div");
|
| 372 |
+
commentsContainer.className = "resource-detail__comments";
|
| 373 |
|
| 374 |
+
detailView.appendChild(commentsContainer);
|
| 375 |
+
|
| 376 |
+
if (currentUser && currentUser.account === itemData.author) {
|
| 377 |
+
const authorActionArea = document.createElement("div");
|
| 378 |
+
authorActionArea.className = "resource-detail__manage";
|
| 379 |
+
|
| 380 |
+
authorActionArea.innerHTML = `
|
| 381 |
+
<div class="resource-detail__manage-title">👑 ${t('market.creator_manage')}</div>
|
| 382 |
+
${IS_WEB_MODE ? '' : `<button type="button" id="btn-edit-item" class="resource-detail__button resource-detail__button--primary">✏️ ${t('market.edit_content')}</button>`}
|
| 383 |
+
<button type="button" id="btn-del-item" class="resource-detail__button resource-detail__button--danger">🗑️ ${t('market.delete_permanently')}</button>
|
| 384 |
+
`;
|
| 385 |
+
|
| 386 |
+
// 📱 Web 模式不渲染编辑按钮,此处需空值保护
|
| 387 |
+
const btnEditItem = authorActionArea.querySelector("#btn-edit-item");
|
| 388 |
+
if (btnEditItem) btnEditItem.onclick = (e) => {
|
| 389 |
+
e.stopPropagation();
|
| 390 |
+
window.dispatchEvent(new CustomEvent("comfy-route-edit-publish", { detail: { itemData, currentUser } }));
|
| 391 |
+
};
|
| 392 |
+
|
| 393 |
+
authorActionArea.querySelector("#btn-del-item").onclick = async (e) => {
|
| 394 |
+
e.stopPropagation();
|
| 395 |
+
await showResourceDeleteDialog({ itemData, currentUser, isCurrent: () => card.isConnected,
|
| 396 |
+
onDeleted: () => window.dispatchEvent(new CustomEvent("comfy-trigger-sidebar-reload")) });
|
| 397 |
+
};
|
| 398 |
+
detailView.appendChild(authorActionArea);
|
| 399 |
}
|
|
|
|
|
|
|
|
|
|
| 400 |
|
| 401 |
+
detailsMounted = true;
|
| 402 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 403 |
|
| 404 |
let isRendered = false;
|
| 405 |
let commentUI = null;
|
|
|
|
| 407 |
let trendChartStopped = false;
|
| 408 |
const toggleButton = summaryView.querySelector('.card-summary__toggle');
|
| 409 |
const setExpanded = (expanded) => {
|
| 410 |
+
if (trendChartStopped) return;
|
| 411 |
if (expanded) {
|
| 412 |
+
mountDetails();
|
| 413 |
mountComments();
|
| 414 |
if (isRendered) setupImageSandboxEvents(detailView);
|
| 415 |
} else cleanupImageSandbox(detailView);
|
|
|
|
| 422 |
trendChart?.setActive(expanded);
|
| 423 |
};
|
| 424 |
summaryView.onclick = (event) => {
|
| 425 |
+
if (trendChartStopped || !ratingCurrent()) return;
|
| 426 |
// 摘要中的作者、评分等独立控件不触发折叠;标题按钮使用浏览器原生键盘行为。
|
| 427 |
const control = event.target.closest('button, a, input, select, textarea, [role="button"]');
|
| 428 |
if (control && control !== toggleButton) return;
|
|
|
|
| 458 |
toggleButton.focus();
|
| 459 |
});
|
| 460 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 461 |
function mountComments() {
|
| 462 |
if (commentUI) return;
|
| 463 |
commentUI = createCommentSection(itemData.id, itemData.commentsData || [], currentUser, (newCount) => {
|
|
|
|
| 466 |
}, itemData.author);
|
| 467 |
commentsContainer.appendChild(commentUI);
|
| 468 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 469 |
|
| 470 |
// 🖼️ 启用图片懒加载(跳过 data URL 和已处理的)
|
| 471 |
lazyLoadImages(card);
|
前端页面/market/发布内容_UI模板.js
CHANGED
|
@@ -13,7 +13,7 @@ export function generatePublishHTML(isEditMode, viewTitle, submitBtnText, hasExi
|
|
| 13 |
|
| 14 |
<div class="ranking-publish__row">
|
| 15 |
<div class="ranking-publish__field">
|
| 16 |
-
<label for="pub-type">${escapeHtml(t('publish.main_category'))} <span class="ranking-publish__required" aria-hidden="true">
|
| 17 |
<select id="pub-type" class="form-input" aria-required="true">
|
| 18 |
<option value="tool">🧰 ${escapeHtml(t('publish.type_tool'))}</option>
|
| 19 |
<option value="skill">⚡ ${escapeHtml(t('publish.type_skill'))}</option>
|
|
@@ -22,7 +22,7 @@ export function generatePublishHTML(isEditMode, viewTitle, submitBtnText, hasExi
|
|
| 22 |
</select>
|
| 23 |
</div>
|
| 24 |
<div id="box-recommend-type" class="ranking-publish__field" style="display: none;">
|
| 25 |
-
<label for="pub-recommend-type">${escapeHtml(t('publish.recommend_form'))} <span class="ranking-publish__required" aria-hidden="true">
|
| 26 |
<select id="pub-recommend-type" class="form-input" aria-required="true">
|
| 27 |
<option value="recommend_tool">🧰 ${escapeHtml(t('publish.recommend_as_tool'))}</option>
|
| 28 |
<option value="recommend_skill">⚡ ${escapeHtml(t('publish.recommend_as_skill'))}</option>
|
|
@@ -31,19 +31,19 @@ export function generatePublishHTML(isEditMode, viewTitle, submitBtnText, hasExi
|
|
| 31 |
</select>
|
| 32 |
</div>
|
| 33 |
<div class="ranking-publish__field ranking-publish__field--wide">
|
| 34 |
-
<label for="pub-title">${escapeHtml(t('publish.name'))} <span class="ranking-publish__required" aria-hidden="true">
|
| 35 |
<input type="text" id="pub-title" placeholder="${escapeHtml(t('publish.name_placeholder'))}" required class="form-input">
|
| 36 |
</div>
|
| 37 |
</div>
|
| 38 |
|
| 39 |
<div class="ranking-publish__field">
|
| 40 |
-
<label for="pub-short">${escapeHtml(t('publish.short_desc'))} <span class="ranking-publish__required" aria-hidden="true">
|
| 41 |
<input type="text" id="pub-short" placeholder="${escapeHtml(t('publish.short_desc_placeholder'))}" maxlength="50" required class="form-input">
|
| 42 |
</div>
|
| 43 |
|
| 44 |
<div class="ranking-publish__row ranking-publish__panel">
|
| 45 |
<div class="ranking-publish__field" id="box-resource-select">
|
| 46 |
-
<label for="pub-resource-type">${escapeHtml(t('publish.resource_type'))} <span class="ranking-publish__required" aria-hidden="true">
|
| 47 |
<select id="pub-resource-type" class="form-input" aria-required="true">
|
| 48 |
<option value="link">🔗 ${escapeHtml(t('publish.resource_link'))}</option>
|
| 49 |
<option value="json">📄 ${escapeHtml(t('publish.resource_json'))}</option>
|
|
@@ -51,15 +51,15 @@ export function generatePublishHTML(isEditMode, viewTitle, submitBtnText, hasExi
|
|
| 51 |
</select>
|
| 52 |
</div>
|
| 53 |
<div class="ranking-publish__field ranking-publish__field--wide" id="box-link">
|
| 54 |
-
<label for="pub-link">${escapeHtml(t('publish.source_url'))} <span class="ranking-publish__required" aria-hidden="true">
|
| 55 |
<input type="text" id="pub-link" placeholder="${escapeHtml(t('publish.source_url_placeholder'))}" class="form-input" aria-required="true">
|
| 56 |
</div>
|
| 57 |
<div class="ranking-publish__field ranking-publish__field--wide" id="box-json" style="display: none;">
|
| 58 |
-
<label for="pub-json">${escapeHtml(t('publish.select_json'))} <span class="ranking-publish__required" aria-hidden="true">
|
| 59 |
<input type="file" id="pub-json" accept=".json" aria-describedby="json-file-hint" class="ranking-publish__file">
|
| 60 |
</div>
|
| 61 |
<div class="ranking-publish__field ranking-publish__field--wide" id="box-netdisk" style="display: none;">
|
| 62 |
-
<label for="pub-netdisk-link">${escapeHtml(t('publish.netdisk_link'))} <span class="ranking-publish__required" aria-hidden="true">
|
| 63 |
<input type="text" id="pub-netdisk-link" placeholder="${escapeHtml(t('publish.netdisk_placeholder'))}" class="form-input" aria-required="true">
|
| 64 |
</div>
|
| 65 |
</div>
|
|
@@ -80,7 +80,7 @@ export function generatePublishHTML(isEditMode, viewTitle, submitBtnText, hasExi
|
|
| 80 |
<span>${escapeHtml(t('publish.private_repo_hint'))}</span>
|
| 81 |
</label>
|
| 82 |
<div id="github-token-container" class="ranking-publish__token" style="display: ${hasExistingToken ? 'block' : 'none'};">
|
| 83 |
-
<label for="pub-github-token" class="ranking-publish__security-label">🔒 ${escapeHtml(t('publish.pat_label'))} <span class="ranking-publish__required" aria-hidden="true">
|
| 84 |
<div id="publish-pat-hint" class="ranking-publish__hint">${escapeHtml(t('publish.pat_hint'))} <strong class="ranking-publish__security-emphasis">${escapeHtml(t('publish.pat_privacy'))}</strong></div>
|
| 85 |
<input type="password" id="pub-github-token" value="${escapeHtml(isEditMode ? (safeData.github_token || '') : '')}" placeholder="${hasExistingToken && !safeData.github_token ? escapeHtml(t('publish.token_keep_hint')) : escapeHtml(t('publish.token_placeholder'))}" class="form-input" aria-describedby="publish-pat-hint">
|
| 86 |
</div>
|
|
@@ -95,7 +95,7 @@ export function generatePublishHTML(isEditMode, viewTitle, submitBtnText, hasExi
|
|
| 95 |
|
| 96 |
<div id="box-price" class="ranking-publish__row">
|
| 97 |
<div class="ranking-publish__field">
|
| 98 |
-
<label for="pub-price">${escapeHtml(t('publish.price'))} <span class="ranking-publish__required" aria-hidden="true">
|
| 99 |
<input type="number" id="pub-price" value="0" min="0" class="form-input ranking-publish__price" aria-required="true" aria-describedby="publish-price-hint price-pending-hint">
|
| 100 |
<div id="price-pending-hint" class="ranking-publish__pending" role="status" style="display: none;"></div>
|
| 101 |
</div>
|
|
|
|
| 13 |
|
| 14 |
<div class="ranking-publish__row">
|
| 15 |
<div class="ranking-publish__field">
|
| 16 |
+
<label for="pub-type">${escapeHtml(t('publish.main_category'))} <span class="ranking-publish__required ranking-required-marker" aria-hidden="true"></span></label>
|
| 17 |
<select id="pub-type" class="form-input" aria-required="true">
|
| 18 |
<option value="tool">🧰 ${escapeHtml(t('publish.type_tool'))}</option>
|
| 19 |
<option value="skill">⚡ ${escapeHtml(t('publish.type_skill'))}</option>
|
|
|
|
| 22 |
</select>
|
| 23 |
</div>
|
| 24 |
<div id="box-recommend-type" class="ranking-publish__field" style="display: none;">
|
| 25 |
+
<label for="pub-recommend-type">${escapeHtml(t('publish.recommend_form'))} <span class="ranking-publish__required ranking-required-marker" aria-hidden="true"></span></label>
|
| 26 |
<select id="pub-recommend-type" class="form-input" aria-required="true">
|
| 27 |
<option value="recommend_tool">🧰 ${escapeHtml(t('publish.recommend_as_tool'))}</option>
|
| 28 |
<option value="recommend_skill">⚡ ${escapeHtml(t('publish.recommend_as_skill'))}</option>
|
|
|
|
| 31 |
</select>
|
| 32 |
</div>
|
| 33 |
<div class="ranking-publish__field ranking-publish__field--wide">
|
| 34 |
+
<label for="pub-title">${escapeHtml(t('publish.name'))} <span class="ranking-publish__required ranking-required-marker" aria-hidden="true"></span></label>
|
| 35 |
<input type="text" id="pub-title" placeholder="${escapeHtml(t('publish.name_placeholder'))}" required class="form-input">
|
| 36 |
</div>
|
| 37 |
</div>
|
| 38 |
|
| 39 |
<div class="ranking-publish__field">
|
| 40 |
+
<label for="pub-short">${escapeHtml(t('publish.short_desc'))} <span class="ranking-publish__required ranking-required-marker" aria-hidden="true"></span></label>
|
| 41 |
<input type="text" id="pub-short" placeholder="${escapeHtml(t('publish.short_desc_placeholder'))}" maxlength="50" required class="form-input">
|
| 42 |
</div>
|
| 43 |
|
| 44 |
<div class="ranking-publish__row ranking-publish__panel">
|
| 45 |
<div class="ranking-publish__field" id="box-resource-select">
|
| 46 |
+
<label for="pub-resource-type">${escapeHtml(t('publish.resource_type'))} <span class="ranking-publish__required ranking-required-marker" aria-hidden="true"></span></label>
|
| 47 |
<select id="pub-resource-type" class="form-input" aria-required="true">
|
| 48 |
<option value="link">🔗 ${escapeHtml(t('publish.resource_link'))}</option>
|
| 49 |
<option value="json">📄 ${escapeHtml(t('publish.resource_json'))}</option>
|
|
|
|
| 51 |
</select>
|
| 52 |
</div>
|
| 53 |
<div class="ranking-publish__field ranking-publish__field--wide" id="box-link">
|
| 54 |
+
<label for="pub-link">${escapeHtml(t('publish.source_url'))} <span class="ranking-publish__required ranking-required-marker" aria-hidden="true"></span></label>
|
| 55 |
<input type="text" id="pub-link" placeholder="${escapeHtml(t('publish.source_url_placeholder'))}" class="form-input" aria-required="true">
|
| 56 |
</div>
|
| 57 |
<div class="ranking-publish__field ranking-publish__field--wide" id="box-json" style="display: none;">
|
| 58 |
+
<label for="pub-json">${escapeHtml(t('publish.select_json'))} <span class="ranking-publish__required ranking-required-marker" aria-hidden="true"></span> <span id="json-file-hint" class="ranking-publish__file-hint" style="display: none;">(${escapeHtml(t('publish.has_cloud_file'))})</span></label>
|
| 59 |
<input type="file" id="pub-json" accept=".json" aria-describedby="json-file-hint" class="ranking-publish__file">
|
| 60 |
</div>
|
| 61 |
<div class="ranking-publish__field ranking-publish__field--wide" id="box-netdisk" style="display: none;">
|
| 62 |
+
<label for="pub-netdisk-link">${escapeHtml(t('publish.netdisk_link'))} <span class="ranking-publish__required ranking-required-marker" aria-hidden="true"></span></label>
|
| 63 |
<input type="text" id="pub-netdisk-link" placeholder="${escapeHtml(t('publish.netdisk_placeholder'))}" class="form-input" aria-required="true">
|
| 64 |
</div>
|
| 65 |
</div>
|
|
|
|
| 80 |
<span>${escapeHtml(t('publish.private_repo_hint'))}</span>
|
| 81 |
</label>
|
| 82 |
<div id="github-token-container" class="ranking-publish__token" style="display: ${hasExistingToken ? 'block' : 'none'};">
|
| 83 |
+
<label for="pub-github-token" class="ranking-publish__security-label">🔒 ${escapeHtml(t('publish.pat_label'))} <span class="ranking-publish__required ranking-required-marker" aria-hidden="true"></span></label>
|
| 84 |
<div id="publish-pat-hint" class="ranking-publish__hint">${escapeHtml(t('publish.pat_hint'))} <strong class="ranking-publish__security-emphasis">${escapeHtml(t('publish.pat_privacy'))}</strong></div>
|
| 85 |
<input type="password" id="pub-github-token" value="${escapeHtml(isEditMode ? (safeData.github_token || '') : '')}" placeholder="${hasExistingToken && !safeData.github_token ? escapeHtml(t('publish.token_keep_hint')) : escapeHtml(t('publish.token_placeholder'))}" class="form-input" aria-describedby="publish-pat-hint">
|
| 86 |
</div>
|
|
|
|
| 95 |
|
| 96 |
<div id="box-price" class="ranking-publish__row">
|
| 97 |
<div class="ranking-publish__field">
|
| 98 |
+
<label for="pub-price">${escapeHtml(t('publish.price'))} <span class="ranking-publish__required ranking-required-marker" aria-hidden="true"></span></label>
|
| 99 |
<input type="number" id="pub-price" value="0" min="0" class="form-input ranking-publish__price" aria-required="true" aria-describedby="publish-price-hint price-pending-hint">
|
| 100 |
<div id="price-pending-hint" class="ranking-publish__pending" role="status" style="display: none;"></div>
|
| 101 |
</div>
|
前端页面/market/发布内容_提交引擎.js
CHANGED
|
@@ -294,7 +294,7 @@ export async function handlePublishSubmit(params) {
|
|
| 294 |
return;
|
| 295 |
}
|
| 296 |
// 已发出的保存可能在服务端提交;仅已知前置拒绝允许原表单重试。
|
| 297 |
-
const rejected = [400, 401, 403, 404, 409, 422, 429].includes(err?.status);
|
| 298 |
outcomeUnknown = saveAttempted && !rejected;
|
| 299 |
if (outcomeUnknown) {
|
| 300 |
showToast(t('publish.save_unconfirmed'), "warning");
|
|
|
|
| 294 |
return;
|
| 295 |
}
|
| 296 |
// 已发出的保存可能在服务端提交;仅已知前置拒绝允许原表单重试。
|
| 297 |
+
const rejected = (err?.requestBodyRejected === true || [400, 401, 403, 404, 409, 422, 429].includes(err?.status));
|
| 298 |
outcomeUnknown = saveAttempted && !rejected;
|
| 299 |
if (outcomeUnknown) {
|
| 300 |
showToast(t('publish.save_unconfirmed'), "warning");
|
前端页面/market/资金与钱包_充值组件.js
CHANGED
|
@@ -234,7 +234,7 @@ export async function openRechargeModal(currentUser, onBalanceChange) {
|
|
| 234 |
pollingTimer = setTimeout(poll, UI.RECHARGE_POLL_INTERVAL);
|
| 235 |
} catch (error) {
|
| 236 |
if (!scope.isCurrent()) return;
|
| 237 |
-
const rejected = [400, 401, 403, 404, 422, 429].includes(error.status);
|
| 238 |
qrLoading.textContent = t(rejected ? 'wallet.recharge.order_failed' : 'wallet.recharge.order_uncertain');
|
| 239 |
if (rejected) {
|
| 240 |
submitting = false;
|
|
|
|
| 234 |
pollingTimer = setTimeout(poll, UI.RECHARGE_POLL_INTERVAL);
|
| 235 |
} catch (error) {
|
| 236 |
if (!scope.isCurrent()) return;
|
| 237 |
+
const rejected = (error.requestBodyRejected === true || [400, 401, 403, 404, 422, 429].includes(error.status));
|
| 238 |
qrLoading.textContent = t(rejected ? 'wallet.recharge.order_failed' : 'wallet.recharge.order_uncertain');
|
| 239 |
if (rejected) {
|
| 240 |
submitting = false;
|
前端页面/market/资金与钱包_提现组件.js
CHANGED
|
@@ -99,7 +99,7 @@ export async function openWithdrawModal(currentUser, onSuccess) {
|
|
| 99 |
</div>
|
| 100 |
|
| 101 |
<div class="wallet-modal__field">
|
| 102 |
-
<label for="withdraw-amount" class="wallet-modal__label">${t('wallet.withdraw.amount_label')} <span class="wallet-modal__danger">
|
| 103 |
<input type="number" id="withdraw-amount" placeholder="${t('wallet.withdraw.amount_placeholder')}" max="${maxWithdraw}" min="1" step="1" class="wallet-modal__input">
|
| 104 |
|
| 105 |
<div id="fee-calc-box" class="wallet-withdraw__fee" style="display:none;">
|
|
@@ -108,17 +108,17 @@ export async function openWithdrawModal(currentUser, onSuccess) {
|
|
| 108 |
</div>
|
| 109 |
|
| 110 |
<div class="wallet-modal__field">
|
| 111 |
-
<label for="withdraw-account" class="wallet-modal__label">${t('wallet.withdraw.alipay_account')} <span class="wallet-modal__danger">
|
| 112 |
<input type="text" id="withdraw-account" placeholder="${t('wallet.withdraw.alipay_placeholder')}" class="wallet-modal__input">
|
| 113 |
</div>
|
| 114 |
|
| 115 |
<div class="wallet-modal__field">
|
| 116 |
-
<label for="withdraw-name" class="wallet-modal__label">${t('wallet.withdraw.real_name')} <span class="wallet-modal__danger">
|
| 117 |
<input type="text" id="withdraw-name" placeholder="${t('wallet.withdraw.real_name_placeholder')}" class="wallet-modal__input">
|
| 118 |
</div>
|
| 119 |
|
| 120 |
<div class="wallet-modal__field wallet-modal__field--last">
|
| 121 |
-
<label for="withdraw-code" class="wallet-modal__label">${t('wallet.withdraw.security_code')} <span class="wallet-modal__danger">
|
| 122 |
<div class="wallet-withdraw__code-row">
|
| 123 |
<input type="text" id="withdraw-code" placeholder="${t('wallet.withdraw.code_placeholder')}" maxlength="6" class="wallet-modal__input wallet-withdraw__code-input">
|
| 124 |
<button type="button" id="btn-send-code" class="wallet-modal__button wallet-modal__button--code">${t('wallet.withdraw.get_code')}</button>
|
|
@@ -230,7 +230,7 @@ export async function openWithdrawModal(currentUser, onSuccess) {
|
|
| 230 |
} catch (error) {
|
| 231 |
clearTimeout(deadline);
|
| 232 |
if (!scope.isCurrent()) return;
|
| 233 |
-
const rejected = [400, 401, 403, 404, 422, 429].includes(error.status);
|
| 234 |
showToast(t(rejected ? 'wallet.withdraw.submit_failed' : 'wallet.withdraw.timeout'), 'warning');
|
| 235 |
if (rejected) {
|
| 236 |
isSubmitting = false;
|
|
|
|
| 99 |
</div>
|
| 100 |
|
| 101 |
<div class="wallet-modal__field">
|
| 102 |
+
<label for="withdraw-amount" class="wallet-modal__label">${t('wallet.withdraw.amount_label')} <span class="wallet-modal__danger ranking-required-marker"></span></label>
|
| 103 |
<input type="number" id="withdraw-amount" placeholder="${t('wallet.withdraw.amount_placeholder')}" max="${maxWithdraw}" min="1" step="1" class="wallet-modal__input">
|
| 104 |
|
| 105 |
<div id="fee-calc-box" class="wallet-withdraw__fee" style="display:none;">
|
|
|
|
| 108 |
</div>
|
| 109 |
|
| 110 |
<div class="wallet-modal__field">
|
| 111 |
+
<label for="withdraw-account" class="wallet-modal__label">${t('wallet.withdraw.alipay_account')} <span class="wallet-modal__danger ranking-required-marker"></span></label>
|
| 112 |
<input type="text" id="withdraw-account" placeholder="${t('wallet.withdraw.alipay_placeholder')}" class="wallet-modal__input">
|
| 113 |
</div>
|
| 114 |
|
| 115 |
<div class="wallet-modal__field">
|
| 116 |
+
<label for="withdraw-name" class="wallet-modal__label">${t('wallet.withdraw.real_name')} <span class="wallet-modal__danger ranking-required-marker"></span></label>
|
| 117 |
<input type="text" id="withdraw-name" placeholder="${t('wallet.withdraw.real_name_placeholder')}" class="wallet-modal__input">
|
| 118 |
</div>
|
| 119 |
|
| 120 |
<div class="wallet-modal__field wallet-modal__field--last">
|
| 121 |
+
<label for="withdraw-code" class="wallet-modal__label">${t('wallet.withdraw.security_code')} <span class="wallet-modal__danger ranking-required-marker"></span></label>
|
| 122 |
<div class="wallet-withdraw__code-row">
|
| 123 |
<input type="text" id="withdraw-code" placeholder="${t('wallet.withdraw.code_placeholder')}" maxlength="6" class="wallet-modal__input wallet-withdraw__code-input">
|
| 124 |
<button type="button" id="btn-send-code" class="wallet-modal__button wallet-modal__button--code">${t('wallet.withdraw.get_code')}</button>
|
|
|
|
| 230 |
} catch (error) {
|
| 231 |
clearTimeout(deadline);
|
| 232 |
if (!scope.isCurrent()) return;
|
| 233 |
+
const rejected = (error.requestBodyRejected === true || [400, 401, 403, 404, 422, 429].includes(error.status));
|
| 234 |
showToast(t(rejected ? 'wallet.withdraw.submit_failed' : 'wallet.withdraw.timeout'), 'warning');
|
| 235 |
if (rejected) {
|
| 236 |
isSubmitting = false;
|
前端页面/post/发布帖子组件.js
CHANGED
|
@@ -403,7 +403,7 @@ export function createPublishPostView(currentUser, editPostData = null) {
|
|
| 403 |
<!-- 图片上传区 -->
|
| 404 |
<div id="image-upload-section" class="post-publish__upload-section">
|
| 405 |
<label for="images-input" class="post-publish__field-label">
|
| 406 |
-
🖼️ ${t('post.upload_images')} <span class="post-publish__required">
|
| 407 |
<span class="post-publish__hint">(${t('post.max_9_images')})</span>
|
| 408 |
</label>
|
| 409 |
<input type="file" id="images-input" accept="image/*" multiple style="display: none;">
|
|
@@ -418,7 +418,7 @@ export function createPublishPostView(currentUser, editPostData = null) {
|
|
| 418 |
<!-- 视频上传区 -->
|
| 419 |
<div id="video-upload-section" style="display: none;" class="post-publish__upload-section">
|
| 420 |
<label for="video-input" class="post-publish__field-label">
|
| 421 |
-
🎬 ${t('post.upload_video')} <span class="post-publish__required">
|
| 422 |
<span class="post-publish__hint">${t('post.video_limits_hint', { megabytes: PUBLISH_MEDIA_LIMITS.VIDEO_MAX_BYTES / (1024 * 1024), minutes: PUBLISH_MEDIA_LIMITS.VIDEO_MAX_SECONDS / 60 })}</span>
|
| 423 |
</label>
|
| 424 |
<input type="file" id="video-input" accept="video/mp4,video/webm,video/quicktime" style="display: none;">
|
|
@@ -462,7 +462,7 @@ export function createPublishPostView(currentUser, editPostData = null) {
|
|
| 462 |
<!-- 标题输入 -->
|
| 463 |
<div class="post-publish__field-group">
|
| 464 |
<label for="title-input" class="post-publish__field-label">
|
| 465 |
-
📝 ${t('post.title_label')} <span class="post-publish__required">
|
| 466 |
</label>
|
| 467 |
<input type="text" id="title-input" class="ranking-publish-input" value="${escapeHtml(editTitle)}" placeholder="${t('post.title_placeholder')}" maxlength="50">
|
| 468 |
<div class="post-publish__counter">
|
|
@@ -1291,7 +1291,7 @@ export function createPublishPostView(currentUser, editPostData = null) {
|
|
| 1291 |
|
| 1292 |
} catch (err) {
|
| 1293 |
if (!scope.isCurrent() || committed) return;
|
| 1294 |
-
outcomeUnknown = saveAttempted && ![400, 401, 403, 404, 409, 422, 429].includes(err?.status);
|
| 1295 |
showToast(t(outcomeUnknown ? 'publish.save_unconfirmed' : (isEditMode ? 'post.edit_failed' : 'post.publish_failed')),
|
| 1296 |
outcomeUnknown ? 'warning' : 'error');
|
| 1297 |
} finally {
|
|
@@ -1379,7 +1379,7 @@ export function createPublishPostView(currentUser, editPostData = null) {
|
|
| 1379 |
|
| 1380 |
} catch (err) {
|
| 1381 |
if (!scope.isCurrent() || committed) return;
|
| 1382 |
-
outcomeUnknown = saveAttempted && ![400, 401, 403, 404, 409, 422, 429].includes(err?.status);
|
| 1383 |
showToast(t(outcomeUnknown ? 'publish.save_unconfirmed' : (isEditMode ? 'post.edit_failed' : 'post.publish_failed')),
|
| 1384 |
outcomeUnknown ? 'warning' : 'error');
|
| 1385 |
} finally {
|
|
|
|
| 403 |
<!-- 图片上传区 -->
|
| 404 |
<div id="image-upload-section" class="post-publish__upload-section">
|
| 405 |
<label for="images-input" class="post-publish__field-label">
|
| 406 |
+
🖼️ ${t('post.upload_images')} <span class="post-publish__required ranking-required-marker"></span>
|
| 407 |
<span class="post-publish__hint">(${t('post.max_9_images')})</span>
|
| 408 |
</label>
|
| 409 |
<input type="file" id="images-input" accept="image/*" multiple style="display: none;">
|
|
|
|
| 418 |
<!-- 视频上传区 -->
|
| 419 |
<div id="video-upload-section" style="display: none;" class="post-publish__upload-section">
|
| 420 |
<label for="video-input" class="post-publish__field-label">
|
| 421 |
+
🎬 ${t('post.upload_video')} <span class="post-publish__required ranking-required-marker"></span>
|
| 422 |
<span class="post-publish__hint">${t('post.video_limits_hint', { megabytes: PUBLISH_MEDIA_LIMITS.VIDEO_MAX_BYTES / (1024 * 1024), minutes: PUBLISH_MEDIA_LIMITS.VIDEO_MAX_SECONDS / 60 })}</span>
|
| 423 |
</label>
|
| 424 |
<input type="file" id="video-input" accept="video/mp4,video/webm,video/quicktime" style="display: none;">
|
|
|
|
| 462 |
<!-- 标题输入 -->
|
| 463 |
<div class="post-publish__field-group">
|
| 464 |
<label for="title-input" class="post-publish__field-label">
|
| 465 |
+
📝 ${t('post.title_label')} <span class="post-publish__required ranking-required-marker"></span>
|
| 466 |
</label>
|
| 467 |
<input type="text" id="title-input" class="ranking-publish-input" value="${escapeHtml(editTitle)}" placeholder="${t('post.title_placeholder')}" maxlength="50">
|
| 468 |
<div class="post-publish__counter">
|
|
|
|
| 1291 |
|
| 1292 |
} catch (err) {
|
| 1293 |
if (!scope.isCurrent() || committed) return;
|
| 1294 |
+
outcomeUnknown = saveAttempted && !(err?.requestBodyRejected === true || [400, 401, 403, 404, 409, 422, 429].includes(err?.status));
|
| 1295 |
showToast(t(outcomeUnknown ? 'publish.save_unconfirmed' : (isEditMode ? 'post.edit_failed' : 'post.publish_failed')),
|
| 1296 |
outcomeUnknown ? 'warning' : 'error');
|
| 1297 |
} finally {
|
|
|
|
| 1379 |
|
| 1380 |
} catch (err) {
|
| 1381 |
if (!scope.isCurrent() || committed) return;
|
| 1382 |
+
outcomeUnknown = saveAttempted && !(err?.requestBodyRejected === true || [400, 401, 403, 404, 409, 422, 429].includes(err?.status));
|
| 1383 |
showToast(t(outcomeUnknown ? 'publish.save_unconfirmed' : (isEditMode ? 'post.edit_failed' : 'post.publish_failed')),
|
| 1384 |
outcomeUnknown ? 'warning' : 'error');
|
| 1385 |
} finally {
|
前端页面/prompt/发布提示词组件.js
CHANGED
|
@@ -395,7 +395,7 @@ export function createPublishPromptView(currentUser, editPromptData = null) {
|
|
| 395 |
|
| 396 |
<!-- 分类选择 -->
|
| 397 |
<div class="prompt-publish__field">
|
| 398 |
-
<label for="category-select" class="prompt-publish__label">🏷️ ${t('prompt.category_label')} <span class="prompt-publish__required">
|
| 399 |
<select id="category-select" class="ranking-publish-input prompt-publish__select">
|
| 400 |
<option value="">${t('prompt.category_select')}</option>
|
| 401 |
</select>
|
|
@@ -412,7 +412,7 @@ export function createPublishPromptView(currentUser, editPromptData = null) {
|
|
| 412 |
|
| 413 |
<!-- 标题输入 -->
|
| 414 |
<div class="prompt-publish__field">
|
| 415 |
-
<label for="title-input" class="prompt-publish__label">📝 ${t('prompt.title_label')} <span class="prompt-publish__required">
|
| 416 |
<input type="text" id="title-input" class="ranking-publish-input" value="${escapeAttr(editTitle)}" placeholder="${t('prompt.title_placeholder')}" maxlength="50">
|
| 417 |
<div class="prompt-publish__count">
|
| 418 |
<span id="title-count">${editTitle.length}</span>/50
|
|
@@ -421,7 +421,7 @@ export function createPublishPromptView(currentUser, editPromptData = null) {
|
|
| 421 |
|
| 422 |
<!-- 文案/简介输入 -->
|
| 423 |
<div class="prompt-publish__field">
|
| 424 |
-
<label for="content-input" class="prompt-publish__label">✍️ ${t('prompt.content_label')} <span class="prompt-publish__required">
|
| 425 |
<textarea id="content-input" class="ranking-publish-input prompt-publish__description" placeholder="${t('prompt.content_placeholder')}" maxlength="2000">${escapeHtml(editContent)}</textarea>
|
| 426 |
<div class="prompt-publish__count">
|
| 427 |
<span id="content-count">${editContent.length}</span>/2000
|
|
@@ -430,7 +430,7 @@ export function createPublishPromptView(currentUser, editPromptData = null) {
|
|
| 430 |
|
| 431 |
<!-- 提示词正文(付费内容) -->
|
| 432 |
<div class="prompt-publish__field">
|
| 433 |
-
<label for="text-input" class="prompt-publish__label">🔑 ${t('prompt.text_label')} <span class="prompt-publish__required">
|
| 434 |
<textarea id="text-input" class="ranking-publish-input prompt-publish__text" placeholder="${t('prompt.text_placeholder')}" maxlength="20000">${escapeHtml(editText)}</textarea>
|
| 435 |
<div class="prompt-publish__count">
|
| 436 |
<span id="text-count">${editText.length}</span>/20000
|
|
@@ -457,7 +457,7 @@ export function createPublishPromptView(currentUser, editPromptData = null) {
|
|
| 457 |
|
| 458 |
<!-- 图片上传区(图像提示词专用:多图 + 拖拽排序,首张为封面) -->
|
| 459 |
<div id="image-upload-section" class="prompt-publish__field">
|
| 460 |
-
<label class="prompt-publish__label">🖼️ ${t('post.upload_images')} <span class="prompt-publish__required">
|
| 461 |
<span class="prompt-publish__optional">(${t('post.max_9_images')})</span>
|
| 462 |
</label>
|
| 463 |
<input type="file" id="images-input" accept="image/*" multiple style="display: none;">
|
|
@@ -471,7 +471,7 @@ export function createPublishPromptView(currentUser, editPromptData = null) {
|
|
| 471 |
|
| 472 |
<!-- 视频上传区(视频提示词专用:截取当前帧或手动上传封面) -->
|
| 473 |
<div id="video-upload-section" style="display: none;" class="prompt-publish__media-section">
|
| 474 |
-
<label class="prompt-publish__label">🎬 ${t('prompt.video_label')} <span id="video-required-mark" class="prompt-publish__required">
|
| 475 |
<input type="file" id="video-input" accept="video/mp4,video/webm,video/quicktime" style="display: none;">
|
| 476 |
<div id="video-preview-area" class="prompt-publish__media">
|
| 477 |
<div id="video-empty-state" class="prompt-publish__empty">
|
|
@@ -512,7 +512,7 @@ export function createPublishPromptView(currentUser, editPromptData = null) {
|
|
| 512 |
|
| 513 |
<!-- 🎵 音频上传区(音乐提示词专用:图片+音频方案,视频可选) -->
|
| 514 |
<div id="audio-upload-section" style="display: none;" class="prompt-publish__media-section">
|
| 515 |
-
<label class="prompt-publish__label">🎵 ${t('prompt.audio_label')} <span class="prompt-publish__required">
|
| 516 |
<div class="prompt-publish__media-hint">${t('prompt.music_media_hint')}</div>
|
| 517 |
<input type="file" id="audio-input" accept="audio/mpeg,audio/wav,audio/x-wav,audio/mp4,audio/x-m4a,audio/ogg,.mp3,.wav,.m4a,.ogg" style="display: none;">
|
| 518 |
<div id="audio-preview-area" class="prompt-publish__media">
|
|
@@ -1694,7 +1694,7 @@ export function createPublishPromptView(currentUser, editPromptData = null) {
|
|
| 1694 |
if (!scope.isCurrent()) return;
|
| 1695 |
if (committed) return;
|
| 1696 |
console.error("提示词发布失败");
|
| 1697 |
-
outcomeUnknown = saveAttempted && ![400, 401, 403, 404, 409, 422, 429].includes(err?.status);
|
| 1698 |
showToast(t(outcomeUnknown ? 'publish.save_unconfirmed' : 'prompt.publish_failed'),
|
| 1699 |
outcomeUnknown ? 'warning' : 'error');
|
| 1700 |
} finally {
|
|
|
|
| 395 |
|
| 396 |
<!-- 分类选择 -->
|
| 397 |
<div class="prompt-publish__field">
|
| 398 |
+
<label for="category-select" class="prompt-publish__label">🏷️ ${t('prompt.category_label')} <span class="prompt-publish__required ranking-required-marker"></span></label>
|
| 399 |
<select id="category-select" class="ranking-publish-input prompt-publish__select">
|
| 400 |
<option value="">${t('prompt.category_select')}</option>
|
| 401 |
</select>
|
|
|
|
| 412 |
|
| 413 |
<!-- 标题输入 -->
|
| 414 |
<div class="prompt-publish__field">
|
| 415 |
+
<label for="title-input" class="prompt-publish__label">📝 ${t('prompt.title_label')} <span class="prompt-publish__required ranking-required-marker"></span></label>
|
| 416 |
<input type="text" id="title-input" class="ranking-publish-input" value="${escapeAttr(editTitle)}" placeholder="${t('prompt.title_placeholder')}" maxlength="50">
|
| 417 |
<div class="prompt-publish__count">
|
| 418 |
<span id="title-count">${editTitle.length}</span>/50
|
|
|
|
| 421 |
|
| 422 |
<!-- 文案/简介输入 -->
|
| 423 |
<div class="prompt-publish__field">
|
| 424 |
+
<label for="content-input" class="prompt-publish__label">✍️ ${t('prompt.content_label')} <span class="prompt-publish__required ranking-required-marker"></span></label>
|
| 425 |
<textarea id="content-input" class="ranking-publish-input prompt-publish__description" placeholder="${t('prompt.content_placeholder')}" maxlength="2000">${escapeHtml(editContent)}</textarea>
|
| 426 |
<div class="prompt-publish__count">
|
| 427 |
<span id="content-count">${editContent.length}</span>/2000
|
|
|
|
| 430 |
|
| 431 |
<!-- 提示词正文(付费内容) -->
|
| 432 |
<div class="prompt-publish__field">
|
| 433 |
+
<label for="text-input" class="prompt-publish__label">🔑 ${t('prompt.text_label')} <span class="prompt-publish__required ranking-required-marker"></span></label>
|
| 434 |
<textarea id="text-input" class="ranking-publish-input prompt-publish__text" placeholder="${t('prompt.text_placeholder')}" maxlength="20000">${escapeHtml(editText)}</textarea>
|
| 435 |
<div class="prompt-publish__count">
|
| 436 |
<span id="text-count">${editText.length}</span>/20000
|
|
|
|
| 457 |
|
| 458 |
<!-- 图片上传区(图像提示词专用:多图 + 拖拽排序,首张为封面) -->
|
| 459 |
<div id="image-upload-section" class="prompt-publish__field">
|
| 460 |
+
<label class="prompt-publish__label">🖼️ ${t('post.upload_images')} <span class="prompt-publish__required ranking-required-marker"></span>
|
| 461 |
<span class="prompt-publish__optional">(${t('post.max_9_images')})</span>
|
| 462 |
</label>
|
| 463 |
<input type="file" id="images-input" accept="image/*" multiple style="display: none;">
|
|
|
|
| 471 |
|
| 472 |
<!-- 视频上传区(视频提示词专用:截取当前帧或手动上传封面) -->
|
| 473 |
<div id="video-upload-section" style="display: none;" class="prompt-publish__media-section">
|
| 474 |
+
<label class="prompt-publish__label">🎬 ${t('prompt.video_label')} <span id="video-required-mark" class="prompt-publish__required ranking-required-marker"></span><span id="video-optional-mark" style="display: none;" class="prompt-publish__optional">${t('prompt.optional_mark')}</span></label>
|
| 475 |
<input type="file" id="video-input" accept="video/mp4,video/webm,video/quicktime" style="display: none;">
|
| 476 |
<div id="video-preview-area" class="prompt-publish__media">
|
| 477 |
<div id="video-empty-state" class="prompt-publish__empty">
|
|
|
|
| 512 |
|
| 513 |
<!-- 🎵 音频上传区(音乐提示词专用:图片+音频方案,视频可选) -->
|
| 514 |
<div id="audio-upload-section" style="display: none;" class="prompt-publish__media-section">
|
| 515 |
+
<label class="prompt-publish__label">🎵 ${t('prompt.audio_label')} <span class="prompt-publish__required ranking-required-marker"></span></label>
|
| 516 |
<div class="prompt-publish__media-hint">${t('prompt.music_media_hint')}</div>
|
| 517 |
<input type="file" id="audio-input" accept="audio/mpeg,audio/wav,audio/x-wav,audio/mp4,audio/x-m4a,audio/ogg,.mp3,.wav,.m4a,.ogg" style="display: none;">
|
| 518 |
<div id="audio-preview-area" class="prompt-publish__media">
|
|
|
|
| 1694 |
if (!scope.isCurrent()) return;
|
| 1695 |
if (committed) return;
|
| 1696 |
console.error("提示词发布失败");
|
| 1697 |
+
outcomeUnknown = saveAttempted && !(err?.requestBodyRejected === true || [400, 401, 403, 404, 409, 422, 429].includes(err?.status));
|
| 1698 |
showToast(t(outcomeUnknown ? 'publish.save_unconfirmed' : 'prompt.publish_failed'),
|
| 1699 |
outcomeUnknown ? 'warning' : 'error');
|
| 1700 |
} finally {
|
前端页面/social/评论数据工具.js
CHANGED
|
@@ -16,7 +16,7 @@ export function isConfirmedCommentDeletion(response) {
|
|
| 16 |
}
|
| 17 |
|
| 18 |
export function isDefiniteCommentRejection(error) {
|
| 19 |
-
return Number.isInteger(error?.status) && error.status >= 400 && error.status < 500 && error.status !== 408;
|
| 20 |
}
|
| 21 |
|
| 22 |
export function isConfirmedDedicatedCommentResponse(response, account, content) {
|
|
|
|
| 16 |
}
|
| 17 |
|
| 18 |
export function isDefiniteCommentRejection(error) {
|
| 19 |
+
return error?.requestBodyRejected === true || (Number.isInteger(error?.status) && error.status >= 400 && error.status < 500 && error.status !== 408);
|
| 20 |
}
|
| 21 |
|
| 22 |
export function isConfirmedDedicatedCommentResponse(response, account, content) {
|
前端页面/styles/主题基础.css
CHANGED
|
@@ -1,4 +1,5 @@
|
|
| 1 |
/* RanKing UI foundation: ComfyUI theme aware defaults with local fallbacks. */
|
|
|
|
| 2 |
.interaction-toggle { flex: 1; min-width: 0; min-height: 36px; padding: 6px; border: 1px solid var(--rk-border, var(--border-color, #555)); border-radius: var(--rk-radius-sm, 6px); background: var(--rk-panel, var(--comfy-input-bg, #292929)); color: var(--rk-text, var(--fg-color, #ddd)); font: inherit; cursor: pointer; overflow-wrap: anywhere; }
|
| 3 |
.interaction-toggle[data-active="true"] { border-color: var(--interaction-color); box-shadow: inset 0 -3px var(--interaction-color); }
|
| 4 |
.interaction-toggle:focus-visible { outline: 2px solid var(--rk-focus, #8ab4ff); outline-offset: 2px; }
|
|
@@ -1351,7 +1352,7 @@ button.ranking-rating__star { cursor: pointer; min-width: 28px; min-height: 28px
|
|
| 1351 |
.ranking-publish > .ranking-publish__field { flex: none; }
|
| 1352 |
.ranking-publish__field--wide { flex: 2 1 200px; min-width: 0; }
|
| 1353 |
.ranking-publish label:not(.ranking-publish__checkbox) { display: block; margin-bottom: 6px; color: inherit; font-weight: 600; overflow-wrap: anywhere; }
|
| 1354 |
-
.ranking-publish__required { color: var(--rk-danger, #ef5350); }
|
| 1355 |
.ranking-publish__security-emphasis { color: var(--rk-danger, #ef5350); }
|
| 1356 |
.ranking-publish .form-input { display: block; width: 100%; min-width: 0; min-height: 36px; padding: 8px; background: var(--rk-panel, var(--comfy-input-bg, #292929)); border: 1px solid var(--rk-border, var(--border-color, #555)); color: inherit; border-radius: var(--rk-radius-sm, 6px); font: inherit; line-height: 1.5; }
|
| 1357 |
.ranking-publish .form-input::placeholder { color: var(--rk-muted, var(--descrip-text, #a4a4a4)); opacity: 1; }
|
|
@@ -1722,29 +1723,29 @@ button.ranking-rating__star { cursor: pointer; min-width: 28px; min-height: 28px
|
|
| 1722 |
@media (forced-colors: active) { .posts-card__play { background: Canvas; border: 1px solid CanvasText; } .posts-card__play-icon { border-left-color: CanvasText; } }
|
| 1723 |
|
| 1724 |
.creator-card__summary:focus-visible { outline:2px solid var(--rk-focus,#8ab4ff); outline-offset:-3px; }
|
| 1725 |
-
|
| 1726 |
-
.comfy-ranking-root .comfy-ranking-request-diagnostic {
|
| 1727 |
-
box-sizing: border-box;
|
| 1728 |
-
grid-column: 1 / -1;
|
| 1729 |
-
width: 100%; max-width: 100%; min-width: 0;
|
| 1730 |
-
padding: 12px;
|
| 1731 |
-
color: var(--rk-muted);
|
| 1732 |
-
text-align: start;
|
| 1733 |
-
}
|
| 1734 |
-
.comfy-ranking-request-diagnostic summary { cursor: pointer; min-height: 24px; }
|
| 1735 |
-
.comfy-ranking-request-diagnostic__label { display: grid; gap: 6px; margin: 10px 0; }
|
| 1736 |
-
.comfy-ranking-request-diagnostic input {
|
| 1737 |
-
box-sizing: border-box; width: 100%; min-width: 0; min-height: 28px;
|
| 1738 |
-
color: var(--rk-text); background: var(--rk-panel);
|
| 1739 |
-
border: 1px solid var(--rk-border); border-radius: var(--rk-radius-sm);
|
| 1740 |
-
padding: 6px; font-family: monospace;
|
| 1741 |
-
}
|
| 1742 |
-
.comfy-ranking-request-diagnostic button {
|
| 1743 |
-
min-width: 48px; min-height: 28px; padding: 4px 10px;
|
| 1744 |
-
color: var(--rk-text); background: var(--rk-panel);
|
| 1745 |
-
border: 1px solid var(--rk-border); border-radius: var(--rk-radius-sm); cursor: pointer;
|
| 1746 |
-
}
|
| 1747 |
-
.comfy-ranking-request-diagnostic button[aria-busy="true"] { opacity: .65; }
|
| 1748 |
.comfy-ranking-request-diagnostic__feedback { margin: 6px 0 0; overflow-wrap: anywhere; }
|
| 1749 |
.comfy-ranking-request-diagnostic summary:focus-visible { outline: 2px solid var(--rk-focus); outline-offset: 3px; }
|
| 1750 |
|
|
@@ -1898,60 +1899,60 @@ button.ranking-rating__star { cursor: pointer; min-width: 28px; min-height: 28px
|
|
| 1898 |
}
|
| 1899 |
|
| 1900 |
.prompt-detail__author-name, .prompt-detail__author-time { display: block; }
|
| 1901 |
-
|
| 1902 |
-
/* Settings follow the shared host palette within their own container. */
|
| 1903 |
-
.ranking-settings { container: ranking-settings / inline-size; display: flex; flex-direction: column; gap: 0; flex: 1; min-width: 0; min-height: 0; overflow-y: auto; box-sizing: border-box; color: var(--rk-text, var(--fg-color, #ddd)); background: var(--comfy-menu-bg, #222); font: inherit; font-size: 14px; line-height: 1.5; overflow-wrap: anywhere; }
|
| 1904 |
-
.ranking-settings *, .ranking-settings *::before, .ranking-settings *::after { box-sizing: border-box; }
|
| 1905 |
-
.ranking-settings__header { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; padding: 16px; border-bottom: 1px solid var(--rk-border, var(--border-color, #555)); }
|
| 1906 |
-
.ranking-settings__title { margin: 0; font-size: 16px; font-weight: 700; }
|
| 1907 |
-
.ranking-settings__body { padding: 0; flex: 1; min-width: 0; }
|
| 1908 |
-
.ranking-settings .setting-item { display: flex; justify-content: space-between; align-items: center; gap: 16px; min-width: 0; padding: 16px; border-bottom: 1px solid var(--rk-border, var(--border-color, #555)); }
|
| 1909 |
-
.ranking-settings__copy, .ranking-settings .setting-shortcuts__copy { flex: 1; min-width: 0; }
|
| 1910 |
-
.ranking-settings__copy-wide { width: 100%; min-width: 0; }
|
| 1911 |
-
.ranking-settings__label, .ranking-settings__stats-label, .ranking-settings .setting-shortcuts__label { margin-bottom: 4px; font-size: 14px; font-weight: 600; }
|
| 1912 |
-
.ranking-settings__description, .ranking-settings__stats-hint, .ranking-settings .setting-shortcuts__desc, .ranking-settings .setting-shortcuts__note, .ranking-settings__preview-copy, .ranking-settings__footer-copy { margin: 0; color: var(--rk-muted, var(--descrip-text, #aaa)); font-size: 12px; line-height: 1.6; }
|
| 1913 |
-
.ranking-settings__heading-general, .ranking-settings__heading-display, .ranking-settings__heading-animation, .ranking-settings__heading-cache, .ranking-settings .setting-shortcuts__heading { margin: 20px 0 0; padding: 12px 16px; font-size: 13px; font-weight: 700; color: inherit; background: var(--rk-panel, var(--comfy-input-bg, #292929)); border-block-end: 1px solid var(--rk-border, var(--border-color, #555)); border-inline-start: 3px solid var(--settings-section-color, var(--rk-accent, #3b82f6)); }
|
| 1914 |
-
.ranking-settings__heading-general { margin-top: 0; --settings-section-color: var(--rk-accent, #3b82f6); }
|
| 1915 |
-
.ranking-settings__heading-display { --settings-section-color: var(--rk-success, #4caf50); }
|
| 1916 |
-
.ranking-settings__heading-animation { --settings-section-color: var(--rk-warning, #e5a642); }
|
| 1917 |
-
.ranking-settings__heading-cache { --settings-section-color: #a35cba; }
|
| 1918 |
-
.ranking-settings .setting-shortcuts__heading { --settings-section-color: var(--rk-focus, #8ab4ff); }
|
| 1919 |
-
.ranking-settings .setting-shortcuts__list { margin: 0; padding: 4px 16px; }
|
| 1920 |
-
.ranking-settings .setting-shortcuts__entry { display: grid; grid-template-columns: minmax(0, 1fr); gap: 4px; padding: 10px 0; border-bottom: 1px solid var(--rk-border, var(--border-color, #555)); }
|
| 1921 |
-
.ranking-settings .setting-shortcuts__entry dt, .ranking-settings .setting-shortcuts__entry dd { margin: 0; font-size: 12px; line-height: 1.6; }
|
| 1922 |
-
.ranking-settings .setting-shortcuts__entry dd { color: var(--rk-muted, var(--descrip-text, #aaa)); }
|
| 1923 |
-
.ranking-settings .setting-shortcuts__entry kbd { font: inherit; font-weight: 600; }
|
| 1924 |
-
.ranking-settings .setting-shortcuts__note { padding: 10px 16px 16px; }
|
| 1925 |
-
.ranking-settings .setting-switch { position: relative; appearance: none; flex: 0 0 44px; width: 44px; height: 24px; min-height: 24px; margin: 0; padding: 0; border: 1px solid var(--rk-border, var(--border-color, #777)); border-radius: 12px; background: var(--rk-panel, var(--comfy-input-bg, #292929)); color: inherit; cursor: pointer; transition: background-color .15s; }
|
| 1926 |
-
.ranking-settings .setting-switch::after { content: ''; position: absolute; top: 2px; left: 2px; width: 18px; height: 18px; border-radius: 50%; background: var(--rk-text, var(--fg-color, #ddd)); transition: left .15s; }
|
| 1927 |
-
.ranking-settings .setting-switch.active { background: #277a39; border-color: #277a39; }
|
| 1928 |
-
.ranking-settings .setting-switch.active::after { left: 22px; background: #fff; }
|
| 1929 |
-
.ranking-settings .setting-select, .ranking-settings .setting-number-input, .ranking-settings__back, .ranking-settings .cache-clear-btn { min-height: 36px; max-width: 100%; margin: 0; padding: 8px 12px; background: var(--rk-panel, var(--comfy-input-bg, #292929)); color: inherit; border: 1px solid var(--rk-border, var(--border-color, #555)); border-radius: var(--rk-radius-sm, 6px); font: inherit; font-size: 13px; line-height: 1.4; }
|
| 1930 |
-
.ranking-settings .setting-select { flex: 0 1 260px; min-width: 0; width: 100%; cursor: pointer; }
|
| 1931 |
-
.ranking-settings .setting-select option { background: var(--rk-panel, var(--comfy-input-bg, #292929)); color: var(--rk-text, var(--fg-color, #ddd)); }
|
| 1932 |
-
.ranking-settings .setting-number-input { width: 98px; min-width: 0; text-align: center; }
|
| 1933 |
-
.ranking-settings__back, .ranking-settings .cache-clear-btn { cursor: pointer; }
|
| 1934 |
-
.ranking-settings__back { flex: 0 1 auto; font-weight: 600; }
|
| 1935 |
-
.ranking-settings :is(button, select, input):focus-visible { outline: 2px solid var(--rk-focus, #8ab4ff); outline-offset: 3px; }
|
| 1936 |
-
.ranking-settings :is(button, select, input):hover:not(:disabled) { border-color: var(--rk-focus, #8ab4ff); }
|
| 1937 |
-
.ranking-settings button:disabled { opacity: .65; cursor: not-allowed; }
|
| 1938 |
-
.ranking-settings .ranking-settings__stack { flex-direction: column; align-items: stretch; gap: 12px; }
|
| 1939 |
-
.ranking-settings__controls, .ranking-settings__stats { display: flex; flex-direction: column; gap: 10px; width: 100%; min-width: 0; }
|
| 1940 |
-
.ranking-settings__range-row { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; width: 100%; min-width: 0; }
|
| 1941 |
-
.ranking-settings .setting-range-slider { appearance: none; flex: 1 1 120px; width: 100%; min-width: 0; height: 6px; margin: 10px 0; border: 0; border-radius: 3px; cursor: pointer; background: linear-gradient(to right, var(--rk-success, #4caf50) var(--settings-range-progress, 0%), var(--rk-border, var(--border-color, #777)) var(--settings-range-progress, 0%)); }
|
| 1942 |
-
.ranking-settings .setting-range-slider::-webkit-slider-thumb { appearance: none; width: 18px; height: 18px; border-radius: 50%; background: var(--rk-success, #4caf50); border: 1px solid var(--rk-text, var(--fg-color, #ddd)); }
|
| 1943 |
-
.ranking-settings .setting-range-slider::-moz-range-thumb { width: 18px; height: 18px; border-radius: 50%; background: var(--rk-success, #4caf50); border: 1px solid var(--rk-text, var(--fg-color, #ddd)); }
|
| 1944 |
-
.ranking-settings__time { min-width: 55px; font-size: 12px; font-variant-numeric: tabular-nums; }
|
| 1945 |
-
.ranking-settings__hint, .ranking-settings__stat, .ranking-settings__stat-muted { padding: 10px 12px; background: var(--rk-panel, var(--comfy-input-bg, #292929)); border-inline-start: 3px solid var(--rk-border, var(--border-color, #555)); border-radius: 4px; font-size: 12px; line-height: 1.6; }
|
| 1946 |
-
.ranking-settings__hint, .ranking-settings__stat-muted { color: var(--rk-muted, var(--descrip-text, #aaa)); }
|
| 1947 |
-
.ranking-settings__stat-title { font-weight: 600; }
|
| 1948 |
-
.ranking-settings__actions { display: flex; flex-wrap: wrap; gap: 10px; width: 100%; }
|
| 1949 |
-
.ranking-settings .cache-clear-btn { flex: 1 1 140px; min-width: 0; white-space: normal; overflow-wrap: anywhere; }
|
| 1950 |
-
.ranking-settings__preview { padding: 16px; margin: 16px; border: 1px dashed var(--rk-border, var(--border-color, #555)); border-radius: 8px; }
|
| 1951 |
-
.ranking-settings__preview-title { margin-bottom: 8px; font-size: 12px; font-weight: 600; }
|
| 1952 |
-
.ranking-settings__footer { padding: 15px; border-top: 1px solid var(--rk-border, var(--border-color, #555)); text-align: center; }
|
| 1953 |
-
@container ranking-settings (max-width: 420px) { .ranking-settings .setting-item:has(.setting-select) { flex-wrap: wrap; } .ranking-settings .setting-select { flex-basis: 100%; } .ranking-settings .setting-range-slider { flex-basis: 100%; } }
|
| 1954 |
-
@media (prefers-reduced-motion: reduce) { .ranking-settings .setting-switch, .ranking-settings .setting-switch::after { transition: none; } }
|
| 1955 |
@media (forced-colors: active) { .ranking-settings .setting-switch { background: ButtonFace; border-color: ButtonText; } .ranking-settings .setting-switch::after { background: ButtonText; } .ranking-settings .setting-switch.active { border: 2px solid Highlight; background: Highlight; } .ranking-settings .setting-switch.active::after { top: 1px; left: 21px; background: HighlightText; } .ranking-settings .setting-range-slider { appearance: auto; background: Canvas; } .ranking-settings__heading-general, .ranking-settings__heading-display, .ranking-settings__heading-animation, .ranking-settings__heading-cache, .ranking-settings .setting-shortcuts__heading { border-inline-start-color: Highlight; } }
|
| 1956 |
.ranking-settings .setting-number-input { width: max(98px, 8ch); }
|
| 1957 |
.ranking-settings { color-scheme: normal; }
|
|
@@ -2271,7 +2272,7 @@ button.ranking-rating__star { cursor: pointer; min-width: 28px; min-height: 28px
|
|
| 2271 |
.discussion-detail .image-sandbox .img-counter { top:134px;bottom:auto;max-width:calc(100% - 4px);padding:2px 4px; }
|
| 2272 |
.discussion-detail .image-sandbox .slider-y { top:192px;height:72px; }
|
| 2273 |
}
|
| 2274 |
-
.discussion-detail .post-detail-author-button { flex-wrap:wrap; }
|
| 2275 |
.discussion-detail .post-detail__identity { flex:1 1 100px; }
|
| 2276 |
|
| 2277 |
.prompt-publish .prompt-publish__field { margin-bottom: 15px; }
|
|
@@ -2491,55 +2492,55 @@ button.ranking-rating__star { cursor: pointer; min-width: 28px; min-height: 28px
|
|
| 2491 |
@media (max-width:360px) { .image-crop-overlay { padding:8px; } .image-crop-dialog { padding:12px; gap:12px; } }
|
| 2492 |
@media (forced-colors:active) { .image-crop-dialog .image-crop-button { color:ButtonText; background:ButtonFace; border-color:ButtonText; } .image-crop-dialog .image-crop-button:disabled { color:GrayText; border-color:GrayText; } .image-crop-dialog .image-crop-viewport { border-color:Highlight; } .image-crop-dialog .image-crop-button:focus-visible, .image-crop-dialog .image-crop-range:focus-visible { outline-color:Highlight; } }
|
| 2493 |
|
| 2494 |
-
.profile-content-list,.profile-transactions,.profile-transaction-list{display:flex;flex-direction:column;min-width:0;gap:10px}
|
| 2495 |
-
.profile-transactions{gap:15px;container-type:inline-size}
|
| 2496 |
-
.profile-transaction-list{gap:8px}
|
| 2497 |
-
.profile-list-section-title{font-size:13px;font-weight:700;color:var(--rk-text,var(--fg-color,#eee));padding:5px 0;margin:0;overflow-wrap:anywhere}
|
| 2498 |
-
.profile-list-section-title:not(:first-child){margin-top:15px}
|
| 2499 |
-
.profile-stats-card,.profile-task-card,.profile-entry-card,.profile-transaction-card{box-sizing:border-box;min-width:0;max-width:100%;padding:12px;background:var(--rk-panel,var(--comfy-input-bg,#292929));color:var(--rk-text,var(--fg-color,#eee));border:1px solid var(--rk-border,var(--border-color,#777));border-radius:8px;font-family:inherit;line-height:1.5;overflow-wrap:anywhere;color-scheme:normal}
|
| 2500 |
-
.profile-stats-card{padding:14px}
|
| 2501 |
-
.profile-stats-card--spaced{margin-bottom:15px}
|
| 2502 |
-
.profile-stats-card__title{font-size:14px;font-weight:700;margin-bottom:12px}
|
| 2503 |
-
.profile-stats-card__grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}
|
| 2504 |
-
.profile-stats-card__cell{min-width:0;text-align:center;padding:8px 4px;border:1px solid var(--rk-border,var(--border-color,#777));border-radius:6px;border-top:3px solid var(--rk-accent,#3b82f6)}
|
| 2505 |
-
.profile-stats-card__cell--income{border-top-color:var(--rk-success,#3a9360)}
|
| 2506 |
-
.profile-stats-card__cell--expense{border-top-color:var(--rk-danger,#d14b4b)}
|
| 2507 |
-
.profile-stats-card__value{font-size:20px;font-weight:700;overflow-wrap:anywhere}
|
| 2508 |
-
.profile-stats-card__label{font-size:11px;color:var(--rk-muted,var(--descrip-text,#b8b8b8));overflow-wrap:anywhere}
|
| 2509 |
-
.profile-task-card,.profile-entry-card{display:block;width:100%;text-align:start;appearance:none;cursor:pointer;transition:border-color .15s}
|
| 2510 |
-
.profile-task-card:hover,.profile-entry-card:hover{border-color:var(--rk-accent,var(--fg-color,#eee))}
|
| 2511 |
-
.profile-task-card:focus-visible,.profile-entry-card:focus-visible{outline:2px solid var(--rk-accent,var(--fg-color,#eee));outline-offset:-3px}
|
| 2512 |
-
.profile-task-card__summary{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center;gap:8px;margin-bottom:8px}
|
| 2513 |
-
.profile-task-card__status,.profile-list-badge{border:1px solid var(--rk-border,var(--border-color,#777));padding:2px 7px;border-radius:4px;font-size:11px;max-width:100%;box-sizing:border-box}
|
| 2514 |
-
.profile-task-card__status--open{border-color:var(--rk-success,#3a9360)}
|
| 2515 |
-
.profile-task-card__status--active,.profile-task-card__status--pending{border-color:var(--rk-accent,#3b82f6)}
|
| 2516 |
-
.profile-task-card__status--disputed{border-color:var(--rk-danger,#d14b4b)}
|
| 2517 |
-
.profile-task-card__price{font-weight:700;min-width:0;overflow-wrap:anywhere}
|
| 2518 |
-
.profile-list-card__title{font-size:14px;font-weight:700;margin-bottom:6px;line-height:1.4;overflow-wrap:anywhere}
|
| 2519 |
-
.profile-list-card__meta{display:flex;align-items:center;flex-wrap:wrap;gap:6px 12px;font-size:11px;color:var(--rk-muted,var(--descrip-text,#b8b8b8));min-width:0}
|
| 2520 |
-
.profile-list-card__meta>*{min-width:0;max-width:100%;overflow-wrap:anywhere}
|
| 2521 |
-
.profile-list-card__time{margin-inline-start:auto}
|
| 2522 |
-
.profile-entry-card__row,.profile-transaction-card__summary{display:flex;align-items:flex-start;gap:10px;min-width:0}
|
| 2523 |
-
.profile-entry-card__media{position:relative;flex-shrink:0;max-width:100%}
|
| 2524 |
-
.profile-entry-card__image{width:60px;height:60px;max-width:100%;object-fit:cover;border-radius:6px;display:block}
|
| 2525 |
-
.profile-entry-card__play{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:28px;height:28px;background:rgba(0,0,0,.6);border-radius:50%;display:flex;align-items:center;justify-content:center;pointer-events:none}
|
| 2526 |
-
.profile-entry-card__play-triangle{width:0;height:0;border-left:10px solid #fff;border-top:6px solid transparent;border-bottom:6px solid transparent;margin-left:2px}
|
| 2527 |
-
.profile-list-card__body{flex:1;min-width:0}
|
| 2528 |
-
.profile-list-badge--price{border-color:var(--rk-accent,#3b82f6)}
|
| 2529 |
-
.profile-list-badge--free{border-color:var(--rk-success,#3a9360)}
|
| 2530 |
-
.profile-transaction-card{display:flex;justify-content:space-between;align-items:flex-start;flex-wrap:wrap;gap:10px}
|
| 2531 |
-
.profile-transaction-card__summary{flex:1 1 140px}
|
| 2532 |
-
.profile-transaction-card__icon{font-size:20px;flex-shrink:0}
|
| 2533 |
-
.profile-transaction-card__heading{display:flex;align-items:center;flex-wrap:wrap;min-width:0}
|
| 2534 |
-
.profile-transaction-card__title{font-size:13px;font-weight:700}
|
| 2535 |
-
.profile-transaction-card__item{color:var(--rk-muted,var(--descrip-text,#b8b8b8));margin-inline-start:6px;min-width:0;max-width:calc(100% - 6px);overflow-wrap:anywhere}
|
| 2536 |
-
.profile-transaction-card__description,.profile-transaction-card__detail,.profile-transaction-card__net{font-size:11px;color:var(--rk-muted,var(--descrip-text,#b8b8b8));margin-top:3px;overflow-wrap:anywhere}
|
| 2537 |
-
.profile-transaction-card__money{min-width:0;max-width:100%;margin-inline-start:auto;text-align:end}
|
| 2538 |
-
.profile-transaction-card__amount{font-weight:700;font-size:15px;overflow-wrap:anywhere;border-inline-start:3px solid var(--rk-danger,#d14b4b);padding-inline-start:7px}
|
| 2539 |
-
.profile-transaction-card__amount--income{border-inline-start-color:var(--rk-success,#3a9360)}
|
| 2540 |
-
@container (max-width:340px){.profile-stats-card__grid{grid-template-columns:minmax(0,1fr)}.profile-stats-card__cell{text-align:start;padding:8px}.profile-stats-card__value{font-size:18px}}
|
| 2541 |
-
@media(prefers-reduced-motion:reduce){.profile-task-card,.profile-entry-card{transition:none}}
|
| 2542 |
-
@media(forced-colors:active){.profile-task-card,.profile-entry-card,.profile-stats-card,.profile-transaction-card,.profile-stats-card__cell,.profile-task-card__status,.profile-list-badge{border-color:CanvasText}.profile-task-card:focus-visible,.profile-entry-card:focus-visible{outline-color:Highlight}}
|
| 2543 |
|
| 2544 |
.task-publish { display:flex; flex-direction:column; flex:1; min-width:0; min-height:0; box-sizing:border-box; overflow-y:auto; color:var(--rk-text,var(--fg-color,#eee)); background:var(--rk-bg,var(--comfy-menu-bg,#202020)); font:inherit; font-size:14px; line-height:1.5; overflow-wrap:anywhere; color-scheme:normal; container-type:inline-size; }
|
| 2545 |
.task-publish *, .task-publish *::before, .task-publish *::after { box-sizing:border-box; }
|
|
@@ -2639,115 +2640,115 @@ button.ranking-rating__star { cursor: pointer; min-width: 28px; min-height: 28px
|
|
| 2639 |
.wallet-modal__danger, .wallet-modal__success { text-decoration-color: CanvasText; }
|
| 2640 |
.wallet-withdraw__summary, .wallet-withdraw__fee, .wallet-recharge__qr { border-color: CanvasText; }
|
| 2641 |
}
|
| 2642 |
-
|
| 2643 |
-
.tip-level { max-width: 100%; overflow-wrap: anywhere; }
|
| 2644 |
-
.tip-level--new, .tip-level--fallback { color: var(--rk-text, var(--fg-color, #ddd)); font-size: .6875rem; }
|
| 2645 |
-
.tip-level__icon { overflow-wrap: anywhere; }
|
| 2646 |
-
.tip-level__icon--sun { font-size: .75rem; }
|
| 2647 |
-
.tip-level__icon--moon { font-size: .6875rem; }
|
| 2648 |
-
.tip-level__icon--star, .tip-level--fallback { font-size: .625rem; }
|
| 2649 |
-
.tip-level--full { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px; font-size: .6875rem; }
|
| 2650 |
-
.tip-level__part { color: var(--rk-text, var(--fg-color, #ddd)); }
|
| 2651 |
-
.tip-level__part--sun { font-weight: bold; }
|
| 2652 |
-
.tip-level--max-compact { color: var(--rk-text, var(--fg-color, #ddd)); font-weight: bold; padding-inline: 2px; border-bottom: 2px solid #c38a00; }
|
| 2653 |
-
.tip-level--max { display: inline-block; box-sizing: border-box; padding: 2px 6px; border: 1px solid #a87500; border-radius: 4px; background: #ffdf80; color: #241c00; font-size: .6875rem; font-weight: bold; }
|
| 2654 |
-
.tip-board-item { --tip-badge-size: 1.25rem; --tip-avatar-size: 1.5rem; --tip-font-size: .75rem; --tip-badge-font: .625rem; --tip-amount-font: .6875rem; --tip-row-padding: 5px; display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 4px 8px; min-width: 0; max-width: 100%; box-sizing: border-box; padding: var(--tip-row-padding) 0; border-bottom: 1px dashed var(--rk-border, var(--border-color, #454545)); color: var(--rk-text, var(--fg-color, #ddd)); font-size: var(--tip-font-size); line-height: 1.5; }
|
| 2655 |
-
.tip-board-item--small { --tip-badge-size: 1rem; --tip-avatar-size: 1.25rem; --tip-font-size: .6875rem; --tip-badge-font: .5625rem; --tip-amount-font: .625rem; --tip-row-padding: 3px; }
|
| 2656 |
-
.tip-board-item--large { --tip-badge-size: 1.5rem; --tip-avatar-size: 1.75rem; --tip-font-size: .875rem; --tip-badge-font: .75rem; --tip-amount-font: .8125rem; --tip-row-padding: 8px; }
|
| 2657 |
-
.tip-board-group { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px; min-width: 0; max-width: 100%; overflow-wrap: anywhere; }
|
| 2658 |
-
.tip-board-item > .tip-board-group:first-child { flex: 1 1 8rem; }
|
| 2659 |
-
.tip-board-item > .tip-board-group:last-child { justify-content: flex-end; margin-inline-start: auto; }
|
| 2660 |
-
.tip-board-badge { display: inline-flex; justify-content: center; align-items: center; flex: 0 0 auto; min-width: var(--tip-badge-size); min-height: var(--tip-badge-size); box-sizing: border-box; padding: 1px 3px; border: 1px solid var(--rk-border, var(--border-color, #454545)); border-radius: 50%; background: var(--rk-panel, var(--comfy-input-bg, #292929)); color: var(--rk-text, var(--fg-color, #ddd)); font-size: var(--tip-badge-font); font-weight: bold; }
|
| 2661 |
-
.tip-board-badge--gold { background: #ffd700; color: #211900; border-color: #b28a00; }
|
| 2662 |
-
.tip-board-badge--silver { background: #c0c0c0; color: #191919; border-color: #777; }
|
| 2663 |
-
.tip-board-badge--bronze { background: #cd7f32; color: #1c1000; border-color: #8d511b; }
|
| 2664 |
-
.tip-board-avatar { width: var(--tip-avatar-size); height: var(--tip-avatar-size); max-width: 100%; border-radius: 50%; object-fit: cover; flex-shrink: 0; background: var(--rk-panel, var(--comfy-input-bg, #292929)); }
|
| 2665 |
-
.tip-board-name, .tip-board-anonymous { min-width: 0; max-width: 100%; color: var(--rk-text, var(--fg-color, #ddd)); overflow-wrap: anywhere; }
|
| 2666 |
-
.tip-board-amount { max-width: 100%; color: var(--rk-text, var(--fg-color, #ddd)); color: color-mix(in srgb, var(--rk-text, var(--fg-color, #ddd)) 80%, var(--rk-success, #4caf50)); font-weight: bold; font-size: var(--tip-amount-font); overflow-wrap: anywhere; }
|
| 2667 |
-
.tip-board-empty { padding: 12px 0; color: var(--rk-text, var(--fg-color, #ddd)); font-size: .75rem; text-align: center; overflow-wrap: anywhere; }
|
| 2668 |
-
@media (forced-colors: active) {
|
| 2669 |
-
.tip-board-item { border-color: CanvasText; color: CanvasText; }
|
| 2670 |
-
.tip-board-badge, .tip-level--max { border-color: CanvasText; background: Canvas; color: CanvasText; }
|
| 2671 |
-
.tip-level--max-compact { color: CanvasText; border-color: CanvasText; }
|
| 2672 |
-
.tip-level__part, .tip-level--new, .tip-level--fallback, .tip-board-name, .tip-board-anonymous, .tip-board-amount, .tip-board-empty { color: CanvasText; }
|
| 2673 |
-
}
|
| 2674 |
-
|
| 2675 |
-
|
| 2676 |
-
.ranking-publish-view { display:flex; flex-direction:column; flex:1; gap:15px; min-width:0; min-height:0; padding:15px; box-sizing:border-box; overflow-y:auto; color:var(--rk-text,var(--fg-color,#eee)); font:inherit; font-size:.875rem; line-height:1.5; color-scheme:normal; }
|
| 2677 |
-
.ranking-publish__image { position:relative; flex:0 0 96px; width:96px; height:96px; min-width:0; box-sizing:border-box; }
|
| 2678 |
-
.ranking-publish__image--sortable { cursor:grab; }
|
| 2679 |
-
.ranking-publish__image:focus-visible { outline:3px solid var(--rk-focus,#8ab4ff); outline-offset:2px; }
|
| 2680 |
-
.ranking-publish__thumbnail { display:block; width:100%; height:100%; object-fit:cover; box-sizing:border-box; border:2px solid var(--rk-border,var(--border-color,#777)); border-radius:6px; }
|
| 2681 |
-
.ranking-publish__image--cover .ranking-publish__thumbnail { border-color:var(--rk-success,#3a9360); }
|
| 2682 |
-
.ranking-publish__cover-label { position:absolute; top:2px; left:2px; max-width:calc(100% - 4px); padding:1px 4px; box-sizing:border-box; border:1px solid var(--rk-success,#3a9360); border-radius:3px; background:var(--rk-panel,var(--comfy-input-bg,#292929)); color:var(--rk-text,var(--fg-color,#eee)); font-size:.625rem; line-height:1.3; font-weight:700; overflow-wrap:anywhere; pointer-events:none; }
|
| 2683 |
-
.ranking-publish .ranking-publish__image-remove { position:absolute; right:2px; bottom:2px; width:36px; height:36px; min-height:36px; padding:0; display:grid; place-items:center; border:2px solid var(--rk-danger,#d14b4b); border-radius:6px; background:var(--rk-panel,var(--comfy-input-bg,#292929)); color:var(--rk-text,var(--fg-color,#eee)); font:inherit; font-size:.875rem; line-height:1; cursor:pointer; }
|
| 2684 |
-
.ranking-publish .ranking-publish__image-remove:hover:not(:disabled) { border-color:var(--rk-focus,#8ab4ff); }
|
| 2685 |
-
.ranking-publish .ranking-publish__image-remove:focus-visible { outline:3px solid var(--rk-focus,#8ab4ff); outline-offset:2px; }
|
| 2686 |
-
.ranking-publish__image--dragging { opacity:.5; }
|
| 2687 |
-
.ranking-publish__image--target::before { content:""; position:absolute; left:-5px; top:0; bottom:0; width:3px; border-radius:2px; background:var(--rk-success,#3a9360); pointer-events:none; }
|
| 2688 |
-
.ranking-publish__pending-value { padding-inline:3px; border-bottom:2px solid var(--rk-success,#3a9360); color:inherit; }
|
| 2689 |
-
.ranking-original-confirm { min-width:0; max-width:100%; color:var(--rk-text,var(--fg-color,#eee)); font:inherit; font-size:.875rem; line-height:1.6; overflow-wrap:anywhere; color-scheme:normal; }
|
| 2690 |
-
.ranking-original-confirm *, .ranking-original-confirm *::before, .ranking-original-confirm *::after { box-sizing:border-box; }
|
| 2691 |
-
.ranking-original-confirm__description { margin:0 0 15px; }
|
| 2692 |
-
.ranking-original-confirm__subtitle { margin:0 0 10px; font-weight:700; }
|
| 2693 |
-
.ranking-original-confirm__list { margin:0 0 15px; padding-inline-start:20px; }
|
| 2694 |
-
.ranking-original-confirm__list li { margin-bottom:5px; }
|
| 2695 |
-
.ranking-original-confirm__warning { margin:15px 0 0; padding:10px; border:1px solid var(--rk-border,var(--border-color,#777)); border-inline-start:3px solid var(--rk-warning,#d97706); border-radius:4px; background:var(--rk-bg,var(--comfy-menu-bg,#202020)); color:inherit; font-size:.75rem; }
|
| 2696 |
-
.ranking-original-confirm__actions { display:flex; flex-wrap:wrap; gap:10px; margin-top:20px; justify-content:flex-end; }
|
| 2697 |
-
.ranking-original-confirm__button { flex:0 1 auto; min-width:0; min-height:36px; max-width:100%; padding:8px 16px; border:1px solid var(--rk-border,var(--border-color,#777)); border-radius:6px; background:var(--rk-panel,var(--comfy-input-bg,#292929)); color:inherit; font:inherit; line-height:1.4; white-space:normal; overflow-wrap:anywhere; cursor:pointer; }
|
| 2698 |
-
.ranking-original-confirm__button--confirm { border-inline-start:3px solid var(--rk-success,#3a9360); font-weight:700; }
|
| 2699 |
-
.ranking-original-confirm__button:hover:not(:disabled) { border-color:var(--rk-focus,#8ab4ff); }
|
| 2700 |
-
.ranking-original-confirm__button:focus-visible { outline:3px solid var(--rk-focus,#8ab4ff); outline-offset:2px; }
|
| 2701 |
-
.ranking-original-confirm__button:disabled { opacity:.7; cursor:default; }
|
| 2702 |
-
@media (forced-colors:active) {
|
| 2703 |
-
.ranking-publish__thumbnail { border-color:CanvasText; }
|
| 2704 |
-
.ranking-publish__image--cover .ranking-publish__thumbnail { border-color:Highlight; }
|
| 2705 |
-
.ranking-publish__image--target::before { background:Highlight; }
|
| 2706 |
-
.ranking-publish__cover-label, .ranking-publish .ranking-publish__image-remove, .ranking-original-confirm__button { background:ButtonFace; color:ButtonText; border-color:ButtonText; }
|
| 2707 |
-
.ranking-publish__image:focus-visible, .ranking-publish .ranking-publish__image-remove:focus-visible, .ranking-original-confirm__button:focus-visible { outline-color:Highlight; }
|
| 2708 |
-
.ranking-publish__pending-value, .ranking-original-confirm__warning, .ranking-original-confirm__button--confirm { border-color:Highlight; }
|
| 2709 |
-
}
|
| 2710 |
-
|
| 2711 |
-
.comfy-ranking-root .sidebar-status-message {
|
| 2712 |
-
box-sizing: border-box;
|
| 2713 |
-
min-width: 0;
|
| 2714 |
-
max-width: 100%;
|
| 2715 |
-
padding: 2.5rem 1.25rem;
|
| 2716 |
-
color: var(--rk-text, var(--fg-color, #f1f1f1));
|
| 2717 |
-
font: inherit;
|
| 2718 |
-
line-height: 1.5;
|
| 2719 |
-
text-align: center;
|
| 2720 |
-
overflow-wrap: anywhere;
|
| 2721 |
-
}
|
| 2722 |
-
.comfy-ranking-root .sidebar-status-more {
|
| 2723 |
-
box-sizing: border-box;
|
| 2724 |
-
width: 100%;
|
| 2725 |
-
min-width: 0;
|
| 2726 |
-
min-height: 2.25rem;
|
| 2727 |
-
margin-top: .625rem;
|
| 2728 |
-
padding: .625rem;
|
| 2729 |
-
border: 1px solid var(--rk-border, var(--border-color, #555));
|
| 2730 |
-
border-radius: .375rem;
|
| 2731 |
-
background: transparent;
|
| 2732 |
-
color: var(--rk-text, var(--fg-color, #f1f1f1));
|
| 2733 |
-
font: inherit;
|
| 2734 |
-
line-height: 1.5;
|
| 2735 |
-
text-align: center;
|
| 2736 |
-
white-space: normal;
|
| 2737 |
-
overflow-wrap: anywhere;
|
| 2738 |
-
cursor: pointer;
|
| 2739 |
-
}
|
| 2740 |
-
.comfy-ranking-root .sidebar-status-more:focus-visible { outline: 2px solid var(--rk-text, var(--fg-color, #f1f1f1)); outline-offset: -3px; }
|
| 2741 |
-
.comfy-ranking-root .sidebar-status-more:disabled { cursor: wait; }
|
| 2742 |
-
@media (forced-colors: active) {
|
| 2743 |
-
.comfy-ranking-root .sidebar-status-message { color: CanvasText; }
|
| 2744 |
-
.comfy-ranking-root .sidebar-status-more { color: ButtonText; border-color: ButtonText; background: ButtonFace; }
|
| 2745 |
-
.comfy-ranking-root .sidebar-status-more:focus-visible { outline-color: Highlight; }
|
| 2746 |
-
.comfy-ranking-root .sidebar-status-more:disabled { color: GrayText; border-color: GrayText; }
|
| 2747 |
-
}
|
| 2748 |
-
|
| 2749 |
-
.comfy-ranking-root .profile-view { display:flex; flex-direction:column; gap:.9375rem; padding:.9375rem; flex:1; min-width:0; min-height:0; box-sizing:border-box; overflow-y:auto; background:var(--rk-bg,var(--comfy-menu-bg,#202020)); color:var(--rk-text,var(--fg-color,#eee)); font-size:.875rem; overflow-wrap:anywhere; }
|
| 2750 |
-
|
| 2751 |
.skill-directory { display:flex; flex-direction:column; gap:.75rem; min-width:0; color:inherit; overflow-wrap:anywhere; }
|
| 2752 |
.skill-directory p { margin:0; }
|
| 2753 |
.skill-directory__label { display:flex; flex-direction:column; gap:.375rem; min-width:0; }
|
|
@@ -2763,6 +2764,16 @@ button.ranking-rating__star { cursor: pointer; min-width: 28px; min-height: 28px
|
|
| 2763 |
@media (forced-colors:active) { .skill-directory :is(input,button) { border-color:ButtonText; } .skill-directory :is(input,button):focus-visible { outline-color:Highlight; } }
|
| 2764 |
|
| 2765 |
.comfy-ranking-root .resource-trend { --resource-trend-text: var(--rk-text); --resource-trend-border: var(--rk-border); --resource-trend-line: var(--rk-text); --resource-trend-panel: var(--rk-panel); min-width:0; min-height:10rem; max-width:100%; transition-property:none; font-family:inherit; font-size:.75rem; color:var(--rk-text); }
|
| 2766 |
-
.comfy-ranking-root .resource-trend__state { display:flex; justify-content:center; align-items:center; min-height:160px; box-sizing:border-box; padding:1rem; text-align:center; font:inherit; line-height:1.5; overflow-wrap:anywhere; color:var(--rk-text); }
|
| 2767 |
-
.comfy-ranking-root .resource-trend__state[role=alert] { border-inline-start:2px solid var(--rk-danger); }
|
| 2768 |
-
@media (forced-colors:active) { .comfy-ranking-root .resource-trend { --resource-trend-text:CanvasText; --resource-trend-border:CanvasText; --resource-trend-line:CanvasText; --resource-trend-panel:Canvas; } .comfy-ranking-root .resource-trend__state { color:CanvasText; } .comfy-ranking-root .resource-trend__state[role=alert] { border-color:CanvasText; } }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
/* RanKing UI foundation: ComfyUI theme aware defaults with local fallbacks. */
|
| 2 |
+
.ranking-required-marker::before { content: "*"; }
|
| 3 |
.interaction-toggle { flex: 1; min-width: 0; min-height: 36px; padding: 6px; border: 1px solid var(--rk-border, var(--border-color, #555)); border-radius: var(--rk-radius-sm, 6px); background: var(--rk-panel, var(--comfy-input-bg, #292929)); color: var(--rk-text, var(--fg-color, #ddd)); font: inherit; cursor: pointer; overflow-wrap: anywhere; }
|
| 4 |
.interaction-toggle[data-active="true"] { border-color: var(--interaction-color); box-shadow: inset 0 -3px var(--interaction-color); }
|
| 5 |
.interaction-toggle:focus-visible { outline: 2px solid var(--rk-focus, #8ab4ff); outline-offset: 2px; }
|
|
|
|
| 1352 |
.ranking-publish > .ranking-publish__field { flex: none; }
|
| 1353 |
.ranking-publish__field--wide { flex: 2 1 200px; min-width: 0; }
|
| 1354 |
.ranking-publish label:not(.ranking-publish__checkbox) { display: block; margin-bottom: 6px; color: inherit; font-weight: 600; overflow-wrap: anywhere; }
|
| 1355 |
+
.ranking-publish__required { color: var(--rk-danger, #ef5350); }
|
| 1356 |
.ranking-publish__security-emphasis { color: var(--rk-danger, #ef5350); }
|
| 1357 |
.ranking-publish .form-input { display: block; width: 100%; min-width: 0; min-height: 36px; padding: 8px; background: var(--rk-panel, var(--comfy-input-bg, #292929)); border: 1px solid var(--rk-border, var(--border-color, #555)); color: inherit; border-radius: var(--rk-radius-sm, 6px); font: inherit; line-height: 1.5; }
|
| 1358 |
.ranking-publish .form-input::placeholder { color: var(--rk-muted, var(--descrip-text, #a4a4a4)); opacity: 1; }
|
|
|
|
| 1723 |
@media (forced-colors: active) { .posts-card__play { background: Canvas; border: 1px solid CanvasText; } .posts-card__play-icon { border-left-color: CanvasText; } }
|
| 1724 |
|
| 1725 |
.creator-card__summary:focus-visible { outline:2px solid var(--rk-focus,#8ab4ff); outline-offset:-3px; }
|
| 1726 |
+
|
| 1727 |
+
.comfy-ranking-root .comfy-ranking-request-diagnostic {
|
| 1728 |
+
box-sizing: border-box;
|
| 1729 |
+
grid-column: 1 / -1;
|
| 1730 |
+
width: 100%; max-width: 100%; min-width: 0;
|
| 1731 |
+
padding: 12px;
|
| 1732 |
+
color: var(--rk-muted);
|
| 1733 |
+
text-align: start;
|
| 1734 |
+
}
|
| 1735 |
+
.comfy-ranking-request-diagnostic summary { cursor: pointer; min-height: 24px; }
|
| 1736 |
+
.comfy-ranking-request-diagnostic__label { display: grid; gap: 6px; margin: 10px 0; }
|
| 1737 |
+
.comfy-ranking-request-diagnostic input {
|
| 1738 |
+
box-sizing: border-box; width: 100%; min-width: 0; min-height: 28px;
|
| 1739 |
+
color: var(--rk-text); background: var(--rk-panel);
|
| 1740 |
+
border: 1px solid var(--rk-border); border-radius: var(--rk-radius-sm);
|
| 1741 |
+
padding: 6px; font-family: monospace;
|
| 1742 |
+
}
|
| 1743 |
+
.comfy-ranking-request-diagnostic button {
|
| 1744 |
+
min-width: 48px; min-height: 28px; padding: 4px 10px;
|
| 1745 |
+
color: var(--rk-text); background: var(--rk-panel);
|
| 1746 |
+
border: 1px solid var(--rk-border); border-radius: var(--rk-radius-sm); cursor: pointer;
|
| 1747 |
+
}
|
| 1748 |
+
.comfy-ranking-request-diagnostic button[aria-busy="true"] { opacity: .65; }
|
| 1749 |
.comfy-ranking-request-diagnostic__feedback { margin: 6px 0 0; overflow-wrap: anywhere; }
|
| 1750 |
.comfy-ranking-request-diagnostic summary:focus-visible { outline: 2px solid var(--rk-focus); outline-offset: 3px; }
|
| 1751 |
|
|
|
|
| 1899 |
}
|
| 1900 |
|
| 1901 |
.prompt-detail__author-name, .prompt-detail__author-time { display: block; }
|
| 1902 |
+
|
| 1903 |
+
/* Settings follow the shared host palette within their own container. */
|
| 1904 |
+
.ranking-settings { container: ranking-settings / inline-size; display: flex; flex-direction: column; gap: 0; flex: 1; min-width: 0; min-height: 0; overflow-y: auto; box-sizing: border-box; color: var(--rk-text, var(--fg-color, #ddd)); background: var(--comfy-menu-bg, #222); font: inherit; font-size: 14px; line-height: 1.5; overflow-wrap: anywhere; }
|
| 1905 |
+
.ranking-settings *, .ranking-settings *::before, .ranking-settings *::after { box-sizing: border-box; }
|
| 1906 |
+
.ranking-settings__header { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; padding: 16px; border-bottom: 1px solid var(--rk-border, var(--border-color, #555)); }
|
| 1907 |
+
.ranking-settings__title { margin: 0; font-size: 16px; font-weight: 700; }
|
| 1908 |
+
.ranking-settings__body { padding: 0; flex: 1; min-width: 0; }
|
| 1909 |
+
.ranking-settings .setting-item { display: flex; justify-content: space-between; align-items: center; gap: 16px; min-width: 0; padding: 16px; border-bottom: 1px solid var(--rk-border, var(--border-color, #555)); }
|
| 1910 |
+
.ranking-settings__copy, .ranking-settings .setting-shortcuts__copy { flex: 1; min-width: 0; }
|
| 1911 |
+
.ranking-settings__copy-wide { width: 100%; min-width: 0; }
|
| 1912 |
+
.ranking-settings__label, .ranking-settings__stats-label, .ranking-settings .setting-shortcuts__label { margin-bottom: 4px; font-size: 14px; font-weight: 600; }
|
| 1913 |
+
.ranking-settings__description, .ranking-settings__stats-hint, .ranking-settings .setting-shortcuts__desc, .ranking-settings .setting-shortcuts__note, .ranking-settings__preview-copy, .ranking-settings__footer-copy { margin: 0; color: var(--rk-muted, var(--descrip-text, #aaa)); font-size: 12px; line-height: 1.6; }
|
| 1914 |
+
.ranking-settings__heading-general, .ranking-settings__heading-display, .ranking-settings__heading-animation, .ranking-settings__heading-cache, .ranking-settings .setting-shortcuts__heading { margin: 20px 0 0; padding: 12px 16px; font-size: 13px; font-weight: 700; color: inherit; background: var(--rk-panel, var(--comfy-input-bg, #292929)); border-block-end: 1px solid var(--rk-border, var(--border-color, #555)); border-inline-start: 3px solid var(--settings-section-color, var(--rk-accent, #3b82f6)); }
|
| 1915 |
+
.ranking-settings__heading-general { margin-top: 0; --settings-section-color: var(--rk-accent, #3b82f6); }
|
| 1916 |
+
.ranking-settings__heading-display { --settings-section-color: var(--rk-success, #4caf50); }
|
| 1917 |
+
.ranking-settings__heading-animation { --settings-section-color: var(--rk-warning, #e5a642); }
|
| 1918 |
+
.ranking-settings__heading-cache { --settings-section-color: #a35cba; }
|
| 1919 |
+
.ranking-settings .setting-shortcuts__heading { --settings-section-color: var(--rk-focus, #8ab4ff); }
|
| 1920 |
+
.ranking-settings .setting-shortcuts__list { margin: 0; padding: 4px 16px; }
|
| 1921 |
+
.ranking-settings .setting-shortcuts__entry { display: grid; grid-template-columns: minmax(0, 1fr); gap: 4px; padding: 10px 0; border-bottom: 1px solid var(--rk-border, var(--border-color, #555)); }
|
| 1922 |
+
.ranking-settings .setting-shortcuts__entry dt, .ranking-settings .setting-shortcuts__entry dd { margin: 0; font-size: 12px; line-height: 1.6; }
|
| 1923 |
+
.ranking-settings .setting-shortcuts__entry dd { color: var(--rk-muted, var(--descrip-text, #aaa)); }
|
| 1924 |
+
.ranking-settings .setting-shortcuts__entry kbd { font: inherit; font-weight: 600; }
|
| 1925 |
+
.ranking-settings .setting-shortcuts__note { padding: 10px 16px 16px; }
|
| 1926 |
+
.ranking-settings .setting-switch { position: relative; appearance: none; flex: 0 0 44px; width: 44px; height: 24px; min-height: 24px; margin: 0; padding: 0; border: 1px solid var(--rk-border, var(--border-color, #777)); border-radius: 12px; background: var(--rk-panel, var(--comfy-input-bg, #292929)); color: inherit; cursor: pointer; transition: background-color .15s; }
|
| 1927 |
+
.ranking-settings .setting-switch::after { content: ''; position: absolute; top: 2px; left: 2px; width: 18px; height: 18px; border-radius: 50%; background: var(--rk-text, var(--fg-color, #ddd)); transition: left .15s; }
|
| 1928 |
+
.ranking-settings .setting-switch.active { background: #277a39; border-color: #277a39; }
|
| 1929 |
+
.ranking-settings .setting-switch.active::after { left: 22px; background: #fff; }
|
| 1930 |
+
.ranking-settings .setting-select, .ranking-settings .setting-number-input, .ranking-settings__back, .ranking-settings .cache-clear-btn { min-height: 36px; max-width: 100%; margin: 0; padding: 8px 12px; background: var(--rk-panel, var(--comfy-input-bg, #292929)); color: inherit; border: 1px solid var(--rk-border, var(--border-color, #555)); border-radius: var(--rk-radius-sm, 6px); font: inherit; font-size: 13px; line-height: 1.4; }
|
| 1931 |
+
.ranking-settings .setting-select { flex: 0 1 260px; min-width: 0; width: 100%; cursor: pointer; }
|
| 1932 |
+
.ranking-settings .setting-select option { background: var(--rk-panel, var(--comfy-input-bg, #292929)); color: var(--rk-text, var(--fg-color, #ddd)); }
|
| 1933 |
+
.ranking-settings .setting-number-input { width: 98px; min-width: 0; text-align: center; }
|
| 1934 |
+
.ranking-settings__back, .ranking-settings .cache-clear-btn { cursor: pointer; }
|
| 1935 |
+
.ranking-settings__back { flex: 0 1 auto; font-weight: 600; }
|
| 1936 |
+
.ranking-settings :is(button, select, input):focus-visible { outline: 2px solid var(--rk-focus, #8ab4ff); outline-offset: 3px; }
|
| 1937 |
+
.ranking-settings :is(button, select, input):hover:not(:disabled) { border-color: var(--rk-focus, #8ab4ff); }
|
| 1938 |
+
.ranking-settings button:disabled { opacity: .65; cursor: not-allowed; }
|
| 1939 |
+
.ranking-settings .ranking-settings__stack { flex-direction: column; align-items: stretch; gap: 12px; }
|
| 1940 |
+
.ranking-settings__controls, .ranking-settings__stats { display: flex; flex-direction: column; gap: 10px; width: 100%; min-width: 0; }
|
| 1941 |
+
.ranking-settings__range-row { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; width: 100%; min-width: 0; }
|
| 1942 |
+
.ranking-settings .setting-range-slider { appearance: none; flex: 1 1 120px; width: 100%; min-width: 0; height: 6px; margin: 10px 0; border: 0; border-radius: 3px; cursor: pointer; background: linear-gradient(to right, var(--rk-success, #4caf50) var(--settings-range-progress, 0%), var(--rk-border, var(--border-color, #777)) var(--settings-range-progress, 0%)); }
|
| 1943 |
+
.ranking-settings .setting-range-slider::-webkit-slider-thumb { appearance: none; width: 18px; height: 18px; border-radius: 50%; background: var(--rk-success, #4caf50); border: 1px solid var(--rk-text, var(--fg-color, #ddd)); }
|
| 1944 |
+
.ranking-settings .setting-range-slider::-moz-range-thumb { width: 18px; height: 18px; border-radius: 50%; background: var(--rk-success, #4caf50); border: 1px solid var(--rk-text, var(--fg-color, #ddd)); }
|
| 1945 |
+
.ranking-settings__time { min-width: 55px; font-size: 12px; font-variant-numeric: tabular-nums; }
|
| 1946 |
+
.ranking-settings__hint, .ranking-settings__stat, .ranking-settings__stat-muted { padding: 10px 12px; background: var(--rk-panel, var(--comfy-input-bg, #292929)); border-inline-start: 3px solid var(--rk-border, var(--border-color, #555)); border-radius: 4px; font-size: 12px; line-height: 1.6; }
|
| 1947 |
+
.ranking-settings__hint, .ranking-settings__stat-muted { color: var(--rk-muted, var(--descrip-text, #aaa)); }
|
| 1948 |
+
.ranking-settings__stat-title { font-weight: 600; }
|
| 1949 |
+
.ranking-settings__actions { display: flex; flex-wrap: wrap; gap: 10px; width: 100%; }
|
| 1950 |
+
.ranking-settings .cache-clear-btn { flex: 1 1 140px; min-width: 0; white-space: normal; overflow-wrap: anywhere; }
|
| 1951 |
+
.ranking-settings__preview { padding: 16px; margin: 16px; border: 1px dashed var(--rk-border, var(--border-color, #555)); border-radius: 8px; }
|
| 1952 |
+
.ranking-settings__preview-title { margin-bottom: 8px; font-size: 12px; font-weight: 600; }
|
| 1953 |
+
.ranking-settings__footer { padding: 15px; border-top: 1px solid var(--rk-border, var(--border-color, #555)); text-align: center; }
|
| 1954 |
+
@container ranking-settings (max-width: 420px) { .ranking-settings .setting-item:has(.setting-select) { flex-wrap: wrap; } .ranking-settings .setting-select { flex-basis: 100%; } .ranking-settings .setting-range-slider { flex-basis: 100%; } }
|
| 1955 |
+
@media (prefers-reduced-motion: reduce) { .ranking-settings .setting-switch, .ranking-settings .setting-switch::after { transition: none; } }
|
| 1956 |
@media (forced-colors: active) { .ranking-settings .setting-switch { background: ButtonFace; border-color: ButtonText; } .ranking-settings .setting-switch::after { background: ButtonText; } .ranking-settings .setting-switch.active { border: 2px solid Highlight; background: Highlight; } .ranking-settings .setting-switch.active::after { top: 1px; left: 21px; background: HighlightText; } .ranking-settings .setting-range-slider { appearance: auto; background: Canvas; } .ranking-settings__heading-general, .ranking-settings__heading-display, .ranking-settings__heading-animation, .ranking-settings__heading-cache, .ranking-settings .setting-shortcuts__heading { border-inline-start-color: Highlight; } }
|
| 1957 |
.ranking-settings .setting-number-input { width: max(98px, 8ch); }
|
| 1958 |
.ranking-settings { color-scheme: normal; }
|
|
|
|
| 2272 |
.discussion-detail .image-sandbox .img-counter { top:134px;bottom:auto;max-width:calc(100% - 4px);padding:2px 4px; }
|
| 2273 |
.discussion-detail .image-sandbox .slider-y { top:192px;height:72px; }
|
| 2274 |
}
|
| 2275 |
+
.discussion-detail .post-detail-author-button { flex-wrap:wrap; }
|
| 2276 |
.discussion-detail .post-detail__identity { flex:1 1 100px; }
|
| 2277 |
|
| 2278 |
.prompt-publish .prompt-publish__field { margin-bottom: 15px; }
|
|
|
|
| 2492 |
@media (max-width:360px) { .image-crop-overlay { padding:8px; } .image-crop-dialog { padding:12px; gap:12px; } }
|
| 2493 |
@media (forced-colors:active) { .image-crop-dialog .image-crop-button { color:ButtonText; background:ButtonFace; border-color:ButtonText; } .image-crop-dialog .image-crop-button:disabled { color:GrayText; border-color:GrayText; } .image-crop-dialog .image-crop-viewport { border-color:Highlight; } .image-crop-dialog .image-crop-button:focus-visible, .image-crop-dialog .image-crop-range:focus-visible { outline-color:Highlight; } }
|
| 2494 |
|
| 2495 |
+
.profile-content-list,.profile-transactions,.profile-transaction-list{display:flex;flex-direction:column;min-width:0;gap:10px}
|
| 2496 |
+
.profile-transactions{gap:15px;container-type:inline-size}
|
| 2497 |
+
.profile-transaction-list{gap:8px}
|
| 2498 |
+
.profile-list-section-title{font-size:13px;font-weight:700;color:var(--rk-text,var(--fg-color,#eee));padding:5px 0;margin:0;overflow-wrap:anywhere}
|
| 2499 |
+
.profile-list-section-title:not(:first-child){margin-top:15px}
|
| 2500 |
+
.profile-stats-card,.profile-task-card,.profile-entry-card,.profile-transaction-card{box-sizing:border-box;min-width:0;max-width:100%;padding:12px;background:var(--rk-panel,var(--comfy-input-bg,#292929));color:var(--rk-text,var(--fg-color,#eee));border:1px solid var(--rk-border,var(--border-color,#777));border-radius:8px;font-family:inherit;line-height:1.5;overflow-wrap:anywhere;color-scheme:normal}
|
| 2501 |
+
.profile-stats-card{padding:14px}
|
| 2502 |
+
.profile-stats-card--spaced{margin-bottom:15px}
|
| 2503 |
+
.profile-stats-card__title{font-size:14px;font-weight:700;margin-bottom:12px}
|
| 2504 |
+
.profile-stats-card__grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}
|
| 2505 |
+
.profile-stats-card__cell{min-width:0;text-align:center;padding:8px 4px;border:1px solid var(--rk-border,var(--border-color,#777));border-radius:6px;border-top:3px solid var(--rk-accent,#3b82f6)}
|
| 2506 |
+
.profile-stats-card__cell--income{border-top-color:var(--rk-success,#3a9360)}
|
| 2507 |
+
.profile-stats-card__cell--expense{border-top-color:var(--rk-danger,#d14b4b)}
|
| 2508 |
+
.profile-stats-card__value{font-size:20px;font-weight:700;overflow-wrap:anywhere}
|
| 2509 |
+
.profile-stats-card__label{font-size:11px;color:var(--rk-muted,var(--descrip-text,#b8b8b8));overflow-wrap:anywhere}
|
| 2510 |
+
.profile-task-card,.profile-entry-card{display:block;width:100%;text-align:start;appearance:none;cursor:pointer;transition:border-color .15s}
|
| 2511 |
+
.profile-task-card:hover,.profile-entry-card:hover{border-color:var(--rk-accent,var(--fg-color,#eee))}
|
| 2512 |
+
.profile-task-card:focus-visible,.profile-entry-card:focus-visible{outline:2px solid var(--rk-accent,var(--fg-color,#eee));outline-offset:-3px}
|
| 2513 |
+
.profile-task-card__summary{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center;gap:8px;margin-bottom:8px}
|
| 2514 |
+
.profile-task-card__status,.profile-list-badge{border:1px solid var(--rk-border,var(--border-color,#777));padding:2px 7px;border-radius:4px;font-size:11px;max-width:100%;box-sizing:border-box}
|
| 2515 |
+
.profile-task-card__status--open{border-color:var(--rk-success,#3a9360)}
|
| 2516 |
+
.profile-task-card__status--active,.profile-task-card__status--pending{border-color:var(--rk-accent,#3b82f6)}
|
| 2517 |
+
.profile-task-card__status--disputed{border-color:var(--rk-danger,#d14b4b)}
|
| 2518 |
+
.profile-task-card__price{font-weight:700;min-width:0;overflow-wrap:anywhere}
|
| 2519 |
+
.profile-list-card__title{font-size:14px;font-weight:700;margin-bottom:6px;line-height:1.4;overflow-wrap:anywhere}
|
| 2520 |
+
.profile-list-card__meta{display:flex;align-items:center;flex-wrap:wrap;gap:6px 12px;font-size:11px;color:var(--rk-muted,var(--descrip-text,#b8b8b8));min-width:0}
|
| 2521 |
+
.profile-list-card__meta>*{min-width:0;max-width:100%;overflow-wrap:anywhere}
|
| 2522 |
+
.profile-list-card__time{margin-inline-start:auto}
|
| 2523 |
+
.profile-entry-card__row,.profile-transaction-card__summary{display:flex;align-items:flex-start;gap:10px;min-width:0}
|
| 2524 |
+
.profile-entry-card__media{position:relative;flex-shrink:0;max-width:100%}
|
| 2525 |
+
.profile-entry-card__image{width:60px;height:60px;max-width:100%;object-fit:cover;border-radius:6px;display:block}
|
| 2526 |
+
.profile-entry-card__play{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:28px;height:28px;background:rgba(0,0,0,.6);border-radius:50%;display:flex;align-items:center;justify-content:center;pointer-events:none}
|
| 2527 |
+
.profile-entry-card__play-triangle{width:0;height:0;border-left:10px solid #fff;border-top:6px solid transparent;border-bottom:6px solid transparent;margin-left:2px}
|
| 2528 |
+
.profile-list-card__body{flex:1;min-width:0}
|
| 2529 |
+
.profile-list-badge--price{border-color:var(--rk-accent,#3b82f6)}
|
| 2530 |
+
.profile-list-badge--free{border-color:var(--rk-success,#3a9360)}
|
| 2531 |
+
.profile-transaction-card{display:flex;justify-content:space-between;align-items:flex-start;flex-wrap:wrap;gap:10px}
|
| 2532 |
+
.profile-transaction-card__summary{flex:1 1 140px}
|
| 2533 |
+
.profile-transaction-card__icon{font-size:20px;flex-shrink:0}
|
| 2534 |
+
.profile-transaction-card__heading{display:flex;align-items:center;flex-wrap:wrap;min-width:0}
|
| 2535 |
+
.profile-transaction-card__title{font-size:13px;font-weight:700}
|
| 2536 |
+
.profile-transaction-card__item{color:var(--rk-muted,var(--descrip-text,#b8b8b8));margin-inline-start:6px;min-width:0;max-width:calc(100% - 6px);overflow-wrap:anywhere}
|
| 2537 |
+
.profile-transaction-card__description,.profile-transaction-card__detail,.profile-transaction-card__net{font-size:11px;color:var(--rk-muted,var(--descrip-text,#b8b8b8));margin-top:3px;overflow-wrap:anywhere}
|
| 2538 |
+
.profile-transaction-card__money{min-width:0;max-width:100%;margin-inline-start:auto;text-align:end}
|
| 2539 |
+
.profile-transaction-card__amount{font-weight:700;font-size:15px;overflow-wrap:anywhere;border-inline-start:3px solid var(--rk-danger,#d14b4b);padding-inline-start:7px}
|
| 2540 |
+
.profile-transaction-card__amount--income{border-inline-start-color:var(--rk-success,#3a9360)}
|
| 2541 |
+
@container (max-width:340px){.profile-stats-card__grid{grid-template-columns:minmax(0,1fr)}.profile-stats-card__cell{text-align:start;padding:8px}.profile-stats-card__value{font-size:18px}}
|
| 2542 |
+
@media(prefers-reduced-motion:reduce){.profile-task-card,.profile-entry-card{transition:none}}
|
| 2543 |
+
@media(forced-colors:active){.profile-task-card,.profile-entry-card,.profile-stats-card,.profile-transaction-card,.profile-stats-card__cell,.profile-task-card__status,.profile-list-badge{border-color:CanvasText}.profile-task-card:focus-visible,.profile-entry-card:focus-visible{outline-color:Highlight}}
|
| 2544 |
|
| 2545 |
.task-publish { display:flex; flex-direction:column; flex:1; min-width:0; min-height:0; box-sizing:border-box; overflow-y:auto; color:var(--rk-text,var(--fg-color,#eee)); background:var(--rk-bg,var(--comfy-menu-bg,#202020)); font:inherit; font-size:14px; line-height:1.5; overflow-wrap:anywhere; color-scheme:normal; container-type:inline-size; }
|
| 2546 |
.task-publish *, .task-publish *::before, .task-publish *::after { box-sizing:border-box; }
|
|
|
|
| 2640 |
.wallet-modal__danger, .wallet-modal__success { text-decoration-color: CanvasText; }
|
| 2641 |
.wallet-withdraw__summary, .wallet-withdraw__fee, .wallet-recharge__qr { border-color: CanvasText; }
|
| 2642 |
}
|
| 2643 |
+
|
| 2644 |
+
.tip-level { max-width: 100%; overflow-wrap: anywhere; }
|
| 2645 |
+
.tip-level--new, .tip-level--fallback { color: var(--rk-text, var(--fg-color, #ddd)); font-size: .6875rem; }
|
| 2646 |
+
.tip-level__icon { overflow-wrap: anywhere; }
|
| 2647 |
+
.tip-level__icon--sun { font-size: .75rem; }
|
| 2648 |
+
.tip-level__icon--moon { font-size: .6875rem; }
|
| 2649 |
+
.tip-level__icon--star, .tip-level--fallback { font-size: .625rem; }
|
| 2650 |
+
.tip-level--full { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px; font-size: .6875rem; }
|
| 2651 |
+
.tip-level__part { color: var(--rk-text, var(--fg-color, #ddd)); }
|
| 2652 |
+
.tip-level__part--sun { font-weight: bold; }
|
| 2653 |
+
.tip-level--max-compact { color: var(--rk-text, var(--fg-color, #ddd)); font-weight: bold; padding-inline: 2px; border-bottom: 2px solid #c38a00; }
|
| 2654 |
+
.tip-level--max { display: inline-block; box-sizing: border-box; padding: 2px 6px; border: 1px solid #a87500; border-radius: 4px; background: #ffdf80; color: #241c00; font-size: .6875rem; font-weight: bold; }
|
| 2655 |
+
.tip-board-item { --tip-badge-size: 1.25rem; --tip-avatar-size: 1.5rem; --tip-font-size: .75rem; --tip-badge-font: .625rem; --tip-amount-font: .6875rem; --tip-row-padding: 5px; display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 4px 8px; min-width: 0; max-width: 100%; box-sizing: border-box; padding: var(--tip-row-padding) 0; border-bottom: 1px dashed var(--rk-border, var(--border-color, #454545)); color: var(--rk-text, var(--fg-color, #ddd)); font-size: var(--tip-font-size); line-height: 1.5; }
|
| 2656 |
+
.tip-board-item--small { --tip-badge-size: 1rem; --tip-avatar-size: 1.25rem; --tip-font-size: .6875rem; --tip-badge-font: .5625rem; --tip-amount-font: .625rem; --tip-row-padding: 3px; }
|
| 2657 |
+
.tip-board-item--large { --tip-badge-size: 1.5rem; --tip-avatar-size: 1.75rem; --tip-font-size: .875rem; --tip-badge-font: .75rem; --tip-amount-font: .8125rem; --tip-row-padding: 8px; }
|
| 2658 |
+
.tip-board-group { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px; min-width: 0; max-width: 100%; overflow-wrap: anywhere; }
|
| 2659 |
+
.tip-board-item > .tip-board-group:first-child { flex: 1 1 8rem; }
|
| 2660 |
+
.tip-board-item > .tip-board-group:last-child { justify-content: flex-end; margin-inline-start: auto; }
|
| 2661 |
+
.tip-board-badge { display: inline-flex; justify-content: center; align-items: center; flex: 0 0 auto; min-width: var(--tip-badge-size); min-height: var(--tip-badge-size); box-sizing: border-box; padding: 1px 3px; border: 1px solid var(--rk-border, var(--border-color, #454545)); border-radius: 50%; background: var(--rk-panel, var(--comfy-input-bg, #292929)); color: var(--rk-text, var(--fg-color, #ddd)); font-size: var(--tip-badge-font); font-weight: bold; }
|
| 2662 |
+
.tip-board-badge--gold { background: #ffd700; color: #211900; border-color: #b28a00; }
|
| 2663 |
+
.tip-board-badge--silver { background: #c0c0c0; color: #191919; border-color: #777; }
|
| 2664 |
+
.tip-board-badge--bronze { background: #cd7f32; color: #1c1000; border-color: #8d511b; }
|
| 2665 |
+
.tip-board-avatar { width: var(--tip-avatar-size); height: var(--tip-avatar-size); max-width: 100%; border-radius: 50%; object-fit: cover; flex-shrink: 0; background: var(--rk-panel, var(--comfy-input-bg, #292929)); }
|
| 2666 |
+
.tip-board-name, .tip-board-anonymous { min-width: 0; max-width: 100%; color: var(--rk-text, var(--fg-color, #ddd)); overflow-wrap: anywhere; }
|
| 2667 |
+
.tip-board-amount { max-width: 100%; color: var(--rk-text, var(--fg-color, #ddd)); color: color-mix(in srgb, var(--rk-text, var(--fg-color, #ddd)) 80%, var(--rk-success, #4caf50)); font-weight: bold; font-size: var(--tip-amount-font); overflow-wrap: anywhere; }
|
| 2668 |
+
.tip-board-empty { padding: 12px 0; color: var(--rk-text, var(--fg-color, #ddd)); font-size: .75rem; text-align: center; overflow-wrap: anywhere; }
|
| 2669 |
+
@media (forced-colors: active) {
|
| 2670 |
+
.tip-board-item { border-color: CanvasText; color: CanvasText; }
|
| 2671 |
+
.tip-board-badge, .tip-level--max { border-color: CanvasText; background: Canvas; color: CanvasText; }
|
| 2672 |
+
.tip-level--max-compact { color: CanvasText; border-color: CanvasText; }
|
| 2673 |
+
.tip-level__part, .tip-level--new, .tip-level--fallback, .tip-board-name, .tip-board-anonymous, .tip-board-amount, .tip-board-empty { color: CanvasText; }
|
| 2674 |
+
}
|
| 2675 |
+
|
| 2676 |
+
|
| 2677 |
+
.ranking-publish-view { display:flex; flex-direction:column; flex:1; gap:15px; min-width:0; min-height:0; padding:15px; box-sizing:border-box; overflow-y:auto; color:var(--rk-text,var(--fg-color,#eee)); font:inherit; font-size:.875rem; line-height:1.5; color-scheme:normal; }
|
| 2678 |
+
.ranking-publish__image { position:relative; flex:0 0 96px; width:96px; height:96px; min-width:0; box-sizing:border-box; }
|
| 2679 |
+
.ranking-publish__image--sortable { cursor:grab; }
|
| 2680 |
+
.ranking-publish__image:focus-visible { outline:3px solid var(--rk-focus,#8ab4ff); outline-offset:2px; }
|
| 2681 |
+
.ranking-publish__thumbnail { display:block; width:100%; height:100%; object-fit:cover; box-sizing:border-box; border:2px solid var(--rk-border,var(--border-color,#777)); border-radius:6px; }
|
| 2682 |
+
.ranking-publish__image--cover .ranking-publish__thumbnail { border-color:var(--rk-success,#3a9360); }
|
| 2683 |
+
.ranking-publish__cover-label { position:absolute; top:2px; left:2px; max-width:calc(100% - 4px); padding:1px 4px; box-sizing:border-box; border:1px solid var(--rk-success,#3a9360); border-radius:3px; background:var(--rk-panel,var(--comfy-input-bg,#292929)); color:var(--rk-text,var(--fg-color,#eee)); font-size:.625rem; line-height:1.3; font-weight:700; overflow-wrap:anywhere; pointer-events:none; }
|
| 2684 |
+
.ranking-publish .ranking-publish__image-remove { position:absolute; right:2px; bottom:2px; width:36px; height:36px; min-height:36px; padding:0; display:grid; place-items:center; border:2px solid var(--rk-danger,#d14b4b); border-radius:6px; background:var(--rk-panel,var(--comfy-input-bg,#292929)); color:var(--rk-text,var(--fg-color,#eee)); font:inherit; font-size:.875rem; line-height:1; cursor:pointer; }
|
| 2685 |
+
.ranking-publish .ranking-publish__image-remove:hover:not(:disabled) { border-color:var(--rk-focus,#8ab4ff); }
|
| 2686 |
+
.ranking-publish .ranking-publish__image-remove:focus-visible { outline:3px solid var(--rk-focus,#8ab4ff); outline-offset:2px; }
|
| 2687 |
+
.ranking-publish__image--dragging { opacity:.5; }
|
| 2688 |
+
.ranking-publish__image--target::before { content:""; position:absolute; left:-5px; top:0; bottom:0; width:3px; border-radius:2px; background:var(--rk-success,#3a9360); pointer-events:none; }
|
| 2689 |
+
.ranking-publish__pending-value { padding-inline:3px; border-bottom:2px solid var(--rk-success,#3a9360); color:inherit; }
|
| 2690 |
+
.ranking-original-confirm { min-width:0; max-width:100%; color:var(--rk-text,var(--fg-color,#eee)); font:inherit; font-size:.875rem; line-height:1.6; overflow-wrap:anywhere; color-scheme:normal; }
|
| 2691 |
+
.ranking-original-confirm *, .ranking-original-confirm *::before, .ranking-original-confirm *::after { box-sizing:border-box; }
|
| 2692 |
+
.ranking-original-confirm__description { margin:0 0 15px; }
|
| 2693 |
+
.ranking-original-confirm__subtitle { margin:0 0 10px; font-weight:700; }
|
| 2694 |
+
.ranking-original-confirm__list { margin:0 0 15px; padding-inline-start:20px; }
|
| 2695 |
+
.ranking-original-confirm__list li { margin-bottom:5px; }
|
| 2696 |
+
.ranking-original-confirm__warning { margin:15px 0 0; padding:10px; border:1px solid var(--rk-border,var(--border-color,#777)); border-inline-start:3px solid var(--rk-warning,#d97706); border-radius:4px; background:var(--rk-bg,var(--comfy-menu-bg,#202020)); color:inherit; font-size:.75rem; }
|
| 2697 |
+
.ranking-original-confirm__actions { display:flex; flex-wrap:wrap; gap:10px; margin-top:20px; justify-content:flex-end; }
|
| 2698 |
+
.ranking-original-confirm__button { flex:0 1 auto; min-width:0; min-height:36px; max-width:100%; padding:8px 16px; border:1px solid var(--rk-border,var(--border-color,#777)); border-radius:6px; background:var(--rk-panel,var(--comfy-input-bg,#292929)); color:inherit; font:inherit; line-height:1.4; white-space:normal; overflow-wrap:anywhere; cursor:pointer; }
|
| 2699 |
+
.ranking-original-confirm__button--confirm { border-inline-start:3px solid var(--rk-success,#3a9360); font-weight:700; }
|
| 2700 |
+
.ranking-original-confirm__button:hover:not(:disabled) { border-color:var(--rk-focus,#8ab4ff); }
|
| 2701 |
+
.ranking-original-confirm__button:focus-visible { outline:3px solid var(--rk-focus,#8ab4ff); outline-offset:2px; }
|
| 2702 |
+
.ranking-original-confirm__button:disabled { opacity:.7; cursor:default; }
|
| 2703 |
+
@media (forced-colors:active) {
|
| 2704 |
+
.ranking-publish__thumbnail { border-color:CanvasText; }
|
| 2705 |
+
.ranking-publish__image--cover .ranking-publish__thumbnail { border-color:Highlight; }
|
| 2706 |
+
.ranking-publish__image--target::before { background:Highlight; }
|
| 2707 |
+
.ranking-publish__cover-label, .ranking-publish .ranking-publish__image-remove, .ranking-original-confirm__button { background:ButtonFace; color:ButtonText; border-color:ButtonText; }
|
| 2708 |
+
.ranking-publish__image:focus-visible, .ranking-publish .ranking-publish__image-remove:focus-visible, .ranking-original-confirm__button:focus-visible { outline-color:Highlight; }
|
| 2709 |
+
.ranking-publish__pending-value, .ranking-original-confirm__warning, .ranking-original-confirm__button--confirm { border-color:Highlight; }
|
| 2710 |
+
}
|
| 2711 |
+
|
| 2712 |
+
.comfy-ranking-root .sidebar-status-message {
|
| 2713 |
+
box-sizing: border-box;
|
| 2714 |
+
min-width: 0;
|
| 2715 |
+
max-width: 100%;
|
| 2716 |
+
padding: 2.5rem 1.25rem;
|
| 2717 |
+
color: var(--rk-text, var(--fg-color, #f1f1f1));
|
| 2718 |
+
font: inherit;
|
| 2719 |
+
line-height: 1.5;
|
| 2720 |
+
text-align: center;
|
| 2721 |
+
overflow-wrap: anywhere;
|
| 2722 |
+
}
|
| 2723 |
+
.comfy-ranking-root .sidebar-status-more {
|
| 2724 |
+
box-sizing: border-box;
|
| 2725 |
+
width: 100%;
|
| 2726 |
+
min-width: 0;
|
| 2727 |
+
min-height: 2.25rem;
|
| 2728 |
+
margin-top: .625rem;
|
| 2729 |
+
padding: .625rem;
|
| 2730 |
+
border: 1px solid var(--rk-border, var(--border-color, #555));
|
| 2731 |
+
border-radius: .375rem;
|
| 2732 |
+
background: transparent;
|
| 2733 |
+
color: var(--rk-text, var(--fg-color, #f1f1f1));
|
| 2734 |
+
font: inherit;
|
| 2735 |
+
line-height: 1.5;
|
| 2736 |
+
text-align: center;
|
| 2737 |
+
white-space: normal;
|
| 2738 |
+
overflow-wrap: anywhere;
|
| 2739 |
+
cursor: pointer;
|
| 2740 |
+
}
|
| 2741 |
+
.comfy-ranking-root .sidebar-status-more:focus-visible { outline: 2px solid var(--rk-text, var(--fg-color, #f1f1f1)); outline-offset: -3px; }
|
| 2742 |
+
.comfy-ranking-root .sidebar-status-more:disabled { cursor: wait; }
|
| 2743 |
+
@media (forced-colors: active) {
|
| 2744 |
+
.comfy-ranking-root .sidebar-status-message { color: CanvasText; }
|
| 2745 |
+
.comfy-ranking-root .sidebar-status-more { color: ButtonText; border-color: ButtonText; background: ButtonFace; }
|
| 2746 |
+
.comfy-ranking-root .sidebar-status-more:focus-visible { outline-color: Highlight; }
|
| 2747 |
+
.comfy-ranking-root .sidebar-status-more:disabled { color: GrayText; border-color: GrayText; }
|
| 2748 |
+
}
|
| 2749 |
+
|
| 2750 |
+
.comfy-ranking-root .profile-view { display:flex; flex-direction:column; gap:.9375rem; padding:.9375rem; flex:1; min-width:0; min-height:0; box-sizing:border-box; overflow-y:auto; background:var(--rk-bg,var(--comfy-menu-bg,#202020)); color:var(--rk-text,var(--fg-color,#eee)); font-size:.875rem; overflow-wrap:anywhere; }
|
| 2751 |
+
|
| 2752 |
.skill-directory { display:flex; flex-direction:column; gap:.75rem; min-width:0; color:inherit; overflow-wrap:anywhere; }
|
| 2753 |
.skill-directory p { margin:0; }
|
| 2754 |
.skill-directory__label { display:flex; flex-direction:column; gap:.375rem; min-width:0; }
|
|
|
|
| 2764 |
@media (forced-colors:active) { .skill-directory :is(input,button) { border-color:ButtonText; } .skill-directory :is(input,button):focus-visible { outline-color:Highlight; } }
|
| 2765 |
|
| 2766 |
.comfy-ranking-root .resource-trend { --resource-trend-text: var(--rk-text); --resource-trend-border: var(--rk-border); --resource-trend-line: var(--rk-text); --resource-trend-panel: var(--rk-panel); min-width:0; min-height:10rem; max-width:100%; transition-property:none; font-family:inherit; font-size:.75rem; color:var(--rk-text); }
|
| 2767 |
+
.comfy-ranking-root .resource-trend__state { display:flex; justify-content:center; align-items:center; min-height:160px; box-sizing:border-box; padding:1rem; text-align:center; font:inherit; line-height:1.5; overflow-wrap:anywhere; color:var(--rk-text); }
|
| 2768 |
+
.comfy-ranking-root .resource-trend__state[role=alert] { border-inline-start:2px solid var(--rk-danger); }
|
| 2769 |
+
@media (forced-colors:active) { .comfy-ranking-root .resource-trend { --resource-trend-text:CanvasText; --resource-trend-border:CanvasText; --resource-trend-line:CanvasText; --resource-trend-panel:Canvas; } .comfy-ranking-root .resource-trend__state { color:CanvasText; } .comfy-ranking-root .resource-trend__state[role=alert] { border-color:CanvasText; } }
|
| 2770 |
+
|
| 2771 |
+
.skeleton-container { padding: 8px; }
|
| 2772 |
+
.skeleton-container .skeleton-item {
|
| 2773 |
+
background: linear-gradient(90deg, var(--rk-panel, var(--comfy-input-bg, #292929)) 25%, var(--rk-border, var(--border-color, #454545)) 50%, var(--rk-panel, var(--comfy-input-bg, #292929)) 75%);
|
| 2774 |
+
background-size: 200% 100%; animation: ranking-skeleton-shimmer 1.5s ease-in-out infinite; border-radius: 6px;
|
| 2775 |
+
}
|
| 2776 |
+
.skeleton-container .skeleton-card { background: var(--rk-panel, var(--comfy-input-bg, #292929)); border: 1px solid var(--rk-border, var(--border-color, #454545)); border-radius: 8px; padding: 12px; margin-bottom: 12px; }
|
| 2777 |
+
@keyframes ranking-skeleton-shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
|
| 2778 |
+
@media (prefers-reduced-motion: reduce) { .skeleton-container .skeleton-item { animation: none; } }
|
| 2779 |
+
@media (forced-colors: active) { .skeleton-container .skeleton-card { background: Canvas; border-color: CanvasText; } .skeleton-container .skeleton-item { background: GrayText; animation: none; } }
|
前端页面/task/任务详情组件.js
CHANGED
|
@@ -487,7 +487,7 @@ function _showConfirmDialog({ scope, title, icon, message, description, confirmT
|
|
| 487 |
await onSuccess(content);
|
| 488 |
} catch (err) {
|
| 489 |
if (!taskModalCurrent(content) || phase === "closed" || phase === "committed") return;
|
| 490 |
-
const rejected = [400, 401, 403, 404, 409, 422, 429].includes(err?.status);
|
| 491 |
phase = rejected ? "idle" : "unconfirmed";
|
| 492 |
showToast(rejected ? errorText : t('task.operation_unconfirmed'), rejected ? "error" : "warning");
|
| 493 |
} finally {
|
|
@@ -559,7 +559,7 @@ function bindTaskTextSubmission({ content, taskId, input, button, confirmText, e
|
|
| 559 |
await onSuccess();
|
| 560 |
} catch (err) {
|
| 561 |
if (!taskModalCurrent(content) || phase === "closed" || phase === "committed") return;
|
| 562 |
-
const rejected = [400, 401, 403, 404, 409, 422, 429].includes(err?.status);
|
| 563 |
phase = rejected ? "idle" : "unconfirmed";
|
| 564 |
showToast(rejected ? errorText : t('task.operation_unconfirmed'), rejected ? "error" : "warning");
|
| 565 |
} finally {
|
|
@@ -764,7 +764,7 @@ function showDeleteCommentConfirmDialog(taskId, comment, container, currentUser)
|
|
| 764 |
await loadTaskComments(container, taskId, currentUser);
|
| 765 |
} catch (err) {
|
| 766 |
if (!taskModalCurrent(content) || phase === "closed" || phase === "committed") return;
|
| 767 |
-
const rejected = [400, 401, 403, 404, 409, 422, 429].includes(err?.status);
|
| 768 |
phase = rejected ? "idle" : "unconfirmed";
|
| 769 |
showToast(t(rejected ? 'post.delete_comment_failed' : 'task.comment_unconfirmed'), rejected ? "error" : "warning");
|
| 770 |
} finally {
|
|
@@ -919,7 +919,7 @@ function showSubmitDialog(task, currentUser) {
|
|
| 919 |
content.classList.add("task-modal");
|
| 920 |
content.innerHTML = `
|
| 921 |
<div class="task-detail__spaced">
|
| 922 |
-
<label for="deliverable-files" class="task-detail__file-label">${t('task.deliverable_images')} <span aria-hidden="true">
|
| 923 |
<input type="file" aria-required="true" aria-describedby="deliverable-hint" id="deliverable-files" multiple accept="image/*" class="task-detail__file-input">
|
| 924 |
<div id="deliverable-hint" class="task-detail__hint">${t('task.support_multiple_images')}</div>
|
| 925 |
</div>
|
|
@@ -990,7 +990,7 @@ function showSubmitDialog(task, currentUser) {
|
|
| 990 |
if (container && currentUser) await loadTaskDetail(container, taskId, currentUser);
|
| 991 |
} catch (err) {
|
| 992 |
if (!taskModalCurrent(content) || phase === "closed" || phase === "committed") return;
|
| 993 |
-
const unknown = saveAttempted && ![400, 401, 403, 404, 409, 422, 429].includes(err?.status);
|
| 994 |
phase = unknown ? "unconfirmed" : "idle";
|
| 995 |
showToast(t(unknown ? 'task.operation_unconfirmed' : (saveAttempted ? 'task.submit_failed' : 'task.upload_failed_retry')),
|
| 996 |
unknown ? "warning" : "error");
|
|
@@ -1277,7 +1277,7 @@ async function loadTaskComments(container, taskId, currentUser) {
|
|
| 1277 |
if (isCurrent()) state.phase = "idle";
|
| 1278 |
} catch (err) {
|
| 1279 |
if (!isCurrent() || state.phase === "committed") return;
|
| 1280 |
-
const rejected = [400, 401, 403, 404, 409, 422, 429].includes(err?.status);
|
| 1281 |
state.phase = rejected ? "idle" : "unconfirmed";
|
| 1282 |
showToast(t(rejected ? 'post.comment_failed' : 'task.comment_unconfirmed'), rejected ? "error" : "warning");
|
| 1283 |
} finally {
|
|
@@ -1374,7 +1374,7 @@ function showDeleteTaskConfirm(task, contentEl) {
|
|
| 1374 |
window.dispatchEvent(new CustomEvent("comfy-route-back"));
|
| 1375 |
} catch (err) {
|
| 1376 |
if (!taskModalCurrent(content) || phase === "closed" || phase === "committed") return;
|
| 1377 |
-
const rejected = [400, 401, 403, 404, 409, 422, 429].includes(err?.status);
|
| 1378 |
phase = rejected ? "idle" : "unconfirmed";
|
| 1379 |
showToast(t(rejected ? 'task.delete_failed' : 'task.delete_unconfirmed'), rejected ? "error" : "warning");
|
| 1380 |
} finally {
|
|
@@ -1396,7 +1396,7 @@ function showDisputeDialog(task, currentUser) {
|
|
| 1396 |
content.className = "task-dispute";
|
| 1397 |
content.innerHTML = `
|
| 1398 |
<div class="task-dispute__field">
|
| 1399 |
-
<label for="dispute-reason" class="task-dispute__label">${t('dispute.reason')} <span aria-hidden="true" class="task-dispute__required">
|
| 1400 |
<textarea id="dispute-reason" aria-required="true" placeholder="${t('dispute.reason_placeholder')}" class="task-dispute__reason"></textarea>
|
| 1401 |
</div>
|
| 1402 |
|
|
|
|
| 487 |
await onSuccess(content);
|
| 488 |
} catch (err) {
|
| 489 |
if (!taskModalCurrent(content) || phase === "closed" || phase === "committed") return;
|
| 490 |
+
const rejected = (err?.requestBodyRejected === true || [400, 401, 403, 404, 409, 422, 429].includes(err?.status));
|
| 491 |
phase = rejected ? "idle" : "unconfirmed";
|
| 492 |
showToast(rejected ? errorText : t('task.operation_unconfirmed'), rejected ? "error" : "warning");
|
| 493 |
} finally {
|
|
|
|
| 559 |
await onSuccess();
|
| 560 |
} catch (err) {
|
| 561 |
if (!taskModalCurrent(content) || phase === "closed" || phase === "committed") return;
|
| 562 |
+
const rejected = (err?.requestBodyRejected === true || [400, 401, 403, 404, 409, 422, 429].includes(err?.status));
|
| 563 |
phase = rejected ? "idle" : "unconfirmed";
|
| 564 |
showToast(rejected ? errorText : t('task.operation_unconfirmed'), rejected ? "error" : "warning");
|
| 565 |
} finally {
|
|
|
|
| 764 |
await loadTaskComments(container, taskId, currentUser);
|
| 765 |
} catch (err) {
|
| 766 |
if (!taskModalCurrent(content) || phase === "closed" || phase === "committed") return;
|
| 767 |
+
const rejected = (err?.requestBodyRejected === true || [400, 401, 403, 404, 409, 422, 429].includes(err?.status));
|
| 768 |
phase = rejected ? "idle" : "unconfirmed";
|
| 769 |
showToast(t(rejected ? 'post.delete_comment_failed' : 'task.comment_unconfirmed'), rejected ? "error" : "warning");
|
| 770 |
} finally {
|
|
|
|
| 919 |
content.classList.add("task-modal");
|
| 920 |
content.innerHTML = `
|
| 921 |
<div class="task-detail__spaced">
|
| 922 |
+
<label for="deliverable-files" class="task-detail__file-label">${t('task.deliverable_images')} <span aria-hidden="true" class="ranking-required-marker"></span></label>
|
| 923 |
<input type="file" aria-required="true" aria-describedby="deliverable-hint" id="deliverable-files" multiple accept="image/*" class="task-detail__file-input">
|
| 924 |
<div id="deliverable-hint" class="task-detail__hint">${t('task.support_multiple_images')}</div>
|
| 925 |
</div>
|
|
|
|
| 990 |
if (container && currentUser) await loadTaskDetail(container, taskId, currentUser);
|
| 991 |
} catch (err) {
|
| 992 |
if (!taskModalCurrent(content) || phase === "closed" || phase === "committed") return;
|
| 993 |
+
const unknown = saveAttempted && !(err?.requestBodyRejected === true || [400, 401, 403, 404, 409, 422, 429].includes(err?.status));
|
| 994 |
phase = unknown ? "unconfirmed" : "idle";
|
| 995 |
showToast(t(unknown ? 'task.operation_unconfirmed' : (saveAttempted ? 'task.submit_failed' : 'task.upload_failed_retry')),
|
| 996 |
unknown ? "warning" : "error");
|
|
|
|
| 1277 |
if (isCurrent()) state.phase = "idle";
|
| 1278 |
} catch (err) {
|
| 1279 |
if (!isCurrent() || state.phase === "committed") return;
|
| 1280 |
+
const rejected = (err?.requestBodyRejected === true || [400, 401, 403, 404, 409, 422, 429].includes(err?.status));
|
| 1281 |
state.phase = rejected ? "idle" : "unconfirmed";
|
| 1282 |
showToast(t(rejected ? 'post.comment_failed' : 'task.comment_unconfirmed'), rejected ? "error" : "warning");
|
| 1283 |
} finally {
|
|
|
|
| 1374 |
window.dispatchEvent(new CustomEvent("comfy-route-back"));
|
| 1375 |
} catch (err) {
|
| 1376 |
if (!taskModalCurrent(content) || phase === "closed" || phase === "committed") return;
|
| 1377 |
+
const rejected = (err?.requestBodyRejected === true || [400, 401, 403, 404, 409, 422, 429].includes(err?.status));
|
| 1378 |
phase = rejected ? "idle" : "unconfirmed";
|
| 1379 |
showToast(t(rejected ? 'task.delete_failed' : 'task.delete_unconfirmed'), rejected ? "error" : "warning");
|
| 1380 |
} finally {
|
|
|
|
| 1396 |
content.className = "task-dispute";
|
| 1397 |
content.innerHTML = `
|
| 1398 |
<div class="task-dispute__field">
|
| 1399 |
+
<label for="dispute-reason" class="task-dispute__label">${t('dispute.reason')} <span aria-hidden="true" class="task-dispute__required ranking-required-marker"></span></label>
|
| 1400 |
<textarea id="dispute-reason" aria-required="true" placeholder="${t('dispute.reason_placeholder')}" class="task-dispute__reason"></textarea>
|
| 1401 |
</div>
|
| 1402 |
|
前端页面/task/发布任务组件.js
CHANGED
|
@@ -130,7 +130,7 @@ export function createPublishTaskView(currentUser, editTaskData = null) {
|
|
| 130 |
<!-- 任务标题 -->
|
| 131 |
<div>
|
| 132 |
<label for="task-title" class="task-publish__label">
|
| 133 |
-
📌 ${t('task.task_title')} <span aria-hidden="true" class="task-publish__required">
|
| 134 |
</label>
|
| 135 |
<input type="text" id="task-title" required maxlength="50" placeholder="${t('task.title_placeholder')}" value="${escapeHtml(editTitle)}"
|
| 136 |
class="task-publish__input">
|
|
@@ -139,7 +139,7 @@ export function createPublishTaskView(currentUser, editTaskData = null) {
|
|
| 139 |
<!-- 任务描述 -->
|
| 140 |
<div>
|
| 141 |
<label for="task-description" class="task-publish__label">
|
| 142 |
-
📄 ${t('task.description')} <span aria-hidden="true" class="task-publish__required">
|
| 143 |
</label>
|
| 144 |
<textarea id="task-description" required aria-describedby="desc-count" rows="6" maxlength="2000" placeholder="${t('task.description_placeholder')}"
|
| 145 |
class="task-publish__textarea">${escapeHtml(editDescription)}</textarea>
|
|
@@ -175,7 +175,7 @@ export function createPublishTaskView(currentUser, editTaskData = null) {
|
|
| 175 |
<!-- 总价格 -->
|
| 176 |
<div>
|
| 177 |
<label for="total-price" class="task-publish__label">
|
| 178 |
-
💰 ${t('task.total_price')} <span aria-hidden="true" class="task-publish__required">
|
| 179 |
</label>
|
| 180 |
<div class="task-publish__amount-wrap">
|
| 181 |
<input type="number" id="total-price" required aria-describedby="task-price-hint" min="0" max="${TASK_LIMITS.MAX_PRICE}" step="1" placeholder="100" value="${escapeHtml(editTotalPrice)}" ${isLockedStatus ? 'disabled' : ''}
|
|
@@ -188,7 +188,7 @@ export function createPublishTaskView(currentUser, editTaskData = null) {
|
|
| 188 |
<!-- 订金比例 -->
|
| 189 |
<div>
|
| 190 |
<label for="deposit-ratio" class="task-publish__label">
|
| 191 |
-
📊 ${t('task.deposit_ratio')} <span aria-hidden="true" class="task-publish__required">
|
| 192 |
</label>
|
| 193 |
<select id="deposit-ratio" required aria-describedby="task-deposit-hint" ${isLockedStatus ? 'disabled' : ''} class="task-publish__select">
|
| 194 |
${TASK_LIMITS.DEPOSIT_RATIOS.map(ratio => `<option value="${ratio}" ${editDepositRatio == ratio ? 'selected' : ''}>${ratio}%</option>`).join('')}
|
|
@@ -210,7 +210,7 @@ export function createPublishTaskView(currentUser, editTaskData = null) {
|
|
| 210 |
<!-- 截止日期 -->
|
| 211 |
<div>
|
| 212 |
<label for="deadline" class="task-publish__label">
|
| 213 |
-
⏰ ${t('task.deadline')} <span aria-hidden="true" class="task-publish__required">
|
| 214 |
</label>
|
| 215 |
<input type="date" id="deadline" required ${isLockedStatus ? 'aria-describedby="task-deadline-hint"' : ''} min="${minDate}" value="${defaultDate}" ${isLockedStatus ? 'disabled' : ''}
|
| 216 |
class="task-publish__date">
|
|
@@ -511,7 +511,7 @@ export function createPublishTaskView(currentUser, editTaskData = null) {
|
|
| 511 |
} catch (err) {
|
| 512 |
if (!scope.isCurrent() || committed) return;
|
| 513 |
console.error(isEditMode ? "修改任务失败" : "发布任务失败");
|
| 514 |
-
outcomeUnknown = saveAttempted && ![400, 401, 403, 404, 409, 422, 429].includes(err?.status);
|
| 515 |
showToast(t(outcomeUnknown ? 'publish.save_unconfirmed' : (isEditMode ? 'task.edit_failed' : 'task.publish_failed')),
|
| 516 |
outcomeUnknown ? 'warning' : 'error');
|
| 517 |
} finally {
|
|
|
|
| 130 |
<!-- 任务标题 -->
|
| 131 |
<div>
|
| 132 |
<label for="task-title" class="task-publish__label">
|
| 133 |
+
📌 ${t('task.task_title')} <span aria-hidden="true" class="task-publish__required ranking-required-marker"></span>
|
| 134 |
</label>
|
| 135 |
<input type="text" id="task-title" required maxlength="50" placeholder="${t('task.title_placeholder')}" value="${escapeHtml(editTitle)}"
|
| 136 |
class="task-publish__input">
|
|
|
|
| 139 |
<!-- 任务描述 -->
|
| 140 |
<div>
|
| 141 |
<label for="task-description" class="task-publish__label">
|
| 142 |
+
📄 ${t('task.description')} <span aria-hidden="true" class="task-publish__required ranking-required-marker"></span>
|
| 143 |
</label>
|
| 144 |
<textarea id="task-description" required aria-describedby="desc-count" rows="6" maxlength="2000" placeholder="${t('task.description_placeholder')}"
|
| 145 |
class="task-publish__textarea">${escapeHtml(editDescription)}</textarea>
|
|
|
|
| 175 |
<!-- 总价格 -->
|
| 176 |
<div>
|
| 177 |
<label for="total-price" class="task-publish__label">
|
| 178 |
+
💰 ${t('task.total_price')} <span aria-hidden="true" class="task-publish__required ranking-required-marker"></span>
|
| 179 |
</label>
|
| 180 |
<div class="task-publish__amount-wrap">
|
| 181 |
<input type="number" id="total-price" required aria-describedby="task-price-hint" min="0" max="${TASK_LIMITS.MAX_PRICE}" step="1" placeholder="100" value="${escapeHtml(editTotalPrice)}" ${isLockedStatus ? 'disabled' : ''}
|
|
|
|
| 188 |
<!-- 订金比例 -->
|
| 189 |
<div>
|
| 190 |
<label for="deposit-ratio" class="task-publish__label">
|
| 191 |
+
📊 ${t('task.deposit_ratio')} <span aria-hidden="true" class="task-publish__required ranking-required-marker"></span>
|
| 192 |
</label>
|
| 193 |
<select id="deposit-ratio" required aria-describedby="task-deposit-hint" ${isLockedStatus ? 'disabled' : ''} class="task-publish__select">
|
| 194 |
${TASK_LIMITS.DEPOSIT_RATIOS.map(ratio => `<option value="${ratio}" ${editDepositRatio == ratio ? 'selected' : ''}>${ratio}%</option>`).join('')}
|
|
|
|
| 210 |
<!-- 截止日期 -->
|
| 211 |
<div>
|
| 212 |
<label for="deadline" class="task-publish__label">
|
| 213 |
+
⏰ ${t('task.deadline')} <span aria-hidden="true" class="task-publish__required ranking-required-marker"></span>
|
| 214 |
</label>
|
| 215 |
<input type="date" id="deadline" required ${isLockedStatus ? 'aria-describedby="task-deadline-hint"' : ''} min="${minDate}" value="${defaultDate}" ${isLockedStatus ? 'disabled' : ''}
|
| 216 |
class="task-publish__date">
|
|
|
|
| 511 |
} catch (err) {
|
| 512 |
if (!scope.isCurrent() || committed) return;
|
| 513 |
console.error(isEditMode ? "修改任务失败" : "发布任务失败");
|
| 514 |
+
outcomeUnknown = saveAttempted && !(err?.requestBodyRejected === true || [400, 401, 403, 404, 409, 422, 429].includes(err?.status));
|
| 515 |
showToast(t(outcomeUnknown ? 'publish.save_unconfirmed' : (isEditMode ? 'task.edit_failed' : 'task.publish_failed')),
|
| 516 |
outcomeUnknown ? 'warning' : 'error');
|
| 517 |
} finally {
|