@ -5,10 +5,9 @@ const config: StorybookConfig = {
|
||||
addons: [
|
||||
"@chromatic-com/storybook",
|
||||
"@storybook/addon-docs",
|
||||
"@storybook/addon-onboarding",
|
||||
"@storybook/addon-a11y",
|
||||
"@storybook/addon-vitest",
|
||||
"@storybook/addon-styling-webpack"
|
||||
"@storybook/addon-styling-webpack",
|
||||
],
|
||||
framework: {
|
||||
name: "@storybook/nextjs-vite",
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import type { Preview } from "@storybook/nextjs-vite";
|
||||
import { Geist, Geist_Mono, Inter, Manrope } from "next/font/google";
|
||||
import { Geist, Geist_Mono, Inter, Manrope, Poppins } from "next/font/google";
|
||||
import "../src/app/globals.css";
|
||||
import React from "react";
|
||||
|
||||
@ -25,6 +25,12 @@ const inter = Inter({
|
||||
weight: ["100", "200", "300", "400", "500", "600", "700", "800", "900"],
|
||||
});
|
||||
|
||||
const poppins = Poppins({
|
||||
variable: "--font-poppins",
|
||||
subsets: ["latin"],
|
||||
weight: ["100", "200", "300", "400", "500", "600", "700", "800", "900"],
|
||||
});
|
||||
|
||||
const preview: Preview = {
|
||||
parameters: {
|
||||
controls: {
|
||||
@ -53,7 +59,7 @@ const preview: Preview = {
|
||||
decorators: [
|
||||
(Story) => (
|
||||
<div
|
||||
className={`${geistSans.variable} ${geistMono.variable} ${manrope.variable} ${inter.variable} flex items-center justify-center size-full max-w-[560px] min-w-xs mx-auto antialiased`}
|
||||
className={`${geistSans.variable} ${geistMono.variable} ${manrope.variable} ${inter.variable} ${poppins.variable} flex items-center justify-center size-full max-w-[560px] min-w-xs mx-auto antialiased`}
|
||||
>
|
||||
<Story />
|
||||
</div>
|
||||
|
||||
132
package-lock.json
generated
@ -9,6 +9,8 @@
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@hookform/resolvers": "^5.2.2",
|
||||
"@radix-ui/react-accordion": "^1.2.12",
|
||||
"@radix-ui/react-avatar": "^1.1.10",
|
||||
"@radix-ui/react-checkbox": "^1.3.3",
|
||||
"@radix-ui/react-dialog": "^1.1.15",
|
||||
"@radix-ui/react-label": "^2.1.7",
|
||||
@ -35,7 +37,6 @@
|
||||
"@eslint/eslintrc": "^3",
|
||||
"@storybook/addon-a11y": "^9.1.6",
|
||||
"@storybook/addon-docs": "^9.1.6",
|
||||
"@storybook/addon-onboarding": "^9.1.6",
|
||||
"@storybook/addon-styling-webpack": "^2.0.0",
|
||||
"@storybook/addon-vitest": "^9.1.6",
|
||||
"@storybook/nextjs-vite": "^9.1.6",
|
||||
@ -1979,6 +1980,37 @@
|
||||
"integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@radix-ui/react-accordion": {
|
||||
"version": "1.2.12",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.12.tgz",
|
||||
"integrity": "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.3",
|
||||
"@radix-ui/react-collapsible": "1.1.12",
|
||||
"@radix-ui/react-collection": "1.1.7",
|
||||
"@radix-ui/react-compose-refs": "1.1.2",
|
||||
"@radix-ui/react-context": "1.1.2",
|
||||
"@radix-ui/react-direction": "1.1.1",
|
||||
"@radix-ui/react-id": "1.1.1",
|
||||
"@radix-ui/react-primitive": "2.1.3",
|
||||
"@radix-ui/react-use-controllable-state": "1.2.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-arrow": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz",
|
||||
@ -2002,6 +2034,33 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-avatar": {
|
||||
"version": "1.1.10",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.10.tgz",
|
||||
"integrity": "sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-context": "1.1.2",
|
||||
"@radix-ui/react-primitive": "2.1.3",
|
||||
"@radix-ui/react-use-callback-ref": "1.1.1",
|
||||
"@radix-ui/react-use-is-hydrated": "0.1.0",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-checkbox": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.3.tgz",
|
||||
@ -2032,6 +2091,36 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-collapsible": {
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.12.tgz",
|
||||
"integrity": "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.3",
|
||||
"@radix-ui/react-compose-refs": "1.1.2",
|
||||
"@radix-ui/react-context": "1.1.2",
|
||||
"@radix-ui/react-id": "1.1.1",
|
||||
"@radix-ui/react-presence": "1.1.5",
|
||||
"@radix-ui/react-primitive": "2.1.3",
|
||||
"@radix-ui/react-use-controllable-state": "1.2.2",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-collection": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz",
|
||||
@ -2528,6 +2617,24 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-use-is-hydrated": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.0.tgz",
|
||||
"integrity": "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"use-sync-external-store": "^1.5.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-use-layout-effect": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
|
||||
@ -3021,20 +3128,6 @@
|
||||
"storybook": "^9.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/addon-onboarding": {
|
||||
"version": "9.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/addon-onboarding/-/addon-onboarding-9.1.6.tgz",
|
||||
"integrity": "sha512-NkV9+08S9sOivtiLBctZo8Xebkw7cbBe0dDE7HsWYRmDiL+ZOOwRn+AUY5055pIBsCYG2GMS5fFfxSPrTJRJgw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/storybook"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"storybook": "^9.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/addon-styling-webpack": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/addon-styling-webpack/-/addon-styling-webpack-2.0.0.tgz",
|
||||
@ -11484,6 +11577,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/use-sync-external-store": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz",
|
||||
"integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/victory-vendor": {
|
||||
"version": "36.9.2",
|
||||
"resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz",
|
||||
|
||||
@ -21,6 +21,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@hookform/resolvers": "^5.2.2",
|
||||
"@radix-ui/react-accordion": "^1.2.12",
|
||||
"@radix-ui/react-avatar": "^1.1.10",
|
||||
"@radix-ui/react-checkbox": "^1.3.3",
|
||||
"@radix-ui/react-dialog": "^1.1.15",
|
||||
"@radix-ui/react-label": "^2.1.7",
|
||||
@ -47,7 +49,6 @@
|
||||
"@eslint/eslintrc": "^3",
|
||||
"@storybook/addon-a11y": "^9.1.6",
|
||||
"@storybook/addon-docs": "^9.1.6",
|
||||
"@storybook/addon-onboarding": "^9.1.6",
|
||||
"@storybook/addon-styling-webpack": "^2.0.0",
|
||||
"@storybook/addon-vitest": "^9.1.6",
|
||||
"@storybook/nextjs-vite": "^9.1.6",
|
||||
|
||||
BIN
public/avatars/male-1.jpg
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
public/avatars/male-2.jpg
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
public/avatars/male-3.jpg
Normal file
|
After Width: | Height: | Size: 24 KiB |
3
public/check-mark.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="14" height="15" viewBox="0 0 14 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7 14.75C8.85652 14.75 10.637 14.0125 11.9497 12.6997C13.2625 11.387 14 9.60652 14 7.75C14 5.89348 13.2625 4.11301 11.9497 2.80025C10.637 1.4875 8.85652 0.75 7 0.75C5.14348 0.75 3.36301 1.4875 2.05025 2.80025C0.737498 4.11301 0 5.89348 0 7.75C0 9.60652 0.737498 11.387 2.05025 12.6997C3.36301 14.0125 5.14348 14.75 7 14.75ZM10.0898 6.46484L6.58984 9.96484C6.33281 10.2219 5.91719 10.2219 5.66289 9.96484L3.91289 8.21484C3.65586 7.95781 3.65586 7.54219 3.91289 7.28789C4.16992 7.03359 4.58555 7.03086 4.83984 7.28789L6.125 8.57305L9.16016 5.53516C9.41719 5.27812 9.83281 5.27812 10.0871 5.53516C10.3414 5.79219 10.3441 6.20781 10.0871 6.46211L10.0898 6.46484Z" fill="#1047A2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 789 B |
BIN
public/soulmate-portrait-delivered-male.jpg
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
public/trial-payment/avatars/1.jpg
Normal file
|
After Width: | Height: | Size: 98 KiB |
BIN
public/trial-payment/avatars/2.jpg
Normal file
|
After Width: | Height: | Size: 140 KiB |
BIN
public/trial-payment/avatars/3.jpg
Normal file
|
After Width: | Height: | Size: 188 KiB |
BIN
public/trial-payment/avatars/4.jpg
Normal file
|
After Width: | Height: | Size: 84 KiB |
BIN
public/trial-payment/avatars/5.jpg
Normal file
|
After Width: | Height: | Size: 194 KiB |
3
public/trial-payment/payment-methods/apple.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="35" height="27" viewBox="0 0 35 27" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M18.2695 11.5469C18.2695 12.5547 17.6543 13.1348 16.5703 13.1348H15.1465V9.95898H16.5762C17.6543 9.95898 18.2695 10.5332 18.2695 11.5469ZM21.0527 15.2148C21.0527 15.7012 21.4746 16.0176 22.1367 16.0176C22.9805 16.0176 23.6133 15.4844 23.6133 14.7344V14.2832L22.2363 14.3711C21.457 14.4238 21.0527 14.7109 21.0527 15.2148ZM34.3125 3.37891V24.0039C34.3125 25.5566 33.0527 26.8164 31.5 26.8164H3.375C1.82227 26.8164 0.5625 25.5566 0.5625 24.0039V3.37891C0.5625 1.82617 1.82227 0.566406 3.375 0.566406H31.5C33.0527 0.566406 34.3125 1.82617 34.3125 3.37891ZM8.05078 10.3047C8.54297 10.3457 9.03516 10.0586 9.3457 9.69531C9.65039 9.32031 9.84961 8.81641 9.79688 8.30664C9.36328 8.32422 8.82422 8.59375 8.51367 8.96875C8.23242 9.29102 7.99219 9.8125 8.05078 10.3047ZM11.6016 14.6699C11.5898 14.6582 10.4531 14.2246 10.4414 12.9121C10.4297 11.8164 11.3379 11.2891 11.3789 11.2598C10.8633 10.498 10.0664 10.416 9.79102 10.3984C9.07617 10.3574 8.4668 10.8027 8.12695 10.8027C7.78125 10.8027 7.26562 10.416 6.70312 10.4277C5.9707 10.4395 5.28516 10.8555 4.91602 11.5176C4.14844 12.8418 4.7168 14.7988 5.46094 15.877C5.82422 16.4102 6.26367 16.9961 6.83789 16.9727C7.38281 16.9492 7.59961 16.6211 8.25586 16.6211C8.91797 16.6211 9.10547 16.9727 9.67969 16.9668C10.2773 16.9551 10.6465 16.4336 11.0156 15.9004C11.4199 15.291 11.5898 14.7051 11.6016 14.6699ZM19.5352 11.541C19.5352 9.98242 18.4512 8.91602 16.9043 8.91602H13.9043V16.9082H15.1465V14.1777H16.8633C18.4336 14.1777 19.5352 13.0996 19.5352 11.541ZM24.8086 12.9297C24.8086 11.7754 23.8828 11.0312 22.4648 11.0312C21.1465 11.0312 20.1738 11.7871 20.1387 12.8184H21.2578C21.3516 12.3262 21.8086 12.0039 22.4297 12.0039C23.1914 12.0039 23.6133 12.3555 23.6133 13.0117V13.4512L22.0664 13.5449C20.625 13.6328 19.8457 14.2246 19.8457 15.25C19.8457 16.2871 20.6484 16.9727 21.8027 16.9727C22.582 16.9727 23.3027 16.5801 23.6309 15.9531H23.6543V16.9141H24.8027V12.9297H24.8086ZM30.7969 11.1074H29.5371L28.0781 15.8301H28.0547L26.5957 11.1074H25.2891L27.3926 16.9258L27.2812 17.2773C27.0938 17.875 26.7832 18.1094 26.2324 18.1094C26.1328 18.1094 25.9453 18.0977 25.8691 18.0918V19.0527C25.9395 19.0762 26.25 19.082 26.3438 19.082C27.5566 19.082 28.125 18.6191 28.623 17.2188L30.7969 11.1074Z" fill="#111827"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
3
public/trial-payment/payment-methods/discover.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="35" height="27" viewBox="0 0 35 27" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M31.3047 10.2402C31.3047 9.77734 30.9824 9.53125 30.3906 9.53125H30.1035V10.9902H30.3789C30.9824 10.9902 31.3047 10.7324 31.3047 10.2402ZM31.75 0.625H3.625C2.07227 0.625 0.8125 1.88477 0.8125 3.4375V24.0625C0.8125 25.6152 2.07227 26.875 3.625 26.875H31.75C33.3027 26.875 34.5625 25.6152 34.5625 24.0625V3.4375C34.5625 1.88477 33.3027 0.625 31.75 0.625ZM29.166 8.76367C30.4902 8.76367 32.2656 8.52344 32.2656 10.1934C32.2656 10.9316 31.8789 11.4062 31.1699 11.5527L32.6816 13.5684H31.5332L30.2324 11.6465H30.1035V13.5684H29.166V8.76367ZM25.8906 8.76953H28.5449V9.58984H26.8281V10.6562H28.4863V11.4648H26.8281V12.7656H28.5449V13.5742H25.8906V8.76953ZM21.8652 8.76953L23.1484 12.0039L24.4492 8.76953H25.4746L23.3945 13.7031H22.8906L20.8398 8.76953H21.8652ZM18.5898 8.59375C20.0371 8.59375 21.2031 9.76562 21.2031 11.207C21.2031 12.6543 20.0312 13.8203 18.5898 13.8203C17.1426 13.8203 15.9766 12.6484 15.9766 11.207C15.9766 9.75977 17.1484 8.59375 18.5898 8.59375ZM15.7012 8.95117V10.0645C14.5234 8.88672 12.959 9.78906 12.959 11.1777C12.959 12.6426 14.5703 13.4336 15.7012 12.3027V13.416C13.9609 14.2539 11.9922 13.082 11.9922 11.1777C11.9922 9.34961 13.9316 8.07227 15.7012 8.95117ZM10.0059 12.8359C10.6738 12.8359 11.3184 11.9395 9.8125 11.4062C8.93359 11.084 8.62891 10.7383 8.62891 10.0762C8.62891 8.7168 10.4219 8.23633 11.541 9.23828L11.0488 9.87109C10.4395 9.19141 9.58984 9.50781 9.58984 10.0176C9.58984 10.2754 9.74805 10.4219 10.3105 10.6211C11.377 11.0078 11.6934 11.3535 11.6934 12.1211C11.6934 13.8496 9.41992 14.3125 8.37695 12.7832L8.98047 12.2031C9.19727 12.6191 9.56055 12.8359 10.0059 12.8359ZM4.05859 13.5742H2.6875V8.76953H4.05859C5.58789 8.76953 6.64258 9.76562 6.64258 11.1777C6.64258 12.2617 5.86914 13.5742 4.05859 13.5742ZM8.01367 13.5742H7.07617V8.76953H8.01367V13.5742ZM32.6875 24.1211C32.6875 24.6016 32.2891 25 31.8086 25H8.3125C19.4219 22.9141 30.7363 16.8438 32.6875 15.625V24.1211ZM5.1543 9.97656C4.84961 9.68945 4.47461 9.58984 3.87109 9.58984H3.625V12.7656H3.87109C4.47461 12.7656 4.86719 12.6484 5.1543 12.3906C5.48828 12.0859 5.67578 11.6406 5.67578 11.1777C5.67578 10.7148 5.48828 10.2695 5.1543 9.97656Z" fill="#F97316"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
8
public/trial-payment/payment-methods/google.svg
Normal file
@ -0,0 +1,8 @@
|
||||
<svg width="34" height="26" viewBox="0 0 34 26" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="34" height="26" rx="3" fill="#111827"/>
|
||||
<path d="M15.2892 17V9.72727H17.8816C18.4474 9.72727 18.9161 9.83026 19.2878 10.0362C19.6595 10.2422 19.9377 10.5239 20.1223 10.8814C20.307 11.2365 20.3993 11.6366 20.3993 12.0817C20.3993 12.5291 20.3058 12.9316 20.1188 13.2891C19.9341 13.6442 19.6548 13.9259 19.2807 14.1342C18.909 14.3402 18.4415 14.4432 17.878 14.4432H16.0953V13.5128H17.7786C18.1361 13.5128 18.4261 13.4512 18.6486 13.3281C18.8712 13.2027 19.0345 13.0322 19.1387 12.8168C19.2428 12.6013 19.2949 12.3563 19.2949 12.0817C19.2949 11.8071 19.2428 11.5632 19.1387 11.3501C19.0345 11.1371 18.87 10.9702 18.6451 10.8494C18.4225 10.7287 18.129 10.6683 17.7644 10.6683H16.3865V17H15.2892ZM23.139 17.1207C22.7934 17.1207 22.4809 17.0568 22.2015 16.929C21.9222 16.7988 21.7008 16.6106 21.5375 16.3643C21.3765 16.1181 21.296 15.8163 21.296 15.4588C21.296 15.151 21.3552 14.8977 21.4735 14.6989C21.5919 14.5 21.7517 14.3426 21.9529 14.2266C22.1542 14.1106 22.3791 14.023 22.6277 13.9638C22.8762 13.9046 23.1296 13.8596 23.3876 13.8288C23.7143 13.791 23.9795 13.7602 24.1831 13.7365C24.3867 13.7105 24.5346 13.669 24.627 13.6122C24.7193 13.5554 24.7654 13.4631 24.7654 13.3352V13.3104C24.7654 13.0002 24.6779 12.7599 24.5027 12.5895C24.3298 12.419 24.0718 12.3338 23.7285 12.3338C23.371 12.3338 23.0893 12.4131 22.8833 12.5717C22.6797 12.728 22.5389 12.902 22.4608 13.0938L21.4629 12.8665C21.5813 12.535 21.7541 12.2675 21.9814 12.0639C22.211 11.858 22.475 11.7088 22.7733 11.6165C23.0716 11.5218 23.3852 11.4744 23.7143 11.4744C23.9321 11.4744 24.1629 11.5005 24.4068 11.5526C24.653 11.6023 24.8826 11.6946 25.0957 11.8295C25.3111 11.9645 25.4875 12.1574 25.6248 12.4084C25.7621 12.657 25.8308 12.9801 25.8308 13.3778V17H24.7939V16.2543H24.7512C24.6826 16.3916 24.5796 16.5265 24.4423 16.6591C24.305 16.7917 24.1286 16.9018 23.9132 16.9893C23.6977 17.0769 23.4397 17.1207 23.139 17.1207ZM23.3699 16.2685C23.6634 16.2685 23.9144 16.2105 24.1227 16.0945C24.3334 15.9785 24.4932 15.8269 24.6021 15.6399C24.7134 15.4505 24.769 15.2481 24.769 15.0327V14.3295C24.7311 14.3674 24.6577 14.4029 24.5488 14.4361C24.4423 14.4669 24.3204 14.4941 24.1831 14.5178C24.0458 14.5391 23.912 14.5592 23.7818 14.5781C23.6516 14.5947 23.5427 14.6089 23.4551 14.6207C23.2491 14.6468 23.0609 14.6906 22.8904 14.7521C22.7224 14.8137 22.5874 14.9025 22.4856 15.0185C22.3862 15.1321 22.3365 15.2836 22.3365 15.473C22.3365 15.7358 22.4335 15.9347 22.6277 16.0696C22.8218 16.2022 23.0692 16.2685 23.3699 16.2685ZM27.7209 19.0455C27.5623 19.0455 27.4179 19.0324 27.2876 19.0064C27.1574 18.9827 27.0604 18.9567 26.9964 18.9283L27.2521 18.0582C27.4463 18.1103 27.6191 18.1328 27.7706 18.1257C27.9221 18.1186 28.0559 18.0618 28.1719 17.9553C28.2902 17.8487 28.3944 17.6747 28.4844 17.4332L28.6158 17.071L26.62 11.5455H27.7564L29.1378 15.7784H29.1946L30.576 11.5455H31.7159L29.468 17.728C29.3639 18.0121 29.2313 18.2524 29.0703 18.4489C28.9093 18.6477 28.7176 18.7969 28.495 18.8963C28.2725 18.9957 28.0144 19.0455 27.7209 19.0455Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.0461 13.079C13.0466 12.7406 13.017 12.4028 12.9579 12.0693H8.12476V13.9818H10.893C10.7785 14.599 10.4087 15.1441 9.86936 15.4907V16.7321H11.5215C12.4888 15.868 13.0461 14.59 13.0461 13.079Z" fill="#4285F4"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.1249 17.9322C9.50796 17.9322 10.6724 17.4922 11.5216 16.7336L9.86951 15.4922C9.40973 15.7943 8.81752 15.9667 8.1249 15.9667C6.78817 15.9667 5.65355 15.0936 5.24785 13.917H3.5459V15.1963C4.41582 16.8736 6.18758 17.9321 8.1249 17.9322Z" fill="#34A853"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.24767 13.9164C5.03314 13.2999 5.03314 12.6321 5.24767 12.0156V10.7363H3.54571C2.8181 12.1392 2.8181 13.7928 3.54571 15.1957L5.24767 13.9164Z" fill="#FBBC04"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.12491 9.96589C8.85577 9.95426 9.56196 10.2218 10.0909 10.7107L11.5537 9.29345C10.6261 8.44939 9.39732 7.98597 8.12491 8.00032C6.18758 8.0004 4.41582 9.05899 3.5459 10.7362L5.24785 12.0155C5.65355 10.839 6.78817 9.96589 8.12491 9.96589Z" fill="#EA4335"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.1 KiB |
8
public/trial-payment/payment-methods/mastercard.svg
Normal file
@ -0,0 +1,8 @@
|
||||
<svg width="34" height="27" viewBox="0 0 34 27" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="34" height="27" rx="3" fill="#D9D9D9"/>
|
||||
<path d="M27 20H7V8H27V20Z" stroke="#E5E7EB"/>
|
||||
<path d="M13 8C16.3137 8 19 10.6863 19 14C19 17.3137 16.3137 20 13 20C9.68629 20 7 17.3137 7 14C7 10.6863 9.68629 8 13 8Z" fill="#EF4444"/>
|
||||
<path d="M13 8C16.3137 8 19 10.6863 19 14C19 17.3137 16.3137 20 13 20C9.68629 20 7 17.3137 7 14C7 10.6863 9.68629 8 13 8Z" stroke="#E5E7EB"/>
|
||||
<path d="M21 8C24.3137 8 27 10.6863 27 14C27 17.3137 24.3137 20 21 20C17.6863 20 15 17.3137 15 14C15 10.6863 17.6863 8 21 8Z" fill="#FB923C"/>
|
||||
<path d="M21 8C24.3137 8 27 10.6863 27 14C27 17.3137 24.3137 20 21 20C17.6863 20 15 17.3137 15 14C15 10.6863 17.6863 8 21 8Z" stroke="#E5E7EB"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 773 B |
3
public/trial-payment/payment-methods/paypal.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="34" height="27" viewBox="0 0 34 27" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10.916 13.8789C10.916 14.5938 10.3477 15.1387 9.62695 15.1387C9.08789 15.1387 8.68945 14.834 8.68945 14.2598C8.68945 13.5449 9.24609 12.9707 9.96094 12.9707C10.5059 12.9707 10.916 13.3047 10.916 13.8789ZM4.7168 11.0371H4.44141C4.35352 11.0371 4.26562 11.0957 4.25391 11.1953L4.00195 12.7598L4.48242 12.7422C5.12695 12.7422 5.625 12.6543 5.74219 11.9102C5.87695 11.125 5.37891 11.0371 4.7168 11.0371ZM21.3574 11.0371H21.0938C20.9883 11.0371 20.918 11.0957 20.9062 11.1953L20.6602 12.7598L21.1289 12.7422C21.8906 12.7422 22.418 12.5664 22.418 11.6875C22.4121 11.0664 21.8555 11.0371 21.3574 11.0371ZM33.75 3.4375V24.0625C33.75 25.6152 32.4902 26.875 30.9375 26.875H2.8125C1.25977 26.875 0 25.6152 0 24.0625V3.4375C0 1.88477 1.25977 0.625 2.8125 0.625H30.9375C32.4902 0.625 33.75 1.88477 33.75 3.4375ZM7.51758 11.3711C7.51758 10.1406 6.56836 9.73047 5.48438 9.73047H3.14062C2.99414 9.73047 2.84766 9.84766 2.83594 10.0059L1.875 15.9883C1.85742 16.1055 1.94531 16.2227 2.0625 16.2227H3.17578C3.33398 16.2227 3.48047 16.0527 3.49805 15.8887L3.76172 14.3301C3.82031 13.9082 4.53516 14.0547 4.81641 14.0547C6.49219 14.0547 7.51758 13.0586 7.51758 11.3711ZM12.4512 11.8867H11.3379C11.1152 11.8867 11.1035 12.209 11.0918 12.3672C10.752 11.8691 10.2598 11.7812 9.70312 11.7812C8.26758 11.7812 7.17188 13.041 7.17188 14.4297C7.17188 15.5723 7.88672 16.3164 9.0293 16.3164C9.55664 16.3164 10.2129 16.0293 10.582 15.6191C10.5527 15.707 10.5234 15.8945 10.5234 15.9824C10.5234 16.1172 10.582 16.2168 10.7109 16.2168H11.7188C11.877 16.2168 12.0117 16.0469 12.041 15.8828L12.6387 12.1152C12.6562 12.0039 12.5684 11.8867 12.4512 11.8867ZM14.8242 17.623L18.5566 12.1973C18.5859 12.168 18.5859 12.1387 18.5859 12.0977C18.5859 11.998 18.498 11.8926 18.3984 11.8926H17.2734C17.1738 11.8926 17.0684 11.9512 17.0098 12.0391L15.457 14.3242L14.8125 12.127C14.7656 11.998 14.6367 11.8926 14.4902 11.8926H13.3945C13.2949 11.8926 13.207 11.998 13.207 12.0977C13.207 12.168 14.3496 15.4258 14.4492 15.7363C14.291 15.959 13.248 17.4121 13.248 17.5879C13.248 17.6934 13.3359 17.7754 13.4355 17.7754H14.5605C14.666 17.7695 14.7656 17.7109 14.8242 17.623ZM24.1582 11.3711C24.1582 10.1406 23.209 9.73047 22.125 9.73047H19.7988C19.6406 9.73047 19.4941 9.84766 19.4766 10.0059L18.5273 15.9824C18.5156 16.0996 18.6035 16.2168 18.7148 16.2168H19.916C20.0332 16.2168 20.1211 16.1289 20.1504 16.0293L20.4141 14.3301C20.4727 13.9082 21.1875 14.0547 21.4688 14.0547C23.1328 14.0547 24.1582 13.0586 24.1582 11.3711ZM29.0918 11.8867H27.9785C27.7559 11.8867 27.7441 12.209 27.7266 12.3672C27.4043 11.8691 26.9062 11.7812 26.3379 11.7812C24.9023 11.7812 23.8066 13.041 23.8066 14.4297C23.8066 15.5723 24.5215 16.3164 25.6641 16.3164C26.209 16.3164 26.8652 16.0293 27.2168 15.6191C27.1992 15.707 27.1582 15.8945 27.1582 15.9824C27.1582 16.1172 27.2168 16.2168 27.3457 16.2168H28.3594C28.5176 16.2168 28.6523 16.0469 28.6816 15.8828L29.2793 12.1152C29.2969 12.0039 29.209 11.8867 29.0918 11.8867ZM31.875 9.93555C31.875 9.81836 31.7871 9.73047 31.6875 9.73047H30.6035C30.5156 9.73047 30.4277 9.80078 30.416 9.88867L29.4668 15.9824L29.4492 16.0117C29.4492 16.1172 29.5371 16.2168 29.6543 16.2168H30.6211C30.7676 16.2168 30.9141 16.0469 30.9258 15.8828L31.875 9.95312V9.93555ZM26.6016 12.9707C25.8867 12.9707 25.3301 13.5391 25.3301 14.2598C25.3301 14.8281 25.7402 15.1387 26.2793 15.1387C26.9824 15.1387 27.5508 14.5996 27.5508 13.8789C27.5566 13.3047 27.1465 12.9707 26.6016 12.9707Z" fill="#1D4ED8"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
3
public/trial-payment/payment-methods/visa.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="34" height="27" viewBox="0 0 34 27" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M27.5449 12.3027C27.5449 12.3027 27.9902 14.4824 28.0898 14.9395H26.1328C26.3262 14.418 27.0703 12.3906 27.0703 12.3906C27.0586 12.4082 27.2637 11.8574 27.3809 11.5176L27.5449 12.3027ZM33.75 3.4375V24.0625C33.75 25.6152 32.4902 26.875 30.9375 26.875H2.8125C1.25977 26.875 0 25.6152 0 24.0625V3.4375C0 1.88477 1.25977 0.625 2.8125 0.625H30.9375C32.4902 0.625 33.75 1.88477 33.75 3.4375ZM8.93555 18.1562L12.6387 9.0625H10.1484L7.8457 15.2734L7.59375 14.0137L6.77344 9.83008C6.63867 9.25 6.22266 9.08594 5.70703 9.0625H1.91602L1.875 9.24414C2.80078 9.47852 3.62695 9.81836 4.34766 10.2461L6.44531 18.1562H8.93555ZM14.4668 18.168L15.9434 9.0625H13.5879L12.1172 18.168H14.4668ZM22.6641 15.1914C22.6758 14.1543 22.043 13.3633 20.6895 12.7129C19.8633 12.2969 19.3594 12.0156 19.3594 11.5879C19.3711 11.2012 19.7871 10.8027 20.7129 10.8027C21.4805 10.7852 22.043 10.9668 22.4648 11.1484L22.6758 11.248L22.998 9.2793C22.5352 9.09766 21.7969 8.89258 20.8887 8.89258C18.5625 8.89258 16.9277 10.1348 16.916 11.9043C16.8984 13.2109 18.0879 13.9375 18.9785 14.377C19.8867 14.8223 20.1973 15.1152 20.1973 15.5078C20.1855 16.1172 19.459 16.3984 18.7852 16.3984C17.8477 16.3984 17.3438 16.252 16.5762 15.9121L16.2656 15.7656L15.9375 17.8105C16.4883 18.0625 17.5078 18.2852 18.5625 18.2969C21.0352 18.3027 22.6465 17.0781 22.6641 15.1914ZM30.9375 18.168L29.0391 9.0625H27.2168C26.6543 9.0625 26.2266 9.22656 25.9863 9.81836L22.4883 18.168H24.9609C24.9609 18.168 25.3652 17.043 25.4531 16.8027H28.4766C28.5469 17.125 28.7578 18.168 28.7578 18.168H30.9375Z" fill="#2563EB"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
BIN
public/trial-payment/portrait-female.jpg
Normal file
|
After Width: | Height: | Size: 57 KiB |
BIN
public/trial-payment/reviews/avatars/1.jpg
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
public/trial-payment/reviews/avatars/2.jpg
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
public/trial-payment/reviews/avatars/3.jpg
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
public/trial-payment/reviews/photos/1.jpg
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
public/trial-payment/reviews/photos/2.jpg
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
public/trial-payment/reviews/photos/3.jpg
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
public/trial-payment/reviews/portraits/1.jpg
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
public/trial-payment/reviews/portraits/2.jpg
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
public/trial-payment/reviews/portraits/3.jpg
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
public/trial-payment/users-portraits/1.jpg
Normal file
|
After Width: | Height: | Size: 49 KiB |
BIN
public/trial-payment/users-portraits/2.jpg
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
public/trial-payment/users-portraits/3.jpg
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
public/trial-payment/wall-portrait-female.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
@ -12,6 +12,7 @@
|
||||
--font-inter: var(--font-inter);
|
||||
--font-geist-sans: var(--font-geist-sans);
|
||||
--font-geist-mono: var(--font-geist-mono);
|
||||
--font-poppins: var(--font-poppins);
|
||||
--color-sidebar-ring: var(--sidebar-ring);
|
||||
--color-sidebar-border: var(--sidebar-border);
|
||||
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||
@ -30,6 +31,7 @@
|
||||
--color-placeholder-foreground: var(--placeholder-foreground);
|
||||
--color-input: var(--input);
|
||||
--color-border: var(--border);
|
||||
--color-border-white: var(--border-white);
|
||||
--color-destructive: var(--destructive);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
--color-accent: var(--accent);
|
||||
@ -56,6 +58,33 @@
|
||||
--shadow-black-glow: 0px 8px 15px 0px #00000026, 0px 4px 6px 0px #00000014;
|
||||
--shadow-coupon: 0px 20px 40px 0px #0000004d, 0px 8px 16px 0px #00000033;
|
||||
--shadow-destructive: 0 0 0 2px rgba(239, 68, 68, 0.2);
|
||||
--shadow-soulmate-portrait: 0px 6px 50px 0px #00000040;
|
||||
|
||||
/* TRIAL PAYMENT */
|
||||
|
||||
--color-trial-payment-background: var(--trial-payment-background);
|
||||
--color-trial-payment-foreground: var(--trial-payment-foreground);
|
||||
|
||||
--color-trial-payment-secondary: var(--trial-payment-secondary);
|
||||
--color-trial-payment-secondary-foreground: var(
|
||||
--trial-payment-secondary-foreground
|
||||
);
|
||||
|
||||
--color-trial-payment-primary: var(--trial-payment-primary);
|
||||
|
||||
--color-trial-payment-border: var(--trial-payment-border);
|
||||
--color-trial-payment-border-secondary: var(--trial-payment-border-secondary);
|
||||
|
||||
/* TRIAL PAYMENT Shadows */
|
||||
--shadow-trial-payment-header: 0px 1px 2px 0px #0000000d;
|
||||
--shadow-trial-payment-card: 0px 1px 2px 0px #0000000d;
|
||||
--shadow-trial-payment-step-active: 0px 10px 15px 0px #0000001a,
|
||||
0px 4px 6px 0px #0000001a;
|
||||
--shadow-trial-payment-step-inactive: 0px 1px 11px 0px #3b82f6;
|
||||
--shadow-trial-payment-review-photo: 0px 2px 4px 0px #00000040;
|
||||
|
||||
/* Animations */
|
||||
--animate-scale-pulse: var(--animate-scale-pulse);
|
||||
}
|
||||
|
||||
:root {
|
||||
@ -98,6 +127,7 @@
|
||||
/* Border и Input */
|
||||
--border: oklch(0.9288 0.0126 255.51); /* Светло-серая граница */
|
||||
--border-black: oklch(0 0 0); /* Черная граница */
|
||||
--border-white: oklch(1 0 0); /* Белая граница */
|
||||
--input: oklch(0.922 0 0); /* Светло-серый фон инпутов */
|
||||
--ring: oklch(0.6231 0.188 259.81); /* Синий фокус */
|
||||
--placeholder-foreground: oklch(
|
||||
@ -126,6 +156,22 @@
|
||||
--primary-light: oklch(0.954 0.025 259.8); /* #EBF5FF - для градиента */
|
||||
--primary-lighter: oklch(0.909 0.045 259.8); /* #DBEAFE - для градиента */
|
||||
--primary-dark: oklch(0.5461 0.2152 262.88); /* #2563EB - для градиента */
|
||||
|
||||
/* TRIAL PAYMENT COLORS */
|
||||
--trial-payment-background: oklch(1 0 0); /* #ffffff */
|
||||
--trial-payment-foreground: oklch(0.2101 0.0318 264.66); /* #111827 */
|
||||
|
||||
--trial-payment-secondary: oklch(0.9846 0.0017 247.84); /* #f9fafb */
|
||||
--trial-payment-secondary-foreground: oklch(
|
||||
0.3729 0.0306 259.73
|
||||
); /* #374151 */
|
||||
|
||||
--trial-payment-primary: oklch(0.5219 0.2176 268.98); /* #3A55E4 */
|
||||
|
||||
--trial-payment-border: oklch(0.967 0.0029 264.54); /* #F3F4F6 */
|
||||
--trial-payment-border-secondary: oklch(0.9276 0.0058 264.53); /* #E5E7EB */
|
||||
|
||||
--animate-scale-pulse: scale-pulse 2s infinite;
|
||||
}
|
||||
|
||||
.dark {
|
||||
@ -144,6 +190,7 @@
|
||||
--accent: oklch(0.269 0 0);
|
||||
--accent-foreground: oklch(0.985 0 0);
|
||||
--destructive: oklch(0.704 0.191 22.216);
|
||||
--border-white: oklch(0 0 0);
|
||||
--border: oklch(1 0 0 / 10%);
|
||||
--input: oklch(1 0 0 / 15%);
|
||||
--ring: oklch(0.556 0 0);
|
||||
@ -170,3 +217,16 @@
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
|
||||
@utility no-scrollbar {
|
||||
@apply [scrollbar-width:none] [&::-webkit-scrollbar]:hidden;
|
||||
}
|
||||
|
||||
@keyframes scale-pulse {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import type { Metadata } from "next";
|
||||
import { Geist, Geist_Mono, Inter, Manrope } from "next/font/google";
|
||||
import { Geist, Geist_Mono, Inter, Manrope, Poppins } from "next/font/google";
|
||||
import "./globals.css";
|
||||
import { AppProviders } from "@/components/providers/AppProviders";
|
||||
|
||||
@ -25,6 +25,12 @@ const inter = Inter({
|
||||
weight: ["100", "200", "300", "400", "500", "600", "700", "800", "900"],
|
||||
});
|
||||
|
||||
const poppins = Poppins({
|
||||
variable: "--font-poppins",
|
||||
subsets: ["latin"],
|
||||
weight: ["100", "200", "300", "400", "500", "600", "700", "800", "900"],
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Create Next App",
|
||||
description: "Generated by create next app",
|
||||
@ -38,7 +44,7 @@ export default function RootLayout({
|
||||
return (
|
||||
<html lang="en">
|
||||
<body
|
||||
className={`${geistSans.variable} ${geistMono.variable} ${manrope.variable} ${inter.variable} antialiased`}
|
||||
className={`${geistSans.variable} ${geistMono.variable} ${manrope.variable} ${inter.variable} ${poppins.variable} antialiased`}
|
||||
>
|
||||
<AppProviders>{children}</AppProviders>
|
||||
</body>
|
||||
|
||||
21
src/components/domains/TrialPayment/Card/Card.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type CardProps = React.ComponentProps<"section">;
|
||||
|
||||
export default function Card({ ...props }: CardProps) {
|
||||
return (
|
||||
<section
|
||||
{...props}
|
||||
className={cn(
|
||||
"w-full",
|
||||
"rounded-[16px]",
|
||||
"p-[17px]",
|
||||
"bg-trial-payment-background",
|
||||
"border border-trial-payment-border-secondary",
|
||||
"shadow-trial-payment-card",
|
||||
"flex flex-col items-center",
|
||||
props.className
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
import { Accordion } from "@/components/ui/accordion";
|
||||
import Typography, {
|
||||
TypographyProps,
|
||||
} from "@/components/ui/Typography/Typography";
|
||||
import { CommonQuestion } from "../..";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useId } from "react";
|
||||
|
||||
interface CommonQuestionsProps
|
||||
extends Omit<React.ComponentProps<"div">, "title"> {
|
||||
title?: TypographyProps<"h3">;
|
||||
questions?: React.ComponentProps<typeof CommonQuestion>[];
|
||||
accordionProps?: React.ComponentProps<typeof Accordion>;
|
||||
}
|
||||
|
||||
export default function CommonQuestions({
|
||||
title,
|
||||
questions,
|
||||
accordionProps,
|
||||
...props
|
||||
}: CommonQuestionsProps) {
|
||||
const commonQuestionId = useId();
|
||||
return (
|
||||
<div {...props} className={cn("w-full", props.className)}>
|
||||
{title && (
|
||||
<Typography
|
||||
as="h3"
|
||||
weight="bold"
|
||||
font="inter"
|
||||
align="center"
|
||||
size="2xl"
|
||||
{...title}
|
||||
className={cn(
|
||||
"text-trial-payment-foreground leading-[32px]",
|
||||
title.className
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{!!questions?.length && (
|
||||
<Accordion
|
||||
className="w-full mt-6 flex flex-col items-center gap-4"
|
||||
type="single"
|
||||
{...accordionProps}
|
||||
>
|
||||
{questions?.map((question, index) => (
|
||||
<CommonQuestion
|
||||
key={`${commonQuestionId}-${index}`}
|
||||
{...question}
|
||||
/>
|
||||
))}
|
||||
</Accordion>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,83 @@
|
||||
import Typography, {
|
||||
TypographyProps,
|
||||
} from "@/components/ui/Typography/Typography";
|
||||
import { Card } from "../..";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface FindingOneGuideProps extends React.ComponentProps<typeof Card> {
|
||||
header?: {
|
||||
emoji?: TypographyProps<"span">;
|
||||
title?: TypographyProps<"h3">;
|
||||
};
|
||||
text?: TypographyProps<"p">;
|
||||
blur?: React.ComponentProps<"div"> & {
|
||||
text?: TypographyProps<"p">;
|
||||
icon?: React.ReactNode;
|
||||
};
|
||||
}
|
||||
|
||||
export default function FindingOneGuide({
|
||||
header,
|
||||
text,
|
||||
blur,
|
||||
...props
|
||||
}: FindingOneGuideProps) {
|
||||
return (
|
||||
<Card {...props} className={cn("p-[21px]", props.className)}>
|
||||
{header && (
|
||||
<div className="w-full flex items-center justify-items-start gap-[5px]">
|
||||
{header.emoji && (
|
||||
<Typography as="span" size="2xl" {...header.emoji} />
|
||||
)}
|
||||
{header.title && (
|
||||
<Typography
|
||||
as="h3"
|
||||
weight="bold"
|
||||
font="inter"
|
||||
{...header.title}
|
||||
className={cn(
|
||||
"text-[18px] text-trial-payment-foreground",
|
||||
header.title.className
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className="w-full relative mt-2.5">
|
||||
{text && (
|
||||
<Typography
|
||||
font="inter"
|
||||
size="sm"
|
||||
{...text}
|
||||
className={cn("text-[#43464C]", text.className)}
|
||||
/>
|
||||
)}
|
||||
{blur && (
|
||||
<div
|
||||
className={cn(
|
||||
"absolute bottom-[-21px] left-[50%] translate-x-[-50%]",
|
||||
"p-8 pb-[50px]",
|
||||
"bg-[#F8FAFC8F]",
|
||||
"backdrop-blur-xs",
|
||||
"rounded-[16px]",
|
||||
"flex flex-col items-center justify-center gap-2",
|
||||
"w-[calc(100%+42px)]"
|
||||
)}
|
||||
>
|
||||
{blur?.icon}
|
||||
{blur.text && (
|
||||
<Typography
|
||||
as="p"
|
||||
font="inter"
|
||||
weight="medium"
|
||||
align="center"
|
||||
className="text-[#A16207]"
|
||||
{...blur.text}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
49
src/components/domains/TrialPayment/Cards/Footer/Footer.tsx
Normal file
@ -0,0 +1,49 @@
|
||||
import Typography, {
|
||||
TypographyProps,
|
||||
} from "@/components/ui/Typography/Typography";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
Contacts,
|
||||
Legal,
|
||||
PaymentMethods,
|
||||
} from "@/components/domains/TrialPayment";
|
||||
|
||||
interface FooterProps extends Omit<React.ComponentProps<"footer">, "title"> {
|
||||
title?: TypographyProps<"h3">;
|
||||
contacts?: React.ComponentProps<typeof Contacts>;
|
||||
legal?: React.ComponentProps<typeof Legal>;
|
||||
paymentMethods?: React.ComponentProps<typeof PaymentMethods>;
|
||||
}
|
||||
|
||||
export default function Footer({
|
||||
title,
|
||||
contacts,
|
||||
legal,
|
||||
paymentMethods,
|
||||
...props
|
||||
}: FooterProps) {
|
||||
return (
|
||||
<footer
|
||||
{...props}
|
||||
className={cn("w-full flex flex-col gap-8", props.className)}
|
||||
>
|
||||
{title && (
|
||||
<Typography
|
||||
as="h3"
|
||||
font="inter"
|
||||
size="2xl"
|
||||
align="center"
|
||||
weight="bold"
|
||||
{...title}
|
||||
className={cn(
|
||||
"leading-[32px] text-trial-payment-foreground",
|
||||
title.className
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{contacts && <Contacts {...contacts} />}
|
||||
{legal && <Legal {...legal} />}
|
||||
{paymentMethods && <PaymentMethods {...paymentMethods} />}
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
import { ActionButton } from "@/components/ui/ActionButton/ActionButton";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface PaymentButtonsProps extends React.ComponentProps<"div"> {
|
||||
buttons: (React.ComponentProps<typeof ActionButton> & {
|
||||
icon?: React.ReactNode;
|
||||
})[];
|
||||
}
|
||||
export default function PaymentButtons({
|
||||
buttons,
|
||||
...props
|
||||
}: PaymentButtonsProps) {
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
className={cn("w-full flex flex-col items-center gap-3", props.className)}
|
||||
>
|
||||
{buttons.map((button, index) => (
|
||||
<ActionButton
|
||||
key={index}
|
||||
{...button}
|
||||
className={cn(
|
||||
"bg-trial-payment-foreground",
|
||||
"font-inter font-medium text-primary-foreground text-base",
|
||||
"rounded-[8px]",
|
||||
"shadow-none",
|
||||
button.className
|
||||
)}
|
||||
>
|
||||
{button.icon}
|
||||
{button.children}
|
||||
</ActionButton>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
import Typography, {
|
||||
TypographyProps,
|
||||
} from "@/components/ui/Typography/Typography";
|
||||
import { Review } from "../..";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useId } from "react";
|
||||
|
||||
interface ReviewsProps extends Omit<React.ComponentProps<"div">, "title"> {
|
||||
title?: TypographyProps<"h3">;
|
||||
reviews: React.ComponentProps<typeof Review>[];
|
||||
}
|
||||
|
||||
export default function Reviews({ reviews, title, ...props }: ReviewsProps) {
|
||||
const reviewId = useId();
|
||||
return (
|
||||
<div {...props}>
|
||||
{title && (
|
||||
<Typography
|
||||
as="h3"
|
||||
weight="bold"
|
||||
font="inter"
|
||||
align="center"
|
||||
{...title}
|
||||
className={cn(
|
||||
"text-[22px]/[28px] text-trial-payment-foreground",
|
||||
title.className
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{!!reviews.length && (
|
||||
<div className={cn("w-full flex flex-col items-center gap-4 mt-8")}>
|
||||
{reviews.map((review, index) => (
|
||||
<Review key={`${reviewId}-${index}`} {...review} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
import Typography, {
|
||||
TypographyProps,
|
||||
} from "@/components/ui/Typography/Typography";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface StepToSeeSoulmateProps
|
||||
extends Omit<React.ComponentProps<"div">, "title"> {
|
||||
title: TypographyProps<"h4">;
|
||||
description: TypographyProps<"p">;
|
||||
icon: React.ReactNode;
|
||||
isActive: boolean;
|
||||
}
|
||||
|
||||
export default function StepToSeeSoulmate({
|
||||
title,
|
||||
description,
|
||||
icon,
|
||||
isActive,
|
||||
...props
|
||||
}: StepToSeeSoulmateProps) {
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
className={cn("w-full flex items-center gap-4", props.className)}
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
"z-1",
|
||||
"size-12",
|
||||
"rounded-full",
|
||||
"flex items-center justify-center shrink-0",
|
||||
"border-4 border-trial-payment-border-secondary",
|
||||
"bg-background shadow-trial-payment-step-inactive",
|
||||
isActive && "bg-[#1047A2]",
|
||||
isActive && "border-border-white",
|
||||
isActive && "shadow-trial-payment-step-active"
|
||||
)}
|
||||
>
|
||||
{icon}
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<Typography
|
||||
as="h4"
|
||||
weight="semiBold"
|
||||
font="inter"
|
||||
size="sm"
|
||||
{...title}
|
||||
className={cn("text-[#1047A2] leading-[20px]", title.className)}
|
||||
/>
|
||||
<Typography
|
||||
as="p"
|
||||
font="inter"
|
||||
size="xs"
|
||||
{...description}
|
||||
className={cn("leading-[16px] text-[#6B7280]", description.className)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
import { cn } from "@/lib/utils";
|
||||
import StepToSeeSoulmate from "./StepToSeeSoulmate";
|
||||
import { ActionButton } from "@/components/ui/ActionButton/ActionButton";
|
||||
|
||||
interface StepsToSeeSoulmateProps extends React.ComponentProps<"div"> {
|
||||
steps: React.ComponentProps<typeof StepToSeeSoulmate>[];
|
||||
button?: React.ComponentProps<typeof ActionButton>;
|
||||
}
|
||||
|
||||
export default function StepsToSeeSoulmate({
|
||||
steps,
|
||||
button,
|
||||
...props
|
||||
}: StepsToSeeSoulmateProps) {
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
className={cn("w-full flex flex-col gap-6", props.className)}
|
||||
>
|
||||
<div className={cn("relative w-full flex flex-col gap-6")}>
|
||||
{steps.map((step, index) => (
|
||||
<StepToSeeSoulmate key={index} {...step} />
|
||||
))}
|
||||
<div className="absolute top-12 left-[23px] w-0.5 h-[calc(100%-96px)] bg-gradient-to-b from-[#1047A2] to-[#FFFFFF]" />
|
||||
</div>
|
||||
{button && (
|
||||
<ActionButton
|
||||
{...button}
|
||||
className={cn(
|
||||
"text-[18px] font-medium animate-scale-pulse",
|
||||
button.className
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,74 @@
|
||||
import { ActionButton } from "@/components/ui/ActionButton/ActionButton";
|
||||
import Typography, {
|
||||
TypographyProps,
|
||||
} from "@/components/ui/Typography/Typography";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface StillHaveQuestionsProps
|
||||
extends Omit<React.ComponentProps<"div">, "title"> {
|
||||
title?: TypographyProps<"h3">;
|
||||
actionButton?: React.ComponentProps<typeof ActionButton>;
|
||||
contactButton?: React.ComponentProps<typeof ActionButton>;
|
||||
}
|
||||
|
||||
export default function StillHaveQuestions({
|
||||
title,
|
||||
actionButton,
|
||||
contactButton,
|
||||
...props
|
||||
}: StillHaveQuestionsProps) {
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
className={cn("w-full flex flex-col items-center gap-4", props.className)}
|
||||
>
|
||||
{title && (
|
||||
<Typography
|
||||
as="h3"
|
||||
font="inter"
|
||||
size="sm"
|
||||
{...title}
|
||||
className={cn("text-[#6B7280] leading-[20px]", title.className)}
|
||||
/>
|
||||
)}
|
||||
{actionButton && (
|
||||
<ActionButton
|
||||
{...actionButton}
|
||||
className={cn(
|
||||
"text-[18px] font-inter font-medium",
|
||||
"rounded-[16px]",
|
||||
"animate-scale-pulse",
|
||||
actionButton.className
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{contactButton && (
|
||||
<ActionButton
|
||||
{...contactButton}
|
||||
className={cn(
|
||||
"bg-transparent",
|
||||
"text-primary text-base font-inter font-medium",
|
||||
"py-3",
|
||||
"rounded-[16px]",
|
||||
contactButton.className
|
||||
)}
|
||||
variant="outline"
|
||||
>
|
||||
<svg
|
||||
width="17"
|
||||
height="16"
|
||||
viewBox="0 0 17 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M5.04688 11.5C5.875 11.5 6.54688 12.1719 6.54688 13V13.5L8.8125 11.8C9.07187 11.6062 9.3875 11.5 9.7125 11.5H14.0469C14.3219 11.5 14.5469 11.275 14.5469 11V2C14.5469 1.725 14.3219 1.5 14.0469 1.5H2.04688C1.77188 1.5 1.54688 1.725 1.54688 2V11C1.54688 11.275 1.77188 11.5 2.04688 11.5H5.04688ZM6.54688 15.375L6.54063 15.3813L6.38125 15.5L5.84688 15.9C5.69688 16.0125 5.49375 16.0312 5.32188 15.9469C5.15 15.8625 5.04688 15.6906 5.04688 15.5V14.8344V14.6344V14.625V14.5V13H3.54688H2.04688C0.94375 13 0.046875 12.1031 0.046875 11V2C0.046875 0.896875 0.94375 0 2.04688 0H14.0469C15.15 0 16.0469 0.896875 16.0469 2V11C16.0469 12.1031 15.15 13 14.0469 13H9.7125L6.54688 15.375Z"
|
||||
fill="#3B82F6"
|
||||
/>
|
||||
</svg>
|
||||
{contactButton.children}
|
||||
</ActionButton>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,131 @@
|
||||
import Typography, {
|
||||
TypographyProps,
|
||||
} from "@/components/ui/Typography/Typography";
|
||||
import Card from "../../Card/Card";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface TotalPriceProps extends Omit<React.ComponentProps<"div">, "title"> {
|
||||
couponContainer: {
|
||||
title?: TypographyProps<"h4">;
|
||||
button?: React.ComponentProps<typeof Button>;
|
||||
};
|
||||
priceContainer?: {
|
||||
title?: TypographyProps<"h4">;
|
||||
price?: TypographyProps<"span">;
|
||||
oldPrice?: TypographyProps<"span">;
|
||||
discount?: TypographyProps<"span">;
|
||||
};
|
||||
}
|
||||
|
||||
export default function TotalPrice({
|
||||
couponContainer,
|
||||
priceContainer,
|
||||
...props
|
||||
}: TotalPriceProps) {
|
||||
return (
|
||||
<Card {...props} className={cn("border-2 p-[22px]", props.className)}>
|
||||
{couponContainer && (
|
||||
<div className="w-full flex items-center justify-between">
|
||||
{couponContainer.title && (
|
||||
<Typography
|
||||
as="h4"
|
||||
font="inter"
|
||||
weight="semiBold"
|
||||
{...couponContainer.title}
|
||||
className={cn(
|
||||
"text-trial-payment-foreground leading-[24px]",
|
||||
couponContainer.title.className
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{couponContainer.button && (
|
||||
<Button
|
||||
{...couponContainer.button}
|
||||
className={cn(
|
||||
"py-2 px-[15px]",
|
||||
"font-inter font-bold text-foreground!",
|
||||
"bg-gradient-to-r from-[#FCD34D] to-[#F59E0B]",
|
||||
"rounded-[8px]",
|
||||
"flex items-center gap-6",
|
||||
couponContainer.button.className
|
||||
)}
|
||||
>
|
||||
{couponContainer.button.children}
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M8 16C10.1217 16 12.1566 15.1571 13.6569 13.6569C15.1571 12.1566 16 10.1217 16 8C16 5.87827 15.1571 3.84344 13.6569 2.34315C12.1566 0.842855 10.1217 0 8 0C5.87827 0 3.84344 0.842855 2.34315 2.34315C0.842855 3.84344 0 5.87827 0 8C0 10.1217 0.842855 12.1566 2.34315 13.6569C3.84344 15.1571 5.87827 16 8 16ZM11.5312 6.53125L7.53125 10.5312C7.2375 10.825 6.7625 10.825 6.47188 10.5312L4.47188 8.53125C4.17813 8.2375 4.17813 7.7625 4.47188 7.47188C4.76562 7.18125 5.24062 7.17813 5.53125 7.47188L7 8.94063L10.4688 5.46875C10.7625 5.175 11.2375 5.175 11.5281 5.46875C11.8187 5.7625 11.8219 6.2375 11.5281 6.52812L11.5312 6.53125Z"
|
||||
fill="white"
|
||||
/>
|
||||
</svg>
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{priceContainer && (
|
||||
<div className="w-full flex items-center justify-between mt-5">
|
||||
{priceContainer.title && (
|
||||
<Typography
|
||||
as="h4"
|
||||
font="inter"
|
||||
weight="bold"
|
||||
size="xl"
|
||||
{...priceContainer.title}
|
||||
className={cn(
|
||||
"text-trial-payment-foreground leading-[28px]",
|
||||
priceContainer.title.className
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
<div className="flex flex-col items-end gap-1">
|
||||
<div className="flex items-center gap-3.5">
|
||||
{priceContainer.oldPrice && (
|
||||
<Typography
|
||||
as="span"
|
||||
font="inter"
|
||||
{...priceContainer.oldPrice}
|
||||
className={cn(
|
||||
"text-[#6B7280] text-[18px]/[28px] line-through",
|
||||
priceContainer.oldPrice.className
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{priceContainer.price && (
|
||||
<Typography
|
||||
as="span"
|
||||
font="inter"
|
||||
weight="black"
|
||||
{...priceContainer.price}
|
||||
className={cn(
|
||||
"text-trial-payment-foreground text-[30px]/[36px]",
|
||||
priceContainer.price.className
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{priceContainer.discount && (
|
||||
<Typography
|
||||
as="span"
|
||||
size="sm"
|
||||
font="inter"
|
||||
weight="bold"
|
||||
{...priceContainer.discount}
|
||||
className={cn(
|
||||
"block bg-[#A162071A] rounded-[6px] px-4 pr-[5px] py-1",
|
||||
"text-[#A16207]",
|
||||
priceContainer.discount.className
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
import Typography, {
|
||||
TypographyProps,
|
||||
} from "@/components/ui/Typography/Typography";
|
||||
import TextList from "@/components/widgets/TextList/TextList";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface TryForDaysProps extends Omit<React.ComponentProps<"div">, "title"> {
|
||||
title?: TypographyProps<"h3">;
|
||||
textListProps?: React.ComponentProps<typeof TextList>;
|
||||
}
|
||||
|
||||
export default function TryForDays({
|
||||
title,
|
||||
textListProps,
|
||||
...props
|
||||
}: TryForDaysProps) {
|
||||
return (
|
||||
<div {...props}>
|
||||
{title && (
|
||||
<Typography as="h3" size="xl" weight="bold" font="inter" {...title} />
|
||||
)}
|
||||
{textListProps && (
|
||||
<TextList
|
||||
itemProps={{
|
||||
font: "inter",
|
||||
weight: "regular",
|
||||
size: "sm",
|
||||
className: "text-trial-payment-foreground ml-30px",
|
||||
}}
|
||||
customMarker={
|
||||
<svg
|
||||
width="14"
|
||||
height="15"
|
||||
viewBox="0 0 14 15"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="absolute left-[-26px] top-1.5"
|
||||
>
|
||||
<path
|
||||
d="M7 14.75C8.85652 14.75 10.637 14.0125 11.9497 12.6997C13.2625 11.387 14 9.60652 14 7.75C14 5.89348 13.2625 4.11301 11.9497 2.80025C10.637 1.4875 8.85652 0.75 7 0.75C5.14348 0.75 3.36301 1.4875 2.05025 2.80025C0.737498 4.11301 0 5.89348 0 7.75C0 9.60652 0.737498 11.387 2.05025 12.6997C3.36301 14.0125 5.14348 14.75 7 14.75ZM10.0898 6.46484L6.58984 9.96484C6.33281 10.2219 5.91719 10.2219 5.66289 9.96484L3.91289 8.21484C3.65586 7.95781 3.65586 7.54219 3.91289 7.28789C4.16992 7.03359 4.58555 7.03086 4.83984 7.28789L6.125 8.57305L9.16016 5.53516C9.41719 5.27812 9.83281 5.27812 10.0871 5.53516C10.3414 5.79219 10.3441 6.20781 10.0871 6.46211L10.0898 6.46484Z"
|
||||
fill="#1047A2"
|
||||
/>
|
||||
</svg>
|
||||
}
|
||||
{...textListProps}
|
||||
className={cn(
|
||||
"mt-[17px] pl-[37px] space-y-3",
|
||||
textListProps.className
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,112 @@
|
||||
import { ActionButton } from "@/components/ui/ActionButton/ActionButton";
|
||||
import Typography, {
|
||||
TypographyProps,
|
||||
} from "@/components/ui/Typography/Typography";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { cn } from "@/lib/utils";
|
||||
import Image from "next/image";
|
||||
|
||||
interface UnlockYourSketchProps
|
||||
extends Omit<React.ComponentProps<"div">, "title"> {
|
||||
title?: TypographyProps<"h3">;
|
||||
subtitle?: TypographyProps<"p">;
|
||||
button?: React.ComponentProps<typeof Button>;
|
||||
image?: React.ComponentProps<typeof Image>;
|
||||
blur?: React.ComponentProps<"div"> & {
|
||||
text?: TypographyProps<"p">;
|
||||
icon?: React.ReactNode;
|
||||
};
|
||||
}
|
||||
|
||||
export default function UnlockYourSketch({
|
||||
title,
|
||||
subtitle: description,
|
||||
button,
|
||||
image,
|
||||
blur,
|
||||
...props
|
||||
}: UnlockYourSketchProps) {
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
className={cn("w-full mt-5 flex flex-col items-center", props.className)}
|
||||
>
|
||||
{title && (
|
||||
<Typography
|
||||
as="h3"
|
||||
weight="bold"
|
||||
align="center"
|
||||
font="inter"
|
||||
{...title}
|
||||
className={cn(
|
||||
"text-[30px] leading-[36px] text-trial-payment-foreground",
|
||||
title.className
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{description && (
|
||||
<Typography
|
||||
as="p"
|
||||
align="center"
|
||||
font="inter"
|
||||
weight="semiBold"
|
||||
size="xl"
|
||||
{...description}
|
||||
className={cn(
|
||||
"mt-1 leading-[28px] text-[#1047A2]",
|
||||
description.className
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
<div className="w-full max-w-[356px] relative">
|
||||
{image && (
|
||||
<Image
|
||||
width={356}
|
||||
height={248}
|
||||
{...image}
|
||||
src={image.src}
|
||||
alt={image.alt}
|
||||
className={cn(
|
||||
"mt-6 rounded-[12px] border border-trial-payment-border-secondary",
|
||||
image.className
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{blur && (
|
||||
<div
|
||||
className={cn(
|
||||
"absolute top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%]",
|
||||
"p-8 pb-[50px]",
|
||||
"bg-[#F8FAFC8F]",
|
||||
"backdrop-blur-sm",
|
||||
"rounded-[16px]",
|
||||
"flex flex-col items-center justify-center gap-2",
|
||||
"w-[calc(100%-120px)] min-w-[235px]",
|
||||
"shadow-[0px_4px_4px_0px_#00000040]"
|
||||
)}
|
||||
>
|
||||
{blur?.icon}
|
||||
{blur.text && (
|
||||
<Typography
|
||||
as="p"
|
||||
weight="semiBold"
|
||||
align="center"
|
||||
className="text-[#A16207]"
|
||||
{...blur.text}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{button && (
|
||||
<ActionButton
|
||||
{...button}
|
||||
className={cn(
|
||||
"mt-4 text-[18px]/[22px] font-medium rounded-[16px] animate-scale-pulse",
|
||||
button.className
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,73 @@
|
||||
import { ActionButton } from "@/components/ui/ActionButton/ActionButton";
|
||||
import Typography, {
|
||||
TypographyProps,
|
||||
} from "@/components/ui/Typography/Typography";
|
||||
import { cn } from "@/lib/utils";
|
||||
import Image from "next/image";
|
||||
|
||||
interface UsersPortraitsProps
|
||||
extends Omit<React.ComponentProps<"div">, "title"> {
|
||||
title?: TypographyProps<"h3">;
|
||||
imgs?: React.ComponentProps<typeof Image>[];
|
||||
button?: React.ComponentProps<typeof ActionButton>;
|
||||
}
|
||||
|
||||
export default function UsersPortraits({
|
||||
title,
|
||||
imgs,
|
||||
button,
|
||||
...props
|
||||
}: UsersPortraitsProps) {
|
||||
return (
|
||||
<div {...props} className={cn("w-full", props.className)}>
|
||||
{title && (
|
||||
<Typography
|
||||
as="h3"
|
||||
weight="bold"
|
||||
font="inter"
|
||||
align="center"
|
||||
size="2xl"
|
||||
{...title}
|
||||
className={cn(
|
||||
"leading-[28px] text-trial-payment-foreground",
|
||||
title.className
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
className={cn(
|
||||
"w-[calc(100%+34px)]",
|
||||
"flex items-center gap-2",
|
||||
"mt-4 ml-[-17px]",
|
||||
"overflow-x-auto no-scrollbar"
|
||||
)}
|
||||
>
|
||||
{imgs &&
|
||||
imgs.map((img, index) => (
|
||||
<Image
|
||||
width={130}
|
||||
height={195}
|
||||
{...img}
|
||||
key={index}
|
||||
alt={img.alt}
|
||||
className={cn(
|
||||
"rounded-[12px] object-cover",
|
||||
index === 0 && "ml-[17px]",
|
||||
index === imgs.length - 1 && "mr-[17px]",
|
||||
img.className
|
||||
)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
{button && (
|
||||
<ActionButton
|
||||
{...button}
|
||||
className={cn(
|
||||
"mt-4 font-medium text-[18px] animate-scale-pulse",
|
||||
button.className
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
11
src/components/domains/TrialPayment/Cards/index.ts
Normal file
@ -0,0 +1,11 @@
|
||||
export { default as UnlockYourSketch } from "./UnlockYourSketch/UnlockYourSketch";
|
||||
export { default as FindingOneGuide } from "./FindingOneGuide/FindingOneGuide";
|
||||
export { default as TotalPrice } from "./TotalPrice/TotalPrice";
|
||||
export { default as PaymentButtons } from "./PaymentButtons/PaymentButtons";
|
||||
export { default as UsersPortraits } from "./UsersPortraits/UsersPortraits";
|
||||
export { default as StepsToSeeSoulmate } from "./StepsToSeeSoulmate/StepsToSeeSoulmate";
|
||||
export { default as TryForDays } from "./TryForDays/TryForDays";
|
||||
export { default as Reviews } from "./Reviews/Reviews";
|
||||
export { default as CommonQuestions } from "./CommonQuestions/CommonQuestions";
|
||||
export { default as StillHaveQuestions } from "./StillHaveQuestions/StillHaveQuestions";
|
||||
export { default as Footer } from "./Footer/Footer";
|
||||
@ -0,0 +1,75 @@
|
||||
import {
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from "@/components/ui/accordion";
|
||||
import { cn } from "@/lib/utils";
|
||||
import Card from "../Card/Card";
|
||||
|
||||
interface CommonQuestionProps
|
||||
extends Omit<React.ComponentProps<typeof AccordionItem>, "content"> {
|
||||
trigger?: React.ComponentProps<typeof AccordionTrigger>;
|
||||
content?: React.ComponentProps<typeof AccordionContent>;
|
||||
}
|
||||
|
||||
export default function CommonQuestion({
|
||||
trigger,
|
||||
content,
|
||||
...props
|
||||
}: CommonQuestionProps) {
|
||||
return (
|
||||
<AccordionItem
|
||||
{...props}
|
||||
className={cn("p-0 w-full border-none", props.className)}
|
||||
>
|
||||
<Card>
|
||||
{trigger && (
|
||||
<AccordionTrigger
|
||||
{...trigger}
|
||||
className={cn(
|
||||
"grid grid-cols-[32px_1fr_28px] items-center gap-3",
|
||||
"hover:no-underline",
|
||||
"p-0",
|
||||
"w-full!",
|
||||
"cursor-pointer",
|
||||
"font-inter font-semibold text-base leading-6 text-trial-payment-foreground",
|
||||
trigger.className
|
||||
)}
|
||||
iconProps={{
|
||||
className: cn(
|
||||
"text-primary size-7",
|
||||
trigger.iconProps?.className
|
||||
),
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center justify-center size-8 rounded-full bg-[#EFF6FF]">
|
||||
<svg
|
||||
width="8"
|
||||
height="13"
|
||||
viewBox="0 0 8 13"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M1.8125 4.125C1.8125 3.15977 2.59727 2.375 3.5625 2.375H4.4375C5.40273 2.375 6.1875 3.15977 6.1875 4.125V4.22344C6.1875 4.81953 5.88398 5.37461 5.38359 5.69453L4.22969 6.43555C3.54062 6.87852 3.125 7.64141 3.125 8.45898V8.5C3.125 8.98398 3.51602 9.375 4 9.375C4.48398 9.375 4.875 8.98398 4.875 8.5V8.46172C4.875 8.2375 4.98984 8.02969 5.17578 7.90937L6.32969 7.16836C7.33047 6.52305 7.9375 5.41563 7.9375 4.22344V4.125C7.9375 2.1918 6.3707 0.625 4.4375 0.625H3.5625C1.6293 0.625 0.0625 2.1918 0.0625 4.125C0.0625 4.60898 0.453516 5 0.9375 5C1.42148 5 1.8125 4.60898 1.8125 4.125ZM4 12.875C4.29008 12.875 4.56828 12.7598 4.7734 12.5546C4.97852 12.3495 5.09375 12.0713 5.09375 11.7812C5.09375 11.4912 4.97852 11.213 4.7734 11.0079C4.56828 10.8027 4.29008 10.6875 4 10.6875C3.70992 10.6875 3.43172 10.8027 3.2266 11.0079C3.02148 11.213 2.90625 11.4912 2.90625 11.7812C2.90625 12.0713 3.02148 12.3495 3.2266 12.5546C3.43172 12.7598 3.70992 12.875 4 12.875Z"
|
||||
fill="#3B82F6"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
{trigger?.children}
|
||||
</AccordionTrigger>
|
||||
)}
|
||||
{content && (
|
||||
<AccordionContent
|
||||
{...content}
|
||||
className={cn(
|
||||
"pl-11 pt-4 w-full",
|
||||
"font-inter text-sm text-[#6B7280]",
|
||||
content.className
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</Card>
|
||||
</AccordionItem>
|
||||
);
|
||||
}
|
||||
91
src/components/domains/TrialPayment/Contacts/Contacts.tsx
Normal file
@ -0,0 +1,91 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
import Typography, {
|
||||
TypographyProps,
|
||||
} from "@/components/ui/Typography/Typography";
|
||||
import { cn } from "@/lib/utils";
|
||||
import Link from "next/link";
|
||||
|
||||
interface ContactsProps extends Omit<React.ComponentProps<"div">, "title"> {
|
||||
title?: TypographyProps<"h3">;
|
||||
email?: React.ComponentProps<typeof Button> & { href: string };
|
||||
address?: TypographyProps<"address">;
|
||||
}
|
||||
export default function Contacts({
|
||||
title,
|
||||
email,
|
||||
address,
|
||||
...props
|
||||
}: ContactsProps) {
|
||||
return (
|
||||
<div {...props} className={cn("flex flex-col gap-4", props.className)}>
|
||||
{title && (
|
||||
<Typography
|
||||
as="h3"
|
||||
font="inter"
|
||||
align="left"
|
||||
weight="bold"
|
||||
{...title}
|
||||
className={cn(
|
||||
"leading-[24px] text-trial-payment-foreground",
|
||||
title.className
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
<div className="flex flex-col gap-3">
|
||||
{email && (
|
||||
<div className="flex items-center gap-[18px]">
|
||||
<svg
|
||||
width="14"
|
||||
height="11"
|
||||
viewBox="0 0 14 11"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="shrink-0"
|
||||
>
|
||||
<path
|
||||
d="M1.75 1.8125C1.50937 1.8125 1.3125 2.00937 1.3125 2.25V2.8543L6.0293 6.72617C6.59531 7.19102 7.40742 7.19102 7.97344 6.72617L12.6875 2.8543V2.25C12.6875 2.00937 12.4906 1.8125 12.25 1.8125H1.75ZM1.3125 4.55234V9.25C1.3125 9.49063 1.50937 9.6875 1.75 9.6875H12.25C12.4906 9.6875 12.6875 9.49063 12.6875 9.25V4.55234L8.80469 7.74062C7.75469 8.60195 6.24258 8.60195 5.19531 7.74062L1.3125 4.55234ZM0 2.25C0 1.28477 0.784766 0.5 1.75 0.5H12.25C13.2152 0.5 14 1.28477 14 2.25V9.25C14 10.2152 13.2152 11 12.25 11H1.75C0.784766 11 0 10.2152 0 9.25V2.25Z"
|
||||
fill="#6B7280"
|
||||
/>
|
||||
</svg>
|
||||
<Button
|
||||
variant="link"
|
||||
asChild
|
||||
{...email}
|
||||
className={cn(
|
||||
"text-sm/5 text-[#6B7280] font-inter underline",
|
||||
email.className
|
||||
)}
|
||||
>
|
||||
<Link href={`mailto:${email.href}`}>{email.children}</Link>
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
{address && (
|
||||
<div className="flex items-center gap-[18px]">
|
||||
<svg
|
||||
width="11"
|
||||
height="15"
|
||||
viewBox="0 0 11 15"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="shrink-0"
|
||||
>
|
||||
<path
|
||||
d="M5.89805 14.4C7.30078 12.6445 10.5 8.38984 10.5 6C10.5 3.10156 8.14844 0.75 5.25 0.75C2.35156 0.75 0 3.10156 0 6C0 8.38984 3.19922 12.6445 4.60195 14.4C4.93828 14.8184 5.56172 14.8184 5.89805 14.4ZM5.25 4.25C5.71413 4.25 6.15925 4.43437 6.48744 4.76256C6.81563 5.09075 7 5.53587 7 6C7 6.46413 6.81563 6.90925 6.48744 7.23744C6.15925 7.56563 5.71413 7.75 5.25 7.75C4.78587 7.75 4.34075 7.56563 4.01256 7.23744C3.68437 6.90925 3.5 6.46413 3.5 6C3.5 5.53587 3.68437 5.09075 4.01256 4.76256C4.34075 4.43437 4.78587 4.25 5.25 4.25Z"
|
||||
fill="#6B7280"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<Typography
|
||||
as="address"
|
||||
font="inter"
|
||||
size="sm"
|
||||
{...address}
|
||||
className={cn("text-[#6B7280] not-italic", address.className)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
71
src/components/domains/TrialPayment/Header/Header.tsx
Normal file
@ -0,0 +1,71 @@
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import Typography, {
|
||||
TypographyProps,
|
||||
} from "@/components/ui/Typography/Typography";
|
||||
import { useTimer, UseTimerOptions } from "@/hooks/timer/useTimer";
|
||||
|
||||
interface HeaderProps extends React.ComponentProps<"header"> {
|
||||
button?: React.ComponentProps<typeof Button>;
|
||||
timerHookProps?: UseTimerOptions;
|
||||
timer?: TypographyProps<"span">;
|
||||
text?: TypographyProps<"p">;
|
||||
}
|
||||
|
||||
export default function Header({
|
||||
button,
|
||||
text,
|
||||
timerHookProps,
|
||||
timer,
|
||||
...props
|
||||
}: HeaderProps) {
|
||||
const { time } = useTimer({
|
||||
initialSeconds: timerHookProps?.initialSeconds || 600,
|
||||
...timerHookProps,
|
||||
});
|
||||
|
||||
return (
|
||||
<header
|
||||
{...props}
|
||||
className={cn(
|
||||
"w-full",
|
||||
"bg-gradient-to-r from-[#FFFBEB] to-[#FFF7ED]",
|
||||
"p-4 min-h-[96px]",
|
||||
"flex justify-between items-center",
|
||||
"border-2 border-[#FDE68A] rounded-[12px]",
|
||||
"shadow-[0px_4px_6px_0px_#0000001A]",
|
||||
props.className
|
||||
)}
|
||||
>
|
||||
<div className="flex flex-col">
|
||||
{text && (
|
||||
<Typography
|
||||
size="sm"
|
||||
weight="semiBold"
|
||||
font="inter"
|
||||
{...text}
|
||||
className={cn("leading-[20px] text-[#92400E]", text.className)}
|
||||
/>
|
||||
)}
|
||||
<Typography
|
||||
size="2xl"
|
||||
weight="bold"
|
||||
font="inter"
|
||||
{...timer}
|
||||
className={cn("leading-[32px] text-[#78350F]", timer?.className)}
|
||||
>
|
||||
{time}
|
||||
</Typography>
|
||||
</div>
|
||||
{button && (
|
||||
<Button
|
||||
{...button}
|
||||
className={cn(
|
||||
"bg-[#D9780E]! rounded-[8px] font-inter py-2 px-6 font-bold animate-scale-pulse",
|
||||
button.className
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</header>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
import Typography, {
|
||||
TypographyProps,
|
||||
} from "@/components/ui/Typography/Typography";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface JoinedTodayProps extends React.ComponentProps<"div"> {
|
||||
icon?: React.ReactNode;
|
||||
count?: TypographyProps<"span">;
|
||||
text?: TypographyProps<"p">;
|
||||
}
|
||||
|
||||
export default function JoinedToday({
|
||||
icon,
|
||||
count,
|
||||
text,
|
||||
...props
|
||||
}: JoinedTodayProps) {
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
className={cn("flex items-center justify-center gap-2", props.className)}
|
||||
>
|
||||
{icon}
|
||||
{count && (
|
||||
<Typography
|
||||
as="p"
|
||||
font="inter"
|
||||
weight="bold"
|
||||
size="sm"
|
||||
align="center"
|
||||
{...count}
|
||||
className={cn("text-[#6B7280]", count.className)}
|
||||
/>
|
||||
)}
|
||||
{text && (
|
||||
<Typography
|
||||
as="p"
|
||||
font="inter"
|
||||
size="sm"
|
||||
align="center"
|
||||
{...text}
|
||||
className={cn("text-[#6B7280]", text.className)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
import Typography, {
|
||||
TypographyProps,
|
||||
} from "@/components/ui/Typography/Typography";
|
||||
import Avatars from "@/components/widgets/Avatars/Avatars";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface JoinedTodayWithAvatarsProps extends React.ComponentProps<"div"> {
|
||||
avatars?: React.ComponentProps<typeof Avatars>;
|
||||
count?: TypographyProps<"span">;
|
||||
text?: TypographyProps<"p">;
|
||||
}
|
||||
|
||||
export default function JoinedTodayWithAvatars({
|
||||
avatars,
|
||||
count,
|
||||
text,
|
||||
...props
|
||||
}: JoinedTodayWithAvatarsProps) {
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
className={cn(
|
||||
"flex flex-col items-center justify-center gap-2",
|
||||
props.className
|
||||
)}
|
||||
>
|
||||
{avatars && (
|
||||
<Avatars
|
||||
generalAvatarProps={{
|
||||
className: "size-12 ring-0!",
|
||||
}}
|
||||
{...avatars}
|
||||
/>
|
||||
)}
|
||||
{text && (
|
||||
<Typography
|
||||
size="sm"
|
||||
weight="semiBold"
|
||||
font="inter"
|
||||
{...text}
|
||||
className={cn("text-[#6B7280]", text.className)}
|
||||
>
|
||||
{count && (
|
||||
<Typography
|
||||
weight="bold"
|
||||
font="inter"
|
||||
{...count}
|
||||
className={cn(
|
||||
"inline-block text-[#6B7280] text-[18px]",
|
||||
count.className
|
||||
)}
|
||||
/>
|
||||
)}{" "}
|
||||
{text.children}
|
||||
</Typography>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
63
src/components/domains/TrialPayment/Legal/Legal.tsx
Normal file
@ -0,0 +1,63 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
import Typography, {
|
||||
TypographyProps,
|
||||
} from "@/components/ui/Typography/Typography";
|
||||
import { cn } from "@/lib/utils";
|
||||
import Link from "next/link";
|
||||
|
||||
interface LegalProps extends Omit<React.ComponentProps<"div">, "title"> {
|
||||
links?: (React.ComponentProps<typeof Button> & { href: string })[];
|
||||
copyright?: TypographyProps<"p">;
|
||||
title?: TypographyProps<"h3">;
|
||||
}
|
||||
|
||||
export default function Legal({
|
||||
links,
|
||||
copyright,
|
||||
title,
|
||||
...props
|
||||
}: LegalProps) {
|
||||
return (
|
||||
<div {...props} className={cn("flex flex-col gap-4", props.className)}>
|
||||
{title && (
|
||||
<Typography
|
||||
as="h3"
|
||||
font="inter"
|
||||
align="left"
|
||||
weight="bold"
|
||||
{...title}
|
||||
className={cn(
|
||||
"leading-[24px] text-trial-payment-foreground",
|
||||
title.className
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
<div className="flex flex-col gap-2">
|
||||
{links &&
|
||||
links.map((link, index) => (
|
||||
<Button
|
||||
variant="link"
|
||||
asChild
|
||||
{...link}
|
||||
key={link.href + index}
|
||||
className={cn(
|
||||
"text-[#6B7280] text-sm/5 font-inter font-bold no-underline!",
|
||||
link.className
|
||||
)}
|
||||
>
|
||||
<Link href={link.href}>{link.children}</Link>
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
{copyright && (
|
||||
<Typography
|
||||
as="p"
|
||||
font="inter"
|
||||
size="xs"
|
||||
{...copyright}
|
||||
className={cn("text-[#6B7280]", copyright.className)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
import Typography, {
|
||||
TypographyProps,
|
||||
} from "@/components/ui/Typography/Typography";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface MoneyBackGuaranteeProps
|
||||
extends Omit<React.ComponentProps<"div">, "title"> {
|
||||
title?: TypographyProps<"h4">;
|
||||
text?: TypographyProps<"p">;
|
||||
icon?: React.ReactNode;
|
||||
}
|
||||
|
||||
export default function MoneyBackGuarantee({
|
||||
title,
|
||||
text,
|
||||
icon,
|
||||
...props
|
||||
}: MoneyBackGuaranteeProps) {
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
className={cn(
|
||||
"w-full max-w-[316px]",
|
||||
"flex items-center justify-center gap-3",
|
||||
props.className
|
||||
)}
|
||||
>
|
||||
{icon ? (
|
||||
icon
|
||||
) : (
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="flex-shrink-0"
|
||||
>
|
||||
<g clipPath="url(#clip0_49_137)">
|
||||
<path
|
||||
d="M12 0C12.2156 0 12.4313 0.046875 12.6281 0.135938L21.4547 3.88125C22.486 4.31719 23.2547 5.33438 23.25 6.5625C23.2266 11.2125 21.3141 19.7203 13.2375 23.5875C12.4547 23.9625 11.5453 23.9625 10.7625 23.5875C2.68596 19.7203 0.773459 11.2125 0.750021 6.5625C0.745334 5.33438 1.51408 4.31719 2.54533 3.88125L11.3766 0.135938C11.5688 0.046875 11.7844 0 12 0ZM12 3.13125V20.85C18.4688 17.7188 20.2078 10.7859 20.25 6.62813L12 3.13125Z"
|
||||
fill="#3B82F6"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_49_137">
|
||||
<path d="M0 0H24V24H0V0Z" fill="white" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
)}
|
||||
<div className="flex flex-col items-start">
|
||||
{title && (
|
||||
<Typography
|
||||
as="h4"
|
||||
weight="bold"
|
||||
font="inter"
|
||||
size="sm"
|
||||
{...title}
|
||||
className={cn(
|
||||
"leading-[20px] text-trial-payment-foreground",
|
||||
title.className
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{text && (
|
||||
<Typography
|
||||
as="p"
|
||||
weight="medium"
|
||||
font="inter"
|
||||
size="xs"
|
||||
{...text}
|
||||
className={cn("leading-[16px] text-[#6B7280]", text.className)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
import Typography, {
|
||||
TypographyProps,
|
||||
} from "@/components/ui/Typography/Typography";
|
||||
import { cn } from "@/lib/utils";
|
||||
import Image from "next/image";
|
||||
|
||||
interface PaymentMethodsProps
|
||||
extends Omit<React.ComponentProps<"div">, "title"> {
|
||||
title?: TypographyProps<"h3">;
|
||||
methods?: React.ComponentProps<typeof Image>[];
|
||||
}
|
||||
|
||||
export default function PaymentMethods({
|
||||
title,
|
||||
methods,
|
||||
...props
|
||||
}: PaymentMethodsProps) {
|
||||
return (
|
||||
<div {...props} className={cn("flex flex-col gap-4", props.className)}>
|
||||
{title && (
|
||||
<Typography
|
||||
as="h3"
|
||||
font="inter"
|
||||
align="left"
|
||||
weight="bold"
|
||||
{...title}
|
||||
className={cn(
|
||||
"leading-[24px] text-trial-payment-foreground",
|
||||
title.className
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
<div className="flex items-center gap-4">
|
||||
{methods &&
|
||||
methods.map((method, index) => (
|
||||
<Image
|
||||
width={34}
|
||||
height={27}
|
||||
{...method}
|
||||
alt={method.alt}
|
||||
key={index}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
24
src/components/domains/TrialPayment/Policy/Policy.tsx
Normal file
@ -0,0 +1,24 @@
|
||||
import Typography, {
|
||||
TypographyProps,
|
||||
} from "@/components/ui/Typography/Typography";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface PolicyProps extends React.ComponentProps<"div"> {
|
||||
text?: TypographyProps<"p">;
|
||||
}
|
||||
|
||||
export default function Policy({ text, ...props }: PolicyProps) {
|
||||
return (
|
||||
<div {...props} className={cn("w-full", props.className)}>
|
||||
{text && (
|
||||
<Typography
|
||||
as="p"
|
||||
font="inter"
|
||||
size="xs"
|
||||
{...text}
|
||||
className={cn("text-[#6B7280]", text.className)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,80 @@
|
||||
import { Progress } from "@/components/ui/progress";
|
||||
import Typography, {
|
||||
TypographyProps,
|
||||
} from "@/components/ui/Typography/Typography";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface ProgressToSeeSoulmateProps
|
||||
extends Omit<React.ComponentProps<"div">, "title"> {
|
||||
title: TypographyProps<"h3">;
|
||||
progress: React.ComponentProps<typeof Progress>;
|
||||
progressText?: {
|
||||
leftText?: TypographyProps<"span">;
|
||||
rightText?: TypographyProps<"span">;
|
||||
};
|
||||
}
|
||||
|
||||
export default function ProgressToSeeSoulmate({
|
||||
title,
|
||||
progress,
|
||||
progressText,
|
||||
...props
|
||||
}: ProgressToSeeSoulmateProps) {
|
||||
return (
|
||||
<div {...props} className={cn("w-full", props.className)}>
|
||||
{title && (
|
||||
<Typography
|
||||
as="h3"
|
||||
weight="bold"
|
||||
font="inter"
|
||||
align="center"
|
||||
{...title}
|
||||
className={cn(
|
||||
"text-[22px]/[28px] text-trial-payment-foreground",
|
||||
title.className
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
<div className="mt-7 flex flex-col gap-2">
|
||||
{progressText && (
|
||||
<div className="w-full flex items-center justify-between">
|
||||
{progressText.leftText && (
|
||||
<Typography
|
||||
as="span"
|
||||
size="sm"
|
||||
font="inter"
|
||||
weight="medium"
|
||||
{...progressText.leftText}
|
||||
className={cn(
|
||||
"text-[#1047A2] leading-[20px]",
|
||||
progressText.leftText.className
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{progressText.rightText && (
|
||||
<Typography
|
||||
as="span"
|
||||
size="sm"
|
||||
font="inter"
|
||||
{...progressText.rightText}
|
||||
className={cn(
|
||||
"text-[#6B7280] leading-[20px]",
|
||||
progressText.rightText.className
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{progress && (
|
||||
<Progress
|
||||
{...progress}
|
||||
classNameProgressContainer={cn(
|
||||
"h-2 [&>div]:bg-[#1047A2]",
|
||||
progress.classNameProgressContainer
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
100
src/components/domains/TrialPayment/Review/Review.tsx
Normal file
@ -0,0 +1,100 @@
|
||||
import Typography, {
|
||||
TypographyProps,
|
||||
} from "@/components/ui/Typography/Typography";
|
||||
import Stars from "@/components/widgets/Stars/Stars";
|
||||
import { cn } from "@/lib/utils";
|
||||
import Image from "next/image";
|
||||
import { Card } from "..";
|
||||
import { ArrowRight } from "lucide-react";
|
||||
import Avatar from "@/components/ui/Avatar/Avatar";
|
||||
|
||||
interface ReviewProps extends React.ComponentProps<typeof Card> {
|
||||
avatar?: React.ComponentProps<typeof Avatar>;
|
||||
name?: TypographyProps<"span">;
|
||||
stars?: React.ComponentProps<typeof Stars>;
|
||||
date?: TypographyProps<"span">;
|
||||
text?: TypographyProps<"p">;
|
||||
portrait?: React.ComponentProps<typeof Image>;
|
||||
photo?: React.ComponentProps<typeof Image>;
|
||||
}
|
||||
|
||||
export default function Review({
|
||||
stars,
|
||||
avatar,
|
||||
name,
|
||||
date,
|
||||
text,
|
||||
portrait,
|
||||
photo,
|
||||
...props
|
||||
}: ReviewProps) {
|
||||
return (
|
||||
<Card {...props}>
|
||||
<div className={cn("w-full flex items-center gap-3")}>
|
||||
{avatar && (
|
||||
<Avatar {...avatar} className={cn("size-10", avatar.className)} />
|
||||
)}
|
||||
<div className={cn("flex flex-col gap-0.5")}>
|
||||
{name && (
|
||||
<Typography
|
||||
font="inter"
|
||||
weight="semiBold"
|
||||
size="sm"
|
||||
{...name}
|
||||
className={cn(
|
||||
"text-trial-payment-foreground leading-[20px]",
|
||||
name.className
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
<div className={cn("flex items-center gap-2")}>
|
||||
{stars && <Stars {...stars} />}
|
||||
{date && (
|
||||
<Typography
|
||||
font="inter"
|
||||
size="xs"
|
||||
{...date}
|
||||
className={cn("text-[#6B7280] leading-4", date.className)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{text && (
|
||||
<Typography
|
||||
font="inter"
|
||||
size="sm"
|
||||
{...text}
|
||||
className={cn("text-trial-payment-foreground mt-3.5", text.className)}
|
||||
/>
|
||||
)}
|
||||
<div className={cn("w-full flex items-center gap-[9px] mt-5")}>
|
||||
{portrait && (
|
||||
<Image
|
||||
width={64}
|
||||
height={64}
|
||||
{...portrait}
|
||||
alt={portrait.alt || "Portrait"}
|
||||
className={cn(
|
||||
"size-16 rounded-[8px] object-cover border-2 border-border-white shadow-trial-payment-review-photo",
|
||||
portrait.className
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
<ArrowRight color={"var(--color-primary)"} />
|
||||
{photo && (
|
||||
<Image
|
||||
width={64}
|
||||
height={64}
|
||||
{...photo}
|
||||
alt={photo.alt || "Photo"}
|
||||
className={cn(
|
||||
"size-16 rounded-[8px] object-cover border-2 border-border-white shadow-trial-payment-review-photo",
|
||||
photo.className
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
import Typography, {
|
||||
TypographyProps,
|
||||
} from "@/components/ui/Typography/Typography";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface TrustedByOverProps extends React.ComponentProps<"div"> {
|
||||
icon?: React.ReactNode;
|
||||
text?: TypographyProps<"p">;
|
||||
}
|
||||
|
||||
export default function TrustedByOver({
|
||||
icon,
|
||||
text,
|
||||
...props
|
||||
}: TrustedByOverProps) {
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
className={cn("flex items-center justify-center gap-2", props.className)}
|
||||
>
|
||||
{icon}
|
||||
{text && (
|
||||
<Typography
|
||||
as="p"
|
||||
font="inter"
|
||||
size="sm"
|
||||
align="center"
|
||||
{...text}
|
||||
className={cn("text-[#6B7280]", text.className)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
13
src/components/domains/TrialPayment/index.ts
Normal file
@ -0,0 +1,13 @@
|
||||
export { default as Header } from "./Header/Header";
|
||||
export { default as Card } from "./Card/Card";
|
||||
export { default as JoinedToday } from "./JoinedToday/JoinedToday";
|
||||
export { default as TrustedByOver } from "./TrustedByOver/TrustedByOver";
|
||||
export { default as MoneyBackGuarantee } from "./MoneyBackGuarantee/MoneyBackGuarantee";
|
||||
export { default as Policy } from "./Policy/Policy";
|
||||
export { default as JoinedTodayWithAvatars } from "./JoinedTodayWithAvatars/JoinedTodayWithAvatars";
|
||||
export { default as ProgressToSeeSoulmate } from "./ProgressToSeeSoulmate/ProgressToSeeSoulmate";
|
||||
export { default as Review } from "./Review/Review";
|
||||
export { default as CommonQuestion } from "./CommonQuestion/CommonQuestion";
|
||||
export { default as Contacts } from "./Contacts/Contacts";
|
||||
export { default as Legal } from "./Legal/Legal";
|
||||
export { default as PaymentMethods } from "./PaymentMethods/PaymentMethods";
|
||||
@ -1,6 +1,7 @@
|
||||
import { Meta, StoryObj } from "@storybook/nextjs-vite";
|
||||
import SoulmatePortrait from "./SoulmatePortrait";
|
||||
import { fn } from "storybook/test";
|
||||
import Typography from "@/components/ui/Typography/Typography";
|
||||
|
||||
/** Reusable SoulmatePortrait page Component */
|
||||
const meta: Meta<typeof SoulmatePortrait> = {
|
||||
@ -30,6 +31,74 @@ const meta: Meta<typeof SoulmatePortrait> = {
|
||||
title: {
|
||||
children: "Soulmate Portrait",
|
||||
},
|
||||
subtitle: {
|
||||
children: "Готов увидеть, кто твоя настоящая Родственная душа?",
|
||||
},
|
||||
textListProps: {
|
||||
items: [
|
||||
{
|
||||
children:
|
||||
"Всего 2 минуты — и Портрет откроет того, кто связан с тобой судьбой.",
|
||||
},
|
||||
{
|
||||
children: "Поразительная точность 99%.",
|
||||
},
|
||||
{
|
||||
children: "Тебя ждёт неожиданное открытие.",
|
||||
},
|
||||
{
|
||||
children: "Осталось лишь осмелиться взглянуть.",
|
||||
},
|
||||
],
|
||||
},
|
||||
soulmatePortraitsDeliveredProps: {
|
||||
image: "/soulmate-portrait-delivered-male.jpg",
|
||||
textProps: {
|
||||
children: "soulmate portraits delivered today",
|
||||
},
|
||||
avatarsProps: {
|
||||
avatars: [
|
||||
{
|
||||
imageProps: {
|
||||
src: "/avatars/male-1.jpg",
|
||||
alt: "Male 1",
|
||||
},
|
||||
fallbackProps: {
|
||||
children: "M1",
|
||||
},
|
||||
},
|
||||
{
|
||||
imageProps: {
|
||||
src: "/avatars/male-2.jpg",
|
||||
alt: "Male 2",
|
||||
},
|
||||
fallbackProps: {
|
||||
children: "M2",
|
||||
},
|
||||
},
|
||||
{
|
||||
imageProps: {
|
||||
src: "/avatars/male-3.jpg",
|
||||
alt: "Male 3",
|
||||
},
|
||||
fallbackProps: {
|
||||
children: "M3",
|
||||
},
|
||||
},
|
||||
{
|
||||
fallbackProps: {
|
||||
children: (
|
||||
<Typography size="xs" weight="bold" className="text-[#FF6B9D]">
|
||||
900+
|
||||
</Typography>
|
||||
),
|
||||
className: "bg-background",
|
||||
},
|
||||
className: "w-fit px-1",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
argTypes: {},
|
||||
};
|
||||
|
||||
@ -3,6 +3,7 @@ import Typography, {
|
||||
} from "@/components/ui/Typography/Typography";
|
||||
import { BottomActionButton } from "@/components/widgets/BottomActionButton/BottomActionButton";
|
||||
import PrivacyTermsConsent from "@/components/widgets/PrivacyTermsConsent/PrivacyTermsConsent";
|
||||
import SoulmatePortraitsDelivered from "@/components/widgets/SoulmatePortraitsDelivered/SoulmatePortraitsDelivered";
|
||||
import { useDynamicSize } from "@/hooks/DOM/useDynamicSize";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
@ -10,13 +11,23 @@ export interface SoulmatePortraitProps
|
||||
extends Omit<React.ComponentProps<"div">, "title"> {
|
||||
bottomActionButtonProps?: React.ComponentProps<typeof BottomActionButton>;
|
||||
privacyTermsConsentProps?: React.ComponentProps<typeof PrivacyTermsConsent>;
|
||||
title?: TypographyProps<"h2">;
|
||||
title?: TypographyProps<"h1">;
|
||||
soulmatePortraitsDeliveredProps?: React.ComponentProps<
|
||||
typeof SoulmatePortraitsDelivered
|
||||
>;
|
||||
subtitle?: TypographyProps<"h2">;
|
||||
textListProps?: React.ComponentProps<"ul"> & {
|
||||
items: TypographyProps<"li">[];
|
||||
};
|
||||
}
|
||||
|
||||
export default function SoulmatePortrait({
|
||||
bottomActionButtonProps,
|
||||
privacyTermsConsentProps,
|
||||
title,
|
||||
subtitle,
|
||||
soulmatePortraitsDeliveredProps,
|
||||
textListProps,
|
||||
...props
|
||||
}: SoulmatePortraitProps) {
|
||||
const {
|
||||
@ -28,7 +39,7 @@ export default function SoulmatePortrait({
|
||||
|
||||
return (
|
||||
<div
|
||||
className="w-full flex flex-col items-center gap-[30px]"
|
||||
className="w-full min-h-dvh flex flex-col items-center gap-[30px] px-[27px]"
|
||||
{...props}
|
||||
style={{
|
||||
paddingBottom: `${bottomActionButtonHeight}px`,
|
||||
@ -41,11 +52,46 @@ export default function SoulmatePortrait({
|
||||
as="h2"
|
||||
size="xl"
|
||||
weight="bold"
|
||||
align="center"
|
||||
{...title}
|
||||
className={cn(title.className, "leading-[125%] text-primary")}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{soulmatePortraitsDeliveredProps && (
|
||||
<SoulmatePortraitsDelivered {...soulmatePortraitsDeliveredProps} />
|
||||
)}
|
||||
<div className="w-full flex flex-col items-center gap-2.5">
|
||||
{subtitle && (
|
||||
<Typography
|
||||
as="h2"
|
||||
weight="bold"
|
||||
align="center"
|
||||
{...subtitle}
|
||||
className={cn(subtitle.className, "leading-[125%] text-[25px]")}
|
||||
/>
|
||||
)}
|
||||
{textListProps && (
|
||||
<ul
|
||||
{...textListProps}
|
||||
className={cn("list-disc pl-6", textListProps?.className)}
|
||||
>
|
||||
{textListProps?.items.map((item, index) => (
|
||||
<Typography
|
||||
as="li"
|
||||
font="inter"
|
||||
weight="medium"
|
||||
{...item}
|
||||
className={cn(
|
||||
"list-item text-[17px] leading-[26px]",
|
||||
item.className
|
||||
)}
|
||||
key={index}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
{bottomActionButtonProps && (
|
||||
<BottomActionButton
|
||||
{...bottomActionButtonProps}
|
||||
|
||||
781
src/components/templates/TrialPayment/TrialPayment.stories.tsx
Normal file
@ -0,0 +1,781 @@
|
||||
import { Meta, StoryObj } from "@storybook/nextjs-vite";
|
||||
import TrialPayment from "./TrialPayment";
|
||||
import { fn } from "storybook/test";
|
||||
|
||||
/** Reusable TrialPayment page Component */
|
||||
const meta: Meta<typeof TrialPayment> = {
|
||||
title: "Templates/TrialPayment",
|
||||
component: TrialPayment,
|
||||
tags: ["autodocs"],
|
||||
parameters: {
|
||||
layout: "fullscreen",
|
||||
},
|
||||
args: {
|
||||
header: {
|
||||
timerHookProps: {
|
||||
initialSeconds: 600,
|
||||
},
|
||||
text: {
|
||||
children: "⚠️ Your sketch expires soon!",
|
||||
},
|
||||
button: {
|
||||
children: "ПОЛУЧИТЬ",
|
||||
onClick: fn(),
|
||||
},
|
||||
},
|
||||
unlockYourSketch: {
|
||||
title: {
|
||||
children: "Unlock Your Sketch",
|
||||
},
|
||||
subtitle: {
|
||||
children: "Just One Click to Reveal Your Match!",
|
||||
},
|
||||
image: {
|
||||
src: "/trial-payment/portrait-female.jpg",
|
||||
alt: "wall portrait female",
|
||||
priority: true,
|
||||
},
|
||||
blur: {
|
||||
text: {
|
||||
children: "Unlock to reveal your personalized portrait",
|
||||
},
|
||||
icon: (
|
||||
<svg
|
||||
width="18"
|
||||
height="21"
|
||||
viewBox="0 0 18 21"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M5.625 6.125V8H11.875V6.125C11.875 4.39844 10.4766 3 8.75 3C7.02344 3 5.625 4.39844 5.625 6.125ZM3.125 8V6.125C3.125 3.01953 5.64453 0.5 8.75 0.5C11.8555 0.5 14.375 3.01953 14.375 6.125V8H15C16.3789 8 17.5 9.12109 17.5 10.5V18C17.5 19.3789 16.3789 20.5 15 20.5H2.5C1.12109 20.5 0 19.3789 0 18V10.5C0 9.12109 1.12109 8 2.5 8H3.125Z"
|
||||
fill="#A16207"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
button: {
|
||||
children: "Get Me Soulmate Sketch",
|
||||
onClick: fn(),
|
||||
},
|
||||
},
|
||||
joinedToday: {
|
||||
icon: (
|
||||
<svg
|
||||
width="15"
|
||||
height="13"
|
||||
viewBox="0 0 15 13"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M2.23906 7.96384L7.18008 12.5767C7.38516 12.7681 7.65586 12.8748 7.9375 12.8748C8.21914 12.8748 8.48984 12.7681 8.69492 12.5767L13.6359 7.96384C14.4672 7.19001 14.9375 6.10447 14.9375 4.9697V4.81111C14.9375 2.89978 13.5566 1.27009 11.6727 0.95564C10.4258 0.747827 9.15703 1.15525 8.26562 2.04666L7.9375 2.37478L7.60938 2.04666C6.71797 1.15525 5.44922 0.747827 4.20234 0.95564C2.31836 1.27009 0.9375 2.89978 0.9375 4.81111V4.9697C0.9375 6.10447 1.40781 7.19001 2.23906 7.96384Z"
|
||||
fill="#1047A2"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
count: {
|
||||
children: "954",
|
||||
},
|
||||
text: {
|
||||
children: "Joined today",
|
||||
},
|
||||
},
|
||||
trustedByOver: {
|
||||
icon: (
|
||||
<svg
|
||||
width="19"
|
||||
height="15"
|
||||
viewBox="0 0 19 15"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M4.6875 0.75C5.26766 0.75 5.82406 0.980468 6.2343 1.3907C6.64453 1.80094 6.875 2.35734 6.875 2.9375C6.875 3.51766 6.64453 4.07406 6.2343 4.4843C5.82406 4.89453 5.26766 5.125 4.6875 5.125C4.10734 5.125 3.55094 4.89453 3.1407 4.4843C2.73047 4.07406 2.5 3.51766 2.5 2.9375C2.5 2.35734 2.73047 1.80094 3.1407 1.3907C3.55094 0.980468 4.10734 0.75 4.6875 0.75ZM14.75 0.75C15.3302 0.75 15.8866 0.980468 16.2968 1.3907C16.707 1.80094 16.9375 2.35734 16.9375 2.9375C16.9375 3.51766 16.707 4.07406 16.2968 4.4843C15.8866 4.89453 15.3302 5.125 14.75 5.125C14.1698 5.125 13.6134 4.89453 13.2032 4.4843C12.793 4.07406 12.5625 3.51766 12.5625 2.9375C12.5625 2.35734 12.793 1.80094 13.2032 1.3907C13.6134 0.980468 14.1698 0.75 14.75 0.75ZM0.75 8.91758C0.75 7.30703 2.05703 6 3.66758 6H4.83516C5.26992 6 5.68281 6.0957 6.05469 6.26523C6.01914 6.46211 6.00273 6.66719 6.00273 6.875C6.00273 7.91953 6.46211 8.85742 7.18672 9.5C7.18125 9.5 7.17578 9.5 7.16758 9.5H1.33242C1.0125 9.5 0.75 9.2375 0.75 8.91758ZM11.8324 9.5C11.827 9.5 11.8215 9.5 11.8133 9.5C12.5406 8.85742 12.9973 7.91953 12.9973 6.875C12.9973 6.66719 12.9781 6.46484 12.9453 6.26523C13.3172 6.09297 13.7301 6 14.1648 6H15.3324C16.943 6 18.25 7.30703 18.25 8.91758C18.25 9.24023 17.9875 9.5 17.6676 9.5H11.8324ZM6.875 6.875C6.875 6.17881 7.15156 5.51113 7.64384 5.01884C8.13613 4.52656 8.80381 4.25 9.5 4.25C10.1962 4.25 10.8639 4.52656 11.3562 5.01884C11.8484 5.51113 12.125 6.17881 12.125 6.875C12.125 7.57119 11.8484 8.23887 11.3562 8.73116C10.8639 9.22344 10.1962 9.5 9.5 9.5C8.80381 9.5 8.13613 9.22344 7.64384 8.73116C7.15156 8.23887 6.875 7.57119 6.875 6.875ZM4.25 14.0199C4.25 12.0074 5.88242 10.375 7.89492 10.375H11.1051C13.1176 10.375 14.75 12.0074 14.75 14.0199C14.75 14.4219 14.4246 14.75 14.0199 14.75H4.98008C4.57812 14.75 4.25 14.4246 4.25 14.0199Z"
|
||||
fill="#1047A2"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
text: {
|
||||
children: (
|
||||
<>
|
||||
Trusted by over <b>355,000</b> people.
|
||||
</>
|
||||
),
|
||||
},
|
||||
},
|
||||
findingOneGuide: {
|
||||
header: {
|
||||
emoji: {
|
||||
children: "❤️",
|
||||
},
|
||||
title: {
|
||||
children: "Finding the One Guide",
|
||||
},
|
||||
},
|
||||
text: {
|
||||
children:
|
||||
"You're not just looking for someone — you're. You're not just looking for someone — you'reYou're not just looking for someone — you'reYou're not just looking for someone — you'reYou're not just looking for someone — you're. You're not just looking for someone — you're. You're not just looking for someone — you'reYou're not just looking for someone — you'reYou're not just looking for someone — you'reYou're not just looking for someone — you're",
|
||||
},
|
||||
blur: {
|
||||
text: {
|
||||
children: "Чтобы открыть весь отчёт, нужен полный доступ.",
|
||||
},
|
||||
icon: (
|
||||
<svg
|
||||
width="18"
|
||||
height="21"
|
||||
viewBox="0 0 18 21"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M5.625 6.125V8H11.875V6.125C11.875 4.39844 10.4766 3 8.75 3C7.02344 3 5.625 4.39844 5.625 6.125ZM3.125 8V6.125C3.125 3.01953 5.64453 0.5 8.75 0.5C11.8555 0.5 14.375 3.01953 14.375 6.125V8H15C16.3789 8 17.5 9.12109 17.5 10.5V18C17.5 19.3789 16.3789 20.5 15 20.5H2.5C1.12109 20.5 0 19.3789 0 18V10.5C0 9.12109 1.12109 8 2.5 8H3.125Z"
|
||||
fill="#A16207"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
},
|
||||
tryForDays: {
|
||||
title: {
|
||||
children: "Попробуйте в течение 7 дней!",
|
||||
},
|
||||
textListProps: {
|
||||
items: [
|
||||
{
|
||||
children:
|
||||
"Receive a hand-drawn sketch of your soulmate, crafted by a trained AI-model.",
|
||||
},
|
||||
{
|
||||
children:
|
||||
"Reveal the path to your soulmate with the Finding the One guide.",
|
||||
},
|
||||
{
|
||||
children:
|
||||
"Talk to live experts and get guidance on finding your soulmate.",
|
||||
},
|
||||
{
|
||||
children:
|
||||
"Start your 7-day trial for just $1.00 — then only $14.50/week for full access.",
|
||||
},
|
||||
{
|
||||
children: "Cancel anytime—just 24 hours before renewal.",
|
||||
},
|
||||
],
|
||||
listStyleType: "none",
|
||||
},
|
||||
},
|
||||
totalPrice: {
|
||||
couponContainer: {
|
||||
title: {
|
||||
children: (
|
||||
<>
|
||||
Coupon
|
||||
<br />
|
||||
Code
|
||||
</>
|
||||
),
|
||||
},
|
||||
button: {
|
||||
children: "SOULMATE94",
|
||||
onClick: fn(),
|
||||
},
|
||||
},
|
||||
priceContainer: {
|
||||
title: {
|
||||
children: "Total",
|
||||
},
|
||||
price: {
|
||||
children: "$1.00",
|
||||
},
|
||||
oldPrice: {
|
||||
children: "$14.99",
|
||||
},
|
||||
discount: {
|
||||
children: "94% discount applied",
|
||||
},
|
||||
},
|
||||
},
|
||||
paymentButtons: {
|
||||
buttons: [
|
||||
{
|
||||
children: "Pay",
|
||||
icon: (
|
||||
<svg
|
||||
width="19"
|
||||
height="24"
|
||||
viewBox="0 0 19 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g clipPath="url(#clip0_49_113)">
|
||||
<path
|
||||
d="M15.8141 12.5953C15.8047 10.875 16.5828 9.57656 18.1578 8.62031C17.2766 7.35938 15.9453 6.66563 14.1875 6.52969C12.5234 6.39844 10.7047 7.5 10.0391 7.5C9.33594 7.5 7.72344 6.57656 6.45781 6.57656C3.84219 6.61875 1.0625 8.6625 1.0625 12.8203C1.0625 14.0484 1.2875 15.3172 1.7375 16.6266C2.3375 18.3469 4.50312 22.5656 6.7625 22.4953C7.94375 22.4672 8.77812 21.6563 10.3156 21.6563C11.8062 21.6563 12.5797 22.4953 13.8969 22.4953C16.175 22.4625 18.1344 18.6281 18.7062 16.9031C15.65 15.4641 15.8141 12.6844 15.8141 12.5953ZM13.1609 4.89844C14.4406 3.37969 14.3234 1.99688 14.2859 1.5C13.1562 1.56563 11.8484 2.26875 11.1031 3.13594C10.2828 4.06406 9.8 5.2125 9.90313 6.50625C11.1266 6.6 12.2422 5.97188 13.1609 4.89844Z"
|
||||
fill="white"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_49_113">
|
||||
<path d="M0.875 0H18.875V24H0.875V0Z" fill="white" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
children: "Pay",
|
||||
icon: (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 48 48"
|
||||
>
|
||||
<path
|
||||
fill="#FFC107"
|
||||
d="M43.611,20.083H42V20H24v8h11.303c-1.649,4.657-6.08,8-11.303,8c-6.627,0-12-5.373-12-12c0-6.627,5.373-12,12-12c3.059,0,5.842,1.154,7.961,3.039l5.657-5.657C34.046,6.053,29.268,4,24,4C12.955,4,4,12.955,4,24c0,11.045,8.955,20,20,20c11.045,0,20-8.955,20-20C44,22.659,43.862,21.35,43.611,20.083z"
|
||||
></path>
|
||||
<path
|
||||
fill="#FF3D00"
|
||||
d="M6.306,14.691l6.571,4.819C14.655,15.108,18.961,12,24,12c3.059,0,5.842,1.154,7.961,3.039l5.657-5.657C34.046,6.053,29.268,4,24,4C16.318,4,9.656,8.337,6.306,14.691z"
|
||||
></path>
|
||||
<path
|
||||
fill="#4CAF50"
|
||||
d="M24,44c5.166,0,9.86-1.977,13.409-5.192l-6.19-5.238C29.211,35.091,26.715,36,24,36c-5.202,0-9.619-3.317-11.283-7.946l-6.522,5.025C9.505,39.556,16.227,44,24,44z"
|
||||
></path>
|
||||
<path
|
||||
fill="#1976D2"
|
||||
d="M43.611,20.083H42V20H24v8h11.303c-0.792,2.237-2.231,4.166-4.087,5.571c0.001-0.001,0.002-0.001,0.003-0.002l6.19,5.238C36.971,39.205,44,34,44,24C44,22.659,43.862,21.35,43.611,20.083z"
|
||||
></path>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
children: "Credit or debit card",
|
||||
icon: (
|
||||
<svg
|
||||
width="19"
|
||||
height="16"
|
||||
viewBox="0 0 19 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g clipPath="url(#clip0_49_125)">
|
||||
<path
|
||||
d="M16.0312 2.5C16.3062 2.5 16.5312 2.725 16.5312 3V4H1.53125V3C1.53125 2.725 1.75625 2.5 2.03125 2.5H16.0312ZM16.5312 7V13C16.5312 13.275 16.3062 13.5 16.0312 13.5H2.03125C1.75625 13.5 1.53125 13.275 1.53125 13V7H16.5312ZM2.03125 1C0.928125 1 0.03125 1.89688 0.03125 3V13C0.03125 14.1031 0.928125 15 2.03125 15H16.0312C17.1344 15 18.0312 14.1031 18.0312 13V3C18.0312 1.89688 17.1344 1 16.0312 1H2.03125ZM3.78125 10.5C3.36562 10.5 3.03125 10.8344 3.03125 11.25C3.03125 11.6656 3.36562 12 3.78125 12H5.28125C5.69688 12 6.03125 11.6656 6.03125 11.25C6.03125 10.8344 5.69688 10.5 5.28125 10.5H3.78125ZM7.78125 10.5C7.36562 10.5 7.03125 10.8344 7.03125 11.25C7.03125 11.6656 7.36562 12 7.78125 12H11.2812C11.6969 12 12.0312 11.6656 12.0312 11.25C12.0312 10.8344 11.6969 10.5 11.2812 10.5H7.78125Z"
|
||||
fill="white"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_49_125">
|
||||
<path d="M0.03125 0H18.0312V16H0.03125V0Z" fill="white" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
),
|
||||
className: "bg-primary",
|
||||
},
|
||||
],
|
||||
},
|
||||
moneyBackGuarantee: {
|
||||
title: {
|
||||
children: "30-DAY MONEY-BACK GUARANTEE",
|
||||
},
|
||||
text: {
|
||||
children:
|
||||
"If you don't receive your soulmate sketch, we'll refund your money!",
|
||||
},
|
||||
},
|
||||
policy: {
|
||||
text: {
|
||||
children:
|
||||
"By clicking Continue, you agree to our Terms of Use & Service and Privacy Policy. You also acknowledge that your 1 week introductory plan to Respontika, billed at $1.00, will automatically renew at $14.50 every 1 week unless canceled before the end of the trial period.",
|
||||
},
|
||||
},
|
||||
usersPortraits: {
|
||||
title: {
|
||||
children: "Our Users' Soulmate Portraits",
|
||||
},
|
||||
imgs: [
|
||||
{
|
||||
src: "/trial-payment/users-portraits/1.jpg",
|
||||
alt: "wall portrait 1",
|
||||
},
|
||||
{
|
||||
src: "/trial-payment/users-portraits/2.jpg",
|
||||
alt: "wall portrait 2",
|
||||
},
|
||||
{
|
||||
src: "/trial-payment/users-portraits/3.jpg",
|
||||
alt: "wall portrait 3",
|
||||
},
|
||||
],
|
||||
button: {
|
||||
children: "Get me soulmate sketch",
|
||||
onClick: fn(),
|
||||
},
|
||||
},
|
||||
joinedTodayWithAvatars: {
|
||||
avatars: {
|
||||
avatars: [
|
||||
{
|
||||
imageProps: {
|
||||
src: "/trial-payment/avatars/1.jpg",
|
||||
alt: "Avatar 1",
|
||||
},
|
||||
fallbackProps: {
|
||||
children: "A1",
|
||||
},
|
||||
},
|
||||
{
|
||||
imageProps: {
|
||||
src: "/trial-payment/avatars/2.jpg",
|
||||
alt: "Avatar 2",
|
||||
},
|
||||
fallbackProps: {
|
||||
children: "A2",
|
||||
},
|
||||
},
|
||||
{
|
||||
imageProps: {
|
||||
src: "/trial-payment/avatars/3.jpg",
|
||||
alt: "Avatar 3",
|
||||
},
|
||||
fallbackProps: {
|
||||
children: "A3",
|
||||
},
|
||||
},
|
||||
{
|
||||
imageProps: {
|
||||
src: "/trial-payment/avatars/4.jpg",
|
||||
alt: "Avatar 4",
|
||||
},
|
||||
fallbackProps: {
|
||||
children: "A4",
|
||||
},
|
||||
},
|
||||
{
|
||||
imageProps: {
|
||||
src: "/trial-payment/avatars/5.jpg",
|
||||
alt: "Avatar 5",
|
||||
},
|
||||
fallbackProps: {
|
||||
children: "A5",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
count: {
|
||||
children: "954",
|
||||
},
|
||||
text: {
|
||||
children: "people joined today",
|
||||
},
|
||||
},
|
||||
progressToSeeSoulmate: {
|
||||
title: {
|
||||
children: "See Your Soulmate – Just One Step Away",
|
||||
},
|
||||
progress: {
|
||||
value: 92,
|
||||
},
|
||||
progressText: {
|
||||
leftText: {
|
||||
children: "Step 2 of 5",
|
||||
},
|
||||
rightText: {
|
||||
children: "99% Complete",
|
||||
},
|
||||
},
|
||||
},
|
||||
stepsToSeeSoulmate: {
|
||||
steps: [
|
||||
{
|
||||
title: { children: "Questions Answered" },
|
||||
description: {
|
||||
children:
|
||||
"You've provided all the necessary information about your preferences and personality.",
|
||||
},
|
||||
icon: (
|
||||
<svg
|
||||
width="12"
|
||||
height="15"
|
||||
viewBox="0 0 12 15"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M6 0.75C4.85703 0.75 3.88359 1.48008 3.52539 2.5H2.5C1.53477 2.5 0.75 3.28477 0.75 4.25V13C0.75 13.9652 1.53477 14.75 2.5 14.75H9.5C10.4652 14.75 11.25 13.9652 11.25 13V4.25C11.25 3.28477 10.4652 2.5 9.5 2.5H8.47461C8.11641 1.48008 7.14297 0.75 6 0.75ZM6 2.5C6.23206 2.5 6.45462 2.59219 6.61872 2.75628C6.78281 2.92038 6.875 3.14294 6.875 3.375C6.875 3.60706 6.78281 3.82962 6.61872 3.99372C6.45462 4.15781 6.23206 4.25 6 4.25C5.76794 4.25 5.54538 4.15781 5.38128 3.99372C5.21719 3.82962 5.125 3.60706 5.125 3.375C5.125 3.14294 5.21719 2.92038 5.38128 2.75628C5.54538 2.59219 5.76794 2.5 6 2.5ZM3.64297 7.01992C3.85898 6.41016 4.43867 6 5.08672 6H6.68086C7.63516 6 8.40625 6.77383 8.40625 7.72539C8.40625 8.34336 8.07539 8.91484 7.53945 9.22383L6.65625 9.72969C6.65078 10.0852 6.3582 10.375 6 10.375C5.63633 10.375 5.34375 10.0824 5.34375 9.71875V9.34961C5.34375 9.11445 5.46953 8.89844 5.67461 8.78086L6.88594 8.08633C7.01445 8.0125 7.09375 7.87578 7.09375 7.72813C7.09375 7.49844 6.90781 7.31523 6.68086 7.31523H5.08672C4.99375 7.31523 4.91172 7.37266 4.88164 7.46016L4.8707 7.49297C4.75039 7.83477 4.37305 8.0125 4.03398 7.89219C3.69492 7.77188 3.51445 7.39453 3.63477 7.05547L3.6457 7.02266L3.64297 7.01992ZM5.125 12.125C5.125 11.8929 5.21719 11.6704 5.38128 11.5063C5.54538 11.3422 5.76794 11.25 6 11.25C6.23206 11.25 6.45462 11.3422 6.61872 11.5063C6.78281 11.6704 6.875 11.8929 6.875 12.125C6.875 12.3571 6.78281 12.5796 6.61872 12.7437C6.45462 12.9078 6.23206 13 6 13C5.76794 13 5.54538 12.9078 5.38128 12.7437C5.21719 12.5796 5.125 12.3571 5.125 12.125Z"
|
||||
fill="white"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
isActive: true,
|
||||
},
|
||||
{
|
||||
title: { children: "Profile Analysis" },
|
||||
description: {
|
||||
children:
|
||||
"Our advanced system is creating your perfect soulmate profile.",
|
||||
},
|
||||
icon: (
|
||||
<svg
|
||||
width="14"
|
||||
height="15"
|
||||
viewBox="0 0 14 15"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M5.03125 0.75C5.87617 0.75 6.5625 1.43633 6.5625 2.28125V13.2188C6.5625 14.0637 5.87617 14.75 5.03125 14.75C4.24102 14.75 3.59023 14.1512 3.5082 13.3801C3.36602 13.4184 3.21563 13.4375 3.0625 13.4375C2.09727 13.4375 1.3125 12.6527 1.3125 11.6875C1.3125 11.4852 1.34805 11.2883 1.41094 11.1078C0.585156 10.7961 0 9.99766 0 9.0625C0 8.19023 0.511328 7.43555 1.25234 7.08555C1.01445 6.7875 0.875 6.41016 0.875 6C0.875 5.16055 1.46563 4.46055 2.25312 4.28828C2.20938 4.13789 2.1875 3.97656 2.1875 3.8125C2.1875 2.99492 2.75078 2.30586 3.5082 2.11445C3.59023 1.34883 4.24102 0.75 5.03125 0.75ZM8.96875 0.75C9.75898 0.75 10.407 1.34883 10.4918 2.11445C11.252 2.30586 11.8125 2.99219 11.8125 3.8125C11.8125 3.97656 11.7906 4.13789 11.7469 4.28828C12.5344 4.45781 13.125 5.16055 13.125 6C13.125 6.41016 12.9855 6.7875 12.7477 7.08555C13.4887 7.43555 14 8.19023 14 9.0625C14 9.99766 13.4148 10.7961 12.5891 11.1078C12.652 11.2883 12.6875 11.4852 12.6875 11.6875C12.6875 12.6527 11.9027 13.4375 10.9375 13.4375C10.7844 13.4375 10.634 13.4184 10.4918 13.3801C10.4098 14.1512 9.75898 14.75 8.96875 14.75C8.12383 14.75 7.4375 14.0637 7.4375 13.2188V2.28125C7.4375 1.43633 8.12383 0.75 8.96875 0.75Z"
|
||||
fill="white"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
isActive: true,
|
||||
},
|
||||
{
|
||||
title: { children: "Sketch Creation" },
|
||||
description: {
|
||||
children: "Your personalized soulmate sketch will be created.",
|
||||
},
|
||||
icon: (
|
||||
<svg
|
||||
width="14"
|
||||
height="15"
|
||||
viewBox="0 0 14 15"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M14 7.75C14 7.77461 14 7.79922 14 7.82383C13.9891 8.82188 13.0813 9.5 12.0832 9.5H9.40625C8.68164 9.5 8.09375 10.0879 8.09375 10.8125C8.09375 10.9055 8.10469 10.9957 8.12109 11.0832C8.17852 11.3621 8.29883 11.6301 8.41641 11.9008C8.5832 12.2781 8.74727 12.6527 8.74727 13.0492C8.74727 13.9187 8.15664 14.709 7.28711 14.7445C7.19141 14.7473 7.0957 14.75 6.99727 14.75C3.13359 14.75 0 11.6164 0 7.75C0 3.88359 3.13359 0.75 7 0.75C10.8664 0.75 14 3.88359 14 7.75ZM3.5 8.625C3.5 8.39294 3.40781 8.17038 3.24372 8.00628C3.07962 7.84219 2.85706 7.75 2.625 7.75C2.39294 7.75 2.17038 7.84219 2.00628 8.00628C1.84219 8.17038 1.75 8.39294 1.75 8.625C1.75 8.85706 1.84219 9.07962 2.00628 9.24372C2.17038 9.40781 2.39294 9.5 2.625 9.5C2.85706 9.5 3.07962 9.40781 3.24372 9.24372C3.40781 9.07962 3.5 8.85706 3.5 8.625ZM3.5 6C3.73206 6 3.95462 5.90781 4.11872 5.74372C4.28281 5.57962 4.375 5.35706 4.375 5.125C4.375 4.89294 4.28281 4.67038 4.11872 4.50628C3.95462 4.34219 3.73206 4.25 3.5 4.25C3.26794 4.25 3.04538 4.34219 2.88128 4.50628C2.71719 4.67038 2.625 4.89294 2.625 5.125C2.625 5.35706 2.71719 5.57962 2.88128 5.74372C3.04538 5.90781 3.26794 6 3.5 6ZM7.875 3.375C7.875 3.14294 7.78281 2.92038 7.61872 2.75628C7.45462 2.59219 7.23206 2.5 7 2.5C6.76794 2.5 6.54538 2.59219 6.38128 2.75628C6.21719 2.92038 6.125 3.14294 6.125 3.375C6.125 3.60706 6.21719 3.82962 6.38128 3.99372C6.54538 4.15781 6.76794 4.25 7 4.25C7.23206 4.25 7.45462 4.15781 7.61872 3.99372C7.78281 3.82962 7.875 3.60706 7.875 3.375ZM10.5 6C10.7321 6 10.9546 5.90781 11.1187 5.74372C11.2828 5.57962 11.375 5.35706 11.375 5.125C11.375 4.89294 11.2828 4.67038 11.1187 4.50628C10.9546 4.34219 10.7321 4.25 10.5 4.25C10.2679 4.25 10.0454 4.34219 9.88128 4.50628C9.71719 4.67038 9.625 4.89294 9.625 5.125C9.625 5.35706 9.71719 5.57962 9.88128 5.74372C10.0454 5.90781 10.2679 6 10.5 6Z"
|
||||
fill="#6B7280"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
isActive: false,
|
||||
},
|
||||
{
|
||||
title: { children: "Астрологические Идеи" },
|
||||
description: {
|
||||
children: "Уникальные астрологич...",
|
||||
},
|
||||
icon: (
|
||||
<svg
|
||||
width="12"
|
||||
height="13"
|
||||
viewBox="0 0 12 13"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M6.86133 0.625C3.48438 0.625 0.75 3.36758 0.75 6.75C0.75 10.1324 3.48438 12.875 6.86133 12.875C8.51836 12.875 10.0195 12.2133 11.1215 11.1414C11.2582 11.0074 11.2937 10.7996 11.2063 10.6301C11.1187 10.4605 10.9301 10.3648 10.7414 10.3977C10.4734 10.4441 10.2 10.4688 9.91836 10.4688C7.26875 10.4688 5.11953 8.31406 5.11953 5.65625C5.11953 3.85703 6.10391 2.29023 7.56133 1.46445C7.72813 1.36875 7.81289 1.17734 7.77187 0.991406C7.73086 0.805469 7.57227 0.666016 7.38086 0.649609C7.20859 0.635938 7.03633 0.627734 6.86133 0.627734V0.625Z"
|
||||
fill="#6B7280"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
isActive: false,
|
||||
},
|
||||
{
|
||||
title: { children: "Персонализированный чат с экспертом" },
|
||||
description: {
|
||||
children: "Персональные советы от экспертов по отношениям.",
|
||||
},
|
||||
icon: (
|
||||
<svg
|
||||
width="18"
|
||||
height="15"
|
||||
viewBox="0 0 18 15"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M5.93755 10.375C9.07935 10.375 11.6251 8.22031 11.6251 5.5625C11.6251 2.90469 9.07935 0.75 5.93755 0.75C2.79576 0.75 0.250055 2.90469 0.250055 5.5625C0.250055 6.61797 0.652008 7.59414 1.33287 8.38984C1.23716 8.64687 1.09498 8.87383 0.944586 9.06523C0.813336 9.23477 0.679352 9.36602 0.580914 9.45625C0.531696 9.5 0.49068 9.53555 0.463336 9.55742C0.449664 9.56836 0.438727 9.57656 0.433258 9.5793L0.427789 9.58477C0.277399 9.69688 0.211774 9.89375 0.27193 10.0715C0.332086 10.2492 0.498883 10.375 0.687555 10.375C1.28365 10.375 1.88521 10.2219 2.3856 10.0332C2.63716 9.9375 2.87232 9.83086 3.0774 9.72148C3.91685 10.1371 4.89302 10.375 5.93755 10.375ZM12.5001 5.5625C12.5001 8.6332 9.79029 10.9465 6.58013 11.2227C7.24459 13.257 9.44849 14.75 12.0626 14.75C13.1071 14.75 14.0833 14.5121 14.9254 14.0965C15.1305 14.2059 15.3629 14.3125 15.6145 14.4082C16.1149 14.5969 16.7165 14.75 17.3126 14.75C17.5012 14.75 17.6708 14.627 17.7282 14.4465C17.7856 14.266 17.7227 14.0691 17.5696 13.957L17.5641 13.9516C17.5586 13.9461 17.5477 13.9406 17.534 13.9297C17.5067 13.9078 17.4657 13.875 17.4165 13.8285C17.318 13.7383 17.184 13.607 17.0528 13.4375C16.9024 13.2461 16.7602 13.0164 16.6645 12.7621C17.3454 11.9691 17.7473 10.993 17.7473 9.93477C17.7473 7.39727 15.4258 5.31641 12.4809 5.13594C12.4919 5.27539 12.4973 5.41758 12.4973 5.55977L12.5001 5.5625Z"
|
||||
fill="#6B7280"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
isActive: false,
|
||||
},
|
||||
],
|
||||
button: {
|
||||
children: "Show Me My Soulmate",
|
||||
onClick: fn(),
|
||||
},
|
||||
},
|
||||
reviews: {
|
||||
title: {
|
||||
children: (
|
||||
<>
|
||||
Loved and Trusted <span className="text-[#1047A2]">Worldwide</span>
|
||||
</>
|
||||
),
|
||||
},
|
||||
reviews: [
|
||||
{
|
||||
avatar: {
|
||||
imageProps: {
|
||||
src: "/trial-payment/reviews/avatars/1.jpg",
|
||||
alt: "Avatar 1",
|
||||
},
|
||||
fallbackProps: {
|
||||
children: "A1",
|
||||
},
|
||||
},
|
||||
portrait: {
|
||||
src: "/trial-payment/reviews/portraits/1.jpg",
|
||||
alt: "Portrait 1",
|
||||
},
|
||||
photo: {
|
||||
src: "/trial-payment/reviews/photos/1.jpg",
|
||||
alt: "Photo 1",
|
||||
},
|
||||
name: {
|
||||
children: "Jennifer Wilson 🇺🇸",
|
||||
},
|
||||
stars: {
|
||||
value: 5,
|
||||
},
|
||||
date: {
|
||||
children: "1 day ago",
|
||||
},
|
||||
text: {
|
||||
children: (
|
||||
<>
|
||||
<b>“Я увидела свои ошибки… и нашла мужа”</b>
|
||||
<br />
|
||||
Портрет сразу зацепил — было чувство, что я уже где-то его
|
||||
видела. Но настоящий перелом произошёл после гайда: я поняла,
|
||||
почему снова и снова выбирала «не тех». И самое удивительное —
|
||||
вскоре я познакомилась с мужчиной, который оказался точной
|
||||
копией того самого портрета. Сейчас он мой муж, и когда мы
|
||||
сравнили рисунок с его фото, сходство было просто вау.
|
||||
</>
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
avatar: {
|
||||
imageProps: {
|
||||
src: "/trial-payment/reviews/avatars/2.jpg",
|
||||
alt: "Avatar 2",
|
||||
},
|
||||
fallbackProps: {
|
||||
children: "A2",
|
||||
},
|
||||
},
|
||||
portrait: {
|
||||
src: "/trial-payment/reviews/portraits/2.jpg",
|
||||
alt: "Portrait 2",
|
||||
},
|
||||
photo: {
|
||||
src: "/trial-payment/reviews/photos/2.jpg",
|
||||
alt: "Photo 2",
|
||||
},
|
||||
name: {
|
||||
children: "Amanda Davis 🇨🇦",
|
||||
},
|
||||
stars: {
|
||||
value: 5,
|
||||
},
|
||||
date: {
|
||||
children: "4 days ago",
|
||||
},
|
||||
text: {
|
||||
children: (
|
||||
<>
|
||||
<b>
|
||||
“Я поняла своего партнёра лучше за один вечер, чем за
|
||||
несколько лет”
|
||||
</b>
|
||||
<br />
|
||||
Прошла тест ради интереса — портрет нас удивил. Но настоящий
|
||||
прорыв случился, когда я прочитала гайд о второй половинке. Там
|
||||
были точные подсказки о том, как мы можем поддерживать друг
|
||||
друга. Цена смешная, а ценность огромная: теперь у нас меньше
|
||||
недопониманий и больше тепла.
|
||||
</>
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
avatar: {
|
||||
imageProps: {
|
||||
src: "/trial-payment/reviews/avatars/3.jpg",
|
||||
alt: "Avatar 3",
|
||||
},
|
||||
fallbackProps: {
|
||||
children: "A3",
|
||||
},
|
||||
},
|
||||
portrait: {
|
||||
src: "/trial-payment/reviews/portraits/3.jpg",
|
||||
alt: "Portrait 3",
|
||||
width: 96,
|
||||
className: "w-[96px] h-[64px]",
|
||||
},
|
||||
photo: {
|
||||
src: "/trial-payment/reviews/photos/3.jpg",
|
||||
alt: "Photo 3",
|
||||
},
|
||||
name: {
|
||||
children: "Michael Johnson 🇬🇧",
|
||||
},
|
||||
stars: {
|
||||
value: 5,
|
||||
},
|
||||
date: {
|
||||
children: "1 week ago",
|
||||
},
|
||||
text: {
|
||||
children: (
|
||||
<>
|
||||
<b>“Увидел её лицо — и мурашки по коже”</b>
|
||||
<br />
|
||||
Когда пришёл результат теста и показали портрет, я реально
|
||||
замер. Это была та самая девушка, с которой я начал встречаться
|
||||
пару недель назад. И гайд прямо описал, почему мы тянемся друг к
|
||||
другу. Честно, я не ожидал такого совпадения.
|
||||
</>
|
||||
),
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
commonQuestions: {
|
||||
title: {
|
||||
children: "Common Questions",
|
||||
},
|
||||
questions: [
|
||||
{
|
||||
value: "when-will-i-receive-my-sketch",
|
||||
trigger: {
|
||||
children: "When will I receive my sketch?",
|
||||
},
|
||||
content: {
|
||||
children:
|
||||
"Your personalized soulmate sketch will be delivered within 24-48 hours after completing your order. You'll receive an email notification when it's ready for viewing in your account.",
|
||||
},
|
||||
},
|
||||
{
|
||||
value: "how-do-i-cancel-my-subscription",
|
||||
trigger: {
|
||||
children: "How do I cancel my subscription?",
|
||||
},
|
||||
content: {
|
||||
children:
|
||||
"Your personalized soulmate sketch will be delivered within 24-48 hours after completing your order. You'll receive an email notification when it's ready for viewing in your account.",
|
||||
},
|
||||
},
|
||||
{
|
||||
value: "how-accurate-are-the-readings",
|
||||
trigger: {
|
||||
children: "How accurate are the readings?",
|
||||
},
|
||||
content: {
|
||||
children:
|
||||
"Your personalized soulmate sketch will be delivered within 24-48 hours after completing your order. You'll receive an email notification when it's ready for viewing in your account.",
|
||||
},
|
||||
},
|
||||
{
|
||||
value: "is-my-data-secure-and-private",
|
||||
trigger: {
|
||||
children: "Is my data secure and private?",
|
||||
},
|
||||
content: {
|
||||
children:
|
||||
"Your personalized soulmate sketch will be delivered within 24-48 hours after completing your order. You'll receive an email notification when it's ready for viewing in your account.",
|
||||
},
|
||||
},
|
||||
],
|
||||
accordionProps: {
|
||||
defaultValue: "when-will-i-receive-my-sketch",
|
||||
type: "single",
|
||||
},
|
||||
},
|
||||
stillHaveQuestions: {
|
||||
title: {
|
||||
children: "Still have questions? We're here to help!",
|
||||
},
|
||||
actionButton: {
|
||||
children: "Get me Soulmate Sketch",
|
||||
onClick: fn(),
|
||||
},
|
||||
contactButton: {
|
||||
children: "Contact Support",
|
||||
onClick: fn(),
|
||||
},
|
||||
},
|
||||
footer: {
|
||||
title: {
|
||||
children: "WIT LAB ©",
|
||||
},
|
||||
contacts: {
|
||||
title: {
|
||||
children: "CONTACTS",
|
||||
},
|
||||
email: {
|
||||
href: "support@witlab.com",
|
||||
children: "support@witlab.com",
|
||||
},
|
||||
address: {
|
||||
children: "Wit Lab 2108 N ST STE N SACRAMENTO, CA95816, US",
|
||||
},
|
||||
},
|
||||
legal: {
|
||||
title: {
|
||||
children: "LEGAL",
|
||||
},
|
||||
links: [
|
||||
{ href: "https://witlab.com/terms", children: "Terms of Service" },
|
||||
{ href: "https://witlab.com/privacy", children: "Privacy Policy" },
|
||||
{ href: "https://witlab.com/privacy", children: "Refund Policy" },
|
||||
],
|
||||
copyright: {
|
||||
children:
|
||||
"Copyright © 2025 Wit Lab™. All rights reserved. All trademarks referenced herein are the properties of their respective owners.",
|
||||
},
|
||||
},
|
||||
paymentMethods: {
|
||||
title: {
|
||||
children: "PAYMENT METHODS",
|
||||
},
|
||||
methods: [
|
||||
{
|
||||
src: "/trial-payment/payment-methods/visa.svg",
|
||||
alt: "visa",
|
||||
},
|
||||
{
|
||||
src: "/trial-payment/payment-methods/mastercard.svg",
|
||||
alt: "mastercard",
|
||||
},
|
||||
{
|
||||
src: "/trial-payment/payment-methods/discover.svg",
|
||||
alt: "discover",
|
||||
},
|
||||
{
|
||||
src: "/trial-payment/payment-methods/apple.svg",
|
||||
alt: "apple",
|
||||
},
|
||||
{
|
||||
src: "/trial-payment/payment-methods/google.svg",
|
||||
alt: "google",
|
||||
},
|
||||
{
|
||||
src: "/trial-payment/payment-methods/paypal.svg",
|
||||
alt: "paypal",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
argTypes: {},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Default = {} satisfies Story;
|
||||
168
src/components/templates/TrialPayment/TrialPayment.tsx
Normal file
@ -0,0 +1,168 @@
|
||||
import {
|
||||
Header,
|
||||
JoinedToday,
|
||||
JoinedTodayWithAvatars,
|
||||
MoneyBackGuarantee,
|
||||
Policy,
|
||||
ProgressToSeeSoulmate,
|
||||
TrustedByOver,
|
||||
} from "@/components/domains/TrialPayment";
|
||||
import {
|
||||
FindingOneGuide,
|
||||
CommonQuestions,
|
||||
PaymentButtons,
|
||||
Reviews,
|
||||
StepsToSeeSoulmate,
|
||||
TotalPrice,
|
||||
TryForDays,
|
||||
UnlockYourSketch,
|
||||
UsersPortraits,
|
||||
StillHaveQuestions,
|
||||
Footer,
|
||||
} from "@/components/domains/TrialPayment/Cards";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface TrialPaymentProps extends React.ComponentProps<"div"> {
|
||||
header?: React.ComponentProps<typeof Header>;
|
||||
unlockYourSketch?: React.ComponentProps<typeof UnlockYourSketch>;
|
||||
joinedToday?: React.ComponentProps<typeof JoinedToday>;
|
||||
trustedByOver?: React.ComponentProps<typeof TrustedByOver>;
|
||||
findingOneGuide?: React.ComponentProps<typeof FindingOneGuide>;
|
||||
tryForDays?: React.ComponentProps<typeof TryForDays>;
|
||||
totalPrice?: React.ComponentProps<typeof TotalPrice>;
|
||||
paymentButtons?: React.ComponentProps<typeof PaymentButtons>;
|
||||
moneyBackGuarantee?: React.ComponentProps<typeof MoneyBackGuarantee>;
|
||||
policy?: React.ComponentProps<typeof Policy>;
|
||||
usersPortraits?: React.ComponentProps<typeof UsersPortraits>;
|
||||
joinedTodayWithAvatars?: React.ComponentProps<typeof JoinedTodayWithAvatars>;
|
||||
progressToSeeSoulmate?: React.ComponentProps<typeof ProgressToSeeSoulmate>;
|
||||
stepsToSeeSoulmate?: React.ComponentProps<typeof StepsToSeeSoulmate>;
|
||||
reviews?: React.ComponentProps<typeof Reviews>;
|
||||
commonQuestions?: React.ComponentProps<typeof CommonQuestions>;
|
||||
stillHaveQuestions?: React.ComponentProps<typeof StillHaveQuestions>;
|
||||
footer?: React.ComponentProps<typeof Footer>;
|
||||
}
|
||||
|
||||
export default function TrialPayment({
|
||||
header,
|
||||
unlockYourSketch,
|
||||
joinedToday,
|
||||
trustedByOver,
|
||||
findingOneGuide,
|
||||
tryForDays,
|
||||
totalPrice,
|
||||
paymentButtons,
|
||||
moneyBackGuarantee,
|
||||
policy,
|
||||
usersPortraits,
|
||||
joinedTodayWithAvatars,
|
||||
progressToSeeSoulmate,
|
||||
stepsToSeeSoulmate,
|
||||
reviews,
|
||||
commonQuestions,
|
||||
stillHaveQuestions,
|
||||
footer,
|
||||
...props
|
||||
}: TrialPaymentProps) {
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
className={cn(
|
||||
"w-full min-h-dvh max-w-[560px] mx-auto bg-trial-payment-secondary",
|
||||
"px-[17px] py-1.5 pb-[82px]",
|
||||
"flex flex-col items-center",
|
||||
props.className
|
||||
)}
|
||||
>
|
||||
{header && <Header {...header} />}
|
||||
{unlockYourSketch && <UnlockYourSketch {...unlockYourSketch} />}
|
||||
{joinedToday && (
|
||||
<JoinedToday
|
||||
{...joinedToday}
|
||||
className={cn("mt-[18px]", joinedToday.className)}
|
||||
/>
|
||||
)}
|
||||
{trustedByOver && (
|
||||
<TrustedByOver
|
||||
{...trustedByOver}
|
||||
className={cn("mt-[9px]", trustedByOver.className)}
|
||||
/>
|
||||
)}
|
||||
{findingOneGuide && (
|
||||
<FindingOneGuide
|
||||
{...findingOneGuide}
|
||||
className={cn("mt-[22px]", findingOneGuide.className)}
|
||||
/>
|
||||
)}
|
||||
{tryForDays && (
|
||||
<TryForDays
|
||||
{...tryForDays}
|
||||
className={cn("mt-[46px]", tryForDays.className)}
|
||||
/>
|
||||
)}
|
||||
{totalPrice && (
|
||||
<TotalPrice
|
||||
{...totalPrice}
|
||||
className={cn("mt-[46px]", totalPrice.className)}
|
||||
/>
|
||||
)}
|
||||
{paymentButtons && (
|
||||
<PaymentButtons
|
||||
{...paymentButtons}
|
||||
className={cn("mt-[46px]", paymentButtons.className)}
|
||||
/>
|
||||
)}
|
||||
{moneyBackGuarantee && (
|
||||
<MoneyBackGuarantee
|
||||
{...moneyBackGuarantee}
|
||||
className={cn("mt-[17px]", moneyBackGuarantee.className)}
|
||||
/>
|
||||
)}
|
||||
{policy && (
|
||||
<Policy {...policy} className={cn("mt-4", policy.className)} />
|
||||
)}
|
||||
{usersPortraits && (
|
||||
<UsersPortraits
|
||||
{...usersPortraits}
|
||||
className={cn("mt-12", usersPortraits.className)}
|
||||
/>
|
||||
)}
|
||||
{joinedTodayWithAvatars && (
|
||||
<JoinedTodayWithAvatars
|
||||
{...joinedTodayWithAvatars}
|
||||
className={cn("mt-[22px]", joinedTodayWithAvatars.className)}
|
||||
/>
|
||||
)}
|
||||
{progressToSeeSoulmate && (
|
||||
<ProgressToSeeSoulmate
|
||||
{...progressToSeeSoulmate}
|
||||
className={cn("mt-12", progressToSeeSoulmate.className)}
|
||||
/>
|
||||
)}
|
||||
{stepsToSeeSoulmate && (
|
||||
<StepsToSeeSoulmate
|
||||
{...stepsToSeeSoulmate}
|
||||
className={cn("mt-12", stepsToSeeSoulmate.className)}
|
||||
/>
|
||||
)}
|
||||
{reviews && (
|
||||
<Reviews {...reviews} className={cn("mt-12", reviews.className)} />
|
||||
)}
|
||||
{commonQuestions && (
|
||||
<CommonQuestions
|
||||
{...commonQuestions}
|
||||
className={cn("mt-[31px]", commonQuestions.className)}
|
||||
/>
|
||||
)}
|
||||
{stillHaveQuestions && (
|
||||
<StillHaveQuestions
|
||||
{...stillHaveQuestions}
|
||||
className={cn("mt-8", stillHaveQuestions.className)}
|
||||
/>
|
||||
)}
|
||||
{footer && (
|
||||
<Footer {...footer} className={cn("mt-[60px]", footer.className)} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
23
src/components/ui/Avatar/Avatar.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import {
|
||||
AvatarImage,
|
||||
Avatar as AvatarComponent,
|
||||
AvatarFallback,
|
||||
} from "../avatar";
|
||||
|
||||
interface AvatarProps extends React.ComponentProps<typeof AvatarComponent> {
|
||||
imageProps?: React.ComponentProps<typeof AvatarImage>;
|
||||
fallbackProps?: React.ComponentProps<typeof AvatarFallback>;
|
||||
}
|
||||
|
||||
export default function Avatar({
|
||||
imageProps,
|
||||
fallbackProps,
|
||||
...props
|
||||
}: AvatarProps) {
|
||||
return (
|
||||
<AvatarComponent {...props}>
|
||||
{imageProps && <AvatarImage {...imageProps} />}
|
||||
{fallbackProps && <AvatarFallback {...fallbackProps} />}
|
||||
</AvatarComponent>
|
||||
);
|
||||
}
|
||||
@ -43,11 +43,12 @@ const typographyVariants = cva(cn("text-center text-foreground block"), {
|
||||
inter: "font-inter",
|
||||
geistSans: "font-geist-sans",
|
||||
geistMono: "font-geist-mono",
|
||||
poppins: "font-poppins",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
size: "md",
|
||||
weight: "regular",
|
||||
weight: "regular",
|
||||
color: "default",
|
||||
align: "left",
|
||||
font: "manrope",
|
||||
@ -56,7 +57,17 @@ const typographyVariants = cva(cn("text-center text-foreground block"), {
|
||||
|
||||
type TypographyElements = Pick<
|
||||
JSX.IntrinsicElements,
|
||||
"span" | "p" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "div"
|
||||
| "span"
|
||||
| "p"
|
||||
| "h1"
|
||||
| "h2"
|
||||
| "h3"
|
||||
| "h4"
|
||||
| "h5"
|
||||
| "h6"
|
||||
| "div"
|
||||
| "li"
|
||||
| "address"
|
||||
>;
|
||||
|
||||
export type TypographyProps<T extends keyof TypographyElements = "span"> =
|
||||
@ -87,12 +98,12 @@ export default function Typography<
|
||||
);
|
||||
|
||||
// 🎨 Если включена разметка и это строка, используем MarkupText
|
||||
if (enableMarkup && typeof children === 'string') {
|
||||
if (enableMarkup && typeof children === "string") {
|
||||
return (
|
||||
<MarkupText
|
||||
as={Component}
|
||||
className={classes}
|
||||
boldClassName={weight === 'bold' ? undefined : 'font-bold'} // Наследуем стиль жирного текста
|
||||
boldClassName={weight === "bold" ? undefined : "font-bold"} // Наследуем стиль жирного текста
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
|
||||
144
src/components/ui/accordion.stories.tsx
Normal file
@ -0,0 +1,144 @@
|
||||
import { Meta, StoryObj } from "@storybook/nextjs-vite";
|
||||
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "./accordion";
|
||||
|
||||
/** Reusable Accordion Component */
|
||||
const meta: Meta<typeof Accordion> = {
|
||||
title: "Shadcn UI/Accordion",
|
||||
component: Accordion,
|
||||
parameters: {
|
||||
layout: "centered",
|
||||
},
|
||||
tags: ["autodocs"],
|
||||
args: {
|
||||
type: "single",
|
||||
collapsible: true,
|
||||
},
|
||||
argTypes: {
|
||||
type: {
|
||||
control: { type: "select" },
|
||||
options: ["single", "multiple"],
|
||||
},
|
||||
collapsible: {
|
||||
control: { type: "boolean" },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Default = {
|
||||
render: (args) => (
|
||||
<Accordion {...args} className="w-[400px]">
|
||||
<AccordionItem value="item-1">
|
||||
<AccordionTrigger>Is it accessible?</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
Yes. It adheres to the WAI-ARIA design pattern.
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
<AccordionItem value="item-2">
|
||||
<AccordionTrigger>Is it styled?</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
Yes. It comes with default styles that matches the other components' aesthetic.
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
<AccordionItem value="item-3">
|
||||
<AccordionTrigger>Is it animated?</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
Yes. It's animated by default, but you can disable it if you prefer.
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
),
|
||||
} satisfies Story;
|
||||
|
||||
export const Multiple = {
|
||||
args: {
|
||||
type: "multiple",
|
||||
},
|
||||
render: (args) => (
|
||||
<Accordion {...args} className="w-[400px]">
|
||||
<AccordionItem value="item-1">
|
||||
<AccordionTrigger>Is it accessible?</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
Yes. It adheres to the WAI-ARIA design pattern.
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
<AccordionItem value="item-2">
|
||||
<AccordionTrigger>Is it styled?</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
Yes. It comes with default styles that matches the other components' aesthetic.
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
<AccordionItem value="item-3">
|
||||
<AccordionTrigger>Is it animated?</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
Yes. It's animated by default, but you can disable it if you prefer.
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
),
|
||||
} satisfies Story;
|
||||
|
||||
export const SingleItem = {
|
||||
render: (args) => (
|
||||
<Accordion {...args} className="w-[400px]">
|
||||
<AccordionItem value="item-1">
|
||||
<AccordionTrigger>What is this component?</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
This is an accordion component built with Radix UI primitives. It provides a collapsible content area that can be expanded or collapsed by clicking the trigger.
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
),
|
||||
} satisfies Story;
|
||||
|
||||
export const LongContent = {
|
||||
render: (args) => (
|
||||
<Accordion {...args} className="w-[400px]">
|
||||
<AccordionItem value="item-1">
|
||||
<AccordionTrigger>What are the features?</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
<div className="space-y-2">
|
||||
<p>This accordion component includes:</p>
|
||||
<ul className="list-disc list-inside space-y-1 ml-4">
|
||||
<li>Accessibility support with WAI-ARIA patterns</li>
|
||||
<li>Smooth animations for opening and closing</li>
|
||||
<li>Keyboard navigation support</li>
|
||||
<li>Customizable styling with Tailwind CSS</li>
|
||||
<li>Single or multiple item selection modes</li>
|
||||
<li>Collapsible functionality</li>
|
||||
</ul>
|
||||
<p className="mt-2">
|
||||
The component is built using Radix UI primitives, ensuring excellent accessibility and user experience across different devices and assistive technologies.
|
||||
</p>
|
||||
</div>
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
),
|
||||
} satisfies Story;
|
||||
|
||||
export const CustomStyling = {
|
||||
render: (args) => (
|
||||
<Accordion {...args} className="w-[400px]">
|
||||
<AccordionItem value="item-1" className="border-2 border-blue-200 rounded-lg mb-2">
|
||||
<AccordionTrigger className="text-blue-600 font-semibold hover:text-blue-800">
|
||||
Custom Styled Item
|
||||
</AccordionTrigger>
|
||||
<AccordionContent className="text-blue-700 bg-blue-50 p-4 rounded-b-lg">
|
||||
This accordion item has custom styling with blue colors and enhanced spacing.
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
<AccordionItem value="item-2" className="border-2 border-green-200 rounded-lg">
|
||||
<AccordionTrigger className="text-green-600 font-semibold hover:text-green-800">
|
||||
Another Custom Item
|
||||
</AccordionTrigger>
|
||||
<AccordionContent className="text-green-700 bg-green-50 p-4 rounded-b-lg">
|
||||
Each item can have its own custom styling while maintaining the accordion functionality.
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
),
|
||||
} satisfies Story;
|
||||
|
||||
75
src/components/ui/accordion.tsx
Normal file
@ -0,0 +1,75 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import * as AccordionPrimitive from "@radix-ui/react-accordion";
|
||||
import { ChevronDownIcon } from "lucide-react";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
function Accordion({
|
||||
...props
|
||||
}: React.ComponentProps<typeof AccordionPrimitive.Root>) {
|
||||
return <AccordionPrimitive.Root data-slot="accordion" {...props} />;
|
||||
}
|
||||
|
||||
function AccordionItem({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof AccordionPrimitive.Item>) {
|
||||
return (
|
||||
<AccordionPrimitive.Item
|
||||
data-slot="accordion-item"
|
||||
className={cn("border-b last:border-b-0", className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function AccordionTrigger({
|
||||
className,
|
||||
children,
|
||||
iconProps,
|
||||
...props
|
||||
}: React.ComponentProps<typeof AccordionPrimitive.Trigger> & {
|
||||
iconProps?: React.ComponentProps<typeof ChevronDownIcon>;
|
||||
}) {
|
||||
return (
|
||||
<AccordionPrimitive.Header className="flex w-full">
|
||||
<AccordionPrimitive.Trigger
|
||||
data-slot="accordion-trigger"
|
||||
className={cn(
|
||||
"focus-visible:border-ring focus-visible:ring-ring/50 flex flex-1 items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-180",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<ChevronDownIcon
|
||||
{...iconProps}
|
||||
className={cn(
|
||||
"text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200",
|
||||
iconProps?.className
|
||||
)}
|
||||
/>
|
||||
</AccordionPrimitive.Trigger>
|
||||
</AccordionPrimitive.Header>
|
||||
);
|
||||
}
|
||||
|
||||
function AccordionContent({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof AccordionPrimitive.Content>) {
|
||||
return (
|
||||
<AccordionPrimitive.Content
|
||||
data-slot="accordion-content"
|
||||
className="data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm"
|
||||
{...props}
|
||||
>
|
||||
<div className={cn("pt-0 pb-4", className)}>{children}</div>
|
||||
</AccordionPrimitive.Content>
|
||||
);
|
||||
}
|
||||
|
||||
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
|
||||
53
src/components/ui/avatar.tsx
Normal file
@ -0,0 +1,53 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import * as AvatarPrimitive from "@radix-ui/react-avatar";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
function Avatar({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof AvatarPrimitive.Root>) {
|
||||
return (
|
||||
<AvatarPrimitive.Root
|
||||
data-slot="avatar"
|
||||
className={cn(
|
||||
"relative flex size-8 shrink-0 overflow-hidden rounded-full bg-background",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function AvatarImage({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof AvatarPrimitive.Image>) {
|
||||
return (
|
||||
<AvatarPrimitive.Image
|
||||
data-slot="avatar-image"
|
||||
className={cn("aspect-square size-full", className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function AvatarFallback({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {
|
||||
return (
|
||||
<AvatarPrimitive.Fallback
|
||||
data-slot="avatar-fallback"
|
||||
className={cn(
|
||||
"bg-muted flex size-full items-center justify-center rounded-full",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export { Avatar, AvatarImage, AvatarFallback };
|
||||
@ -17,7 +17,7 @@ const buttonVariants = cva(
|
||||
destructive:
|
||||
"bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
|
||||
outline:
|
||||
"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
|
||||
"border-2 border-primary bg-background shadow-xs dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
|
||||
secondary:
|
||||
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||
ghost:
|
||||
|
||||
@ -68,7 +68,7 @@ export const Complete = {
|
||||
export const CustomColors = {
|
||||
args: {
|
||||
value: 80,
|
||||
classNameProgress: "bg-green-200 [&>div]:bg-green-600",
|
||||
classNameProgressContainer: "bg-green-200 [&>div]:bg-green-600",
|
||||
},
|
||||
} satisfies Story;
|
||||
|
||||
|
||||
@ -8,12 +8,12 @@ import { Label } from "./label";
|
||||
interface ProgressProps
|
||||
extends React.ComponentProps<typeof ProgressPrimitive.Root> {
|
||||
label?: string;
|
||||
classNameProgress?: string;
|
||||
classNameProgressContainer?: string;
|
||||
}
|
||||
|
||||
function Progress({
|
||||
className,
|
||||
classNameProgress,
|
||||
classNameProgressContainer,
|
||||
value,
|
||||
label,
|
||||
...props
|
||||
@ -29,7 +29,7 @@ function Progress({
|
||||
data-slot="progress"
|
||||
className={cn(
|
||||
"bg-border relative h-1.5 w-full overflow-hidden rounded-full",
|
||||
classNameProgress
|
||||
classNameProgressContainer
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
|
||||
58
src/components/widgets/Avatars/Avatars.stories.tsx
Normal file
@ -0,0 +1,58 @@
|
||||
import { Meta, StoryObj } from "@storybook/nextjs-vite";
|
||||
import Avatars from "./Avatars";
|
||||
import Typography from "@/components/ui/Typography/Typography";
|
||||
|
||||
/** Reusable Avatars Component */
|
||||
const meta: Meta<typeof Avatars> = {
|
||||
title: "Widgets/Avatars",
|
||||
component: Avatars,
|
||||
tags: ["autodocs"],
|
||||
args: {
|
||||
avatars: [
|
||||
{
|
||||
imageProps: {
|
||||
src: "/avatars/male-1.jpg",
|
||||
alt: "Male 1",
|
||||
},
|
||||
fallbackProps: {
|
||||
children: "M1",
|
||||
},
|
||||
},
|
||||
{
|
||||
imageProps: {
|
||||
src: "/avatars/male-2.jpg",
|
||||
alt: "Male 2",
|
||||
},
|
||||
fallbackProps: {
|
||||
children: "M2",
|
||||
},
|
||||
},
|
||||
{
|
||||
imageProps: {
|
||||
src: "/avatars/male-3.jpg",
|
||||
alt: "Male 3",
|
||||
},
|
||||
fallbackProps: {
|
||||
children: "M3",
|
||||
},
|
||||
},
|
||||
{
|
||||
fallbackProps: {
|
||||
children: (
|
||||
<Typography size="xs" weight="bold" className="text-[#FF6B9D]">
|
||||
900+
|
||||
</Typography>
|
||||
),
|
||||
className: "bg-background",
|
||||
},
|
||||
className: "w-fit px-1",
|
||||
},
|
||||
],
|
||||
},
|
||||
argTypes: {},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Default = {} satisfies Story;
|
||||
38
src/components/widgets/Avatars/Avatars.tsx
Normal file
@ -0,0 +1,38 @@
|
||||
import Avatar from "@/components/ui/Avatar/Avatar";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface AvatarsProps extends React.ComponentProps<"div"> {
|
||||
avatars: React.ComponentProps<typeof Avatar>[];
|
||||
generalAvatarProps?: React.ComponentProps<typeof Avatar>;
|
||||
}
|
||||
export default function Avatars({
|
||||
avatars,
|
||||
generalAvatarProps,
|
||||
...props
|
||||
}: AvatarsProps) {
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
className={cn(
|
||||
"*:data-[slot=avatar]:ring-background flex -space-x-2 *:data-[slot=avatar]:ring-2",
|
||||
props.className
|
||||
)}
|
||||
>
|
||||
{avatars.map((avatar, index) => (
|
||||
<Avatar
|
||||
{...generalAvatarProps}
|
||||
{...avatar}
|
||||
imageProps={{
|
||||
...generalAvatarProps?.imageProps,
|
||||
...avatar.imageProps,
|
||||
}}
|
||||
fallbackProps={{
|
||||
...generalAvatarProps?.fallbackProps,
|
||||
...avatar.fallbackProps,
|
||||
}}
|
||||
key={index}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
import { Meta, StoryObj } from "@storybook/nextjs-vite";
|
||||
import SoulmatePortraitsDelivered from "./SoulmatePortraitsDelivered";
|
||||
import Typography from "@/components/ui/Typography/Typography";
|
||||
|
||||
/** Reusable SoulmatePortraitsDelivered Component */
|
||||
const meta: Meta<typeof SoulmatePortraitsDelivered> = {
|
||||
title: "Widgets/SoulmatePortraitsDelivered",
|
||||
component: SoulmatePortraitsDelivered,
|
||||
tags: ["autodocs"],
|
||||
args: {
|
||||
image: "/soulmate-portrait-delivered-male.jpg",
|
||||
textProps: {
|
||||
children: "soulmate portraits delivered today",
|
||||
},
|
||||
avatarsProps: {
|
||||
avatars: [
|
||||
{
|
||||
imageProps: {
|
||||
src: "/avatars/male-1.jpg",
|
||||
alt: "Male 1",
|
||||
},
|
||||
fallbackProps: {
|
||||
children: "M1",
|
||||
},
|
||||
},
|
||||
{
|
||||
imageProps: {
|
||||
src: "/avatars/male-2.jpg",
|
||||
alt: "Male 2",
|
||||
},
|
||||
fallbackProps: {
|
||||
children: "M2",
|
||||
},
|
||||
},
|
||||
{
|
||||
imageProps: {
|
||||
src: "/avatars/male-3.jpg",
|
||||
alt: "Male 3",
|
||||
},
|
||||
fallbackProps: {
|
||||
children: "M3",
|
||||
},
|
||||
},
|
||||
{
|
||||
fallbackProps: {
|
||||
children: (
|
||||
<Typography size="xs" weight="bold" className="text-[#FF6B9D]">
|
||||
900+
|
||||
</Typography>
|
||||
),
|
||||
className: "bg-background",
|
||||
},
|
||||
className: "w-fit px-1",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
argTypes: {},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Default = {} satisfies Story;
|
||||
@ -0,0 +1,52 @@
|
||||
import { cn } from "@/lib/utils";
|
||||
import Avatars from "../Avatars/Avatars";
|
||||
import Typography, {
|
||||
TypographyProps,
|
||||
} from "@/components/ui/Typography/Typography";
|
||||
|
||||
interface SoulmatePortraitsDeliveredProps extends React.ComponentProps<"div"> {
|
||||
image?: string;
|
||||
textProps?: TypographyProps<"p">;
|
||||
avatarsProps?: React.ComponentProps<typeof Avatars>;
|
||||
}
|
||||
|
||||
export default function SoulmatePortraitsDelivered({
|
||||
image,
|
||||
avatarsProps,
|
||||
textProps,
|
||||
...props
|
||||
}: SoulmatePortraitsDeliveredProps) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
backgroundImage: `url(${image})`,
|
||||
}}
|
||||
{...props}
|
||||
className={cn(
|
||||
"flex flex-col items-center justify-end",
|
||||
"w-full max-w-[336px] h-[220px]",
|
||||
"p-5",
|
||||
"rounded-3xl",
|
||||
"shadow-soulmate-portrait",
|
||||
"bg-cover bg-top bg-no-repeat",
|
||||
props.className
|
||||
)}
|
||||
>
|
||||
<div className={cn("flex gap-[9px]")}>
|
||||
{avatarsProps && <Avatars {...avatarsProps} />}
|
||||
{textProps && (
|
||||
<Typography
|
||||
size="sm"
|
||||
weight="medium"
|
||||
color="primary"
|
||||
{...textProps}
|
||||
className={cn(
|
||||
"leading-[20px] text-shadow-lg/50",
|
||||
textProps.className
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
31
src/components/widgets/Stars/Stars.tsx
Normal file
@ -0,0 +1,31 @@
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface StarsProps extends React.ComponentProps<"div"> {
|
||||
value?: number;
|
||||
star?: React.ReactNode;
|
||||
}
|
||||
|
||||
export default function Stars({ value = 5, star, ...props }: StarsProps) {
|
||||
return (
|
||||
<div {...props} className={cn("flex gap-[1px]", props.className)}>
|
||||
{Array.from({ length: value }).map(
|
||||
(_, index) =>
|
||||
star || (
|
||||
<svg
|
||||
key={index}
|
||||
width="16"
|
||||
height="15"
|
||||
viewBox="0 0 16 15"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M8.66522 1.24219C8.52029 0.941406 8.21404 0.75 7.87772 0.75C7.54139 0.75 7.23787 0.941406 7.09021 1.24219L5.33201 4.85977L1.40545 5.43945C1.07732 5.48867 0.803887 5.71836 0.702715 6.03281C0.601543 6.34727 0.683575 6.69453 0.918731 6.92695L3.76795 9.74609L3.09529 13.7301C3.04061 14.0582 3.17732 14.3918 3.44803 14.5859C3.71873 14.7801 4.07693 14.8047 4.37225 14.6488L7.88045 12.7758L11.3887 14.6488C11.684 14.8047 12.0422 14.7828 12.3129 14.5859C12.5836 14.3891 12.7203 14.0582 12.6656 13.7301L11.9902 9.74609L14.8394 6.92695C15.0746 6.69453 15.1594 6.34727 15.0554 6.03281C14.9515 5.71836 14.6808 5.48867 14.3527 5.43945L10.4234 4.85977L8.66522 1.24219Z"
|
||||
fill="#FACC15"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
78
src/components/widgets/TextList/TextList.stories.tsx
Normal file
@ -0,0 +1,78 @@
|
||||
import { Meta, StoryObj } from "@storybook/nextjs-vite";
|
||||
import TextList from "./TextList";
|
||||
import { TypographyProps } from "@/components/ui/Typography/Typography";
|
||||
|
||||
const meta: Meta<typeof TextList> = {
|
||||
title: "Widgets/TextList",
|
||||
component: TextList,
|
||||
parameters: {
|
||||
layout: "centered",
|
||||
},
|
||||
tags: ["autodocs"],
|
||||
argTypes: {
|
||||
items: {
|
||||
control: { type: "object" },
|
||||
description: "Массив элементов списка с пропсами Typography",
|
||||
},
|
||||
listStyleType: {
|
||||
control: { type: "select" },
|
||||
options: ["decimal", "disc", "none"],
|
||||
description: "Тип маркера списка",
|
||||
},
|
||||
markerImage: {
|
||||
control: { type: "text" },
|
||||
description: "URL изображения для маркера списка",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
const defaultItems: TypographyProps<"li">[] = [
|
||||
{
|
||||
children: "Первый элемент списка",
|
||||
},
|
||||
{
|
||||
children: "Второй элемент списка",
|
||||
},
|
||||
{
|
||||
children: "Третий элемент списка",
|
||||
},
|
||||
];
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
items: defaultItems,
|
||||
listStyleType: "disc",
|
||||
},
|
||||
};
|
||||
|
||||
export const Decimal: Story = {
|
||||
args: {
|
||||
items: defaultItems,
|
||||
listStyleType: "decimal",
|
||||
},
|
||||
};
|
||||
|
||||
export const Disc: Story = {
|
||||
args: {
|
||||
items: defaultItems,
|
||||
listStyleType: "disc",
|
||||
},
|
||||
};
|
||||
|
||||
export const None: Story = {
|
||||
args: {
|
||||
items: defaultItems,
|
||||
listStyleType: "none",
|
||||
},
|
||||
};
|
||||
|
||||
export const WithImage: Story = {
|
||||
args: {
|
||||
items: defaultItems,
|
||||
listStyleType: "image",
|
||||
markerImage: "/check-mark.svg",
|
||||
},
|
||||
};
|
||||
71
src/components/widgets/TextList/TextList.tsx
Normal file
@ -0,0 +1,71 @@
|
||||
import Typography, {
|
||||
TypographyProps,
|
||||
} from "@/components/ui/Typography/Typography";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cva, VariantProps } from "class-variance-authority";
|
||||
import React, { useId } from "react";
|
||||
|
||||
const textListVariants = cva("", {
|
||||
variants: {
|
||||
listStyleType: {
|
||||
decimal: "list-decimal pl-6",
|
||||
disc: "list-disc pl-6",
|
||||
image: "list-image pl-6",
|
||||
none: "list-none pl-0",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
listStyleType: "disc",
|
||||
},
|
||||
});
|
||||
|
||||
interface TextListProps
|
||||
extends React.ComponentProps<"ul">,
|
||||
VariantProps<typeof textListVariants> {
|
||||
items?: TypographyProps<"li">[];
|
||||
itemProps?: Partial<TypographyProps<"li">>;
|
||||
markerImage?: string;
|
||||
customMarker?: React.ReactNode;
|
||||
}
|
||||
|
||||
export default function TextList({
|
||||
items,
|
||||
itemProps,
|
||||
listStyleType,
|
||||
markerImage,
|
||||
customMarker,
|
||||
...props
|
||||
}: TextListProps) {
|
||||
const itemId = useId();
|
||||
return (
|
||||
<ul
|
||||
{...props}
|
||||
className={cn(
|
||||
textListVariants({ listStyleType }),
|
||||
markerImage && `list-image-[url(${markerImage})]`,
|
||||
props.className
|
||||
)}
|
||||
>
|
||||
{items?.map((item, index) => (
|
||||
<Typography
|
||||
as="li"
|
||||
{...itemProps}
|
||||
{...item}
|
||||
key={`${itemId}-${index}`}
|
||||
className={cn(
|
||||
"list-item text-trial-payment-foreground",
|
||||
customMarker && "relative",
|
||||
item.className
|
||||
)}
|
||||
>
|
||||
{customMarker && (
|
||||
<React.Fragment key={`marker-${index}`}>
|
||||
{customMarker}
|
||||
</React.Fragment>
|
||||
)}
|
||||
{item.children || itemProps?.children}
|
||||
</Typography>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
71
src/hooks/timer/useTimer.ts
Normal file
@ -0,0 +1,71 @@
|
||||
"use client";
|
||||
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
|
||||
import { formatSecondsToHHMMSS } from "@/shared/utils/date";
|
||||
|
||||
export interface UseTimerOptions {
|
||||
initialSeconds: number;
|
||||
persist?: boolean;
|
||||
storageKey?: string;
|
||||
}
|
||||
|
||||
export function useTimer({
|
||||
initialSeconds,
|
||||
persist = false,
|
||||
storageKey,
|
||||
}: UseTimerOptions) {
|
||||
const [seconds, setSeconds] = useState<number>(() => {
|
||||
if (persist && storageKey) {
|
||||
const saved = localStorage.getItem(storageKey);
|
||||
if (saved !== null) {
|
||||
const parsed = parseInt(saved, 10);
|
||||
if (!isNaN(parsed)) return parsed;
|
||||
}
|
||||
}
|
||||
return initialSeconds;
|
||||
});
|
||||
|
||||
const intervalRef = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (persist && storageKey) {
|
||||
localStorage.setItem(storageKey, seconds.toString());
|
||||
}
|
||||
}, [seconds, persist, storageKey]);
|
||||
|
||||
useEffect(() => {
|
||||
if (seconds <= 0) return;
|
||||
intervalRef.current = setInterval(() => {
|
||||
setSeconds((prev) => {
|
||||
if (prev <= 1) {
|
||||
if (intervalRef.current) {
|
||||
clearInterval(intervalRef.current);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return prev - 1;
|
||||
});
|
||||
}, 1000);
|
||||
return () => {
|
||||
if (intervalRef.current) clearInterval(intervalRef.current);
|
||||
};
|
||||
}, [seconds]);
|
||||
|
||||
const reset = useCallback(() => {
|
||||
setSeconds(initialSeconds);
|
||||
if (persist && storageKey) {
|
||||
localStorage.setItem(storageKey, initialSeconds.toString());
|
||||
}
|
||||
}, [initialSeconds, persist, storageKey]);
|
||||
|
||||
return useMemo(
|
||||
() => ({
|
||||
time: formatSecondsToHHMMSS(seconds, { isHours: false }),
|
||||
seconds,
|
||||
reset,
|
||||
isFinished: seconds === 0,
|
||||
}),
|
||||
[seconds, reset]
|
||||
);
|
||||
}
|
||||
40
src/shared/utils/date.ts
Normal file
@ -0,0 +1,40 @@
|
||||
export const formatDate = (date: string | null) => {
|
||||
if (!date) return null;
|
||||
return new Date(date).toLocaleDateString("en-US", {
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
});
|
||||
};
|
||||
|
||||
export const formatTime = (date: string | null) => {
|
||||
if (!date) return null;
|
||||
return new Date(date).toLocaleTimeString("en-US", {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
});
|
||||
};
|
||||
|
||||
export const formatSecondsToHHMMSS = (
|
||||
seconds: number,
|
||||
availableValues?: Partial<
|
||||
Record<"isHours" | "isMinutes" | "isSeconds", boolean>
|
||||
>
|
||||
) => {
|
||||
const {
|
||||
isHours = true,
|
||||
isMinutes = true,
|
||||
isSeconds = true,
|
||||
} = availableValues || {};
|
||||
const hours = Math.floor(seconds / 3600);
|
||||
const minutes = Math.floor((seconds % 3600) / 60);
|
||||
const secs = seconds % 60;
|
||||
|
||||
return [
|
||||
isHours && String(hours).padStart(2, "0"),
|
||||
isMinutes && String(minutes).padStart(2, "0"),
|
||||
isSeconds && String(secs).padStart(2, "0"),
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(":");
|
||||
};
|
||||