diff --git a/public/images/cover/maya-home.webp b/public/images/cover/maya-home.webp
new file mode 100644
index 00000000..0b5e8642
Binary files /dev/null and b/public/images/cover/maya-home.webp differ
diff --git a/src/app/splash/components/__tests__/tailwind-components.test.tsx b/src/app/splash/components/__tests__/tailwind-components.test.tsx
index 19c3e6fb..0630d2ca 100644
--- a/src/app/splash/components/__tests__/tailwind-components.test.tsx
+++ b/src/app/splash/components/__tests__/tailwind-components.test.tsx
@@ -12,7 +12,7 @@ describe("splash Tailwind components", () => {
expect(html).toContain("z-2");
expect(html).toContain("inline-flex");
- expect(html).toContain("block h-auto w-auto");
+ expect(html).toContain("block h-auto w-[clamp(136px,38vw,158px)]");
expect(html).toContain("%2Fimages%2Fsplash%2Fic-logo-home.png");
});
@@ -30,10 +30,9 @@ describe("splash Tailwind components", () => {
it("renders SplashContent with Tailwind typography classes", () => {
const html = renderToStaticMarkup();
- expect(html).toContain("flex flex-col gap-md");
+ expect(html).toContain("Welcome to Maya's private world.");
+ expect(html).toContain("Just you and me.");
expect(html).toContain("font-(family-name:--font-athelas)");
- expect(html).toContain("whitespace-pre-line");
- expect(html).toContain("Welcome to Maya");
});
it("renders SplashButton as an always-ready action", () => {
diff --git a/src/app/splash/components/splash-background.tsx b/src/app/splash/components/splash-background.tsx
index 698ddb82..f8c84343 100644
--- a/src/app/splash/components/splash-background.tsx
+++ b/src/app/splash/components/splash-background.tsx
@@ -12,8 +12,10 @@ import Image from "next/image";
export function SplashBackground({
src,
+ objectPosition,
}: {
src: string;
+ objectPosition?: string;
}) {
return (
@@ -24,6 +26,7 @@ export function SplashBackground({
priority
sizes="(max-width: 540px) 100vw, 540px"
className="object-cover object-center"
+ style={{ objectPosition }}
/>
);
diff --git a/src/app/splash/components/splash-content.tsx b/src/app/splash/components/splash-content.tsx
index c83b1d40..f2a15e07 100644
--- a/src/app/splash/components/splash-content.tsx
+++ b/src/app/splash/components/splash-content.tsx
@@ -2,17 +2,15 @@
* Splash 主内容文案
*/
-const APOSTROPHE = "'";
-
export function SplashContent({ characterName }: { characterName: string }) {
return (
-
-
- Welcome to {characterName}{APOSTROPHE}s secret hideout~
- {"\n"}It{APOSTROPHE}s just the two of us now.
- {"\n"}Feel free to whisper your
- {"\n"}little secrets.
+
+
+ Welcome to {characterName}'s private world.
+
+ Just you and me.
+
);
}
diff --git a/src/app/splash/components/splash-latest-message.module.css b/src/app/splash/components/splash-latest-message.module.css
index 16ef8947..09f4ba18 100644
--- a/src/app/splash/components/splash-latest-message.module.css
+++ b/src/app/splash/components/splash-latest-message.module.css
@@ -1,16 +1,15 @@
.card {
display: grid;
+ box-sizing: border-box;
width: 100%;
+ height: 80px;
grid-template-columns: auto 1fr;
align-items: center;
- gap: 12px;
- margin-top: var(--page-section-gap-lg, 26px);
- padding: 12px 14px;
- border: 1px solid rgba(255, 255, 255, 0.22);
- border-radius: 24px;
- background:
- linear-gradient(135deg, rgba(255, 255, 255, 0.24), rgba(255, 255, 255, 0.1)),
- rgba(28, 19, 30, 0.18);
+ gap: 10px;
+ padding: 9px 11px;
+ border: 1px solid rgba(255, 255, 255, 0.28);
+ border-radius: 16px;
+ background: rgba(31, 22, 29, 0.48);
color: #ffffff;
cursor: pointer;
font: inherit;
@@ -19,8 +18,8 @@
touch-action: manipulation;
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.18),
- 0 18px 42px rgba(46, 22, 38, 0.18);
- backdrop-filter: blur(18px);
+ 0 12px 30px rgba(31, 17, 27, 0.2);
+ backdrop-filter: blur(14px);
animation: messageFloatIn 0.5s ease 0.08s backwards;
transition:
border-color 0.18s ease,
@@ -53,8 +52,8 @@
.avatarWrap {
display: grid;
- width: 48px;
- height: 48px;
+ width: 40px;
+ height: 40px;
place-items: center;
border: 2px solid rgba(255, 255, 255, 0.74);
border-radius: 9999px;
@@ -92,10 +91,15 @@
}
.message {
+ display: -webkit-box;
+ min-height: 2.6em;
+ overflow: hidden;
color: #ffffff;
- font-size: clamp(14px, 3.333vw, 17px);
- font-weight: 760;
- line-height: 1.35;
+ font-size: clamp(13px, 3.45vw, 16px);
+ font-weight: 720;
+ line-height: 1.3;
+ -webkit-box-orient: vertical;
+ -webkit-line-clamp: 2;
}
.messageLoading {
diff --git a/src/app/splash/components/splash-logo.tsx b/src/app/splash/components/splash-logo.tsx
index 1db104e4..df0c8305 100644
--- a/src/app/splash/components/splash-logo.tsx
+++ b/src/app/splash/components/splash-logo.tsx
@@ -9,7 +9,7 @@ export function SplashLogo() {
width={180}
height={60}
priority
- className="block h-auto w-auto"
+ className="block h-auto w-[clamp(136px,38vw,158px)]"
/>
);
diff --git a/src/app/splash/components/splash-screen.module.css b/src/app/splash/components/splash-screen.module.css
index 0b3aad53..c5fcfed1 100644
--- a/src/app/splash/components/splash-screen.module.css
+++ b/src/app/splash/components/splash-screen.module.css
@@ -8,16 +8,13 @@
overflow: hidden;
}
-/* 渐变:accent (bottom-left) → transparent (center-right) */
-.gradientOverlay {
+.imageScrim {
position: absolute;
inset: 0;
- background: linear-gradient(
- to top right,
- var(--color-accent),
- transparent 60%
- );
- opacity: 0.5;
+ background: rgba(25, 17, 23, 0.08);
+ box-shadow:
+ inset 0 -290px 150px -145px rgba(20, 12, 18, 0.78),
+ inset 0 110px 90px -90px rgba(11, 8, 10, 0.42);
z-index: 1;
pointer-events: none;
}
@@ -49,15 +46,9 @@
flex: 1 1 auto;
}
-.buttonArea {
- margin-top: var(--page-section-gap-lg, 26px);
-}
-
-.bottom {
- margin: var(--page-section-gap-lg, 32px) 0 0 0;
- font-size: var(--responsive-body, var(--font-size-md));
- font-weight: 400;
- line-height: 1.5;
- color: rgba(255, 255, 255, 0.9);
- text-align: left;
+.bottomStack {
+ display: flex;
+ flex-direction: column;
+ gap: clamp(12px, 3.6vw, 18px);
+ padding-bottom: clamp(12px, 3.6vw, 18px);
}
diff --git a/src/app/splash/splash-screen.tsx b/src/app/splash/splash-screen.tsx
index f1c69bad..e0553e8a 100644
--- a/src/app/splash/splash-screen.tsx
+++ b/src/app/splash/splash-screen.tsx
@@ -62,12 +62,17 @@ export function SplashScreen() {
pwaUtil.prepareInstallPrompt();
}, []);
+ const hasLatestMessage =
+ latestMessage.isLoading || Boolean(latestMessage.message);
+
return (
-
- {/* 渐变叠加层:accent → transparent (bottom-left → center-right) */}
-
+
+
-
-
-
+
+ {hasLatestMessage ? (
+
+ ) : null}
+
-
- {character.displayName}, {character.tagline}
-
- 24/7 online | Chat | Companion | Heal | Sweet moments
-
{
it("resolves characters by id and normalized slug", () => {
expect(getCharacterById("maya-tan")?.displayName).toBe("Maya Tan");
+ expect(getCharacterById("maya-tan")?.assets.splashCover).toBe(
+ "/images/cover/maya-home.webp",
+ );
expect(getCharacterBySlug(" NAYELI ")?.displayName).toBe(
"Nayeli Cervantes",
);
diff --git a/src/data/constants/character.ts b/src/data/constants/character.ts
index 1d33b46c..b94264fc 100644
--- a/src/data/constants/character.ts
+++ b/src/data/constants/character.ts
@@ -16,6 +16,7 @@ export interface CharacterProfile {
readonly assets: {
readonly avatar: string;
readonly cover: string;
+ readonly splashCover?: string;
readonly chatBackground: string;
readonly privateZoneBanner: string;
};
@@ -97,6 +98,7 @@ const CHARACTER_PROFILES: readonly CharacterProfile[] = Object.freeze([
assets: {
avatar: "/images/avatar/maya.png",
cover: "/images/cover/maya.webp",
+ splashCover: "/images/cover/maya-home.webp",
chatBackground: "/images/chat/bg-chatpage.png",
privateZoneBanner: "/images/private-zone/banner/maya.png",
},