Browse Source

fix: 暂存(切换master)

pull/18/head
leiyuee 2 weeks ago
parent
commit
ac3eea6c98
  1. 8
      src/dialog/app-download-mac/index.tsx
  2. 102
      src/layouts/Layout/Layout.scss
  3. 47
      src/layouts/Layout/Layout.tsx
  4. 29
      src/layouts/globalPromptPanel/globalPromptPanel.scss
  5. 5
      src/layouts/globalPromptPanel/globalPromptPanel.tsx
  6. 1
      src/layouts/globalPromptPanel/utils.ts
  7. 5
      src/locales/en-US.json
  8. 5
      src/locales/zh-CN.json
  9. 5
      src/locales/zh-TW.json
  10. 7
      src/pages/CharactersCreate/index.scss
  11. 10
      src/pages/Create/index.scss
  12. 2
      src/pages/Explore/ExploreTemplateFeed/ExploreTemplateFeed.tsx
  13. 6
      src/pages/Profile/index.scss
  14. 8
      src/pages/Voice/index.scss
  15. 3
      src/pages/subscribe/index.scss
  16. 11
      src/store/index.ts

8
src/dialog/app-download-mac/index.tsx

@ -1,4 +1,5 @@
import { Message } from "@arco-design/web-react";
import { createPortal } from "react-dom";
import { useTranslation } from "react-i18next";
import "./index.scss";
@ -86,11 +87,14 @@ export default function AppMacDownloadDialog({
}
export function AppMacDownloadDialogOverlay({ macIntelUrl, macArmUrl, windowsUrl, onClose }: AppMacDownloadDialogProps) {
return (
if (typeof document === "undefined") return null;
return createPortal(
<div className="appDownloadDialogOverlay" role="presentation" onClick={() => onClose?.()}>
<div className="appDownloadDialogOverlay__panel" role="none" onClick={(event) => event.stopPropagation()}>
<AppMacDownloadDialog macIntelUrl={macIntelUrl} macArmUrl={macArmUrl} windowsUrl={windowsUrl} onClose={onClose} />
</div>
</div>
</div>,
document.body,
);
}

102
src/layouts/Layout/Layout.scss

@ -146,79 +146,6 @@
}
}
.layoutShell__sidebarCollapse {
position: absolute;
top: calc(var(--layout-promo-height) + 27px);
left: max(16px, calc(var(--layout-sidebar-width) - 18px));
z-index: 45;
width: 36px;
height: 36px;
padding: 10px;
border: 0;
border-radius: 24px;
background: #ffffff;
color: #333333;
cursor: pointer;
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 3px;
transition:
top var(--layout-sidebar-transition),
left var(--layout-sidebar-transition),
width var(--layout-sidebar-transition),
height var(--layout-sidebar-transition),
padding var(--layout-sidebar-transition),
transform var(--layout-sidebar-transition),
box-shadow var(--layout-sidebar-transition);
.layoutShell__sidebarCollapseText {
max-height: 0;
opacity: 0;
overflow: hidden;
color: #333333;
font-size: 14px;
font-weight: 400;
line-height: 20px;
text-align: center;
white-space: pre-line;
transition:
max-height var(--layout-sidebar-transition),
opacity 0.14s ease;
}
img {
width: 16px;
height: 16px;
display: block;
object-fit: contain;
transition: transform var(--layout-sidebar-transition);
}
}
&.layoutShell_sidebarCollapsed .layoutShell__sidebarCollapse {
top: calc(var(--layout-promo-height) + ((100vh - var(--layout-promo-height)) / 2));
left: 0;
width: 36px;
height: 91px;
padding: 16px 10px;
transform: translateY(-50%);
.layoutShell__sidebarCollapseText {
max-height: 40px;
opacity: 1;
transition:
max-height var(--layout-sidebar-transition),
opacity 0.16s ease 0.1s;
}
}
&.layoutShell_sidebarCollapsed .layoutShell__sidebarCollapse img {
transform: rotate(-180deg);
}
.layoutShell__topbar {
position: absolute;
top: var(--layout-promo-height);
@ -649,10 +576,6 @@
background: #ffffff;
}
&.layoutShell_sidebarCollapsed .layoutShell__body {
background: #f2f2f2;
}
.layoutShell__sidebar {
position: absolute;
top: 0;
@ -665,15 +588,7 @@
box-sizing: border-box;
display: flex;
flex-direction: column;
transition:
opacity var(--layout-sidebar-transition),
transform var(--layout-sidebar-transition);
}
&.layoutShell_sidebarCollapsed .layoutShell__sidebar {
transform: translateX(-110px);
opacity: 0;
pointer-events: none;
transition: transform var(--layout-sidebar-transition);
}
.layoutShell__sidebar_footerPopoverOpen {
@ -911,6 +826,7 @@
overflow: auto;
scrollbar-width: none;
-ms-overflow-style: none;
padding-left: 30px;
>.createPage {
height: 100%;
@ -1082,20 +998,6 @@
padding: 14px 8px;
}
&.layoutShell_sidebarCollapsed .layoutShell__sidebar {
transform: translateX(-76px);
}
.layoutShell__sidebarCollapse {
top: 17px;
left: max(10px, calc(var(--layout-sidebar-width) - 18px));
}
&.layoutShell_sidebarCollapsed .layoutShell__sidebarCollapse {
top: calc(var(--layout-promo-height) + ((100vh - var(--layout-promo-height)) / 2));
left: 0;
}
.layoutShell__brand,
.layoutShell__sideNav,
.layoutShell__footer,

47
src/layouts/Layout/Layout.tsx

@ -43,7 +43,6 @@ interface LayoutSideNavIconProps {
const LAYOUT_NAV_ASSETS = {
logo: new URL("@/assets/images/layout/nav/popi-logo.png", import.meta.url).href,
collapse: new URL("@/assets/images/layout/nav/collapse.png", import.meta.url).href,
explore: new URL("@/assets/images/layout/nav/explore.png", import.meta.url).href,
exploreActive: new URL("@/assets/images/layout/nav/explore_active.png", import.meta.url).href,
characters: new URL("@/assets/images/layout/nav/characters.png", import.meta.url).href,
@ -81,6 +80,13 @@ const LAYOUT_SIDE_NAV_ITEMS: readonly LayoutSideNavItem[] = [
activeIconSrc: LAYOUT_NAV_ASSETS.charactersActive,
to: ROUTES.CHARACTERS,
},
{
id: "voice",
labelKey: "layout.nav.voice",
iconSrc: LAYOUT_NAV_ASSETS.voice,
activeIconSrc: LAYOUT_NAV_ASSETS.voiceActive,
to: ROUTES.VOICE,
},
{
id: "create",
labelKey: "layout.nav.create",
@ -96,13 +102,6 @@ const LAYOUT_SIDE_NAV_ITEMS: readonly LayoutSideNavItem[] = [
to: CANVAS_BASE_URL ?? "",
badgeKey: "layout.nav.canvasBadge",
},
{
id: "voice",
labelKey: "layout.nav.voice",
iconSrc: LAYOUT_NAV_ASSETS.voice,
activeIconSrc: LAYOUT_NAV_ASSETS.voiceActive,
to: ROUTES.VOICE,
},
];
const LANGUAGE_LABEL_KEYS: Record<AppLanguage, string> = {
@ -188,7 +187,6 @@ export function Layout({ children }: LayoutProps) {
const [languageMenuOpen, setLanguageMenuOpen] = useState(false);
const [footerPopoverOpen, setFooterPopoverOpen] = useState(false);
const [topbarServiceQrOpen, setTopbarServiceQrOpen] = useState(false);
const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
const [promoBarVisible, setPromoBarVisible] = useState(() => !isLayoutPromoBarDismissed());
const activePromptPanelHost = useComposerStore((s) => s.activePromptPanelHost);
@ -204,7 +202,6 @@ export function Layout({ children }: LayoutProps) {
const requestComposerCollapse = useComposerStore((s) => s.requestComposerCollapse);
const requestComposerExpand = useComposerStore((s) => s.requestComposerExpand);
const prevPathnameRef = useRef(pathname);
const prevPathnameForCharactersCreateRef = useRef(pathname);
useEffect(() => {
if (!getToken()) {
@ -254,11 +251,8 @@ export function Layout({ children }: LayoutProps) {
}
};
/** 角色创建页:侧栏固定收起且不可展开 */
const isCharactersCreateRoute = pathname === ROUTES.CHARACTERS_CREATE;
const isVoiceArea = pathname === ROUTES.VOICE || pathname.startsWith(`${ROUTES.VOICE_MUSIC_SHARE}/`);
const shouldShowFloatingComposer = pathname !== ROUTES.SUBSCRIBE && pathname !== ROUTES.CHARACTERS_CREATE && !isVoiceArea;
const effectiveSidebarCollapsed = isCharactersCreateRoute || sidebarCollapsed;
const handlePromoBarClose = useCallback((evt: ReactMouseEvent<HTMLButtonElement>) => {
evt.stopPropagation();
@ -294,14 +288,6 @@ export function Layout({ children }: LayoutProps) {
window.scrollTo(0, 0);
}, [pathname]);
useEffect(() => {
const prev = prevPathnameForCharactersCreateRef.current;
if (prev === ROUTES.CHARACTERS_CREATE && pathname !== ROUTES.CHARACTERS_CREATE) {
setSidebarCollapsed(false);
}
prevPathnameForCharactersCreateRef.current = pathname;
}, [pathname]);
useEffect(() => {
if (prevPathnameRef.current === pathname) return;
prevPathnameRef.current = pathname;
@ -420,7 +406,7 @@ export function Layout({ children }: LayoutProps) {
<div className="layoutShellViewport" ref={layoutViewportRef}>
<div className="layoutShellScaleSpacer" ref={scaleSpacerRef}>
<div className="layoutShellScaleInner" ref={scaleInnerRef}>
<div className={classNames("layoutShell", effectiveSidebarCollapsed ? "layoutShell_sidebarCollapsed" : "", !promoBarVisible ? "layoutShell_promoDismissed" : "")}>
<div className={["layoutShell", !promoBarVisible ? "layoutShell_promoDismissed" : ""].filter(Boolean).join(" ")}>
{promoBarVisible ? (
<div className="layoutShell__promoBar" role="banner" aria-label={t("layout.promo.aria")} onClick={() => navigate(ROUTES.SUBSCRIBE)}>
<div className="layoutShell__promoBarInner">
@ -453,19 +439,6 @@ export function Layout({ children }: LayoutProps) {
</button>
</div>
) : null}
<button
type="button"
className="layoutShell__sidebarCollapse"
aria-disabled={isCharactersCreateRoute}
onClick={() => {
if (!isCharactersCreateRoute) setSidebarCollapsed((v) => !v);
}}
aria-label={effectiveSidebarCollapsed ? t("layout.sidebar.expand") : t("layout.sidebar.collapse")}
aria-expanded={!effectiveSidebarCollapsed}
>
<span className="layoutShell__sidebarCollapseText">{t("layout.sidebar.menuLabel")}</span>
<img src={LAYOUT_NAV_ASSETS.collapse} alt="" />
</button>
<header className="layoutShell__topbar" aria-label={t("layout.aria.topbar")} onClick={dismissMainDetailModals}>
<div className="layoutShell__topbarRight" aria-label={t("layout.aria.userArea")}>
<div className="layoutShell__topbarTools">
@ -688,7 +661,7 @@ export function Layout({ children }: LayoutProps) {
const isActive = pathname === item.to || (item.to !== "/" && pathname.startsWith(`${item.to}/`));
const className = ["layoutShell__sideItem", isActive ? "layoutShell__sideItem_active" : ""].filter(Boolean).join(" ");
return (
<Link key={item.id} to={item.to} className={className} title={effectiveSidebarCollapsed ? t(item.labelKey) : undefined} onClick={(evt) => handleLayoutNavClick(evt, item.to)}>
<Link key={item.id} to={item.to} className={className} onClick={(evt) => handleLayoutNavClick(evt, item.to)}>
<LayoutSideNavIcon item={item} />
<span className="layoutShell__sideText">{t(item.labelKey)}</span>
{item.badgeKey ? <span className="layoutShell__sideBadge">{t(item.badgeKey)}</span> : null}
@ -702,7 +675,7 @@ export function Layout({ children }: LayoutProps) {
const isActive = pathname === item.to || (item.to !== "/" && pathname.startsWith(`${item.to}/`));
const className = ["layoutShell__sideItem", isActive ? "layoutShell__sideItem_active" : ""].filter(Boolean).join(" ");
return (
<Link key={item.id} to={item.to} className={className} title={effectiveSidebarCollapsed ? t(item.labelKey) : undefined} onClick={(evt) => handleLayoutNavClick(evt, item.to)}>
<Link key={item.id} to={item.to} className={className} onClick={(evt) => handleLayoutNavClick(evt, item.to)}>
<LayoutSideNavIcon item={item} />
<span className="layoutShell__sideText">{t(item.labelKey)}</span>
</Link>

29
src/layouts/globalPromptPanel/globalPromptPanel.scss

@ -675,6 +675,10 @@
background: #ffffff;
box-shadow: 0 2px 15px 0 rgba(51, 51, 51, 0.2);
box-sizing: border-box;
max-height: min(620px, calc(100vh - 120px));
display: flex;
flex-direction: column;
overflow: hidden;
.layoutShell__composerModelDropdownTitle {
margin: 0;
@ -689,6 +693,11 @@
display: flex;
flex-direction: column;
gap: 0;
min-height: 0;
overflow-x: hidden;
overflow-y: auto;
overscroll-behavior: contain;
scrollbar-width: thin;
.layoutShell__composerModelDropdownItem {
width: 100%;
@ -894,6 +903,10 @@
background: #ffffff;
box-shadow: 0 2px 15px 0 rgba(51, 51, 51, 0.2);
box-sizing: border-box;
max-height: min(620px, calc(100vh - 120px));
display: flex;
flex-direction: column;
overflow: hidden;
.layoutShell__composerModelDropdownTitle {
margin: 0;
@ -908,6 +921,11 @@
display: flex;
flex-direction: column;
gap: 0;
min-height: 0;
overflow-x: hidden;
overflow-y: auto;
overscroll-behavior: contain;
scrollbar-width: thin;
}
.layoutShell__composerModelDropdownItem {
@ -971,6 +989,10 @@
background: #ffffff;
box-shadow: 0 2px 15px 0 rgba(51, 51, 51, 0.2);
box-sizing: border-box;
max-height: min(620px, calc(100vh - 120px));
display: flex;
flex-direction: column;
overflow: hidden;
.layoutShell__composerModelDropdownTitle {
margin: 0;
@ -985,6 +1007,11 @@
display: flex;
flex-direction: column;
gap: 0;
min-height: 0;
overflow-x: hidden;
overflow-y: auto;
overscroll-behavior: contain;
scrollbar-width: thin;
}
.layoutShell__composerModelDropdownItem {
@ -1268,4 +1295,4 @@
display: block;
flex-shrink: 0;
}
}
}

5
src/layouts/globalPromptPanel/globalPromptPanel.tsx

@ -115,6 +115,7 @@ type AiCategoryItem = {
taskSubType: number;
name?: string;
icon?: string;
activeIcon?: string;
id?: number | string;
};
@ -834,6 +835,7 @@ export function GlobalPromptPanel({ mode = "floating", embeddedVisible = false,
taskSubType: subTypeNum,
name: typeof row.name === "string" ? row.name : undefined,
icon: typeof row.icon === "string" ? row.icon : undefined,
activeIcon: typeof row.activeIcon === "string" ? row.activeIcon : undefined,
id: typeof row.id === "number" || typeof row.id === "string" ? row.id : undefined,
};
})
@ -1618,6 +1620,7 @@ export function GlobalPromptPanel({ mode = "floating", embeddedVisible = false,
>
{aiCategories.map((item, idx) => {
const isActive = activeTaskSubType === item.taskSubType;
const tabIcon = isActive ? item.activeIcon || item.icon : item.icon;
return (
<button
key={`${String(item.taskSubType ?? item.id ?? "category")}-${idx}`}
@ -1628,7 +1631,7 @@ export function GlobalPromptPanel({ mode = "floating", embeddedVisible = false,
data-task-sub-type={item.taskSubType}
onClick={() => handleTaskSubTypeChange(item.taskSubType)}
>
{typeof item.icon === "string" && item.icon ? <img src={/^https?:\/\//i.test(item.icon) || item.icon.startsWith("data:") ? item.icon : new URL(item.icon, import.meta.url).href} /> : null}
{typeof tabIcon === "string" && tabIcon ? <img src={tabIcon} /> : null}
<span>{item.taskSubType === 999 ? t("composer.tabs.template") : item.name}</span>
</button>
);

1
src/layouts/globalPromptPanel/utils.ts

@ -35,6 +35,7 @@ export const OTHER_CATEGORY = [
taskSubType: 999,
name: "Template",
icon: new URL("/src/assets/images/AiCategories_template.png", import.meta.url).href,
activeIcon: new URL("/src/assets/images/AiCategories_template.png", import.meta.url).href,
},
];

5
src/locales/en-US.json

@ -12,9 +12,6 @@
"layout.aria.sideNav": "Sidebar navigation",
"layout.aria.content": "Content",
"layout.brand.aria": "Popi home",
"layout.sidebar.expand": "Expand sidebar",
"layout.sidebar.collapse": "Collapse sidebar",
"layout.sidebar.menuLabel": "Menu",
"layout.language.tooltip": "Switch language",
"layout.language.menuAria": "Switch language",
"layout.language.zhCN": "简体中文",
@ -88,7 +85,7 @@
"layout.nav.voice": "Voice",
"layout.nav.points": "Points",
"layout.topbar.skill": "SKILL",
"layout.footer.subscribe": "Subscribe",
"layout.footer.subscribe": "Membership",
"layout.footer.profile": "Profile",
"layout.footer.navAria": "Footer navigation",
"layout.footerPopover.menuAria": "More and legal",

5
src/locales/zh-CN.json

@ -12,9 +12,6 @@
"layout.aria.sideNav": "侧边栏菜单",
"layout.aria.content": "内容区",
"layout.brand.aria": "Popi 首页",
"layout.sidebar.expand": "展开侧边栏",
"layout.sidebar.collapse": "收起侧边栏",
"layout.sidebar.menuLabel": "菜\n单",
"layout.language.tooltip": "切换语言",
"layout.language.menuAria": "切换语言",
"layout.language.zhCN": "简体中文",
@ -88,7 +85,7 @@
"layout.nav.voice": "声音",
"layout.nav.points": "积分",
"layout.topbar.skill": "SKILL",
"layout.footer.subscribe": "订阅",
"layout.footer.subscribe": "会员",
"layout.footer.profile": "个人",
"layout.footer.navAria": "底部导航",
"layout.footerPopover.menuAria": "更多与协议",

5
src/locales/zh-TW.json

@ -12,9 +12,6 @@
"layout.aria.sideNav": "側邊欄選單",
"layout.aria.content": "內容區",
"layout.brand.aria": "Popi 首頁",
"layout.sidebar.expand": "展開側邊欄",
"layout.sidebar.collapse": "收起側邊欄",
"layout.sidebar.menuLabel": "菜\n單",
"layout.language.tooltip": "切換語言",
"layout.language.menuAria": "切換語言",
"layout.language.zhCN": "简体中文",
@ -88,7 +85,7 @@
"layout.nav.voice": "聲音",
"layout.nav.points": "積分",
"layout.topbar.skill": "SKILL",
"layout.footer.subscribe": "訂閱",
"layout.footer.subscribe": "會員",
"layout.footer.profile": "個人",
"layout.footer.navAria": "底部導覽",
"layout.footerPopover.menuAria": "更多與協議",

7
src/pages/CharactersCreate/index.scss

@ -10,7 +10,7 @@ $font: "Source Han Sans CN", "Noto Sans SC", system-ui, sans-serif;
overflow: hidden;
display: flex;
flex-direction: column;
background: #f7f7f7;
// background: #f7f7f7;
*,
*::before,
@ -648,7 +648,7 @@ $font: "Source Han Sans CN", "Noto Sans SC", system-ui, sans-serif;
box-sizing: border-box;
}
.charactersCreate__composerUploadCard > img {
.charactersCreate__composerUploadCard>img {
width: 25px;
height: 25px;
display: block;
@ -1531,6 +1531,7 @@ $font: "Source Han Sans CN", "Noto Sans SC", system-ui, sans-serif;
}
@media (prefers-reduced-motion: reduce) {
.charactersCreate__rightPromptCardMain,
.charactersCreate__rightPromptCardMask {
transition-duration: 0.01ms;
@ -1741,4 +1742,4 @@ $font: "Source Han Sans CN", "Noto Sans SC", system-ui, sans-serif;
.charactersCreate__createGlobal.charactersCreate__createGlobal_active {
cursor: pointer;
opacity: 1;
}
}

10
src/pages/Create/index.scss

@ -9,14 +9,14 @@
overflow: hidden;
display: flex;
flex-direction: column;
background: #f9f9f9;
background: #f2f2f2;
}
.createPage__toolbar {
flex-shrink: 0;
padding: 22px 29px 16px;
box-sizing: border-box;
background: #f9f9f9;
background: #f2f2f2;
}
.createPage__toolbar_primary_only {
@ -106,7 +106,7 @@
flex-wrap: wrap;
gap: 10px 16px;
margin-top: 0;
background: #f9f9f9;
// background: #f9f9f9;
}
.createPage__filters {
@ -137,7 +137,7 @@
}
.createPage__filterPill_active {
background: #f0f0f0;
background: #ffffff;
color: #333333;
}
@ -247,4 +247,4 @@
flex-direction: column;
align-items: stretch;
}
}
}

2
src/pages/Explore/ExploreTemplateFeed/ExploreTemplateFeed.tsx

@ -9,7 +9,7 @@ import { useTranslation } from "react-i18next";
import "./ExploreTemplateFeed.scss";
const FEED_PAGE_SIZE = 50;
const TEMPLATE_LOGO_SRC = new URL("/src/assets/images/layout/nav/popi-logo.png", import.meta.url).href;
const TEMPLATE_LOGO_SRC = new URL("/src/assets/images/popi_avatar.png", import.meta.url).href;
type TemplateListResponse = {
data?: {

6
src/pages/Profile/index.scss

@ -1,7 +1,7 @@
.profilePage {
height: 100%;
padding: 0 0 44px;
background: #f9f9f9;
background: #f2f2f2;
overflow-y: scroll;
scrollbar-width: none;
will-change: transform; // 提示浏览器优化滚动容器
@ -200,7 +200,7 @@
margin-right: 0;
border: 0;
border-radius: 9px;
background: #f9f9f9;
// background: #f9f9f9;
color: #333333;
font-size: 14px;
font-weight: 400;
@ -346,4 +346,4 @@
column-gap: 14px;
}
}
}
}

8
src/pages/Voice/index.scss

@ -9,7 +9,7 @@ $font: "Source Han Sans CN", "Noto Sans SC", system-ui, sans-serif;
display: flex;
flex-direction: column;
// overflow: hidden;
background: #f9f9f9;
background: #f2f2f2;
position: relative;
--voice-player-bar-bottom: calc(20px + 12px);
@ -108,7 +108,7 @@ $font: "Source Han Sans CN", "Noto Sans SC", system-ui, sans-serif;
flex: 1 1 0;
min-width: 0;
min-height: 0;
background: #f9f9f9;
// background: #f9f9f9;
border-radius: 24px;
}
@ -131,7 +131,7 @@ $font: "Source Han Sans CN", "Noto Sans SC", system-ui, sans-serif;
padding: 25px;
border: none;
border-radius: 24px;
background: #f0f0f0;
background: #ffffff;
cursor: pointer;
text-align: left;
}
@ -619,7 +619,7 @@ $font: "Source Han Sans CN", "Noto Sans SC", system-ui, sans-serif;
align-items: center;
gap: 10px;
padding-top: 4px;
background: #f9f9f9;
// background: #f9f9f9;
.layoutShell__composerModelDropdownTrigger {
display: inline-flex;

3
src/pages/subscribe/index.scss

@ -1,4 +1,7 @@
.subscribe-page {
min-height: 100%;
background: #f2f2f2;
.subscribe-overview {
width: min(100%, 100%);
margin: 13px auto 0;

11
src/store/index.ts

@ -1,12 +1,5 @@
import { create } from "zustand";
interface AppState {
/** 示例:侧栏折叠 */
sidebarCollapsed: boolean;
setSidebarCollapsed: (v: boolean) => void;
}
type AppState = Record<string, never>;
export const useAppStore = create<AppState>((set) => ({
sidebarCollapsed: false,
setSidebarCollapsed: (v) => set({ sidebarCollapsed: v }),
}));
export const useAppStore = create<AppState>(() => ({}));

Loading…
Cancel
Save