Polish mobile homepage experience
This commit is contained in:
parent
a41b45e1f9
commit
8e207a0e83
@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, type ReactNode } from "react";
|
||||
import { useEffect, useState, type CSSProperties, type ReactNode } from "react";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { ThemeProvider } from "../components/theme";
|
||||
import { LanguageProvider } from "../i18n/LanguageProvider";
|
||||
@ -20,18 +20,42 @@ export function AppProviders({
|
||||
const { isOpen, isMinimized, close, toggleOpen } = useMoltbotStore();
|
||||
const applyDefaults = useOpenClawConsoleStore((state) => state.applyDefaults);
|
||||
const pathname = usePathname();
|
||||
const [isMobileViewport, setIsMobileViewport] = useState(false);
|
||||
const isOpenClawWorkspace =
|
||||
pathname.startsWith("/xworkmate") ||
|
||||
pathname.startsWith("/services/openclaw");
|
||||
|
||||
// Always reserve space if open and not minimized, since we only have "Float/Sidebar" mode now
|
||||
// and user wants it to NEVER cover the homepage.
|
||||
const reserveSpace = !isOpenClawWorkspace && isOpen && !isMinimized;
|
||||
const reserveSpace =
|
||||
!isOpenClawWorkspace && isOpen && !isMinimized && !isMobileViewport;
|
||||
|
||||
useEffect(() => {
|
||||
applyDefaults(assistantDefaults);
|
||||
}, [applyDefaults, assistantDefaults]);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof window === "undefined") {
|
||||
return;
|
||||
}
|
||||
|
||||
const mediaQuery = window.matchMedia("(max-width: 1023px)");
|
||||
const syncViewport = () => {
|
||||
setIsMobileViewport(mediaQuery.matches);
|
||||
};
|
||||
|
||||
syncViewport();
|
||||
mediaQuery.addEventListener("change", syncViewport);
|
||||
|
||||
return () => {
|
||||
mediaQuery.removeEventListener("change", syncViewport);
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isMobileViewport && !isOpenClawWorkspace) {
|
||||
close();
|
||||
}
|
||||
}, [close, isMobileViewport, isOpenClawWorkspace]);
|
||||
|
||||
return (
|
||||
<ThemeProvider>
|
||||
<LanguageProvider>
|
||||
@ -40,7 +64,7 @@ export function AppProviders({
|
||||
style={
|
||||
{
|
||||
"--assistant-reserve-offset": reserveSpace ? "400px" : "0px",
|
||||
} as React.CSSProperties
|
||||
} as CSSProperties
|
||||
}
|
||||
className={cn(
|
||||
"flex-1 flex flex-col relative w-full overflow-hidden transition-[padding] duration-300 ease-in-out",
|
||||
|
||||
@ -77,12 +77,12 @@ export default function HomePage() {
|
||||
)}
|
||||
>
|
||||
<div className="flex-1 overflow-y-auto relative">
|
||||
<div className="relative mx-auto max-w-6xl px-6 pb-20">
|
||||
<div className="relative mx-auto max-w-6xl px-4 pb-16 sm:px-6 sm:pb-20">
|
||||
<div
|
||||
className="absolute inset-0 bg-gradient-app-from opacity-20 pointer-events-none"
|
||||
className="pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_top_left,rgba(37,78,219,0.08),transparent_28%),radial-gradient(circle_at_bottom_right,rgba(15,23,42,0.05),transparent_32%),linear-gradient(180deg,rgba(255,255,255,0.82),transparent_58%)]"
|
||||
aria-hidden
|
||||
/>
|
||||
<main className="relative space-y-12 pt-10">
|
||||
<main className="relative space-y-8 pt-6 sm:space-y-12 sm:pt-10">
|
||||
<HeroSection />
|
||||
<NextStepsSection />
|
||||
<StatsSection />
|
||||
@ -104,43 +104,45 @@ export function HeroSection() {
|
||||
const t = translations[language].marketing.home;
|
||||
|
||||
return (
|
||||
<section className="grid gap-12 lg:grid-cols-[0.9fr_1.1fr]">
|
||||
<div className="flex flex-col justify-center space-y-8">
|
||||
<div className="space-y-4">
|
||||
<section className="grid gap-8 lg:grid-cols-[0.9fr_1.1fr] lg:gap-12">
|
||||
<div className="flex flex-col justify-center space-y-6 sm:space-y-8">
|
||||
<div className="space-y-3 sm:space-y-4">
|
||||
{t.hero.eyebrow && (
|
||||
<p className="font-semibold uppercase tracking-wider text-text-subtle">
|
||||
<p className="font-semibold uppercase tracking-[0.28em] text-text-subtle">
|
||||
{t.hero.eyebrow}
|
||||
</p>
|
||||
)}
|
||||
<h1 className="text-xl font-bold tracking-tight text-heading sm:text-3xl">
|
||||
<h1 className="max-w-[12ch] text-[2.22rem] font-semibold leading-[0.92] tracking-[-0.075em] text-heading sm:max-w-none sm:text-3xl lg:text-[3.35rem]">
|
||||
{t.hero.title}
|
||||
</h1>
|
||||
<p className="text-base text-text-muted">{t.hero.subtitle}</p>
|
||||
<p className="max-w-xl text-[1.02rem] leading-7 text-text-muted">
|
||||
{t.hero.subtitle}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-3">
|
||||
<div className="grid gap-2 sm:flex sm:flex-wrap sm:items-center sm:gap-3">
|
||||
{user ? (
|
||||
<div className="flex items-center gap-2 rounded-full border border-success/30 bg-success/10 px-4 py-1.5 text-sm font-medium text-success">
|
||||
<div className="flex items-center justify-center gap-2 rounded-full border border-success/30 bg-success/10 px-4 py-2 text-sm font-medium text-success sm:justify-start sm:py-1.5">
|
||||
<div className="h-2 w-2 rounded-full bg-success animate-pulse" />
|
||||
{t.signedIn.replace("{{username}}", user.username)}
|
||||
</div>
|
||||
) : (
|
||||
<button className="flex items-center gap-2 rounded-full bg-primary px-6 py-2.5 text-sm font-semibold text-white transition hover:bg-primary-hover">
|
||||
<button className="flex items-center justify-center gap-2 rounded-full bg-primary px-6 py-3 text-sm font-semibold text-white transition hover:bg-primary-hover sm:py-2.5">
|
||||
<PlusCircle className="h-4 w-4" />
|
||||
{t.heroButtons.create}
|
||||
</button>
|
||||
)}
|
||||
<button className="flex items-center gap-2 rounded-full border border-surface-border bg-surface px-6 py-2.5 text-sm font-semibold text-text transition hover:bg-surface-hover">
|
||||
<button className="flex items-center justify-center gap-2 rounded-full border border-surface-border bg-surface/90 px-6 py-3 text-sm font-semibold text-text transition hover:bg-surface-hover sm:py-2.5">
|
||||
<Play className="h-4 w-4" />
|
||||
{t.heroButtons.playground}
|
||||
</button>
|
||||
<button className="flex items-center gap-2 rounded-full border border-surface-border bg-surface px-6 py-2.5 text-sm font-semibold text-text transition hover:bg-surface-hover">
|
||||
<button className="flex items-center justify-center gap-2 rounded-full border border-surface-border bg-surface/90 px-6 py-3 text-sm font-semibold text-text transition hover:bg-surface-hover sm:py-2.5">
|
||||
<BookOpen className="h-4 w-4" />
|
||||
{t.heroButtons.tutorials}
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex flex-col gap-3 text-sm">
|
||||
<p className="text-text-muted">{t.trustedBy}</p>
|
||||
<div className="flex gap-2 flex-wrap">
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<LogoPill label="Next.js" />
|
||||
<LogoPill label="Go" />
|
||||
<LogoPill label="Vercel" />
|
||||
@ -149,8 +151,8 @@ export function HeroSection() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-col gap-4 relative">
|
||||
<div className="flex flex-col gap-3 sm:gap-4">
|
||||
<div className="relative flex flex-col gap-3 sm:gap-4">
|
||||
{t.heroCards.map((card) => {
|
||||
const Icon = getIcon(card.title, PlusCircle);
|
||||
return (
|
||||
@ -174,12 +176,12 @@ export function NextStepsSection() {
|
||||
const t = translations[language].marketing.home;
|
||||
|
||||
return (
|
||||
<section className="space-y-4">
|
||||
<header className="flex items-center gap-3 text-sm text-text-muted">
|
||||
<p className="text-xs font-semibold uppercase tracking-[0.2em] text-text-subtle">
|
||||
<section className="space-y-4 rounded-[1.75rem] border border-surface-border/70 bg-white/70 p-5 shadow-[0_16px_45px_rgba(15,23,42,0.05)] lg:rounded-none lg:border-transparent lg:bg-transparent lg:p-0 lg:shadow-none">
|
||||
<header className="flex flex-col gap-2 text-sm text-text-muted sm:flex-row sm:items-center sm:gap-3">
|
||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-text-subtle">
|
||||
{t.nextSteps.title}
|
||||
</p>
|
||||
<span className="rounded-full bg-surface-muted px-3 py-1 text-xs font-semibold text-primary">
|
||||
<span className="w-fit rounded-full bg-surface-muted px-3 py-1 text-xs font-semibold text-primary">
|
||||
{t.nextSteps.badge}
|
||||
</span>
|
||||
</header>
|
||||
@ -189,9 +191,9 @@ export function NextStepsSection() {
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className="flex items-start gap-3 rounded-xl border border-surface-border bg-surface p-4 shadow-lg shadow-shadow-sm"
|
||||
className="flex items-start gap-3 rounded-[1.4rem] border border-surface-border bg-surface/92 p-4 shadow-lg shadow-shadow-sm"
|
||||
>
|
||||
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-primary/15 text-primary">
|
||||
<div className="flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-primary/12 text-primary">
|
||||
<Icon className="h-5 w-5" aria-hidden />
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
@ -284,14 +286,19 @@ export function StatsSection() {
|
||||
];
|
||||
|
||||
return (
|
||||
<section className="rounded-2xl border border-surface-border bg-gradient-to-r from-surface-muted via-surface/0 to-surface-muted p-6 shadow-inner shadow-shadow-sm">
|
||||
<div className="grid gap-6 grid-cols-2 md:grid-cols-3 lg:grid-cols-5">
|
||||
<section className="overflow-hidden rounded-[1.9rem] border border-surface-border/70 bg-[linear-gradient(135deg,rgba(255,255,255,0.92),rgba(243,244,246,0.88))] p-5 shadow-[0_18px_40px_rgba(15,23,42,0.05)] sm:p-6">
|
||||
<div className="grid grid-cols-2 gap-x-4 gap-y-6 md:grid-cols-3 lg:grid-cols-5">
|
||||
{displayStats.map((stat, index: number) => (
|
||||
<div key={index} className="space-y-1 text-center md:text-left">
|
||||
<div className="text-3xl font-semibold text-heading">
|
||||
<div
|
||||
key={index}
|
||||
className="space-y-1 text-left even:text-right md:text-left"
|
||||
>
|
||||
<div className="text-[2rem] font-semibold tracking-[-0.06em] text-heading sm:text-3xl">
|
||||
{stat.value}
|
||||
</div>
|
||||
<p className="text-sm text-text-muted">{stat.label}</p>
|
||||
<p className="max-w-[9rem] text-sm text-text-muted even:ml-auto md:max-w-none">
|
||||
{stat.label}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
@ -345,22 +352,22 @@ export function ShortcutsSection() {
|
||||
}));
|
||||
|
||||
return (
|
||||
<section className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<section className="space-y-4 rounded-[1.75rem] border border-surface-border/70 bg-white/70 p-5 shadow-[0_16px_45px_rgba(15,23,42,0.05)] lg:rounded-none lg:border-transparent lg:bg-transparent lg:p-0 lg:shadow-none">
|
||||
<div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div>
|
||||
<p className="text-xs font-semibold uppercase tracking-[0.2em] text-text-subtle">
|
||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-text-subtle">
|
||||
{t.shortcuts.title}
|
||||
</p>
|
||||
<p className="text-sm text-text-muted">{t.shortcuts.subtitle}</p>
|
||||
<p className="mt-1 text-sm text-text-muted">{t.shortcuts.subtitle}</p>
|
||||
</div>
|
||||
<div className="flex gap-2 text-xs font-semibold text-primary">
|
||||
<button className="rounded-full border border-surface-border bg-surface-muted px-3 py-1 transition hover:bg-surface-hover">
|
||||
<div className="flex flex-wrap gap-2 text-xs font-semibold text-primary">
|
||||
<button className="rounded-full border border-surface-border bg-surface-muted px-3 py-2 transition hover:bg-surface-hover">
|
||||
{t.shortcuts.buttons.start}
|
||||
</button>
|
||||
<button className="rounded-full border border-surface-border bg-surface-muted px-3 py-1 transition hover:bg-surface-hover">
|
||||
<button className="rounded-full border border-surface-border bg-surface-muted px-3 py-2 transition hover:bg-surface-hover">
|
||||
{t.shortcuts.buttons.docs}
|
||||
</button>
|
||||
<button className="rounded-full border border-surface-border bg-surface-muted px-3 py-1 transition hover:bg-surface-hover">
|
||||
<button className="rounded-full border border-surface-border bg-surface-muted px-3 py-2 transition hover:bg-surface-hover">
|
||||
{t.shortcuts.buttons.guides}
|
||||
</button>
|
||||
</div>
|
||||
@ -372,12 +379,12 @@ export function ShortcutsSection() {
|
||||
<a
|
||||
key={index}
|
||||
href={item.href}
|
||||
className="group flex items-start gap-3 rounded-xl border border-surface-border bg-surface p-4 transition hover:-translate-y-[1px] hover:border-primary/50 hover:bg-surface-hover"
|
||||
className="group flex items-start gap-3 rounded-[1.4rem] border border-surface-border bg-surface/92 p-4 transition hover:-translate-y-[1px] hover:border-primary/50 hover:bg-surface-hover"
|
||||
>
|
||||
<div className="mt-1 flex h-10 w-10 items-center justify-center rounded-full bg-primary/15 text-primary">
|
||||
<div className="mt-1 flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-primary/12 text-primary">
|
||||
<Icon className="h-5 w-5" aria-hidden />
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<div className="min-w-0 space-y-1">
|
||||
<div className="text-sm font-semibold text-heading">
|
||||
{item.title}
|
||||
</div>
|
||||
@ -403,7 +410,7 @@ type LatestBlogPost = {
|
||||
|
||||
function LogoPill({ label }: { label: string }) {
|
||||
return (
|
||||
<span className="inline-flex items-center gap-2 rounded-full border border-surface-border bg-surface-muted px-3 py-1 text-xs font-semibold text-text">
|
||||
<span className="inline-flex items-center gap-2 rounded-full border border-surface-border bg-surface/88 px-3.5 py-1.5 text-xs font-semibold text-text shadow-[0_8px_22px_rgba(15,23,42,0.04)]">
|
||||
<div className="h-2 w-2 rounded-full bg-success" />
|
||||
{label}
|
||||
</span>
|
||||
|
||||
@ -50,57 +50,67 @@ export function AskAIDialog({
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"fixed bottom-0 right-0 z-[40] border-l border-[color:var(--color-surface-border)] bg-[var(--color-background)]/95 shadow-xl backdrop-blur",
|
||||
)}
|
||||
style={{
|
||||
width: "400px",
|
||||
top: "var(--app-shell-nav-offset, 64px)",
|
||||
height: "calc(100vh - var(--app-shell-nav-offset, 64px))",
|
||||
display: open ? "block" : "none",
|
||||
}}
|
||||
>
|
||||
<div className="flex h-full min-h-0 flex-col">
|
||||
<div className="flex items-center justify-between gap-3 border-b border-[color:var(--color-surface-border)] px-4 py-3">
|
||||
<div>
|
||||
<p className="text-xs font-semibold uppercase tracking-[0.2em] text-[var(--color-text-subtle)]">
|
||||
XWorkmate
|
||||
</p>
|
||||
<h2 className="text-sm font-semibold text-[var(--color-heading)]">
|
||||
AI Assistant
|
||||
</h2>
|
||||
<>
|
||||
{open ? (
|
||||
<button
|
||||
type="button"
|
||||
aria-label="Close assistant"
|
||||
onClick={onMinimize}
|
||||
className="fixed inset-0 z-[35] bg-black/18 backdrop-blur-sm md:hidden"
|
||||
/>
|
||||
) : null}
|
||||
|
||||
<div
|
||||
className={cn(
|
||||
"fixed bottom-0 left-0 right-0 z-[40] overflow-hidden border border-[color:var(--color-surface-border)] bg-[var(--color-background)]/96 shadow-2xl backdrop-blur transition-transform duration-300 ease-out md:left-auto md:right-0 md:w-[400px] md:border-l md:border-t-0 md:rounded-none",
|
||||
open
|
||||
? "translate-y-0 md:translate-x-0"
|
||||
: "translate-y-full md:translate-x-full",
|
||||
"rounded-t-[1.75rem] md:rounded-none",
|
||||
"top-[calc(var(--app-shell-nav-offset,64px)+0.75rem)] h-[calc(100vh-var(--app-shell-nav-offset,64px)-0.75rem)] md:top-[var(--app-shell-nav-offset,64px)] md:h-[calc(100vh-var(--app-shell-nav-offset,64px))]",
|
||||
)}
|
||||
>
|
||||
<div className="flex h-full min-h-0 flex-col">
|
||||
<div className="flex items-center justify-between gap-3 border-b border-[color:var(--color-surface-border)] px-4 py-3 md:px-4">
|
||||
<div>
|
||||
<p className="text-[11px] font-semibold uppercase tracking-[0.22em] text-[var(--color-text-subtle)]">
|
||||
XWorkmate
|
||||
</p>
|
||||
<h2 className="text-sm font-semibold text-[var(--color-heading)]">
|
||||
AI Assistant
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-1 text-[var(--color-text-subtle)]">
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleMaximize}
|
||||
className="rounded-xl p-2 transition hover:bg-[var(--color-surface-muted)] hover:text-[var(--color-text)]"
|
||||
title="Open workspace"
|
||||
>
|
||||
<Maximize2 className="h-4 w-4" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onMinimize}
|
||||
className="rounded-xl p-2 transition hover:bg-[var(--color-surface-muted)] hover:text-[var(--color-text)]"
|
||||
title="Close sidebar"
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-1 text-[var(--color-text-subtle)]">
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleMaximize}
|
||||
className="rounded-xl p-2 transition hover:bg-[var(--color-surface-muted)] hover:text-[var(--color-text)]"
|
||||
title="Open workspace"
|
||||
>
|
||||
<Maximize2 className="h-4 w-4" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onMinimize}
|
||||
className="rounded-xl p-2 transition hover:bg-[var(--color-surface-muted)] hover:text-[var(--color-text)]"
|
||||
title="Close sidebar"
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
</button>
|
||||
<div className="min-h-0 flex-1">
|
||||
<OpenClawAssistantPane
|
||||
defaults={resolvedDefaults}
|
||||
initialQuestion={initialQuestion?.text}
|
||||
initialQuestionKey={initialQuestion?.key}
|
||||
variant="sidebar"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="min-h-0 flex-1">
|
||||
<OpenClawAssistantPane
|
||||
defaults={resolvedDefaults}
|
||||
initialQuestion={initialQuestion?.text}
|
||||
initialQuestionKey={initialQuestion?.key}
|
||||
variant="sidebar"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@ -59,23 +59,25 @@ export function HeroCard({
|
||||
onClick={hasGuide ? openGuide : undefined}
|
||||
onKeyDown={handleCardKeyDown}
|
||||
className={cn(
|
||||
"group relative flex items-start gap-4 rounded-2xl border border-surface-border bg-surface p-6 transition-all duration-300",
|
||||
"group relative flex items-start gap-4 overflow-hidden rounded-[1.6rem] border border-surface-border bg-white/88 p-5 shadow-[0_18px_42px_rgba(15,23,42,0.05)] transition-all duration-300 sm:rounded-2xl sm:p-6",
|
||||
hasGuide
|
||||
? "cursor-pointer hover:border-primary/50 hover:bg-surface-hover"
|
||||
: "hover:border-primary/50 hover:bg-surface-hover",
|
||||
showGuide ? "border-primary/50 shadow-lg" : "",
|
||||
)}
|
||||
>
|
||||
<div className="mt-1 rounded-full border border-surface-border bg-surface-muted p-2 group-hover:border-primary/50 group-hover:text-primary">
|
||||
<div className="mt-1 rounded-full border border-surface-border bg-surface-muted p-2.5 group-hover:border-primary/50 group-hover:text-primary">
|
||||
<Icon className="h-5 w-5" />
|
||||
</div>
|
||||
<div className="flex w-full items-start justify-between gap-4">
|
||||
<div className="flex w-full flex-col gap-3 sm:flex-row sm:items-start sm:justify-between sm:gap-4">
|
||||
<div className="space-y-1">
|
||||
<h3 className="font-semibold text-heading">{title}</h3>
|
||||
<p className="text-sm text-text-muted">{description}</p>
|
||||
<h3 className="text-base font-semibold tracking-[-0.03em] text-heading">
|
||||
{title}
|
||||
</h3>
|
||||
<p className="text-sm leading-6 text-text-muted">{description}</p>
|
||||
</div>
|
||||
{hasGuide ? (
|
||||
<span className="inline-flex shrink-0 items-center gap-1 rounded-full border border-primary/20 bg-primary/10 px-3 py-1 text-xs font-semibold text-primary">
|
||||
<span className="inline-flex w-fit shrink-0 items-center gap-1 rounded-full border border-primary/20 bg-primary/10 px-3 py-1.5 text-xs font-semibold text-primary">
|
||||
点击查看向导
|
||||
<ArrowRight className="h-3.5 w-3.5" />
|
||||
</span>
|
||||
@ -86,13 +88,16 @@ export function HeroCard({
|
||||
{guide ? (
|
||||
<div
|
||||
className={cn(
|
||||
"fixed top-0 right-0 z-[100] h-full w-[400px] transform border-l border-surface-border bg-surface shadow-2xl transition-transform duration-300 ease-in-out",
|
||||
showGuide ? "translate-x-0" : "translate-x-full",
|
||||
"fixed bottom-3 left-3 right-3 z-[100] transform overflow-hidden rounded-[1.75rem] border border-surface-border bg-surface shadow-2xl transition-transform duration-300 ease-in-out md:bottom-0 md:left-auto md:right-0 md:w-[400px] md:rounded-none md:border-l md:border-t-0",
|
||||
"top-[calc(var(--app-shell-nav-offset,64px)+0.75rem)] h-[calc(100vh-var(--app-shell-nav-offset,64px)-0.75rem)] md:top-[var(--app-shell-nav-offset,64px)] md:h-[calc(100vh-var(--app-shell-nav-offset,64px))]",
|
||||
showGuide
|
||||
? "translate-y-0 md:translate-x-0"
|
||||
: "translate-y-full md:translate-x-full",
|
||||
)}
|
||||
>
|
||||
<div className="flex h-full flex-col overflow-y-auto p-8">
|
||||
<div className="mb-8 flex items-center justify-between">
|
||||
<h4 className="flex items-center gap-3 text-xl font-bold text-heading">
|
||||
<div className="flex h-full flex-col overflow-y-auto p-5 sm:p-8">
|
||||
<div className="mb-6 flex items-center justify-between sm:mb-8">
|
||||
<h4 className="flex items-center gap-3 text-lg font-bold text-heading sm:text-xl">
|
||||
<span className="relative flex h-3 w-3">
|
||||
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-primary opacity-75" />
|
||||
<span className="relative inline-flex h-3 w-3 rounded-full bg-primary" />
|
||||
@ -109,7 +114,7 @@ export function HeroCard({
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 space-y-8">
|
||||
<div className="flex-1 space-y-6 sm:space-y-8">
|
||||
{guide.steps.map((step, idx) => (
|
||||
<div key={idx} className="group/step relative pl-8">
|
||||
{idx !== guide.steps.length - 1 ? (
|
||||
|
||||
Loading…
Reference in New Issue
Block a user