feat(ui): adopt low-profile callout capsule for spotlight tour in update guide
This commit is contained in:
@@ -33,6 +33,7 @@ export const i18n = {
|
||||
shortcutDropRelease: "松开,从快捷栏移除",
|
||||
shortcutBarAnchorTip: "固定入口,不可移动",
|
||||
updateGuideStartTour: "🎯 界面按键遮罩导览",
|
||||
updateGuideTourBanner: "💡 想在主界面实地体验?点击开启按键遮罩导览 ›",
|
||||
updateGuideNavigationTitle: "悬停,看懂每个入口",
|
||||
updateGuideNavigationBody: "左下角的按钮保持原来的大小。鼠标悬停或用键盘选中时,图标会切换成文字;稍作停留可以查看完整用途。依次为工具箱、扫描、模型医生、节点助手、素材库和设置。",
|
||||
updateGuideTransferTitle: "导入导出,统一到工具箱",
|
||||
@@ -1249,6 +1250,7 @@ export const i18n = {
|
||||
shortcutDropRelease: "Release to remove from shortcuts",
|
||||
shortcutBarAnchorTip: "Fixed anchor, cannot be moved",
|
||||
updateGuideStartTour: "🎯 Spotlight Tour",
|
||||
updateGuideTourBanner: "💡 Prefer to see them in action? Start Spotlight Tour ›",
|
||||
updateGuideNavigationTitle: "Hover to identify each action",
|
||||
updateGuideNavigationBody: "The lower-left buttons keep their compact size. Hover or focus with the keyboard to replace an icon with a short label; pause for its full description. The actions are Toolbox, Scan, Model Doctor, Node Assistant, Material Library and Settings.",
|
||||
updateGuideTransferTitle: "Workflow sharing lives in Toolbox",
|
||||
|
||||
@@ -254,47 +254,54 @@ export function ensureTourStyles() {
|
||||
background: #1d4ed8;
|
||||
}
|
||||
.anomalous-btn-tour {
|
||||
display: inline-flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
gap: 6px !important;
|
||||
background: linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%) !important;
|
||||
color: #ffffff !important;
|
||||
border: 1px solid rgba(147, 197, 253, 0.7) !important;
|
||||
border-radius: 6px !important;
|
||||
padding: 7px 16px !important;
|
||||
font-size: 12px !important;
|
||||
font-weight: 600 !important;
|
||||
cursor: pointer !important;
|
||||
box-shadow: 0 0 12px rgba(37, 99, 235, 0.45), inset 0 1px 0 rgba(255, 255, 255, 0.2) !important;
|
||||
transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1) !important;
|
||||
animation: anomalous-tour-btn-pulse 2.6s infinite ease-in-out !important;
|
||||
letter-spacing: 0.2px !important;
|
||||
}
|
||||
@keyframes anomalous-tour-btn-pulse {
|
||||
0%, 100% {
|
||||
box-shadow: 0 0 10px rgba(37, 99, 235, 0.4), 0 0 0 0 rgba(59, 130, 246, 0.4);
|
||||
}
|
||||
50% {
|
||||
box-shadow: 0 0 18px rgba(37, 99, 235, 0.75), 0 0 0 3px rgba(59, 130, 246, 0.25);
|
||||
}
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
background: #2563eb;
|
||||
color: #ffffff;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
border-radius: 6px;
|
||||
padding: 7px 16px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s ease;
|
||||
}
|
||||
.anomalous-btn-tour:hover {
|
||||
background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%) !important;
|
||||
border-color: #ffffff !important;
|
||||
color: #ffffff !important;
|
||||
box-shadow: 0 0 20px rgba(59, 130, 246, 0.7), 0 4px 14px rgba(0, 0, 0, 0.35) !important;
|
||||
transform: translateY(-1px) !important;
|
||||
animation: none !important;
|
||||
background: #1d4ed8;
|
||||
border-color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
.anomalous-btn-tour:active {
|
||||
transform: translateY(0) !important;
|
||||
box-shadow: 0 0 8px rgba(37, 99, 235, 0.5) !important;
|
||||
.anomalous-update-guide-tour-banner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
margin: 2px auto 14px auto;
|
||||
padding: 6px 16px;
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: 20px;
|
||||
color: #94a3b8;
|
||||
font-size: 11.5px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
|
||||
max-width: fit-content;
|
||||
text-align: center;
|
||||
user-select: none;
|
||||
letter-spacing: 0.2px;
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.anomalous-btn-tour {
|
||||
animation: none !important;
|
||||
}
|
||||
.anomalous-update-guide-tour-banner:hover {
|
||||
background: rgba(59, 130, 246, 0.12);
|
||||
border-color: rgba(96, 165, 250, 0.4);
|
||||
color: #93c5fd;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
.anomalous-update-guide-tour-banner:active {
|
||||
transform: translateY(0);
|
||||
background: rgba(59, 130, 246, 0.2);
|
||||
}
|
||||
`;
|
||||
(document.head || document.body)?.appendChild(style);
|
||||
|
||||
@@ -64,25 +64,31 @@ export function showUpdateGuide(owner, { force = false, guide = CURRENT_UPDATE_G
|
||||
title.id = 'anomalous-update-guide-title';
|
||||
const body = text(dialog, 'p', '');
|
||||
body.id = 'anomalous-update-guide-body';
|
||||
const tourBanner = text(dialog, 'button', t('updateGuideTourBanner') || '💡 想在主界面实地体验?点击开启按键遮罩导览 ›', 'anomalous-update-guide-tour-banner');
|
||||
tourBanner.type = 'button';
|
||||
tourBanner.id = 'anomalous-update-guide-tour-btn';
|
||||
tourBanner.onclick = () => {
|
||||
closeUpdateGuide(owner, true);
|
||||
startSpotlightTour(owner);
|
||||
};
|
||||
const progress = text(dialog, 'p', '', 'anomalous-update-guide-progress');
|
||||
progress.setAttribute('aria-live', 'polite');
|
||||
const footer = text(dialog, 'div', '', 'anomalous-update-guide-footer');
|
||||
const skip = text(footer, 'button', t('updateGuideSkip'), 'anomalous-btn-ghost');
|
||||
const startTour = text(footer, 'button', t('updateGuideStartTour') || '🎯 界面按键遮罩导览', 'anomalous-btn-tour');
|
||||
startTour.id = 'anomalous-update-guide-tour-btn';
|
||||
startTour.onclick = () => {
|
||||
closeUpdateGuide(owner, true);
|
||||
startSpotlightTour(owner);
|
||||
};
|
||||
const back = text(footer, 'button', t('updateGuideBack'), 'anomalous-btn-ghost');
|
||||
const next = text(footer, 'button', '', 'anomalous-btn-primary');
|
||||
for (const button of [skip, startTour, back, next]) button.type = 'button';
|
||||
const navGroup = text(footer, 'div', '', 'anomalous-update-guide-nav-group');
|
||||
navGroup.style.display = 'flex';
|
||||
navGroup.style.gap = '8px';
|
||||
navGroup.style.alignItems = 'center';
|
||||
const back = text(navGroup, 'button', t('updateGuideBack'), 'anomalous-btn-ghost');
|
||||
const next = text(navGroup, 'button', '', 'anomalous-btn-primary');
|
||||
for (const button of [skip, back, next, tourBanner]) button.type = 'button';
|
||||
let index = 0;
|
||||
const render = () => {
|
||||
const step = guide.steps[index];
|
||||
icon.textContent = step.icon;
|
||||
title.textContent = t(step.titleKey);
|
||||
body.textContent = t(step.bodyKey);
|
||||
tourBanner.textContent = t('updateGuideTourBanner') || '💡 想在主界面实地体验?点击开启按键遮罩导览 ›';
|
||||
progress.textContent = t('updateGuideProgress', { current: index + 1, total: guide.steps.length });
|
||||
back.disabled = index === 0;
|
||||
next.textContent = t(index === guide.steps.length - 1 ? 'updateGuideDone' : 'updateGuideNext');
|
||||
|
||||
Reference in New Issue
Block a user