Polish website flow and add Questions story
This commit is contained in:
@@ -20,7 +20,7 @@ const features = [
|
||||
icon: CalendarDays,
|
||||
title: "Turn a visit into context you can review",
|
||||
description:
|
||||
"Type or paste notes, import a portal screenshot or document, or use consent-gated recording to create a summary you can check.",
|
||||
"Keep the important details from a visit together in a summary you can check and revisit.",
|
||||
points: [
|
||||
"Keep the visit and summary easy to revisit",
|
||||
"Review important details before relying on them",
|
||||
@@ -53,13 +53,13 @@ const features = [
|
||||
id: "questions",
|
||||
label: "Questions",
|
||||
icon: MessageCircle,
|
||||
title: "Facts first, fluent answers second",
|
||||
title: "Keep the question for the right conversation",
|
||||
description:
|
||||
"Ask about a visit or medication using the context you have already collected. Dosing changes, diagnosis, and treatment decisions stay with a clinician or pharmacist.",
|
||||
"Ask about a visit or medication. When professional judgment is needed, save the question and keep guidance on who may be helpful to ask.",
|
||||
points: [
|
||||
"Keep answers connected to your own context",
|
||||
"Prepare for a clearer care conversation",
|
||||
"High-risk or unsupported questions defer to a professional",
|
||||
"Capture questions as they come up",
|
||||
"Keep a ready list for the next appointment",
|
||||
"See whether a doctor, prescriber, or pharmacist may be helpful",
|
||||
],
|
||||
image: "/screenshots/product-bezel-2026-08-23-complete/ask-black.webp",
|
||||
darkImage:
|
||||
@@ -143,10 +143,10 @@ export function FeatureShowcase() {
|
||||
onClick={() => setActiveId(feature.id)}
|
||||
onKeyDown={onTabKeyDown}
|
||||
className={cn(
|
||||
"focus-visible:ring-primary/40 inline-flex min-h-11 shrink-0 items-center gap-2 rounded-full border px-4 py-2 text-sm font-semibold transition-colors outline-none focus-visible:ring-2",
|
||||
"focus-visible:ring-primary/40 inline-flex min-h-11 shrink-0 items-center gap-2 rounded-full px-4 py-2 text-sm font-semibold transition-colors outline-none focus-visible:ring-2",
|
||||
isActive
|
||||
? "border-primary-button bg-primary-button text-white shadow-sm"
|
||||
: "border-border-soft bg-surface/75 text-muted-foreground hover:border-primary/30 hover:text-foreground backdrop-blur-xl",
|
||||
? "bg-primary-button text-white shadow-sm"
|
||||
: "bg-surface/75 text-muted-foreground hover:bg-surface-soft hover:text-foreground backdrop-blur-xl",
|
||||
)}
|
||||
>
|
||||
<Icon className="size-4" aria-hidden="true" />
|
||||
@@ -190,7 +190,7 @@ export function FeatureShowcase() {
|
||||
</div>
|
||||
|
||||
<div className="justify-self-center lg:justify-self-end">
|
||||
<div className="glass-panel rounded-[2.5rem] p-5 sm:p-7">
|
||||
<div className="surface-panel rounded-[2.5rem] p-5 sm:p-7">
|
||||
<PhoneMockup
|
||||
src={active.image}
|
||||
darkSrc={active.darkImage}
|
||||
|
||||
@@ -55,7 +55,7 @@ export function LoginForm({ redirectTo }: LoginFormProps) {
|
||||
<div className="relative flex min-h-screen items-center justify-center px-4 py-16">
|
||||
<ScreenBackground />
|
||||
|
||||
<Card className="w-full max-w-md border-border-soft/80 bg-surface/95 shadow-[0_20px_50px_rgba(15,23,42,0.12)] backdrop-blur-sm">
|
||||
<Card className="w-full max-w-md bg-surface/95 shadow-[0_20px_50px_rgba(15,23,42,0.12)] backdrop-blur-sm">
|
||||
<CardHeader className="items-center space-y-4 text-center">
|
||||
<MedscribeLogo className="h-8 w-[100px] text-foreground" />
|
||||
<div className="space-y-2">
|
||||
@@ -81,7 +81,6 @@ export function LoginForm({ redirectTo }: LoginFormProps) {
|
||||
name="password"
|
||||
type="password"
|
||||
autoComplete="current-password"
|
||||
autoFocus
|
||||
required
|
||||
value={password}
|
||||
onChange={(event) => setPassword(event.target.value)}
|
||||
@@ -103,7 +102,7 @@ export function LoginForm({ redirectTo }: LoginFormProps) {
|
||||
className="w-full"
|
||||
disabled={isSubmitting || password.length === 0}
|
||||
>
|
||||
{isSubmitting ? "Checking..." : "Continue"}
|
||||
{isSubmitting ? "Checking…" : "Continue"}
|
||||
</Button>
|
||||
</form>
|
||||
</CardContent>
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
import { ArrowUpRight, Check, MessageCircleQuestion, Plus } from "lucide-react";
|
||||
|
||||
import { cn } from "~/lib/utils";
|
||||
|
||||
const questions = [
|
||||
{
|
||||
question: "Could this change be related to my medication?",
|
||||
recipient: "Prescriber",
|
||||
},
|
||||
{
|
||||
question: "What should I expect at the follow-up?",
|
||||
recipient: "Care team",
|
||||
},
|
||||
{
|
||||
question: "Is this still the right time to take it?",
|
||||
recipient: "Pharmacist",
|
||||
},
|
||||
] as const;
|
||||
|
||||
export function QuestionsPreview({ className }: { className?: string }) {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"surface-panel overflow-hidden rounded-[2rem] p-5 sm:p-6",
|
||||
className,
|
||||
)}
|
||||
aria-label="Illustrative Questions list in Medscribe"
|
||||
>
|
||||
<div className="flex items-start justify-between gap-5 px-1 pb-5">
|
||||
<div>
|
||||
<p className="text-primary text-xs font-bold tracking-[0.16em] uppercase">
|
||||
Questions
|
||||
</p>
|
||||
<h3 className="text-foreground mt-2 font-serif text-2xl font-semibold tracking-[-0.02em]">
|
||||
Ready for the conversation
|
||||
</h3>
|
||||
</div>
|
||||
<span className="bg-primary-light text-primary flex size-10 shrink-0 items-center justify-center rounded-full">
|
||||
<MessageCircleQuestion className="size-5" aria-hidden="true" />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="bg-canvas/70 overflow-hidden rounded-[1.35rem]">
|
||||
{questions.map((item, index) => (
|
||||
<div
|
||||
key={item.question}
|
||||
className={cn(
|
||||
"grid grid-cols-[1fr_auto] gap-4 px-4 py-4 sm:px-5",
|
||||
index > 0 && "border-border-soft/55 border-t",
|
||||
)}
|
||||
>
|
||||
<div className="min-w-0">
|
||||
<p className="text-foreground text-sm leading-snug font-semibold text-pretty">
|
||||
{item.question}
|
||||
</p>
|
||||
<p className="text-muted-foreground mt-2 flex items-center gap-1.5 text-xs">
|
||||
Ask your {item.recipient.toLowerCase()}
|
||||
<ArrowUpRight className="size-3" aria-hidden="true" />
|
||||
</p>
|
||||
</div>
|
||||
<span className="bg-success-light text-success mt-0.5 flex size-6 items-center justify-center rounded-full">
|
||||
<Check className="size-3.5" aria-hidden="true" />
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="text-muted-foreground mt-5 flex items-center gap-2 px-1 text-xs leading-relaxed">
|
||||
<span className="bg-primary-light text-primary flex size-7 shrink-0 items-center justify-center rounded-full">
|
||||
<Plus className="size-3.5" aria-hidden="true" />
|
||||
</span>
|
||||
Save a question the moment it comes to you.
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -2,9 +2,6 @@ export function ScreenBackground() {
|
||||
return (
|
||||
<div className="pointer-events-none fixed inset-0 -z-10 overflow-hidden print:hidden">
|
||||
<div className="ambient-canvas absolute inset-0" />
|
||||
<div className="bg-primary-light/22 absolute -top-48 -left-40 size-[34rem] rounded-full blur-3xl" />
|
||||
<div className="absolute top-[28vh] -right-52 size-[38rem] rounded-full bg-[#d9ecff]/30 blur-3xl dark:bg-[#123d5b]/28" />
|
||||
<div className="absolute bottom-[6vh] -left-56 size-[38rem] rounded-full bg-[#fbe9d7]/32 blur-3xl dark:bg-[#4a3026]/24" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ const footerLinks = [
|
||||
export function SiteFooter() {
|
||||
return (
|
||||
<footer className="print-hidden px-3 pb-3 sm:px-5 sm:pb-5">
|
||||
<div className="glass-panel mx-auto grid max-w-6xl gap-10 rounded-[2rem] px-6 py-10 text-sm sm:px-8 md:grid-cols-[1.3fr_0.7fr_0.7fr]">
|
||||
<div className="surface-panel mx-auto grid max-w-6xl gap-10 rounded-[2rem] px-6 py-10 text-sm sm:px-8 md:grid-cols-[1.3fr_0.7fr_0.7fr]">
|
||||
<div>
|
||||
<Link
|
||||
href="/"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { Menu } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { usePathname } from "next/navigation";
|
||||
@@ -11,15 +12,38 @@ import { cn } from "~/lib/utils";
|
||||
const navigation = [
|
||||
{ href: "/", label: "Home" },
|
||||
{ href: "/how-it-works", label: "How it works" },
|
||||
{ href: "/#questions", label: "Questions" },
|
||||
{ href: "/privacy", label: "Privacy" },
|
||||
] as const;
|
||||
|
||||
export function SiteHeader() {
|
||||
const pathname = usePathname();
|
||||
const [hash, setHash] = useState("");
|
||||
const mobileMenu = useRef<HTMLDetailsElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const updateHash = () => setHash(window.location.hash);
|
||||
updateHash();
|
||||
window.addEventListener("hashchange", updateHash);
|
||||
|
||||
return () => window.removeEventListener("hashchange", updateHash);
|
||||
}, [pathname]);
|
||||
|
||||
const isActive = (href: (typeof navigation)[number]["href"]) => {
|
||||
if (href === "/#questions") {
|
||||
return pathname === "/" && hash === "#questions";
|
||||
}
|
||||
|
||||
if (href === "/") {
|
||||
return pathname === "/" && hash !== "#questions";
|
||||
}
|
||||
|
||||
return pathname === href;
|
||||
};
|
||||
|
||||
return (
|
||||
<header className="print-hidden sticky top-0 z-50 px-3 pt-3 sm:px-5">
|
||||
<div className="glass-panel-strong relative mx-auto flex h-14 max-w-6xl items-center gap-5 rounded-[1.25rem] px-3.5 sm:px-5">
|
||||
<div className="surface-panel-strong relative mx-auto flex h-14 max-w-6xl items-center gap-5 rounded-[1.25rem] px-3.5 sm:px-5">
|
||||
<Link
|
||||
href="/"
|
||||
className="text-foreground focus-visible:ring-primary/40 absolute left-1/2 flex shrink-0 -translate-x-1/2 items-center gap-2.5 rounded-md transition-opacity outline-none hover:opacity-75 focus-visible:ring-2 md:static md:translate-x-0"
|
||||
@@ -39,11 +63,11 @@ export function SiteHeader() {
|
||||
<Link
|
||||
key={item.href}
|
||||
href={item.href}
|
||||
aria-current={pathname === item.href ? "page" : undefined}
|
||||
aria-current={isActive(item.href) ? "page" : undefined}
|
||||
className={cn(
|
||||
"focus-visible:ring-primary/40 rounded-full px-3 py-2 text-sm font-medium transition-all outline-none focus-visible:ring-2",
|
||||
pathname === item.href
|
||||
? "text-foreground border border-white/45 bg-white/[0.48] shadow-[inset_0_1px_0_rgba(255,255,255,0.5),0_5px_16px_rgba(15,118,110,0.1)] dark:border-white/10 dark:bg-white/8"
|
||||
"focus-visible:ring-primary/40 rounded-full px-3 py-2 text-sm font-medium transition-colors outline-none focus-visible:ring-2",
|
||||
isActive(item.href)
|
||||
? "bg-primary-light/70 text-primary"
|
||||
: "text-muted-foreground hover:bg-primary-light/60 hover:text-foreground",
|
||||
)}
|
||||
>
|
||||
@@ -55,23 +79,24 @@ export function SiteHeader() {
|
||||
</Button>
|
||||
</nav>
|
||||
|
||||
<details className="group relative ml-auto md:hidden">
|
||||
<summary className="border-border-soft/70 bg-surface/70 text-foreground focus-visible:ring-primary/40 flex size-10 cursor-pointer list-none items-center justify-center rounded-full border outline-none marker:content-none focus-visible:ring-2 [&::-webkit-details-marker]:hidden">
|
||||
<details ref={mobileMenu} className="group relative ml-auto md:hidden">
|
||||
<summary className="bg-surface-soft text-foreground focus-visible:ring-primary/40 flex size-10 cursor-pointer list-none items-center justify-center rounded-full outline-none marker:content-none focus-visible:ring-2 [&::-webkit-details-marker]:hidden">
|
||||
<Menu className="size-5" aria-hidden="true" />
|
||||
<span className="sr-only">Open navigation</span>
|
||||
</summary>
|
||||
<nav
|
||||
aria-label="Mobile navigation"
|
||||
className="glass-panel-strong absolute top-12 right-0 flex w-64 flex-col rounded-[1.4rem] p-2"
|
||||
className="surface-panel-strong absolute top-12 right-0 flex w-64 flex-col rounded-[1.4rem] p-2"
|
||||
>
|
||||
{navigation.map((item) => (
|
||||
<Link
|
||||
key={item.href}
|
||||
href={item.href}
|
||||
aria-current={pathname === item.href ? "page" : undefined}
|
||||
className={cn(
|
||||
"text-foreground focus-visible:ring-primary/40 rounded-xl px-4 py-3 text-sm font-medium outline-none focus-visible:ring-2",
|
||||
pathname === item.href
|
||||
key={item.href}
|
||||
href={item.href}
|
||||
onClick={() => mobileMenu.current?.removeAttribute("open")}
|
||||
aria-current={isActive(item.href) ? "page" : undefined}
|
||||
className={cn(
|
||||
"text-foreground focus-visible:ring-primary/40 rounded-xl px-4 py-3 text-sm font-medium outline-none focus-visible:ring-2",
|
||||
isActive(item.href)
|
||||
? "bg-primary-light/75 shadow-[inset_0_1px_0_rgba(255,255,255,0.35)]"
|
||||
: "hover:bg-primary-light/60",
|
||||
)}
|
||||
@@ -81,6 +106,7 @@ export function SiteHeader() {
|
||||
))}
|
||||
<Link
|
||||
href="/access"
|
||||
onClick={() => mobileMenu.current?.removeAttribute("open")}
|
||||
className="bg-primary-button hover:bg-primary-button/90 focus-visible:ring-primary/40 mt-1 rounded-xl px-4 py-3 text-center text-sm font-semibold text-white outline-none focus-visible:ring-2"
|
||||
>
|
||||
Request access
|
||||
|
||||
@@ -9,7 +9,7 @@ const badgeVariants = cva(
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-primary-light text-primary",
|
||||
outline: "border border-border-soft bg-surface text-muted-foreground",
|
||||
outline: "bg-surface-soft text-muted-foreground",
|
||||
success: "bg-success-light text-success",
|
||||
},
|
||||
},
|
||||
|
||||
@@ -5,14 +5,14 @@ import { cva, type VariantProps } from "class-variance-authority";
|
||||
import { cn } from "~/lib/utils";
|
||||
|
||||
const buttonVariants = cva(
|
||||
"print-hidden inline-flex shrink-0 items-center justify-center gap-2 rounded-full text-sm font-semibold whitespace-nowrap transition-all outline-none focus-visible:ring-2 focus-visible:ring-primary/30 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
||||
"print-hidden inline-flex shrink-0 items-center justify-center gap-2 rounded-full text-sm font-semibold whitespace-nowrap transition-[color,background-color,box-shadow,transform] duration-200 outline-none focus-visible:ring-2 focus-visible:ring-primary/30 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
"bg-primary-button text-white shadow-[0_10px_25px_rgba(15,118,110,0.2)] hover:-translate-y-0.5 hover:bg-primary-button/90",
|
||||
"bg-primary-button text-white shadow-[0_8px_22px_rgba(15,118,110,0.16)] hover:-translate-y-0.5 hover:bg-primary-button/90",
|
||||
outline:
|
||||
"border border-border-soft bg-surface/75 text-foreground backdrop-blur-xl hover:-translate-y-0.5 hover:bg-surface-soft",
|
||||
"bg-surface/85 text-foreground shadow-[0_4px_16px_rgba(15,23,42,0.06)] backdrop-blur-xl hover:-translate-y-0.5 hover:bg-surface-soft",
|
||||
secondary: "bg-primary-light text-primary hover:bg-primary-light/80",
|
||||
ghost:
|
||||
"text-muted-foreground hover:bg-surface-soft hover:text-foreground",
|
||||
|
||||
@@ -6,7 +6,7 @@ function Card({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"rounded-lg border border-border-soft bg-surface text-foreground shadow-[0_1px_4px_rgba(0,0,0,0.05)]",
|
||||
"rounded-2xl bg-surface text-foreground shadow-[0_14px_40px_rgba(15,23,42,0.08)]",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
||||
Reference in New Issue
Block a user