@stevederico/skateboard-ui 2.3.1 → 2.5.0
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/CHANGELOG.md +16 -0
- package/README.md +18 -0
- package/layout/Layout.jsx +9 -4
- package/package.json +1 -1
- package/views/LandingView.jsx +54 -46
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
2.5.0
|
|
4
|
+
|
|
5
|
+
Add configurable LandingView constants
|
|
6
|
+
Add navLinks constant
|
|
7
|
+
Add pricing.title constant
|
|
8
|
+
Add pricing.extras constant
|
|
9
|
+
Add ctaHeading constant
|
|
10
|
+
Add footerLinks constant
|
|
11
|
+
Add copyrightText constant
|
|
12
|
+
Use stripeProducts features and interval
|
|
13
|
+
Conditionally render pricing section
|
|
14
|
+
|
|
15
|
+
2.4.0
|
|
16
|
+
|
|
17
|
+
Add sidebarCollapsed constant
|
|
18
|
+
|
|
3
19
|
2.3.1
|
|
4
20
|
|
|
5
21
|
Remove sidebar rail hover border
|
package/README.md
CHANGED
|
@@ -123,6 +123,24 @@ const constants = {
|
|
|
123
123
|
}
|
|
124
124
|
],
|
|
125
125
|
|
|
126
|
+
// Optional: Landing page customization
|
|
127
|
+
navLinks: [ // Override header nav links
|
|
128
|
+
{ label: "Features", href: "#features" },
|
|
129
|
+
{ label: "Pricing", href: "#pricing" },
|
|
130
|
+
{ label: "Blog", href: "/blog" }
|
|
131
|
+
],
|
|
132
|
+
pricing: {
|
|
133
|
+
title: "Simple Pricing", // Pricing section heading
|
|
134
|
+
extras: ["Priority Customer Support", "Cancel anytime"] // Extra bullets after product features
|
|
135
|
+
},
|
|
136
|
+
ctaHeading: "Ready To Build?", // CTA section heading
|
|
137
|
+
footerLinks: [ // Override footer links
|
|
138
|
+
{ label: "Privacy", href: "/privacy" },
|
|
139
|
+
{ label: "Terms", href: "/terms" },
|
|
140
|
+
{ label: "EULA", href: "/eula" }
|
|
141
|
+
],
|
|
142
|
+
copyrightText: "All rights reserved.", // Copyright suffix after "© {year} {companyName}."
|
|
143
|
+
|
|
126
144
|
// Optional: Legal documents (plain text, supports _COMPANY_, _WEBSITE_, _EMAIL_ placeholders)
|
|
127
145
|
termsOfService: "Terms of Service for _COMPANY_...",
|
|
128
146
|
privacyPolicy: "Privacy Policy for _COMPANY_...",
|
package/layout/Layout.jsx
CHANGED
|
@@ -14,6 +14,9 @@ import { getState } from '../core/Context.jsx';
|
|
|
14
14
|
* Set `constants.hideSidebarInsetRounding` to true to remove the
|
|
15
15
|
* rounded corners on the main content area.
|
|
16
16
|
*
|
|
17
|
+
* Set `constants.sidebarCollapsed` to true to start the sidebar
|
|
18
|
+
* in its collapsed (icon-only) state.
|
|
19
|
+
*
|
|
17
20
|
* @param {Object} props
|
|
18
21
|
* @param {React.ReactNode} [props.children] - Child content (unused, Outlet renders routes)
|
|
19
22
|
* @returns {JSX.Element} Layout with sidebar, main content, and tab bar
|
|
@@ -37,10 +40,12 @@ export default function Layout({ children }) {
|
|
|
37
40
|
|
|
38
41
|
return (
|
|
39
42
|
<div className="min-h-screen flex flex-col pt-[env(safe-area-inset-top)] pb-[calc(5rem+env(safe-area-inset-bottom))] md:pb-[env(safe-area-inset-bottom)] pl-[env(safe-area-inset-left)] pr-[env(safe-area-inset-right)]">
|
|
40
|
-
<SidebarProvider
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
<SidebarProvider
|
|
44
|
+
defaultOpen={!constants.sidebarCollapsed}
|
|
45
|
+
style={{
|
|
46
|
+
'--sidebar-width': 'calc(var(--spacing) * 72)',
|
|
47
|
+
'--header-height': '3.5rem',
|
|
48
|
+
}}>
|
|
44
49
|
{showSidebar && <Sidebar variant="inset" />}
|
|
45
50
|
<SidebarInset className={constants.hideSidebarInsetRounding ? "md:peer-data-[variant=inset]:rounded-none" : ""}>
|
|
46
51
|
<Outlet />
|
package/package.json
CHANGED
package/views/LandingView.jsx
CHANGED
|
@@ -13,8 +13,8 @@ import { Separator } from '../shadcn/ui/separator.jsx';
|
|
|
13
13
|
* Default landing page with hero section, features grid, pricing card,
|
|
14
14
|
* CTA section, and footer.
|
|
15
15
|
*
|
|
16
|
-
* Reads app branding, tagline, features, and
|
|
17
|
-
*
|
|
16
|
+
* Reads app branding, tagline, features, pricing, and layout from constants.
|
|
17
|
+
* All sections are configurable via optional constants keys with sensible defaults.
|
|
18
18
|
*
|
|
19
19
|
* @returns {JSX.Element} Full landing page
|
|
20
20
|
*
|
|
@@ -43,9 +43,13 @@ export default function LandingView() {
|
|
|
43
43
|
</div>
|
|
44
44
|
|
|
45
45
|
<div className="hidden md:flex gap-6">
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
{(constants.navLinks || [
|
|
47
|
+
{ label: 'Features', href: '#features' },
|
|
48
|
+
...(constants.stripeProducts?.length > 0 ? [{ label: 'Pricing', href: '#pricing' }] : []),
|
|
49
|
+
{ label: 'Terms', href: '/terms' },
|
|
50
|
+
]).map((link, index) => (
|
|
51
|
+
<a key={index} href={link.href} className="text-muted-foreground hover:text-foreground transition-colors font-semibold">{link.label}</a>
|
|
52
|
+
))}
|
|
49
53
|
</div>
|
|
50
54
|
|
|
51
55
|
<div className="flex gap-3 items-center">
|
|
@@ -91,50 +95,50 @@ export default function LandingView() {
|
|
|
91
95
|
</section>
|
|
92
96
|
|
|
93
97
|
{/* Pricing Section */}
|
|
94
|
-
|
|
95
|
-
<
|
|
96
|
-
<
|
|
97
|
-
|
|
98
|
-
<
|
|
99
|
-
<
|
|
100
|
-
<
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
<
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
<
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
</
|
|
120
|
-
</
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
</
|
|
126
|
-
</
|
|
127
|
-
</
|
|
98
|
+
{constants.stripeProducts?.length > 0 && (
|
|
99
|
+
<section id="pricing" className="py-16 md:py-24">
|
|
100
|
+
<div className="max-w-7xl mx-auto px-6">
|
|
101
|
+
<h2 className="text-center text-4xl md:text-5xl font-bold mb-16">{constants.pricing?.title || 'Pricing'}</h2>
|
|
102
|
+
<div className="max-w-md mx-auto">
|
|
103
|
+
<Card>
|
|
104
|
+
<CardHeader className="text-center">
|
|
105
|
+
<CardTitle className="text-2xl font-bold">{constants.stripeProducts[0]?.title || 'Monthly Plan'}</CardTitle>
|
|
106
|
+
<CardDescription>per {constants.stripeProducts[0]?.interval || 'month'}</CardDescription>
|
|
107
|
+
</CardHeader>
|
|
108
|
+
<CardContent className="text-center">
|
|
109
|
+
<div className="text-5xl font-bold text-foreground mb-8">{constants.stripeProducts[0]?.price || '$5.00'}</div>
|
|
110
|
+
<ul className="text-left space-y-4 mb-8">
|
|
111
|
+
{(constants.stripeProducts[0]?.features || []).map((feature, index) => (
|
|
112
|
+
<li key={index} className="flex items-center gap-2">
|
|
113
|
+
<Check size={16} className="text-primary shrink-0" />
|
|
114
|
+
{feature}
|
|
115
|
+
</li>
|
|
116
|
+
))}
|
|
117
|
+
{(constants.pricing?.extras || []).map((extra, index) => (
|
|
118
|
+
<li key={`extra-${index}`} className="flex items-center gap-2">
|
|
119
|
+
<Check size={16} className="text-primary shrink-0" />
|
|
120
|
+
{extra}
|
|
121
|
+
</li>
|
|
122
|
+
))}
|
|
123
|
+
</ul>
|
|
124
|
+
</CardContent>
|
|
125
|
+
<CardFooter>
|
|
126
|
+
<Button variant="default" size="cta" className="w-full" onClick={() => navigate('/app')}>
|
|
127
|
+
{constants.cta}
|
|
128
|
+
</Button>
|
|
129
|
+
</CardFooter>
|
|
130
|
+
</Card>
|
|
131
|
+
</div>
|
|
128
132
|
</div>
|
|
129
|
-
</
|
|
130
|
-
|
|
133
|
+
</section>
|
|
134
|
+
)}
|
|
131
135
|
|
|
132
136
|
{/* CTA Section */}
|
|
133
137
|
<section className="py-16 md:py-24">
|
|
134
138
|
<div className="max-w-7xl mx-auto px-6">
|
|
135
139
|
<Card className="bg-primary text-primary-foreground py-16 text-center">
|
|
136
140
|
<CardContent>
|
|
137
|
-
<h2 className="text-4xl md:text-5xl font-bold mb-10">Ready To Build
|
|
141
|
+
<h2 className="text-4xl md:text-5xl font-bold mb-10">{constants.ctaHeading || 'Ready To Build?'}</h2>
|
|
138
142
|
<Button variant="secondary" size="cta" onClick={() => navigate('/app')}>
|
|
139
143
|
{constants.cta}
|
|
140
144
|
</Button>
|
|
@@ -149,11 +153,15 @@ export default function LandingView() {
|
|
|
149
153
|
<div className="max-w-7xl mx-auto px-6">
|
|
150
154
|
<Separator className="mb-8" />
|
|
151
155
|
<div className="flex justify-center gap-8 mb-6">
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
156
|
+
{(constants.footerLinks || [
|
|
157
|
+
...(constants.privacyPolicy ? [{ label: 'Privacy', href: '/privacy' }] : []),
|
|
158
|
+
...(constants.termsOfService ? [{ label: 'Terms', href: '/terms' }] : []),
|
|
159
|
+
...(constants.EULA ? [{ label: 'EULA', href: '/eula' }] : []),
|
|
160
|
+
]).map((link, index) => (
|
|
161
|
+
<a key={index} href={link.href} className="text-muted-foreground hover:text-foreground transition-colors font-semibold">{link.label}</a>
|
|
162
|
+
))}
|
|
155
163
|
</div>
|
|
156
|
-
<p className="text-center text-muted-foreground">© {new Date().getFullYear()} {constants.companyName}. All rights reserved
|
|
164
|
+
<p className="text-center text-muted-foreground">© {new Date().getFullYear()} {constants.companyName}. {constants.copyrightText || 'All rights reserved.'}</p>
|
|
157
165
|
</div>
|
|
158
166
|
</footer>
|
|
159
167
|
</div>
|