Browse Source
Refactor video pages to use a shared VideoStepScreen component; streamline UI components and improve code organization
master
Refactor video pages to use a shared VideoStepScreen component; streamline UI components and improve code organization
master
13 changed files with 1404 additions and 1089 deletions
-
165src/app/details/[section]/detail-section-client.tsx
-
2src/app/details/[section]/page.tsx
-
49src/app/details/complete/page.tsx
-
166src/app/details/page.tsx
-
355src/app/globals.css
-
24src/app/intro/page.tsx
-
62src/app/page.tsx
-
176src/app/questions/page.tsx
-
184src/app/rules/page.tsx
-
236src/app/video-2/page.tsx
-
236src/app/video/page.tsx
-
202src/components/screens/video-step-screen.tsx
-
214src/components/ui/fabric-mobile.tsx
@ -1,37 +1,46 @@ |
|||
import Link from "next/link"; |
|||
import { |
|||
CheckIcon, |
|||
FabricCard, |
|||
FabricPill, |
|||
FabricScreen, |
|||
FabricStatusBar, |
|||
fabricSecondaryButtonClass, |
|||
} from "@/components/ui/fabric-mobile"; |
|||
|
|||
export default function DetailedQuestionsCompletePage() { |
|||
return ( |
|||
<main className="flex min-h-screen items-center justify-center bg-[#444446] p-2 sm:p-4"> |
|||
<section className="relative aspect-[375/813] w-full max-w-[375px] overflow-hidden rounded-[24px] bg-[#FCF8F7] shadow-[0_30px_70px_rgba(0,0,0,0.34)]"> |
|||
<div className="absolute inset-0 bg-[radial-gradient(circle_at_top,#FFBDD2_0%,rgba(255,189,210,0.24)_14%,rgba(255,255,255,0)_36%),linear-gradient(180deg,#FFFDFD_0%,#FAF4F7_100%)]" /> |
|||
<FabricScreen contentClassName="justify-center"> |
|||
<FabricStatusBar /> |
|||
|
|||
<div className="relative z-10 flex h-full flex-col items-center justify-center px-7 text-center"> |
|||
<div className="flex h-24 w-24 items-center justify-center rounded-full bg-linear-to-r from-[#F04C99] to-[#FF8575] text-[34px] font-semibold text-white shadow-[0_24px_44px_rgba(240,76,153,0.25)]"> |
|||
✓ |
|||
<div className="mt-auto flex flex-col items-center text-center"> |
|||
<div className="flex h-24 w-24 items-center justify-center rounded-full bg-[linear-gradient(135deg,#AF5568_0%,#D6765C_100%)] text-white shadow-[0_24px_44px_rgba(175,85,104,0.25)]"> |
|||
<CheckIcon /> |
|||
</div> |
|||
|
|||
<h1 |
|||
className="mt-10 text-[32px] font-semibold leading-[1.15] text-[#2E2327]" |
|||
style={{ fontFamily: "Georgia, Times New Roman, serif" }} |
|||
> |
|||
<FabricPill className="mt-6">All sections complete</FabricPill> |
|||
|
|||
<h1 className="fabric-display mt-6 text-[34px] leading-[1.06] text-[#2E2327]"> |
|||
Your profile details are complete |
|||
</h1> |
|||
|
|||
<p className="mt-5 max-w-[280px] text-[16px] leading-8 text-[#665D63]"> |
|||
We have received all of the required information. Our review may |
|||
take a little time, and we will notify you as soon as there is an |
|||
update. |
|||
<p className="mt-5 max-w-[290px] text-[16px] leading-8 text-[#665D63]"> |
|||
We have received all of the required information. Our review may take |
|||
a little time, and we will notify you as soon as there is an update. |
|||
</p> |
|||
|
|||
<FabricCard className="mt-8 w-full px-5 py-5 text-left"> |
|||
<p className="fabric-kicker">What happens next</p> |
|||
<p className="mt-3 text-[14px] leading-7 text-[#665953]"> |
|||
Your answers stay attached to this intake flow, and the team can now |
|||
review the completed profile as one unified submission. |
|||
</p> |
|||
</FabricCard> |
|||
|
|||
<Link |
|||
className="mt-12 flex h-[48px] w-full max-w-[290px] items-center justify-center rounded-[14px] bg-[#242424] text-[18px] font-semibold text-white shadow-[0_14px_30px_rgba(0,0,0,0.18)]" |
|||
href="/" |
|||
> |
|||
<Link className={`${fabricSecondaryButtonClass} mt-8`} href="/"> |
|||
Return Home |
|||
</Link> |
|||
</div> |
|||
</section> |
|||
</main> |
|||
</FabricScreen> |
|||
); |
|||
} |
|||
@ -1,5 +1,360 @@ |
|||
@import "tailwindcss"; |
|||
|
|||
:root { |
|||
--fabric-display: |
|||
"Iowan Old Style", "Palatino Linotype", "Book Antiqua", Georgia, serif; |
|||
--fabric-body: "Aptos", "Trebuchet MS", "Segoe UI", sans-serif; |
|||
--fabric-ink: #30211d; |
|||
--fabric-muted: #6f5e58; |
|||
--fabric-rose: #af5568; |
|||
--fabric-rust: #d6765c; |
|||
--fabric-paper: #fff9f4; |
|||
--fabric-paper-soft: #fff4ed; |
|||
--fabric-shell: #f2dfd0; |
|||
--fabric-stroke: #e4d0c4; |
|||
} |
|||
|
|||
body { |
|||
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; |
|||
} |
|||
|
|||
.fabric-body { |
|||
color: var(--fabric-ink); |
|||
font-family: var(--fabric-body); |
|||
} |
|||
|
|||
.fabric-display { |
|||
font-family: var(--fabric-display); |
|||
} |
|||
|
|||
.fabric-stage { |
|||
align-items: center; |
|||
background: radial-gradient( |
|||
circle at top, |
|||
#6d5b58 0%, |
|||
#514544 42%, |
|||
#392f31 100% |
|||
); |
|||
display: flex; |
|||
justify-content: center; |
|||
min-height: 100vh; |
|||
padding: 0.75rem; |
|||
} |
|||
|
|||
.fabric-phone { |
|||
aspect-ratio: 375 / 813; |
|||
background: linear-gradient(180deg, #f8eee5 0%, #f0ddcf 100%); |
|||
border: 1px solid rgb(255 255 255 / 15%); |
|||
border-radius: 32px; |
|||
box-shadow: 0 32px 90px rgb(25 12 14 / 42%); |
|||
max-width: 390px; |
|||
overflow: hidden; |
|||
position: relative; |
|||
width: 100%; |
|||
} |
|||
|
|||
.fabric-phone::before { |
|||
background: |
|||
radial-gradient( |
|||
circle at 15% 0%, |
|||
rgb(255 255 255 / 82%) 0%, |
|||
rgb(255 255 255 / 0%) 28% |
|||
), |
|||
radial-gradient( |
|||
circle at 100% 85%, |
|||
rgb(212 137 110 / 18%) 0%, |
|||
rgb(212 137 110 / 0%) 28% |
|||
), |
|||
linear-gradient( |
|||
180deg, |
|||
rgb(255 255 255 / 40%) 0%, |
|||
rgb(255 255 255 / 0%) 30%, |
|||
rgb(157 107 90 / 8%) 100% |
|||
); |
|||
content: ""; |
|||
inset: 0; |
|||
position: absolute; |
|||
} |
|||
|
|||
.fabric-phone::after { |
|||
background-image: |
|||
repeating-linear-gradient( |
|||
0deg, |
|||
rgb(157 117 99 / 18%) 0 1px, |
|||
transparent 1px 12px |
|||
), |
|||
repeating-linear-gradient( |
|||
90deg, |
|||
rgb(255 255 255 / 28%) 0 1px, |
|||
transparent 1px 16px |
|||
); |
|||
content: ""; |
|||
inset: 0; |
|||
mix-blend-mode: soft-light; |
|||
opacity: 0.24; |
|||
position: absolute; |
|||
} |
|||
|
|||
.fabric-screen { |
|||
background: linear-gradient( |
|||
180deg, |
|||
rgb(255 252 248 / 72%) 0%, |
|||
rgb(246 236 226 / 62%) 100% |
|||
); |
|||
display: flex; |
|||
flex-direction: column; |
|||
height: 100%; |
|||
padding: 1.25rem; |
|||
position: relative; |
|||
z-index: 1; |
|||
} |
|||
|
|||
.fabric-status { |
|||
align-items: center; |
|||
color: var(--fabric-ink); |
|||
display: flex; |
|||
font-size: 0.875rem; |
|||
font-weight: 600; |
|||
justify-content: space-between; |
|||
letter-spacing: 0.01em; |
|||
padding: 0 0.4rem; |
|||
} |
|||
|
|||
.fabric-signal { |
|||
align-items: center; |
|||
display: flex; |
|||
gap: 0.35rem; |
|||
opacity: 0.85; |
|||
} |
|||
|
|||
.fabric-signal-bar { |
|||
border: 1px solid currentcolor; |
|||
border-radius: 0.3rem; |
|||
display: block; |
|||
height: 0.45rem; |
|||
width: 1.15rem; |
|||
} |
|||
|
|||
.fabric-signal-dot { |
|||
background: currentcolor; |
|||
border-radius: 999px; |
|||
display: block; |
|||
height: 0.45rem; |
|||
width: 0.45rem; |
|||
} |
|||
|
|||
.fabric-nav-button { |
|||
align-items: center; |
|||
backdrop-filter: blur(8px); |
|||
background: linear-gradient( |
|||
180deg, |
|||
rgb(255 255 255 / 92%) 0%, |
|||
rgb(255 247 243 / 78%) 100% |
|||
); |
|||
border: 1px solid rgb(255 255 255 / 72%); |
|||
border-radius: 1.15rem; |
|||
box-shadow: 0 14px 28px rgb(79 48 38 / 12%); |
|||
color: var(--fabric-ink); |
|||
display: flex; |
|||
height: 2.85rem; |
|||
justify-content: center; |
|||
transition: |
|||
box-shadow 180ms ease, |
|||
opacity 180ms ease, |
|||
transform 180ms ease; |
|||
width: 2.85rem; |
|||
} |
|||
|
|||
.fabric-nav-button:hover { |
|||
box-shadow: 0 18px 32px rgb(79 48 38 / 16%); |
|||
transform: translateY(-1px); |
|||
} |
|||
|
|||
.fabric-nav-button:disabled { |
|||
box-shadow: none; |
|||
opacity: 0.38; |
|||
transform: none; |
|||
} |
|||
|
|||
.fabric-card { |
|||
backdrop-filter: blur(8px); |
|||
background: linear-gradient( |
|||
180deg, |
|||
rgb(255 255 255 / 94%) 0%, |
|||
rgb(255 249 244 / 84%) 100% |
|||
); |
|||
border: 1px solid rgb(255 255 255 / 70%); |
|||
border-radius: 1.75rem; |
|||
box-shadow: 0 20px 45px rgb(99 63 50 / 13%); |
|||
} |
|||
|
|||
.fabric-muted-panel { |
|||
background: rgb(251 244 239 / 80%); |
|||
border: 1px solid rgb(228 208 196 / 80%); |
|||
border-radius: 1.35rem; |
|||
box-shadow: inset 0 1px 0 rgb(255 255 255 / 55%); |
|||
} |
|||
|
|||
.fabric-kicker { |
|||
color: #a05d63; |
|||
font-size: 0.72rem; |
|||
font-weight: 700; |
|||
letter-spacing: 0.22em; |
|||
text-transform: uppercase; |
|||
} |
|||
|
|||
.fabric-pill { |
|||
align-items: center; |
|||
background: #f6e4dd; |
|||
border-radius: 999px; |
|||
color: #99535b; |
|||
display: inline-flex; |
|||
font-size: 0.75rem; |
|||
font-weight: 700; |
|||
gap: 0.35rem; |
|||
letter-spacing: 0.08em; |
|||
padding: 0.45rem 0.85rem; |
|||
text-transform: uppercase; |
|||
} |
|||
|
|||
.fabric-progress-track { |
|||
background: #ead4ca; |
|||
border-radius: 999px; |
|||
height: 0.55rem; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.fabric-progress-fill { |
|||
background: linear-gradient( |
|||
135deg, |
|||
var(--fabric-rose) 0%, |
|||
var(--fabric-rust) 100% |
|||
); |
|||
border-radius: 999px; |
|||
box-shadow: 0 4px 12px rgb(175 85 104 / 32%); |
|||
height: 100%; |
|||
transition: width 260ms ease; |
|||
} |
|||
|
|||
.fabric-input { |
|||
background: linear-gradient(180deg, #fffcfa 0%, #fff7f1 100%); |
|||
border: 1px solid var(--fabric-stroke); |
|||
border-radius: 1.25rem; |
|||
box-shadow: |
|||
inset 0 1px 0 rgb(255 255 255 / 85%), |
|||
0 10px 24px rgb(121 84 70 / 6%); |
|||
color: var(--fabric-ink); |
|||
font-family: var(--fabric-body); |
|||
font-size: 1rem; |
|||
min-height: 3.6rem; |
|||
outline: none; |
|||
padding: 0 1rem; |
|||
transition: |
|||
border-color 180ms ease, |
|||
box-shadow 180ms ease, |
|||
transform 180ms ease; |
|||
width: 100%; |
|||
} |
|||
|
|||
.fabric-input::placeholder { |
|||
color: #9e8a83; |
|||
} |
|||
|
|||
.fabric-input:focus, |
|||
.fabric-textarea:focus { |
|||
border-color: var(--fabric-rose); |
|||
box-shadow: |
|||
inset 0 1px 0 rgb(255 255 255 / 85%), |
|||
0 0 0 4px rgb(245 213 205 / 60%), |
|||
0 12px 28px rgb(121 84 70 / 8%); |
|||
} |
|||
|
|||
.fabric-textarea { |
|||
line-height: 1.7; |
|||
min-height: 9.5rem; |
|||
padding: 1rem; |
|||
resize: none; |
|||
} |
|||
|
|||
.fabric-primary-button, |
|||
.fabric-secondary-button { |
|||
align-items: center; |
|||
border-radius: 1rem; |
|||
display: flex; |
|||
font-family: var(--fabric-body); |
|||
font-size: 1.05rem; |
|||
font-weight: 700; |
|||
justify-content: center; |
|||
min-height: 3.25rem; |
|||
transition: |
|||
box-shadow 180ms ease, |
|||
filter 180ms ease, |
|||
opacity 180ms ease, |
|||
transform 180ms ease; |
|||
width: 100%; |
|||
} |
|||
|
|||
.fabric-primary-button { |
|||
background: linear-gradient( |
|||
135deg, |
|||
var(--fabric-rose) 0%, |
|||
var(--fabric-rust) 100% |
|||
); |
|||
box-shadow: 0 18px 36px rgb(175 85 104 / 28%); |
|||
color: #fff; |
|||
} |
|||
|
|||
.fabric-primary-button:hover, |
|||
.fabric-secondary-button:hover { |
|||
transform: translateY(-1px); |
|||
} |
|||
|
|||
.fabric-primary-button:disabled, |
|||
.fabric-secondary-button:disabled { |
|||
box-shadow: none; |
|||
filter: saturate(0.7); |
|||
opacity: 0.52; |
|||
transform: none; |
|||
} |
|||
|
|||
.fabric-secondary-button { |
|||
background: #2f241f; |
|||
box-shadow: 0 14px 30px rgb(47 36 31 / 20%); |
|||
color: #fff; |
|||
} |
|||
|
|||
.fabric-link-disabled { |
|||
filter: saturate(0.7); |
|||
opacity: 0.48; |
|||
pointer-events: none; |
|||
} |
|||
|
|||
.fabric-scroll { |
|||
scrollbar-width: none; |
|||
} |
|||
|
|||
.fabric-scroll::-webkit-scrollbar { |
|||
display: none; |
|||
} |
|||
|
|||
.fabric-accent-dot { |
|||
background: linear-gradient( |
|||
135deg, |
|||
var(--fabric-rose) 0%, |
|||
var(--fabric-rust) 100% |
|||
); |
|||
border-radius: 999px; |
|||
box-shadow: 0 0 0 6px rgb(245 213 205 / 50%); |
|||
height: 0.55rem; |
|||
width: 0.55rem; |
|||
} |
|||
|
|||
.fabric-divider { |
|||
background: linear-gradient( |
|||
90deg, |
|||
rgb(190 160 146 / 0%) 0%, |
|||
rgb(190 160 146 / 70%) 50%, |
|||
rgb(190 160 146 / 0%) 100% |
|||
); |
|||
height: 1px; |
|||
} |
|||
@ -1,237 +1,11 @@ |
|||
"use client"; |
|||
|
|||
import Image from "next/image"; |
|||
import Link from "next/link"; |
|||
import { useEffect, useState } from "react"; |
|||
|
|||
function BackIcon() { |
|||
return ( |
|||
<svg |
|||
aria-hidden="true" |
|||
fill="none" |
|||
height="18" |
|||
viewBox="0 0 18 18" |
|||
width="18" |
|||
xmlns="http://www.w3.org/2000/svg" |
|||
> |
|||
<path |
|||
d="M10.5 4.5 6 9l4.5 4.5" |
|||
stroke="currentColor" |
|||
strokeLinecap="round" |
|||
strokeLinejoin="round" |
|||
strokeWidth="1.8" |
|||
/> |
|||
</svg> |
|||
); |
|||
} |
|||
|
|||
function HistoryIcon() { |
|||
return ( |
|||
<svg |
|||
aria-hidden="true" |
|||
fill="none" |
|||
height="18" |
|||
viewBox="0 0 18 18" |
|||
width="18" |
|||
xmlns="http://www.w3.org/2000/svg" |
|||
> |
|||
<path |
|||
d="M3.75 8.25a5.25 5.25 0 1 1 1.539 3.711" |
|||
stroke="currentColor" |
|||
strokeLinecap="round" |
|||
strokeLinejoin="round" |
|||
strokeWidth="1.6" |
|||
/> |
|||
<path |
|||
d="M3.75 4.5v3.75H7.5" |
|||
stroke="currentColor" |
|||
strokeLinecap="round" |
|||
strokeLinejoin="round" |
|||
strokeWidth="1.6" |
|||
/> |
|||
</svg> |
|||
); |
|||
} |
|||
|
|||
function PlayIcon() { |
|||
return ( |
|||
<svg |
|||
aria-hidden="true" |
|||
fill="none" |
|||
height="28" |
|||
viewBox="0 0 28 28" |
|||
width="28" |
|||
xmlns="http://www.w3.org/2000/svg" |
|||
> |
|||
<path d="M10 8.75 20 14l-10 5.25V8.75Z" fill="white" /> |
|||
</svg> |
|||
); |
|||
} |
|||
|
|||
const metrics = [ |
|||
{ label: "marriage applicants", value: "120" }, |
|||
{ label: "Successful marriage", value: "120" }, |
|||
]; |
|||
|
|||
const mockVideoDuration = 12; |
|||
import VideoStepScreen from "@/components/screens/video-step-screen"; |
|||
|
|||
export default function VideoPageTwo() { |
|||
const [isPlaying, setIsPlaying] = useState(false); |
|||
const [watchedSeconds, setWatchedSeconds] = useState(0); |
|||
const isCompleted = watchedSeconds >= mockVideoDuration; |
|||
const progressPercent = Math.min( |
|||
(watchedSeconds / mockVideoDuration) * 100, |
|||
100, |
|||
); |
|||
|
|||
useEffect(() => { |
|||
if (!isPlaying || isCompleted) { |
|||
return; |
|||
} |
|||
|
|||
const timer = window.setInterval(() => { |
|||
setWatchedSeconds((currentValue) => { |
|||
const nextValue = Math.min(currentValue + 1, mockVideoDuration); |
|||
|
|||
if (nextValue >= mockVideoDuration) { |
|||
setIsPlaying(false); |
|||
} |
|||
|
|||
return nextValue; |
|||
}); |
|||
}, 1000); |
|||
|
|||
return () => window.clearInterval(timer); |
|||
}, [isCompleted, isPlaying]); |
|||
|
|||
const handlePlay = () => { |
|||
if (isCompleted) { |
|||
setWatchedSeconds(0); |
|||
} |
|||
|
|||
setIsPlaying((currentValue) => !currentValue || isCompleted); |
|||
}; |
|||
|
|||
return ( |
|||
<main className="flex min-h-screen items-center justify-center bg-[#444446] p-2 sm:p-4"> |
|||
<section className="relative aspect-[375/813] w-full max-w-[375px] overflow-hidden rounded-[24px] bg-[#FCF8F7] shadow-[0_30px_70px_rgba(0,0,0,0.34)]"> |
|||
<div className="absolute inset-0 bg-[radial-gradient(circle_at_top,#FF9BB8_0%,rgba(255,155,184,0.32)_14%,rgba(255,255,255,0)_34%),linear-gradient(180deg,rgba(255,255,255,0.72)_0%,rgba(255,255,255,0.98)_34%,#FCF8F7_100%)]" /> |
|||
<div className="absolute inset-0 opacity-40 [background-image:linear-gradient(45deg,rgba(226,201,206,0.28)_25%,transparent_25%),linear-gradient(-45deg,rgba(226,201,206,0.28)_25%,transparent_25%),linear-gradient(45deg,transparent_75%,rgba(226,201,206,0.22)_75%),linear-gradient(-45deg,transparent_75%,rgba(226,201,206,0.22)_75%)] [background-position:0_0,0_8px,8px_-8px,-8px_0] [background-size:16px_16px]" /> |
|||
|
|||
<div className="relative z-10 flex h-full flex-col px-4 pb-4 pt-5"> |
|||
<div className="flex items-center justify-between px-2 text-[#1C1C1E]"> |
|||
<span className="text-[14px] font-semibold">9:41</span> |
|||
<div className="flex items-center gap-1.5"> |
|||
<span className="block h-[7px] w-[18px] rounded-[3px] border border-current opacity-85" /> |
|||
<span className="block h-[7px] w-[7px] rounded-full bg-current opacity-85" /> |
|||
</div> |
|||
</div> |
|||
|
|||
<div className="mt-4 flex items-center justify-between px-1"> |
|||
<Link |
|||
aria-label="Back to rules" |
|||
className="flex h-11 w-11 items-center justify-center rounded-full bg-white text-[#202020] shadow-[0_10px_24px_rgba(0,0,0,0.08)]" |
|||
href="/rules" |
|||
> |
|||
<BackIcon /> |
|||
</Link> |
|||
|
|||
<h1 |
|||
className="text-[20px] font-semibold text-[#2A1D1E]" |
|||
style={{ fontFamily: "Georgia, Times New Roman, serif" }} |
|||
> |
|||
Habib Marriage |
|||
</h1> |
|||
|
|||
<button |
|||
aria-label="Open watch history" |
|||
className="flex h-11 w-11 items-center justify-center rounded-full bg-white text-[#202020] shadow-[0_10px_24px_rgba(0,0,0,0.08)]" |
|||
type="button" |
|||
> |
|||
<HistoryIcon /> |
|||
</button> |
|||
</div> |
|||
|
|||
<div className="mt-[110px] px-1"> |
|||
<div className="relative overflow-hidden rounded-[20px] shadow-[0_18px_40px_rgba(0,0,0,0.22)]"> |
|||
<Image |
|||
alt="Video preview for Habib Marriage" |
|||
height={420} |
|||
priority |
|||
sizes="(max-width: 375px) 100vw, 320px" |
|||
src="/assets/images/Rectangle 3077.png" |
|||
width={640} |
|||
/> |
|||
<div className="absolute inset-0 bg-[linear-gradient(180deg,rgba(6,8,14,0.08)_0%,rgba(6,8,14,0.44)_100%)]" /> |
|||
<div className="absolute inset-x-0 top-0 h-16 bg-[linear-gradient(180deg,rgba(6,8,14,0.38)_0%,rgba(6,8,14,0)_100%)] px-4 py-3 text-white"> |
|||
<div className="flex items-center justify-between text-[11px] font-medium uppercase tracking-[0.16em]"> |
|||
<span>Mock video</span> |
|||
<span>{watchedSeconds}s / 12s</span> |
|||
</div> |
|||
</div> |
|||
<div className="absolute inset-x-4 bottom-4"> |
|||
<div className="h-1.5 overflow-hidden rounded-full bg-white/30"> |
|||
<div |
|||
className="h-full rounded-full bg-[#F04C99] transition-[width] duration-700" |
|||
style={{ width: `${progressPercent}%` }} |
|||
<VideoStepScreen |
|||
backHref="/rules" |
|||
nextHref="/questions" |
|||
stepLabel="Step 3" |
|||
/> |
|||
</div> |
|||
</div> |
|||
<button |
|||
aria-label={ |
|||
isCompleted |
|||
? "Replay mock video" |
|||
: isPlaying |
|||
? "Pause mock video" |
|||
: "Play mock video" |
|||
} |
|||
className="absolute left-1/2 top-1/2 flex h-20 w-20 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full bg-[#BF2F2F] shadow-[0_18px_35px_rgba(191,47,47,0.45)]" |
|||
onClick={handlePlay} |
|||
type="button" |
|||
> |
|||
<PlayIcon /> |
|||
</button> |
|||
</div> |
|||
</div> |
|||
|
|||
<p className="mt-4 px-2 text-center text-[12px] font-medium text-[#6D6268]"> |
|||
Watch the full mock video to unlock the next step. |
|||
</p> |
|||
|
|||
<div className="mt-[102px] grid grid-cols-2 gap-4 px-4 text-center text-[#242424]"> |
|||
{metrics.map((metric) => ( |
|||
<div key={metric.label}> |
|||
<p className="text-[20px] font-semibold">{metric.value}</p> |
|||
<p className="mt-2 text-[13px] font-semibold leading-5"> |
|||
{metric.label} |
|||
</p> |
|||
</div> |
|||
))} |
|||
</div> |
|||
|
|||
<div className="mt-auto space-y-3"> |
|||
<button |
|||
className="h-[44px] w-full rounded-[14px] bg-linear-to-r from-[#F04C99] to-[#FF8575] text-[18px] font-semibold text-white shadow-[0_16px_36px_rgba(240,76,153,0.28)]" |
|||
type="button" |
|||
> |
|||
Information recording |
|||
</button> |
|||
|
|||
<Link |
|||
aria-disabled={!isCompleted} |
|||
className={`flex h-[44px] items-center justify-center rounded-[14px] text-[18px] font-semibold transition-opacity ${ |
|||
isCompleted |
|||
? "bg-[#242424] text-white shadow-[0_14px_30px_rgba(0,0,0,0.18)]" |
|||
: "pointer-events-none bg-[#D9D2D5] text-[#857D82] opacity-80" |
|||
}`}
|
|||
href={isCompleted ? "/questions" : "/video-2"} |
|||
tabIndex={isCompleted ? 0 : -1} |
|||
> |
|||
Next |
|||
</Link> |
|||
</div> |
|||
</div> |
|||
</section> |
|||
</main> |
|||
); |
|||
} |
|||
@ -1,237 +1,5 @@ |
|||
"use client"; |
|||
|
|||
import Image from "next/image"; |
|||
import Link from "next/link"; |
|||
import { useEffect, useState } from "react"; |
|||
|
|||
function BackIcon() { |
|||
return ( |
|||
<svg |
|||
aria-hidden="true" |
|||
fill="none" |
|||
height="18" |
|||
viewBox="0 0 18 18" |
|||
width="18" |
|||
xmlns="http://www.w3.org/2000/svg" |
|||
> |
|||
<path |
|||
d="M10.5 4.5 6 9l4.5 4.5" |
|||
stroke="currentColor" |
|||
strokeLinecap="round" |
|||
strokeLinejoin="round" |
|||
strokeWidth="1.8" |
|||
/> |
|||
</svg> |
|||
); |
|||
} |
|||
|
|||
function HistoryIcon() { |
|||
return ( |
|||
<svg |
|||
aria-hidden="true" |
|||
fill="none" |
|||
height="18" |
|||
viewBox="0 0 18 18" |
|||
width="18" |
|||
xmlns="http://www.w3.org/2000/svg" |
|||
> |
|||
<path |
|||
d="M3.75 8.25a5.25 5.25 0 1 1 1.539 3.711" |
|||
stroke="currentColor" |
|||
strokeLinecap="round" |
|||
strokeLinejoin="round" |
|||
strokeWidth="1.6" |
|||
/> |
|||
<path |
|||
d="M3.75 4.5v3.75H7.5" |
|||
stroke="currentColor" |
|||
strokeLinecap="round" |
|||
strokeLinejoin="round" |
|||
strokeWidth="1.6" |
|||
/> |
|||
</svg> |
|||
); |
|||
} |
|||
|
|||
function PlayIcon() { |
|||
return ( |
|||
<svg |
|||
aria-hidden="true" |
|||
fill="none" |
|||
height="28" |
|||
viewBox="0 0 28 28" |
|||
width="28" |
|||
xmlns="http://www.w3.org/2000/svg" |
|||
> |
|||
<path d="M10 8.75 20 14l-10 5.25V8.75Z" fill="white" /> |
|||
</svg> |
|||
); |
|||
} |
|||
|
|||
const metrics = [ |
|||
{ label: "marriage applicants", value: "120" }, |
|||
{ label: "Successful marriage", value: "120" }, |
|||
]; |
|||
|
|||
const mockVideoDuration = 12; |
|||
import VideoStepScreen from "@/components/screens/video-step-screen"; |
|||
|
|||
export default function VideoPage() { |
|||
const [isPlaying, setIsPlaying] = useState(false); |
|||
const [watchedSeconds, setWatchedSeconds] = useState(0); |
|||
const isCompleted = watchedSeconds >= mockVideoDuration; |
|||
const progressPercent = Math.min( |
|||
(watchedSeconds / mockVideoDuration) * 100, |
|||
100, |
|||
); |
|||
|
|||
useEffect(() => { |
|||
if (!isPlaying || isCompleted) { |
|||
return; |
|||
} |
|||
|
|||
const timer = window.setInterval(() => { |
|||
setWatchedSeconds((currentValue) => { |
|||
const nextValue = Math.min(currentValue + 1, mockVideoDuration); |
|||
|
|||
if (nextValue >= mockVideoDuration) { |
|||
setIsPlaying(false); |
|||
} |
|||
|
|||
return nextValue; |
|||
}); |
|||
}, 1000); |
|||
|
|||
return () => window.clearInterval(timer); |
|||
}, [isCompleted, isPlaying]); |
|||
|
|||
const handlePlay = () => { |
|||
if (isCompleted) { |
|||
setWatchedSeconds(0); |
|||
} |
|||
|
|||
setIsPlaying((currentValue) => !currentValue || isCompleted); |
|||
}; |
|||
|
|||
return ( |
|||
<main className="flex min-h-screen items-center justify-center bg-[#444446] p-2 sm:p-4"> |
|||
<section className="relative aspect-[375/813] w-full max-w-[375px] overflow-hidden rounded-[24px] bg-[#FCF8F7] shadow-[0_30px_70px_rgba(0,0,0,0.34)]"> |
|||
<div className="absolute inset-0 bg-[radial-gradient(circle_at_top,#FF9BB8_0%,rgba(255,155,184,0.32)_14%,rgba(255,255,255,0)_34%),linear-gradient(180deg,rgba(255,255,255,0.72)_0%,rgba(255,255,255,0.98)_34%,#FCF8F7_100%)]" /> |
|||
<div className="absolute inset-0 opacity-40 [background-image:linear-gradient(45deg,rgba(226,201,206,0.28)_25%,transparent_25%),linear-gradient(-45deg,rgba(226,201,206,0.28)_25%,transparent_25%),linear-gradient(45deg,transparent_75%,rgba(226,201,206,0.22)_75%),linear-gradient(-45deg,transparent_75%,rgba(226,201,206,0.22)_75%)] [background-position:0_0,0_8px,8px_-8px,-8px_0] [background-size:16px_16px]" /> |
|||
|
|||
<div className="relative z-10 flex h-full flex-col px-4 pb-4 pt-5"> |
|||
<div className="flex items-center justify-between px-2 text-[#1C1C1E]"> |
|||
<span className="text-[14px] font-semibold">9:41</span> |
|||
<div className="flex items-center gap-1.5"> |
|||
<span className="block h-[7px] w-[18px] rounded-[3px] border border-current opacity-85" /> |
|||
<span className="block h-[7px] w-[7px] rounded-full bg-current opacity-85" /> |
|||
</div> |
|||
</div> |
|||
|
|||
<div className="mt-4 flex items-center justify-between px-1"> |
|||
<Link |
|||
aria-label="Back to home" |
|||
className="flex h-11 w-11 items-center justify-center rounded-full bg-white text-[#202020] shadow-[0_10px_24px_rgba(0,0,0,0.08)]" |
|||
href="/" |
|||
> |
|||
<BackIcon /> |
|||
</Link> |
|||
|
|||
<h1 |
|||
className="text-[20px] font-semibold text-[#2A1D1E]" |
|||
style={{ fontFamily: "Georgia, Times New Roman, serif" }} |
|||
> |
|||
Habib Marriage |
|||
</h1> |
|||
|
|||
<button |
|||
aria-label="Open watch history" |
|||
className="flex h-11 w-11 items-center justify-center rounded-full bg-white text-[#202020] shadow-[0_10px_24px_rgba(0,0,0,0.08)]" |
|||
type="button" |
|||
> |
|||
<HistoryIcon /> |
|||
</button> |
|||
</div> |
|||
|
|||
<div className="mt-[110px] px-1"> |
|||
<div className="relative overflow-hidden rounded-[20px] shadow-[0_18px_40px_rgba(0,0,0,0.22)]"> |
|||
<Image |
|||
alt="Video preview for Habib Marriage" |
|||
height={420} |
|||
priority |
|||
sizes="(max-width: 375px) 100vw, 320px" |
|||
src="/assets/images/Rectangle 3077.png" |
|||
width={640} |
|||
/> |
|||
<div className="absolute inset-0 bg-[linear-gradient(180deg,rgba(6,8,14,0.08)_0%,rgba(6,8,14,0.44)_100%)]" /> |
|||
<div className="absolute inset-x-0 top-0 h-16 bg-[linear-gradient(180deg,rgba(6,8,14,0.38)_0%,rgba(6,8,14,0)_100%)] px-4 py-3 text-white"> |
|||
<div className="flex items-center justify-between text-[11px] font-medium uppercase tracking-[0.16em]"> |
|||
<span>Mock video</span> |
|||
<span>{watchedSeconds}s / 12s</span> |
|||
</div> |
|||
</div> |
|||
<div className="absolute inset-x-4 bottom-4"> |
|||
<div className="h-1.5 overflow-hidden rounded-full bg-white/30"> |
|||
<div |
|||
className="h-full rounded-full bg-[#F04C99] transition-[width] duration-700" |
|||
style={{ width: `${progressPercent}%` }} |
|||
/> |
|||
</div> |
|||
</div> |
|||
<button |
|||
aria-label={ |
|||
isCompleted |
|||
? "Replay mock video" |
|||
: isPlaying |
|||
? "Pause mock video" |
|||
: "Play mock video" |
|||
} |
|||
className="absolute left-1/2 top-1/2 flex h-20 w-20 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full bg-[#BF2F2F] shadow-[0_18px_35px_rgba(191,47,47,0.45)]" |
|||
onClick={handlePlay} |
|||
type="button" |
|||
> |
|||
<PlayIcon /> |
|||
</button> |
|||
</div> |
|||
</div> |
|||
|
|||
<p className="mt-4 px-2 text-center text-[12px] font-medium text-[#6D6268]"> |
|||
Watch the full mock video to unlock the next step. |
|||
</p> |
|||
|
|||
<div className="mt-[102px] grid grid-cols-2 gap-4 px-4 text-center text-[#242424]"> |
|||
{metrics.map((metric) => ( |
|||
<div key={metric.label}> |
|||
<p className="text-[20px] font-semibold">{metric.value}</p> |
|||
<p className="mt-2 text-[13px] font-semibold leading-5"> |
|||
{metric.label} |
|||
</p> |
|||
</div> |
|||
))} |
|||
</div> |
|||
|
|||
<div className="mt-auto space-y-3"> |
|||
<button |
|||
className="h-[44px] w-full rounded-[14px] bg-linear-to-r from-[#F04C99] to-[#FF8575] text-[18px] font-semibold text-white shadow-[0_16px_36px_rgba(240,76,153,0.28)]" |
|||
type="button" |
|||
> |
|||
Information recording |
|||
</button> |
|||
|
|||
<Link |
|||
aria-disabled={!isCompleted} |
|||
className={`flex h-[44px] items-center justify-center rounded-[14px] text-[18px] font-semibold transition-opacity ${ |
|||
isCompleted |
|||
? "bg-[#242424] text-white shadow-[0_14px_30px_rgba(0,0,0,0.18)]" |
|||
: "pointer-events-none bg-[#D9D2D5] text-[#857D82] opacity-80" |
|||
}`}
|
|||
href={isCompleted ? "/rules" : "/video"} |
|||
tabIndex={isCompleted ? 0 : -1} |
|||
> |
|||
Next |
|||
</Link> |
|||
</div> |
|||
</div> |
|||
</section> |
|||
</main> |
|||
); |
|||
return <VideoStepScreen backHref="/" nextHref="/rules" stepLabel="Step 1" />; |
|||
} |
|||
@ -0,0 +1,202 @@ |
|||
"use client"; |
|||
|
|||
import Image from "next/image"; |
|||
import Link from "next/link"; |
|||
import { useEffect, useState } from "react"; |
|||
import { |
|||
BackIcon, |
|||
FabricCard, |
|||
FabricIconButton, |
|||
FabricIconLink, |
|||
FabricPill, |
|||
FabricProgress, |
|||
FabricScreen, |
|||
FabricStatusBar, |
|||
fabricDisabledLinkClass, |
|||
fabricMutedPanelClass, |
|||
fabricSecondaryButtonClass, |
|||
HistoryIcon, |
|||
PlayIcon, |
|||
} from "@/components/ui/fabric-mobile"; |
|||
|
|||
const metrics = [ |
|||
{ label: "Marriage applicants", value: "120" }, |
|||
{ label: "Successful marriages", value: "120" }, |
|||
] as const; |
|||
|
|||
const mockVideoDuration = 12; |
|||
|
|||
export default function VideoStepScreen({ |
|||
backHref, |
|||
nextHref, |
|||
stepLabel, |
|||
}: { |
|||
backHref: string; |
|||
nextHref: string; |
|||
stepLabel: string; |
|||
}) { |
|||
const [isPlaying, setIsPlaying] = useState(false); |
|||
const [watchedSeconds, setWatchedSeconds] = useState(0); |
|||
const isCompleted = watchedSeconds >= mockVideoDuration; |
|||
const progressPercent = Math.min( |
|||
(watchedSeconds / mockVideoDuration) * 100, |
|||
100, |
|||
); |
|||
|
|||
useEffect(() => { |
|||
if (!isPlaying || isCompleted) { |
|||
return; |
|||
} |
|||
|
|||
const timer = window.setInterval(() => { |
|||
setWatchedSeconds((currentValue) => { |
|||
const nextValue = Math.min(currentValue + 1, mockVideoDuration); |
|||
|
|||
if (nextValue >= mockVideoDuration) { |
|||
setIsPlaying(false); |
|||
} |
|||
|
|||
return nextValue; |
|||
}); |
|||
}, 1000); |
|||
|
|||
return () => window.clearInterval(timer); |
|||
}, [isCompleted, isPlaying]); |
|||
|
|||
const handlePlay = () => { |
|||
if (isCompleted) { |
|||
setWatchedSeconds(0); |
|||
} |
|||
|
|||
setIsPlaying((currentValue) => !currentValue || isCompleted); |
|||
}; |
|||
|
|||
return ( |
|||
<FabricScreen> |
|||
<FabricStatusBar /> |
|||
|
|||
<div className="mt-5 flex items-center justify-between"> |
|||
<FabricIconLink aria-label="Go back" href={backHref}> |
|||
<BackIcon /> |
|||
</FabricIconLink> |
|||
|
|||
<div className="text-center"> |
|||
<p className="fabric-kicker">Guided intake</p> |
|||
<h1 className="fabric-display mt-2 text-[28px] leading-none text-[#2E211E]"> |
|||
Habib Marriage |
|||
</h1> |
|||
</div> |
|||
|
|||
<FabricIconButton aria-label="Open watch history"> |
|||
<HistoryIcon /> |
|||
</FabricIconButton> |
|||
</div> |
|||
|
|||
<FabricCard className="mt-6 px-5 py-5"> |
|||
<div className="flex items-start justify-between gap-4"> |
|||
<div> |
|||
<p className="fabric-kicker">Orientation video</p> |
|||
<h2 className="fabric-display mt-3 text-[30px] leading-[1.02] text-[#2E211E]"> |
|||
Watch this short introduction before continuing |
|||
</h2> |
|||
</div> |
|||
<FabricPill className="shrink-0">{stepLabel}</FabricPill> |
|||
</div> |
|||
|
|||
<p className="mt-4 text-[14px] leading-7 text-[#6E5E58]"> |
|||
This preview explains the tone of the platform and unlocks the next |
|||
step once the full clip has been watched. |
|||
</p> |
|||
</FabricCard> |
|||
|
|||
<div className="mt-5 px-1"> |
|||
<div className="relative overflow-hidden rounded-[30px] border border-white/65 bg-[#241914] shadow-[0_24px_48px_rgba(56,31,27,0.28)]"> |
|||
<Image |
|||
alt="Video preview for Habib Marriage" |
|||
height={420} |
|||
priority |
|||
sizes="(max-width: 390px) 100vw, 340px" |
|||
src="/assets/images/Rectangle 3077.png" |
|||
width={640} |
|||
/> |
|||
<div className="absolute inset-0 bg-[linear-gradient(180deg,rgba(18,12,10,0.12)_0%,rgba(18,12,10,0.52)_100%)]" /> |
|||
|
|||
<div className="absolute inset-x-0 top-0 px-5 py-4 text-white"> |
|||
<div className="flex items-center justify-between"> |
|||
<FabricPill className="bg-white/18 text-white backdrop-blur"> |
|||
12s walkthrough |
|||
</FabricPill> |
|||
<span className="text-[12px] font-semibold uppercase tracking-[0.18em] text-white/82"> |
|||
{watchedSeconds}s / {mockVideoDuration}s |
|||
</span> |
|||
</div> |
|||
</div> |
|||
|
|||
<div className="absolute inset-x-5 bottom-5"> |
|||
<FabricProgress |
|||
className="h-2 bg-white/25" |
|||
fillClassName="bg-[linear-gradient(135deg,#E68C79_0%,#F7C29A_100%)] shadow-none" |
|||
value={progressPercent} |
|||
/> |
|||
</div> |
|||
|
|||
<button |
|||
aria-label={ |
|||
isCompleted |
|||
? "Replay the introduction" |
|||
: isPlaying |
|||
? "Pause the introduction" |
|||
: "Play the introduction" |
|||
} |
|||
className="absolute left-1/2 top-1/2 flex h-[88px] w-[88px] -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full border border-white/28 bg-[radial-gradient(circle_at_top,#C16777_0%,#A14556_48%,#7E2F3B_100%)] text-white shadow-[0_20px_42px_rgba(126,47,59,0.42)] backdrop-blur" |
|||
onClick={handlePlay} |
|||
type="button" |
|||
> |
|||
<PlayIcon /> |
|||
</button> |
|||
</div> |
|||
</div> |
|||
|
|||
<div className="mt-4 grid grid-cols-2 gap-3 px-1"> |
|||
{metrics.map((metric) => ( |
|||
<FabricCard className="px-4 py-4 text-center" key={metric.label}> |
|||
<p className="fabric-display text-[28px] leading-none text-[#2F221E]"> |
|||
{metric.value} |
|||
</p> |
|||
<p className="mt-3 text-[12px] font-semibold uppercase tracking-[0.14em] text-[#7A655D]"> |
|||
{metric.label} |
|||
</p> |
|||
</FabricCard> |
|||
))} |
|||
</div> |
|||
|
|||
<div className="mt-auto space-y-3"> |
|||
<div className={`${fabricMutedPanelClass} px-4 py-4`}> |
|||
<div className="flex items-start gap-3"> |
|||
<span className="fabric-accent-dot mt-1 shrink-0" /> |
|||
<div> |
|||
<p className="text-[14px] font-semibold text-[#47302A]"> |
|||
Watch until the end to unlock the next screen. |
|||
</p> |
|||
<p className="mt-1 text-[13px] leading-6 text-[#7A665F]"> |
|||
Your progress bar fills as the preview runs. Replay is available |
|||
after completion. |
|||
</p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<Link |
|||
aria-disabled={!isCompleted} |
|||
className={`${fabricSecondaryButtonClass} ${ |
|||
!isCompleted ? fabricDisabledLinkClass : "" |
|||
}`}
|
|||
href={nextHref} |
|||
tabIndex={isCompleted ? 0 : -1} |
|||
> |
|||
Next |
|||
</Link> |
|||
</div> |
|||
</FabricScreen> |
|||
); |
|||
} |
|||
@ -0,0 +1,214 @@ |
|||
import Link from "next/link"; |
|||
import type { |
|||
ButtonHTMLAttributes, |
|||
ComponentPropsWithoutRef, |
|||
ReactNode, |
|||
} from "react"; |
|||
|
|||
function mergeClasses(...classes: Array<string | false | null | undefined>) { |
|||
return classes.filter(Boolean).join(" "); |
|||
} |
|||
|
|||
export function FabricScreen({ |
|||
children, |
|||
className, |
|||
contentClassName, |
|||
}: { |
|||
children: ReactNode; |
|||
className?: string; |
|||
contentClassName?: string; |
|||
}) { |
|||
return ( |
|||
<main className="fabric-stage fabric-body"> |
|||
<section className={mergeClasses("fabric-phone", className)}> |
|||
<div className={mergeClasses("fabric-screen", contentClassName)}> |
|||
{children} |
|||
</div> |
|||
</section> |
|||
</main> |
|||
); |
|||
} |
|||
|
|||
export function FabricStatusBar() { |
|||
return ( |
|||
<div className="fabric-status"> |
|||
<span>9:41</span> |
|||
<div className="fabric-signal"> |
|||
<span className="fabric-signal-bar" /> |
|||
<span className="fabric-signal-dot" /> |
|||
</div> |
|||
</div> |
|||
); |
|||
} |
|||
|
|||
export function FabricCard({ |
|||
children, |
|||
className, |
|||
}: { |
|||
children: ReactNode; |
|||
className?: string; |
|||
}) { |
|||
return ( |
|||
<div className={mergeClasses("fabric-card", className)}>{children}</div> |
|||
); |
|||
} |
|||
|
|||
export function FabricPill({ |
|||
children, |
|||
className, |
|||
}: { |
|||
children: ReactNode; |
|||
className?: string; |
|||
}) { |
|||
return ( |
|||
<span className={mergeClasses("fabric-pill", className)}>{children}</span> |
|||
); |
|||
} |
|||
|
|||
export function FabricProgress({ |
|||
className, |
|||
fillClassName, |
|||
value, |
|||
}: { |
|||
className?: string; |
|||
fillClassName?: string; |
|||
value: number; |
|||
}) { |
|||
const clampedValue = Math.max(0, Math.min(value, 100)); |
|||
|
|||
return ( |
|||
<div className={mergeClasses("fabric-progress-track", className)}> |
|||
<div |
|||
className={mergeClasses("fabric-progress-fill", fillClassName)} |
|||
style={{ width: `${clampedValue}%` }} |
|||
/> |
|||
</div> |
|||
); |
|||
} |
|||
|
|||
export function FabricIconButton({ |
|||
children, |
|||
className, |
|||
type = "button", |
|||
...props |
|||
}: ButtonHTMLAttributes<HTMLButtonElement> & { |
|||
children: ReactNode; |
|||
className?: string; |
|||
}) { |
|||
return ( |
|||
<button |
|||
className={mergeClasses("fabric-nav-button", className)} |
|||
type={type} |
|||
{...props} |
|||
> |
|||
{children} |
|||
</button> |
|||
); |
|||
} |
|||
|
|||
export function FabricIconLink({ |
|||
children, |
|||
className, |
|||
...props |
|||
}: ComponentPropsWithoutRef<typeof Link> & { |
|||
children: ReactNode; |
|||
className?: string; |
|||
}) { |
|||
return ( |
|||
<Link className={mergeClasses("fabric-nav-button", className)} {...props}> |
|||
{children} |
|||
</Link> |
|||
); |
|||
} |
|||
|
|||
export function BackIcon() { |
|||
return ( |
|||
<svg |
|||
aria-hidden="true" |
|||
fill="none" |
|||
height="18" |
|||
viewBox="0 0 18 18" |
|||
width="18" |
|||
xmlns="http://www.w3.org/2000/svg" |
|||
> |
|||
<path |
|||
d="M10.5 4.5 6 9l4.5 4.5" |
|||
stroke="currentColor" |
|||
strokeLinecap="round" |
|||
strokeLinejoin="round" |
|||
strokeWidth="1.8" |
|||
/> |
|||
</svg> |
|||
); |
|||
} |
|||
|
|||
export function HistoryIcon() { |
|||
return ( |
|||
<svg |
|||
aria-hidden="true" |
|||
fill="none" |
|||
height="18" |
|||
viewBox="0 0 18 18" |
|||
width="18" |
|||
xmlns="http://www.w3.org/2000/svg" |
|||
> |
|||
<path |
|||
d="M3.75 8.25a5.25 5.25 0 1 1 1.539 3.711" |
|||
stroke="currentColor" |
|||
strokeLinecap="round" |
|||
strokeLinejoin="round" |
|||
strokeWidth="1.6" |
|||
/> |
|||
<path |
|||
d="M3.75 4.5v3.75H7.5" |
|||
stroke="currentColor" |
|||
strokeLinecap="round" |
|||
strokeLinejoin="round" |
|||
strokeWidth="1.6" |
|||
/> |
|||
</svg> |
|||
); |
|||
} |
|||
|
|||
export function PlayIcon() { |
|||
return ( |
|||
<svg |
|||
aria-hidden="true" |
|||
fill="none" |
|||
height="28" |
|||
viewBox="0 0 28 28" |
|||
width="28" |
|||
xmlns="http://www.w3.org/2000/svg" |
|||
> |
|||
<path d="M10 8.75 20 14l-10 5.25V8.75Z" fill="white" /> |
|||
</svg> |
|||
); |
|||
} |
|||
|
|||
export function CheckIcon() { |
|||
return ( |
|||
<svg |
|||
aria-hidden="true" |
|||
fill="none" |
|||
height="28" |
|||
viewBox="0 0 28 28" |
|||
width="28" |
|||
xmlns="http://www.w3.org/2000/svg" |
|||
> |
|||
<path |
|||
d="m7.5 14.5 4.25 4.25 8.75-9" |
|||
stroke="currentColor" |
|||
strokeLinecap="round" |
|||
strokeLinejoin="round" |
|||
strokeWidth="2.2" |
|||
/> |
|||
</svg> |
|||
); |
|||
} |
|||
|
|||
export const fabricInputClass = "fabric-input"; |
|||
export const fabricTextareaClass = "fabric-input fabric-textarea"; |
|||
export const fabricPrimaryButtonClass = "fabric-primary-button"; |
|||
export const fabricSecondaryButtonClass = "fabric-secondary-button"; |
|||
export const fabricMutedPanelClass = "fabric-muted-panel"; |
|||
export const fabricDisabledLinkClass = "fabric-link-disabled"; |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue