ui icon indicating copy to clipboard operation
ui copied to clipboard

feat(cli): add config option to capitalize component filenames

Open plbstl opened this issue 2 years ago • 8 comments

filenames are not capitalized when overwriting

See #748

plbstl avatar Jun 29 '23 15:06 plbstl

@plbstl is attempting to deploy a commit to the shadcn-pro Team on Vercel.

A member of the Team first needs to authorize it.

vercel[bot] avatar Jun 29 '23 15:06 vercel[bot]

I agree, I always capitalize my components, and I know many people also do. I would love it if this feature was implemented!

jacob-leger avatar Jul 04 '23 23:07 jacob-leger

I think that we would get too many prompts in the init command. What about having it just in the component.json? And then maybe add a section in the CLI page where the component.json can be explained better.

dan5py avatar Jul 05 '23 20:07 dan5py

I think that we would get too many prompts in the init command. What about having it just in the component.json?

I agree with you. This implementation does not modify the init command and allows the new config option to be optional.

And then maybe add a section in the CLI page where the component.json can be explained better.

Yes. #773

plbstl avatar Jul 05 '23 22:07 plbstl

I definitely want to support casing for file names. I'll label this and get back to it. I'll think about the best to implement this so that we can support any naming convention.

Thanks for starting the work on this @plbstl

shadcn avatar Sep 19 '23 11:09 shadcn

Dropping this here as a temporary workaround.

Usage

npm run add-component button
# will install the button component and rename file from button.tsx to Button.tsx 

Installation

npm i -D tsx @types/node
// File: package.json

scripts: {
  // ...
  "add-component": "tsx ./npm-scripts/add-component.ts"
  // ...
}
// File: npm-scripts/add-component.ts

import { exec } from 'node:child_process'
import { rename } from 'node:fs'
import { dirname, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
const __dirname = import.meta.dirname ?? dirname(fileURLToPath(import.meta.url))

// modify this to match the path of your ui components folder (relative to this file)
const base = resolve(__dirname, '..', 'src', 'components', 'ui')

main()

function main() {
  const componentName = process.argv[2]
  if (!componentName) {
    console.error('Please provide a component name.')
  } else {
    createComponent(componentName)
  }
}

function createComponent(componentName: string) {
  const command = `npx shadcn-ui@latest add ${componentName}`
  exec(command, (error, stdout, stderr) => {
    if (error) {
      console.error(`Error executing command: ${error.message}`)
      return
    }
    if (stdout) console.log(`${stdout}`)
    if (stderr) console.log(`${stderr}`)

    const oldFilePath = resolve(base, `${componentName}.tsx`)
    const newFilePath = resolve(base, `${renamer(componentName)}.tsx`)
    renameFile(oldFilePath, newFilePath)
  })
}

function renamer(name: string) {
  // change from kebab-case to PascalCase
  return name
    .split('-')
    .map(part => part.charAt(0).toUpperCase() + part.slice(1))
    .join('')
}

function renameFile(oldPath: string, newPath: string) {
  rename(oldPath, newPath, err => {
    if (err) {
      console.error(`Error renaming file: ${err}`)
      return
    }
    console.log(`File renamed to ${newPath}`)
  })
}

atej avatar Feb 03 '24 19:02 atej

Just started incorporating shadcn recently and I'd advice a bit of care with @atej's solution, as I found cross dependencies between some components, which would remain with invalid filenames on import. They are easily fixable but it should be taken in consideration.

One example of this happening is with the Alert Dialog component, which requires buttonVariants (but not the Button component). Can't really say if this is a good approach or not, but it's not documented as a composition of other components, doesn't warn about the Button dependency and isn't self contained on automatic installation.

// src/components/alert-dialog

"use client"
 
import * as React from "react"
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"
 
import { cn } from "@/lib/utils"
import { buttonVariants } from "@/components/ui/button"

...

👍 +1 to having a config option for this

FelipeBodelon avatar Feb 10 '24 00:02 FelipeBodelon

Hello, I've created #2723. I think my PR partially solves your task. Please check it. I added the case property to component.json. If you set the case property to pascal and overwrite the button component, the file name describing the component will always be Button.tsx(.jsx)

alexiuscrow avatar Feb 10 '24 21:02 alexiuscrow

Can someone please review and merge this PR?

Armadillidiid avatar Apr 20 '24 07:04 Armadillidiid