@windrun-huaiin/third-ui 5.12.1 → 5.12.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main/index.d.mts +6 -1
- package/dist/main/index.d.ts +6 -1
- package/dist/main/index.js +304 -288
- package/dist/main/index.js.map +1 -1
- package/dist/main/index.mjs +249 -235
- package/dist/main/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/main/cta.tsx +2 -1
- package/src/main/faq.tsx +3 -2
- package/src/main/features.tsx +3 -2
- package/src/main/index.ts +2 -1
- package/src/main/price-plan.tsx +45 -65
- package/src/main/rich-text-expert.tsx +35 -0
- package/src/main/seo-content.tsx +6 -5
- package/src/main/tips.tsx +11 -6
- package/src/main/usage.tsx +3 -2
package/package.json
CHANGED
package/src/main/cta.tsx
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { GradientButton } from "@third-ui/fuma/mdx/gradient-button";
|
|
4
4
|
import { useTranslations } from 'next-intl';
|
|
5
5
|
import { cn } from '@lib/utils';
|
|
6
|
+
import { richText } from '@third-ui/main/rich-text-expert';
|
|
6
7
|
|
|
7
8
|
export function CTA({ sectionClassName }: { sectionClassName?: string }) {
|
|
8
9
|
const t = useTranslations('cta');
|
|
@@ -18,7 +19,7 @@ export function CTA({ sectionClassName }: { sectionClassName?: string }) {
|
|
|
18
19
|
{t('title')} <span className="text-purple-400">{t('eyesOn')}</span>?
|
|
19
20
|
</h2>
|
|
20
21
|
<p className="text-2xl mx-auto mb-8">
|
|
21
|
-
{t
|
|
22
|
+
{richText(t, 'description1')}
|
|
22
23
|
<br />
|
|
23
24
|
<span className="text-purple-400">{t('description2')}</span>
|
|
24
25
|
</p>
|
package/src/main/faq.tsx
CHANGED
|
@@ -4,6 +4,7 @@ import { useState } from "react";
|
|
|
4
4
|
import { useTranslations } from 'next-intl';
|
|
5
5
|
import { globalLucideIcons as icons } from '@base-ui/components/global-icon';
|
|
6
6
|
import { cn } from '@lib/utils';
|
|
7
|
+
import { richText } from '@third-ui/main/rich-text-expert';
|
|
7
8
|
|
|
8
9
|
export function FAQ({ sectionClassName }: { sectionClassName?: string }) {
|
|
9
10
|
const t = useTranslations('faq');
|
|
@@ -27,7 +28,7 @@ export function FAQ({ sectionClassName }: { sectionClassName?: string }) {
|
|
|
27
28
|
{t('title')}
|
|
28
29
|
</h2>
|
|
29
30
|
<p className="text-center text-gray-600 dark:text-gray-400 mb-12 text-base md:text-lg mx-auto">
|
|
30
|
-
{t
|
|
31
|
+
{richText(t, 'description')}
|
|
31
32
|
</p>
|
|
32
33
|
<div className="space-y-6">
|
|
33
34
|
{items.map((item, idx) => {
|
|
@@ -48,7 +49,7 @@ export function FAQ({ sectionClassName }: { sectionClassName?: string }) {
|
|
|
48
49
|
</button>
|
|
49
50
|
{isOpen && (
|
|
50
51
|
<div className="mt-4 text-gray-700 dark:text-gray-300 text-base">
|
|
51
|
-
{
|
|
52
|
+
{richText(t, `items.${idx}.answer`)}
|
|
52
53
|
</div>
|
|
53
54
|
)}
|
|
54
55
|
</div>
|
package/src/main/features.tsx
CHANGED
|
@@ -4,6 +4,7 @@ import { getGlobalIcon } from '@base-ui/components/global-icon';
|
|
|
4
4
|
import { useTranslations } from 'next-intl'
|
|
5
5
|
import { globalLucideIcons as icons } from '@base-ui/components/global-icon';
|
|
6
6
|
import { cn } from '@lib/utils';
|
|
7
|
+
import { richText } from '@third-ui/main/rich-text-expert';
|
|
7
8
|
|
|
8
9
|
export function Features({ sectionClassName }: { sectionClassName?: string }) {
|
|
9
10
|
const t = useTranslations('features');
|
|
@@ -21,7 +22,7 @@ export function Features({ sectionClassName }: { sectionClassName?: string }) {
|
|
|
21
22
|
{t('title')} <span className="text-purple-500">{t('eyesOn')}</span>
|
|
22
23
|
</h2>
|
|
23
24
|
<p className="text-center text-gray-600 dark:text-gray-400 mb-12 text-base md:text-lg mx-auto whitespace-nowrap">
|
|
24
|
-
{t
|
|
25
|
+
{richText(t, 'description')}
|
|
25
26
|
</p>
|
|
26
27
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-8 gap-y-12">
|
|
27
28
|
{featureItems.map((feature, index) => {
|
|
@@ -35,7 +36,7 @@ export function Features({ sectionClassName }: { sectionClassName?: string }) {
|
|
|
35
36
|
<Icon className="w-8 h-8" />
|
|
36
37
|
</div>
|
|
37
38
|
<h3 className="text-xl font-semibold mb-3 text-gray-900 dark:text-gray-100">{feature.title}</h3>
|
|
38
|
-
<p className="text-gray-700 dark:text-gray-300">{
|
|
39
|
+
<p className="text-gray-700 dark:text-gray-300">{richText(t, `items.${index}.description`)}</p>
|
|
39
40
|
</div>
|
|
40
41
|
)
|
|
41
42
|
})}
|
package/src/main/index.ts
CHANGED
package/src/main/price-plan.tsx
CHANGED
|
@@ -149,18 +149,18 @@ export function PricePlan({ currency = '$', pricePlanConfig, sectionClassName }:
|
|
|
149
149
|
top: Math.max(8, y),
|
|
150
150
|
zIndex: 9999,
|
|
151
151
|
maxWidth: 200,
|
|
152
|
-
|
|
153
|
-
color: '#fff',
|
|
154
|
-
borderRadius: 10,
|
|
155
|
-
padding: '16px',
|
|
156
|
-
boxShadow: '0 4px 24px 0 rgba(0,0,0,0.25)',
|
|
157
|
-
fontSize: 15,
|
|
158
|
-
lineHeight: 1.6,
|
|
152
|
+
transform: 'translateY(-50%)',
|
|
159
153
|
pointerEvents: 'none',
|
|
160
154
|
whiteSpace: 'pre-line',
|
|
161
|
-
transform: 'translateY(-50%)',
|
|
162
155
|
}
|
|
163
|
-
return
|
|
156
|
+
return (
|
|
157
|
+
<div
|
|
158
|
+
style={style}
|
|
159
|
+
className="bg-gray-700 dark:bg-gray-200 text-gray-100 dark:text-gray-800 text-xs leading-relaxed px-3 py-2 rounded-lg shadow-lg border border-gray-300 dark:border-gray-600 backdrop-blur-sm"
|
|
160
|
+
>
|
|
161
|
+
{content}
|
|
162
|
+
</div>
|
|
163
|
+
)
|
|
164
164
|
}
|
|
165
165
|
|
|
166
166
|
return (
|
|
@@ -174,65 +174,45 @@ export function PricePlan({ currency = '$', pricePlanConfig, sectionClassName }:
|
|
|
174
174
|
</p>
|
|
175
175
|
|
|
176
176
|
{/* billing switch button */}
|
|
177
|
-
<div className="flex
|
|
178
|
-
{/*
|
|
179
|
-
<div className="flex
|
|
180
|
-
<
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
)}
|
|
207
|
-
</span>
|
|
208
|
-
);
|
|
209
|
-
})()}
|
|
177
|
+
<div className="flex flex-col items-center">
|
|
178
|
+
{/* Binary toggle buttons */}
|
|
179
|
+
<div className="flex items-center relative mb-3">
|
|
180
|
+
<div className="flex bg-white dark:bg-gray-900 border border-gray-300 dark:border-gray-700 rounded-full p-1">
|
|
181
|
+
<button
|
|
182
|
+
className={cn(
|
|
183
|
+
'min-w-[120px] px-6 py-2 font-medium transition text-lg relative',
|
|
184
|
+
billingKey === 'monthly'
|
|
185
|
+
? 'text-white bg-gradient-to-r from-purple-400 to-pink-500 hover:from-purple-500 hover:to-pink-600 dark:from-purple-500 dark:to-pink-600 dark:hover:from-purple-600 rounded-full shadow-sm'
|
|
186
|
+
: 'text-gray-800 dark:text-gray-200 hover:text-gray-900 dark:hover:text-gray-100 rounded-full'
|
|
187
|
+
)}
|
|
188
|
+
onClick={() => setBillingKey('monthly')}
|
|
189
|
+
type="button"
|
|
190
|
+
>
|
|
191
|
+
{(billingSwitch.options.find((opt: any) => opt.key === 'monthly')?.name) || 'Monthly'}
|
|
192
|
+
</button>
|
|
193
|
+
<button
|
|
194
|
+
className={cn(
|
|
195
|
+
'min-w-[120px] px-6 py-2 font-medium transition text-lg relative',
|
|
196
|
+
billingKey === 'yearly'
|
|
197
|
+
? 'text-white bg-gradient-to-r from-purple-400 to-pink-500 hover:from-purple-500 hover:to-pink-600 dark:from-purple-500 dark:to-pink-600 dark:hover:from-purple-600 rounded-full shadow-sm'
|
|
198
|
+
: 'text-gray-800 dark:text-gray-200 hover:text-gray-900 dark:hover:text-gray-100 rounded-full'
|
|
199
|
+
)}
|
|
200
|
+
onClick={() => setBillingKey('yearly')}
|
|
201
|
+
type="button"
|
|
202
|
+
>
|
|
203
|
+
{(billingSwitch.options.find((opt: any) => opt.key === 'yearly')?.name) || 'Yearly'}
|
|
204
|
+
</button>
|
|
205
|
+
</div>
|
|
210
206
|
</div>
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
className={cn(
|
|
215
|
-
'min-w-[120px] px-6 py-2 rounded-full font-medium border transition text-lg',
|
|
216
|
-
billingKey === 'yearly'
|
|
217
|
-
? 'text-white bg-gradient-to-r from-purple-400 to-pink-500 hover:from-purple-500 hover:to-pink-600 dark:from-purple-500 dark:to-pink-600 dark:hover:from-purple-600'
|
|
218
|
-
: 'bg-white dark:bg-gray-900 border-gray-300 dark:border-gray-700 text-gray-800 dark:text-gray-200 hover:border-purple-400',
|
|
219
|
-
'ml-4'
|
|
220
|
-
)}
|
|
221
|
-
onClick={() => setBillingKey('yearly')}
|
|
222
|
-
type="button"
|
|
223
|
-
>
|
|
224
|
-
{(billingSwitch.options.find((opt: any) => opt.key === 'yearly')?.name) || 'Yearly'}
|
|
225
|
-
</button>
|
|
226
|
-
{/* tag (from left to right), invisible when not selected */}
|
|
207
|
+
|
|
208
|
+
{/* Discount info - fixed position between buttons and cards */}
|
|
209
|
+
<div className="h-8 flex items-center justify-center mb-3">
|
|
227
210
|
{(() => {
|
|
228
|
-
const opt = billingSwitch.options.find((opt: any) => opt.key ===
|
|
229
|
-
const bOpt = billingOptions.find((opt: any) => opt.key ===
|
|
230
|
-
if (!(opt && bOpt && opt.discountText && bOpt.discount !== 0)) return
|
|
211
|
+
const opt = billingSwitch.options.find((opt: any) => opt.key === billingKey);
|
|
212
|
+
const bOpt = billingOptions.find((opt: any) => opt.key === billingKey);
|
|
213
|
+
if (!(opt && bOpt && opt.discountText && bOpt.discount !== 0)) return null;
|
|
231
214
|
return (
|
|
232
|
-
<span className=
|
|
233
|
-
"min-w-[80px] px-2 py-1 text-xs rounded bg-yellow-100 text-yellow-800 font-semibold align-middle text-center inline-flex items-center justify-center whitespace-nowrap",
|
|
234
|
-
billingKey !== 'yearly' && 'invisible'
|
|
235
|
-
)}>
|
|
215
|
+
<span className="px-2 py-1 text-xs rounded bg-yellow-100 text-yellow-800 font-semibold align-middle text-center inline-flex items-center justify-center whitespace-nowrap">
|
|
236
216
|
{opt.discountText.replace(
|
|
237
217
|
'{percent}',
|
|
238
218
|
String(Math.round(Math.abs(bOpt.discount) * 100))
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
// default tag renderers
|
|
4
|
+
const defaultTagRenderers = {
|
|
5
|
+
// text Stong
|
|
6
|
+
strong: (chunks: React.ReactNode) => <strong>{chunks}</strong>,
|
|
7
|
+
// text Emphasis
|
|
8
|
+
em: (chunks: React.ReactNode) => <em>{chunks}</em>,
|
|
9
|
+
// text Underline
|
|
10
|
+
u: (chunks: React.ReactNode) => <u>{chunks}</u>,
|
|
11
|
+
// text Mark
|
|
12
|
+
mark: (chunks: React.ReactNode) => <mark className="bg-purple-300 dark:bg-purple-500 text-neutral-800 dark:text-neutral-300 px-1 rounded">{chunks}</mark>,
|
|
13
|
+
// text Delete
|
|
14
|
+
del: (chunks: React.ReactNode) => <del>{chunks}</del>,
|
|
15
|
+
// text Subscript
|
|
16
|
+
sub: (chunks: React.ReactNode) => <sub>{chunks}</sub>,
|
|
17
|
+
// text Superscript
|
|
18
|
+
sup: (chunks: React.ReactNode) => <sup>{chunks}</sup>,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// custom tag renderers
|
|
22
|
+
type TagRenderer = (chunks: React.ReactNode) => React.ReactElement;
|
|
23
|
+
type TagRenderers = Record<string, TagRenderer>;
|
|
24
|
+
|
|
25
|
+
// create rich text renderer
|
|
26
|
+
export function createRichTextRenderer(customRenderers?: TagRenderers) {
|
|
27
|
+
const renderers = { ...defaultTagRenderers, ...customRenderers };
|
|
28
|
+
|
|
29
|
+
return function richText(t: any, key: string) {
|
|
30
|
+
return t.rich(key, renderers);
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// default rich text renderer
|
|
35
|
+
export const richText = createRichTextRenderer();
|
package/src/main/seo-content.tsx
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
import { useTranslations } from 'next-intl'
|
|
5
5
|
import { cn } from '@lib/utils';
|
|
6
|
+
import { richText } from '@third-ui/main/rich-text-expert';
|
|
6
7
|
|
|
7
8
|
interface Section {
|
|
8
9
|
title: string;
|
|
@@ -14,28 +15,28 @@ export function SeoContent({ sectionClassName }: { sectionClassName?: string })
|
|
|
14
15
|
|
|
15
16
|
return (
|
|
16
17
|
<section id="seo" className={cn("px-16 py-10 mx-16 md:mx-32 scroll-mt-20", sectionClassName)}>
|
|
17
|
-
<
|
|
18
|
+
<h2 className="text-3xl md:text-4xl font-bold text-center mb-8">
|
|
18
19
|
{t('title')} <span className="text-purple-500">{t('eyesOn')}</span>
|
|
19
|
-
</
|
|
20
|
+
</h2>
|
|
20
21
|
<h3 className="text-center text-gray-600 dark:text-gray-400 mb-12 text-lg">
|
|
21
22
|
{t('description')}
|
|
22
23
|
</h3>
|
|
23
24
|
<div className="bg-gray-50 dark:bg-gray-800/60 border border-gray-200 dark:border-gray-700 rounded-2xl p-8 md:p-12 shadow-sm dark:shadow-none">
|
|
24
25
|
<div className="space-y-10">
|
|
25
26
|
<p className="text-gray-600 dark:text-gray-400 text-lg">
|
|
26
|
-
{t
|
|
27
|
+
{richText(t, 'intro')}
|
|
27
28
|
</p>
|
|
28
29
|
{t.raw('sections').map((section: Section, index: number) => (
|
|
29
30
|
<div key={index}>
|
|
30
31
|
<h2 className="text-xl font-semibold mb-3 text-gray-900 dark:text-gray-100 flex items-center">
|
|
31
32
|
{section.title}
|
|
32
33
|
</h2>
|
|
33
|
-
<p className="text-gray-700 dark:text-gray-300">{
|
|
34
|
+
<p className="text-gray-700 dark:text-gray-300">{richText(t, `sections.${index}.content`)}</p>
|
|
34
35
|
</div>
|
|
35
36
|
))}
|
|
36
37
|
</div>
|
|
37
38
|
<p className="mt-10 text-gray-600 dark:text-gray-400 text-lg">
|
|
38
|
-
{t
|
|
39
|
+
{richText(t, 'conclusion')}
|
|
39
40
|
</p>
|
|
40
41
|
</div>
|
|
41
42
|
</section>
|
package/src/main/tips.tsx
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { useTranslations } from 'next-intl'
|
|
4
4
|
import { cn } from '@lib/utils';
|
|
5
|
+
import { richText } from '@third-ui/main/rich-text-expert';
|
|
5
6
|
|
|
6
7
|
interface Tip {
|
|
7
8
|
title: string;
|
|
@@ -24,12 +25,16 @@ export function Tips({ sectionClassName }: { sectionClassName?: string }) {
|
|
|
24
25
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-12 bg-gray-50 dark:bg-gray-800/60 border border-gray-200 dark:border-gray-700 rounded-2xl p-8 md:p-12 shadow-sm dark:shadow-none">
|
|
25
26
|
{[leftColumn, rightColumn].map((column: Tip[], colIndex) => (
|
|
26
27
|
<div key={colIndex} className="space-y-8">
|
|
27
|
-
{column.map((tip: Tip, tipIndex) =>
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
{column.map((tip: Tip, tipIndex) => {
|
|
29
|
+
// calculate the actual index in the original array
|
|
30
|
+
const actualIndex = colIndex === 0 ? tipIndex : tipIndex + midPoint;
|
|
31
|
+
return (
|
|
32
|
+
<div key={tipIndex} className="space-y-4">
|
|
33
|
+
<h3 className="text-2xl font-semibold">{tip.title}</h3>
|
|
34
|
+
<p className="">{richText(t, `sections.${actualIndex}.description`)}</p>
|
|
35
|
+
</div>
|
|
36
|
+
);
|
|
37
|
+
})}
|
|
33
38
|
</div>
|
|
34
39
|
))}
|
|
35
40
|
</div>
|
package/src/main/usage.tsx
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { useTranslations } from 'next-intl'
|
|
4
4
|
import { cn } from '@lib/utils';
|
|
5
5
|
import { globalLucideIcons as icons, getGlobalIcon } from '@base-ui/components/global-icon'
|
|
6
|
+
import { richText } from '@third-ui/main/rich-text-expert';
|
|
6
7
|
|
|
7
8
|
export function Usage({ sectionClassName }: { sectionClassName?: string }) {
|
|
8
9
|
const t = useTranslations('usage');
|
|
@@ -18,7 +19,7 @@ export function Usage({ sectionClassName }: { sectionClassName?: string }) {
|
|
|
18
19
|
{t('title')} <span className="text-purple-500">{t('eyesOn')}</span>
|
|
19
20
|
</h2>
|
|
20
21
|
<p className="text-center text-gray-600 dark:text-gray-400 mb-12 text-base md:text-lg mx-auto whitespace-nowrap">
|
|
21
|
-
{t
|
|
22
|
+
{richText(t, 'description')}
|
|
22
23
|
</p>
|
|
23
24
|
<div className="bg-gray-50 dark:bg-gray-800/60 border border-gray-200 dark:border-gray-700 rounded-2xl p-8 md:p-12 shadow-sm dark:shadow-none">
|
|
24
25
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-8 gap-y-12">
|
|
@@ -33,7 +34,7 @@ export function Usage({ sectionClassName }: { sectionClassName?: string }) {
|
|
|
33
34
|
<h3 className="text-xl font-semibold mb-3 text-gray-900 dark:text-gray-100 flex items-center">
|
|
34
35
|
{`${idx + 1}. ${step.title}`}
|
|
35
36
|
</h3>
|
|
36
|
-
<p className="text-gray-700 dark:text-gray-300">{
|
|
37
|
+
<p className="text-gray-700 dark:text-gray-300">{richText(t, `steps.${idx}.description`)}</p>
|
|
37
38
|
</div>
|
|
38
39
|
</div>
|
|
39
40
|
)
|