11/** biome-ignore-all lint/suspicious/noArrayIndexKey: Would need to look into this trivial issue */
22"use client" ;
33
4+ import { CodeBlock } from "fumadocs-ui/components/codeblock" ;
45import defaultMdxComponents from "fumadocs-ui/mdx" ;
56import { cn } from "fumadocs-ui/utils/cn" ;
67import {
78 BlocksIcon ,
89 GitMergeIcon ,
910 HomeIcon ,
1011 SailboatIcon ,
12+ TerminalIcon ,
13+ Trash2Icon ,
1114 ZapIcon ,
1215} from "lucide-react" ;
1316import Image from "next/image" ;
1417import Link from "next/link" ;
15- import { useState } from "react" ;
18+ import { type HTMLProps , type ReactNode , useState } from "react" ;
19+ import { Pre } from "@/components/codeblock" ;
1620import { buttonVariants } from "@/components/ui/button" ;
1721import CkanDevstallerDemo from "./ckan-devstaller-demo.gif" ;
1822
@@ -37,6 +41,7 @@ export default function HomePage() {
3741 >
3842 < div className = "relative mb-4" >
3943 < Hero />
44+ < Why />
4045 </ div >
4146 </ div >
4247 < hr className = "mt-12 mb-4" />
@@ -48,10 +53,20 @@ export default function HomePage() {
4853 href = "https://dathere.com"
4954 target = "_blank"
5055 className = "font-medium text-blue-400"
56+ rel = "noopener"
5157 >
5258 datHere
5359 </ a >
54- . < a href = "https://dathere.com/privacy-policy/" target = "_blank" className = "font-medium text-blue-400" > Privacy Policy</ a > .
60+ .{ " " }
61+ < a
62+ href = "https://dathere.com/privacy-policy/"
63+ target = "_blank"
64+ className = "font-medium text-blue-400"
65+ rel = "noopener"
66+ >
67+ Privacy Policy
68+ </ a >
69+ .
5570 </ p >
5671 </ footer >
5772 </ main >
@@ -123,33 +138,28 @@ function Hero() {
123138 Source Code
124139 </ Link >
125140 </ div >
126- < Cards >
127- < Card
128- icon = { < ZapIcon /> }
129- href = "/docs"
130- title = "Quick start"
131- >
132- Get started with ckan-devstaller and install CKAN within minutes
133- </ Card >
134- < Card icon = { < BlocksIcon /> } href = "/docs/builder" title = "Builder" >
135- Customize your installation with an interactive web GUI
136- </ Card >
137- < Card
138- icon = { < HomeIcon /> }
139- href = "/docs/reference/installation-architecture"
140- title = "Installation architecture"
141- >
142- Learn about where files are installed after running
143- ckan-devstaller
144- </ Card >
145- < Card
146- icon = { < GitMergeIcon /> }
147- href = "https://github.com/dathere/ckan-devstaller"
148- title = "Source code"
149- >
150- View the source code of ckan-devstaller on GitHub
151- </ Card >
152- </ Cards >
141+ < Cards >
142+ < Card icon = { < ZapIcon /> } href = "/docs" title = "Quick start" >
143+ Get started with ckan-devstaller and install CKAN within minutes
144+ </ Card >
145+ < Card icon = { < BlocksIcon /> } href = "/docs/builder" title = "Builder" >
146+ Customize your installation with an interactive web GUI
147+ </ Card >
148+ < Card
149+ icon = { < HomeIcon /> }
150+ href = "/docs/reference/installation-architecture"
151+ title = "Installation architecture"
152+ >
153+ Learn about where files are installed after running ckan-devstaller
154+ </ Card >
155+ < Card
156+ icon = { < GitMergeIcon /> }
157+ href = "https://github.com/dathere/ckan-devstaller"
158+ title = "Source code"
159+ >
160+ View the source code of ckan-devstaller on GitHub
161+ </ Card >
162+ </ Cards >
153163 < PreviewImages />
154164 </ div >
155165 ) ;
@@ -199,3 +209,213 @@ function PreviewImages() {
199209 </ div >
200210 ) ;
201211}
212+
213+ function Why ( ) {
214+ return (
215+ < div className = "relative overflow-hidden border-x border-t p-2" >
216+ < WhyInteractive
217+ codeblockInstall = {
218+ < CodeBlock lang = "bash" >
219+ < Pre className = "text-wrap pl-4" > ./ckan-devstaller</ Pre >
220+ </ CodeBlock >
221+ }
222+ codeblockUninstall = {
223+ < CodeBlock lang = "bash" >
224+ < Pre className = "text-wrap pl-4" > ./ckan-devstaller uninstall</ Pre >
225+ </ CodeBlock >
226+ }
227+ />
228+ </ div >
229+ ) ;
230+ }
231+
232+ export function WhyInteractive ( props : {
233+ codeblockInstall : ReactNode ;
234+ codeblockUninstall : ReactNode ;
235+ } ) {
236+ const [ active , setActive ] = useState ( 0 ) ;
237+ const items = [
238+ [
239+ < ZapIcon className = "w-4 h-4 inline-block" key = { 0 } /> ,
240+ "Install CKAN within minutes" ,
241+ ] ,
242+ [
243+ < BlocksIcon className = "w-4 h-4 inline-block" key = { 1 } /> ,
244+ "Customize your installation" ,
245+ ] ,
246+ [
247+ < TerminalIcon className = "w-4 h-4 inline-block" key = { 2 } /> ,
248+ "Designed for developers" ,
249+ ] ,
250+ [
251+ < Trash2Icon className = "w-4 h-4 inline-block" key = { 3 } /> ,
252+ "Uninstall with ease" ,
253+ ] ,
254+ ] ;
255+
256+ return (
257+ < div
258+ id = "why-interactive"
259+ className = "flex flex-col-reverse gap-3 md:flex-row md:min-h-[200px]"
260+ >
261+ < div className = "flex flex-col" >
262+ { items . map ( ( item , i ) => (
263+ < button
264+ key = { item [ 1 ] as string }
265+ ref = { ( element ) => {
266+ if ( ! element || i !== active ) return ;
267+ } }
268+ type = "button"
269+ className = { cn (
270+ "transition-colors text-nowrap border border-transparent rounded-lg px-3 py-2.5 text-start text-sm text-fd-muted-foreground font-medium" ,
271+ i === active
272+ ? "text-fd-primary bg-fd-primary/10 border-fd-primary/10"
273+ : "hover:text-fd-accent-foreground/80 cursor-pointer" ,
274+ ) }
275+ onClick = { ( ) => {
276+ setActive ( i ) ;
277+ } }
278+ >
279+ { item [ 0 ] } { item [ 1 ] }
280+ </ button >
281+ ) ) }
282+ </ div >
283+ < style >
284+ { `
285+ @keyframes why-interactive-x {
286+ from {
287+ width: 0px;
288+ }
289+
290+ to {
291+ width: 100%;
292+ }
293+ }` }
294+ </ style >
295+
296+ < div className = "flex-1 p-4 border border-fd-primary/10 bg-fd-card/40 rounded-lg shadow-lg" >
297+ { active === 0 ? (
298+ < WhyPanel >
299+ < h3 >
300+ < ZapIcon className = "w-4 h-4 inline-block mr-1 mb-1" />
301+ Install CKAN within minutes.
302+ </ h3 >
303+ < p >
304+ One of the primary goals of ckan-devstaller is to ease
305+ installation of CKAN for development. Built with Rust for speed
306+ and streamlining installation with{ " " }
307+ < a href = "https://github.com/tino097/ckan-compose/tree/ckan-devstaller" >
308+ ckan-compose
309+ </ a >
310+ , ckan-devstaller improves installation speeds{ " " }
311+ < strong > from hours/days to just minutes</ strong > depending on your
312+ download speed.
313+ </ p >
314+ < div className = "flex gap-2" >
315+ < Link href = "/docs" className = { cn ( buttonVariants ( ) , "not-prose" ) } >
316+ Get started
317+ </ Link >
318+ < Link
319+ href = "/docs/builder"
320+ className = { cn ( buttonVariants ( ) , "not-prose" ) }
321+ >
322+ Customize your installation
323+ </ Link >
324+ </ div >
325+ </ WhyPanel >
326+ ) : null }
327+ { active === 1 ? (
328+ < WhyPanel >
329+ < h3 >
330+ < BlocksIcon className = "w-4 h-4 inline-block mr-1 mb-1" />
331+ Customize your installation with the Builder.
332+ </ h3 >
333+ < p >
334+ Try out the interactive web GUI for customizing your CKAN
335+ installation. You can select:
336+ </ p >
337+ < ul >
338+ < li > Presets</ li >
339+ < li > CKAN version</ li >
340+ < li > Extensions</ li >
341+ < li > Features</ li >
342+ </ ul >
343+ < p >
344+ Then you can copy the provided ckan-devstaller command to run your
345+ selected configuration.
346+ </ p >
347+ < div className = "mt-4 flex flex-row items-center gap-1.5 not-prose" >
348+ < Link href = "/docs/builder" className = { cn ( buttonVariants ( ) ) } >
349+ Try out the Builder
350+ </ Link >
351+ </ div >
352+ </ WhyPanel >
353+ ) : null }
354+ { active === 2 ? (
355+ < WhyPanel >
356+ < h3 >
357+ < TerminalIcon className = "w-4 h-4 inline-block mr-1 mb-1" />
358+ Designed for developers.
359+ </ h3 >
360+ < p >
361+ We've kept development use cases in mind while developing
362+ ckan-devstaller, such as:
363+ </ p >
364+ < ul >
365+ < li > Trying out a new version of CKAN</ li >
366+ < li > Developing CKAN extensions and themes</ li >
367+ </ ul >
368+ < div className = "flex gap-2" >
369+ < Link
370+ href = "/docs/reference/installation-architecture"
371+ className = { cn ( buttonVariants ( ) , "not-prose" ) }
372+ >
373+ View the installation architecture
374+ </ Link >
375+ < Link
376+ href = "https://github.com/dathere/ckan-devstaller"
377+ className = { cn ( buttonVariants ( { variant : "ghost" } ) ) }
378+ >
379+ Source code
380+ </ Link >
381+ </ div >
382+ </ WhyPanel >
383+ ) : null }
384+ { active === 3 ? (
385+ < WhyPanel >
386+ < h3 >
387+ < Trash2Icon className = "w-4 h-4 inline-block mr-1 mb-1" />
388+ Uninstall CKAN with ease.
389+ </ h3 >
390+ < p >
391+ After you've installed CKAN with ckan-devstaller, you can
392+ uninstall CKAN with ease. This allows for quickly re-installing
393+ CKAN for a different use case.
394+ </ p >
395+ { props . codeblockUninstall }
396+ < Link
397+ href = "/docs/tutorials/uninstall-ckan"
398+ className = { cn ( buttonVariants ( ) , "not-prose" ) }
399+ >
400+ Learn more about uninstalling
401+ </ Link >
402+ </ WhyPanel >
403+ ) : null }
404+ </ div >
405+ </ div >
406+ ) ;
407+ }
408+
409+ function WhyPanel ( props : HTMLProps < HTMLDivElement > ) {
410+ return (
411+ < div
412+ { ...props }
413+ className = { cn (
414+ "duration-700 animate-in fade-in text-sm prose" ,
415+ props . className ,
416+ ) }
417+ >
418+ { props . children }
419+ </ div >
420+ ) ;
421+ }
0 commit comments