Skip to content

Commit

Permalink
Kurt Cobain
Browse files Browse the repository at this point in the history
  • Loading branch information
irsyadadl committed Sep 16, 2024
1 parent e4bf9c3 commit e8d09e8
Show file tree
Hide file tree
Showing 87 changed files with 770 additions and 483 deletions.
5 changes: 4 additions & 1 deletion app/aside/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,10 @@ export default function Layout({ children }: { children: React.ReactNode }) {
aside={
<>
<Aside.Header>
<Link className="flex items-center gap-x-2" href="#">
<Link
className="flex items-center gap-x-2"
href="https://getjustd.com/docs/components/layouts/aside"
>
<IconBrandJustd />
<strong>Justd</strong>
</Link>
Expand Down
Binary file modified bun.lockb
Binary file not shown.
10 changes: 5 additions & 5 deletions components/docs/rehype/code.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,10 @@ function Code({ className, lang = "tsx", code, withImportCopy = true }: CodeProp

function CodeContainer({ children, isOpened }: { children: React.ReactNode; isOpened: boolean }) {
return (
<CollapsibleContent forceMount className={!isOpened ? "h-32" : ""}>
<CollapsibleContent forceMount className={!isOpened ? "max-h-32" : ""}>
<div
className={cn(
"[&_pre]:my-0 [&_pre]:!border-0 [&_pre]:h-[32rem] [&_pre]:pb-[100px]",
"[&_pre]:my-0 [&_pre]:!border-0 [&_pre]:max-h-[32rem] [&_pre]:pb-[100px]",
!isOpened ? "[&_pre]:overflow-hidden" : "[&_pre]:overflow-auto"
)}
>
Expand Down Expand Up @@ -142,7 +142,7 @@ export function CopyRawButton({ code }: { className?: string; code: string }) {
return <CopyButton ariaLabel="Copy raw code" isCopied={copied === "raw"} onPress={copyRaw} />
}

const CodeHighlighter: React.FC<CodeProps> = ({ lang = "tsx", code }) => {
const CodeHighlighter = ({ lang = "tsx", code, ...props }: CodeProps) => {
const [formattedCode, setFormattedCode] = useState("")
const [error, setError] = useState("")

Expand Down Expand Up @@ -176,7 +176,7 @@ const CodeHighlighter: React.FC<CodeProps> = ({ lang = "tsx", code }) => {
return <p>Error: {error}</p>
}

return <div dangerouslySetInnerHTML={{ __html: formattedCode }} />
return <div {...props} dangerouslySetInnerHTML={{ __html: formattedCode }} />
}

export { CodeContainer, CodeExpandButton, CodeCollapsible, Code }
export { CodeHighlighter, CodeContainer, CodeExpandButton, CodeCollapsible, Code }
262 changes: 262 additions & 0 deletions components/installation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
"use client"

import React from "react"

import { CodeHighlighter } from "@/components/docs/rehype/code"
import { trackEvent } from "@openpanel/nextjs"
import { AnimatePresence, motion } from "framer-motion"
import { IconCheck, IconDuplicate } from "justd-icons"
import { Button, type ButtonProps } from "react-aria-components"
import { tv } from "tailwind-variants"
import { Link, Menu } from "ui"
import { copyToClipboard } from "usemods"

const manualText =
"Sometimes, using the CLI is the way to go, so make sure you install the necessary\n" +
" dependencies for the components you want to use."

const installationStyles = tv({
slots: {
copyButton:
"focus:outline-none absolute right-0 mr-2 inset-y-1/2 -translate-y-1/2 pressed:bg-zinc-800 size-[1.85rem] grid place-content-center text-white border border-zinc-700 rounded-md bg-black/10 backdrop-blur hover:bg-zinc-800",
install:
"flex h-12 border pr-8 relative overflow-hidden rounded-lg bg-[#0e0e10] items-center [&_[data-rehype-pretty-code-figure]_pre]:border-0"
}
})

const { copyButton, install } = installationStyles()

export interface InstallationProps {
items: string[]
command?: string
options: {
isInit?: boolean
isComponent?: boolean
isManual?: boolean
isExecutor?: boolean
}
}

export function Installation(props: InstallationProps) {
const {
options = { isExecutor: false, isInit: false, isComponent: false, isManual: false },
items
} = props
const [pkgManager, setPkgManager] = React.useState({
name: "npm",
action: "i"
})
const [isCopied, setIsCopied] = React.useState(false)

React.useEffect(() => {
let timer: NodeJS.Timeout
if (isCopied) {
timer = setTimeout(() => setIsCopied(false), 2000)
}
return () => clearTimeout(timer)
}, [isCopied])

return (
<>
{options.isComponent && (
<p>
If you hit any issues, make sure you check out the installation guide{" "}
<Link
className="not-prose font-medium"
intent="primary"
href="/docs/getting-started/installation"
target="_blank"
rel="noreferrer"
>
here
</Link>
.
</p>
)}
{options.isManual && <p>{manualText}</p>}
<div className={install()}>
<CodeHighlighter
className="flex-1 overflow-x-auto pr-4"
lang="bash"
code={
props.command ||
(options.isInit
? "npx justd-cli@latest init"
: options.isComponent
? `npx justd-cli@latest add ${items[0]}`
: `${pkgManager.name} ${pkgManager.action} ${items.join(" ")}`)
}
/>
{props.command ? (
<ButtonCopy
onPress={() => {
copyToClipboard(props.command as string).then(() => {
setIsCopied(true)
trackEvent("cli pressed", { copy: props.command })
})
}}
isCopied={isCopied}
/>
) : options.isComponent ? (
<ButtonCopy
onPress={() => {
copyToClipboard(`npx justd-cli@latest add ${items[0]}`).then(() => {
setIsCopied(true)
trackEvent("cli pressed", { copy: `add ${items.join(" ")}` })
})
}}
isCopied={isCopied}
/>
) : options.isInit ? (
<ButtonCopy
onPress={() => {
copyToClipboard(`npx justd-cli@latest init`).then(() => {
setIsCopied(true)
trackEvent("cli pressed", { copy: `init` })
})
}}
isCopied={isCopied}
/>
) : (
<ChoosePkgManager
{...{
isExecutor: options.isExecutor,
isCopied,
setIsCopied,
setPkgManager,
items
}}
/>
)}
</div>
</>
)
}

const copyVariants = {
hidden: { opacity: 0, scale: 0.5 },
visible: { opacity: 1, scale: 1 }
}

interface PkgManager {
name: string
action: string
executor?: string
}

interface ChoosePkgManagerProps {
isCopied: boolean
setIsCopied: (isCopied: boolean) => void
setPkgManager: (pkgManager: PkgManager) => void
items: string[]
isExecutor?: boolean
}

function ChoosePkgManager({
isExecutor,
items,
setIsCopied,
setPkgManager,
...props
}: ChoosePkgManagerProps) {
function handleAction(tool: string) {
let selectedPkgManager: PkgManager = {
name: "",
executor: "",
action: ""
}

switch (tool) {
case "npm":
selectedPkgManager = {
name: "npm",
executor: "npx",
action: "i"
}
break
case "yarn":
selectedPkgManager = {
name: "yarn",
executor: "yarn dlx",
action: "add"
}
break
case "pnpm":
selectedPkgManager = {
name: "pnpm",
executor: "pnpm dlx",
action: "add"
}
break
case "bun":
selectedPkgManager = {
name: "bun",
executor: "bunx",
action: "add"
}
break
}

setPkgManager(selectedPkgManager)

const executor = isExecutor ? selectedPkgManager.executor : selectedPkgManager.name
copyToClipboard(`${executor} ${selectedPkgManager.action} ${items.join(" ")}`).then(() => {
setIsCopied(true)
trackEvent("cli pressed", {
copy: `${executor} ${selectedPkgManager.action} ${items.join(" ")}`
})
})
}

return (
<Menu>
<ButtonCopy isCopied={props.isCopied} />
<Menu.Content showArrow placement="bottom end">
{[
{ name: "NPM", vendor: "npm" },
{ name: "Yarn", vendor: "yarn" },
{ name: "Bun", vendor: "bun" },
{ name: "PNPM", vendor: "pnpm" }
].map(({ name, vendor }) => (
<Menu.Item key={name} onAction={() => handleAction(vendor)}>
{name}
</Menu.Item>
))}
</Menu.Content>
</Menu>
)
}

interface ButtonCopyProps extends ButtonProps {
isCopied: boolean
}

function ButtonCopy({ isCopied, ...props }: ButtonCopyProps) {
return (
<Button className={copyButton()} {...props}>
<AnimatePresence mode="wait" initial={false}>
{isCopied ? (
<motion.span
key="check"
variants={copyVariants}
initial="hidden"
animate="visible"
exit="hidden"
>
<IconCheck />
</motion.span>
) : (
<motion.span
key="copy"
variants={copyVariants}
initial="hidden"
animate="visible"
exit="hidden"
>
<IconDuplicate />
</motion.span>
)}
</AnimatePresence>
</Button>
)
}
2 changes: 2 additions & 0 deletions components/mdx-components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { PlainCode } from "@/components/docs/rehype/plain-code"
import { SourceCode } from "@/components/docs/rehype/source-code"
import type { InstallCommandProps } from "@/components/install-command"
import { InstallCommand } from "@/components/install-command"
import { Installation, InstallationProps } from "@/components/installation"
import { useMDXComponent } from "@/resources/hooks/use-mdx"
import Image from "next/image"
import { Link, type LinkProps } from "ui"
Expand All @@ -22,6 +23,7 @@ export function MDXContent({ code }: MdxProps) {
<Component
components={{
InstallCommand: (props: InstallCommandProps) => <InstallCommand {...props} />,
Installation: (props: InstallationProps) => <Installation {...props} />,
Note: DocNote,
Composed: DocComposed,
Image,
Expand Down
10 changes: 6 additions & 4 deletions components/ui/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ interface ButtonProps extends ButtonPrimitiveProps {
}

const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, intent, children, appearance, size, shape, ...props }, ref) => {
({ className, intent, appearance, size, shape, ...props }, ref) => {
return (
<ButtonPrimitive
ref={ref}
Expand All @@ -145,9 +145,11 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
})
)}
>
{cr(children, (children) => (
<TouchTarget>{children}</TouchTarget>
))}
{(values) => (
<TouchTarget>
{typeof props.children === "function" ? props.children(values) : props.children}
</TouchTarget>
)}
</ButtonPrimitive>
)
}
Expand Down
8 changes: 5 additions & 3 deletions components/ui/dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,11 @@ type DialogHeaderProps = React.HTMLAttributes<HTMLDivElement> & {

const Trigger = (props: ButtonPrimitiveProps) => (
<ButtonPrimitive {...props}>
{cr(props.children, (children) => (
<TouchTarget>{children}</TouchTarget>
))}
{(values) => (
<TouchTarget>
{typeof props.children === "function" ? props.children(values) : props.children}
</TouchTarget>
)}
</ButtonPrimitive>
)

Expand Down
8 changes: 5 additions & 3 deletions components/ui/menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,11 @@ interface MenuTriggerProps extends ButtonProps {

const Trigger = ({ className, ...props }: MenuTriggerProps) => (
<Button className={trigger({ className })} {...props}>
{cr(props.children, (children) => (
<TouchTarget>{children}</TouchTarget>
))}
{(values) => (
<TouchTarget>
{typeof props.children === "function" ? props.children(values) : props.children}
</TouchTarget>
)}
</Button>
)

Expand Down
Loading

0 comments on commit e8d09e8

Please sign in to comment.