@popina/cli 5.0.0-20260203082304Z → 5.0.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 +19 -0
- package/package.json +3 -3
- package/turbo/generators/config.ts +11 -0
- package/turbo/generators/package.json +3 -0
- package/turbo/generators/plopGenerator/api.ts +456 -0
- package/turbo/generators/plopGenerator/component.ts +63 -0
- package/turbo/generators/plopGenerator/icon.ts +201 -0
- package/turbo/generators/templates/api/api-controller.hbs +46 -0
- package/turbo/generators/templates/api/api-param-schema.hbs +22 -0
- package/turbo/generators/templates/api/api-router.hbs +28 -0
- package/turbo/generators/templates/api/api-schema.hbs +90 -0
- package/turbo/generators/templates/api/api-service.hbs +42 -0
- package/turbo/generators/templates/component/component-index.hbs +1 -0
- package/turbo/generators/templates/component/component-react.hbs +14 -0
- package/turbo/generators/templates/component/component-story.hbs +21 -0
- package/turbo/generators/templates/component/component-test.hbs +14 -0
- package/turbo/generators/templates/icon/icon-react.hbs +32 -0
- package/build/index.d.ts +0 -1
- package/build/index.js +0 -12861
- package/build/index.js.map +0 -1
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import type { PlopTypes } from '@turbo/gen'
|
|
4
|
+
|
|
5
|
+
export const generatorIcon = (plop: PlopTypes.NodePlopAPI) => {
|
|
6
|
+
plop.setGenerator('icon', {
|
|
7
|
+
description: 'Create a new icon in @pragma/ui',
|
|
8
|
+
prompts: [
|
|
9
|
+
// Prompt the user to choose how to create the icon
|
|
10
|
+
{
|
|
11
|
+
type: 'list',
|
|
12
|
+
name: 'iconSource',
|
|
13
|
+
message: 'How do you want to create the icon?',
|
|
14
|
+
choices: [
|
|
15
|
+
'🔸 Import Lucide React from "https://lucide.dev/icons/"',
|
|
16
|
+
'🔹 Create Custom SVG',
|
|
17
|
+
],
|
|
18
|
+
},
|
|
19
|
+
// Prompt to enter the name of the Lucide icon to import (if chosen)
|
|
20
|
+
{
|
|
21
|
+
type: 'input',
|
|
22
|
+
name: 'importedIconName',
|
|
23
|
+
message: 'Enter the name of the Lucide icon you want to import:',
|
|
24
|
+
when: (answers) =>
|
|
25
|
+
answers.iconSource ===
|
|
26
|
+
'🔸 Import Lucide React from "https://lucide.dev/icons/"',
|
|
27
|
+
validate: (input) => {
|
|
28
|
+
if (!input) {
|
|
29
|
+
return 'Icon name is required.'
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Trim and convert the icon name to PascalCase
|
|
33
|
+
const importedIconName = input.trim()
|
|
34
|
+
const pascalCaseImportedIconName =
|
|
35
|
+
importedIconName[0].toUpperCase() + importedIconName.slice(1)
|
|
36
|
+
const importedIconFileName = `${importedIconName}.js`
|
|
37
|
+
|
|
38
|
+
// Build file paths
|
|
39
|
+
const importedIconFilePath = path.join(
|
|
40
|
+
plop.getDestBasePath(),
|
|
41
|
+
'/node_modules/lucide-react/dist/esm/icons/' + importedIconFileName,
|
|
42
|
+
)
|
|
43
|
+
const iconIndexFilePath = path.join(
|
|
44
|
+
plop.getDestBasePath(),
|
|
45
|
+
'packages/ui/src/icons/index.tsx',
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
// Check if the Lucide icon file exists
|
|
49
|
+
if (!fs.existsSync(importedIconFilePath)) {
|
|
50
|
+
return `The icon ${importedIconName} is not found in the Lucide React list. Please choose a different name or verify the icon exists. Refer to the website: 👉 https://lucide.dev/icons/ 👈`
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Check if the Lucide icon name already exists in the index.tsx file
|
|
54
|
+
if (fs.existsSync(iconIndexFilePath)) {
|
|
55
|
+
const iconIndexContent = fs.readFileSync(iconIndexFilePath, 'utf-8')
|
|
56
|
+
const iconIndexPattern = new RegExp(
|
|
57
|
+
`\\b${pascalCaseImportedIconName}\\b`,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
if (iconIndexPattern.test(iconIndexContent)) {
|
|
61
|
+
return `The icon name "${pascalCaseImportedIconName}" already exists in the index.tsx file. Please choose a different name.`
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return true
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
// Prompt to enter the name of the custom SVG icon (if chosen)
|
|
69
|
+
{
|
|
70
|
+
type: 'input',
|
|
71
|
+
name: 'customIconName',
|
|
72
|
+
message: 'What is the name of the icon you want to create?',
|
|
73
|
+
when: (answers) => answers.iconSource === '🔹 Create Custom SVG',
|
|
74
|
+
validate: (input) => {
|
|
75
|
+
if (!input) {
|
|
76
|
+
return 'Icon name is required.'
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Trim and convert the icon name to PascalCase
|
|
80
|
+
const pascalCaseCustomIconName = plop.getHelper('pascalCase')(input)
|
|
81
|
+
|
|
82
|
+
// Build the file path for the custom SVG icon
|
|
83
|
+
const customIconFilePath = path.join(
|
|
84
|
+
plop.getDestBasePath(),
|
|
85
|
+
'packages/ui/src/icons/index.tsx',
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
// Check if the custom SVG icon file already exists
|
|
89
|
+
if (fs.existsSync(customIconFilePath)) {
|
|
90
|
+
const iconIndexContent = fs.readFileSync(
|
|
91
|
+
customIconFilePath,
|
|
92
|
+
'utf-8',
|
|
93
|
+
)
|
|
94
|
+
const iconIndexPattern = new RegExp(
|
|
95
|
+
`\\b${pascalCaseCustomIconName}\\b`,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
if (iconIndexPattern.test(iconIndexContent)) {
|
|
99
|
+
return `The icon name "${pascalCaseCustomIconName}" already exists in the index.tsx file. Please choose a different name.`
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return true
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
actions: function (answers) {
|
|
108
|
+
const actions: PlopTypes.Actions = []
|
|
109
|
+
|
|
110
|
+
if (answers && answers.iconSource === '🔹 Create Custom SVG') {
|
|
111
|
+
const iconName = plop.getHelper('pascalCase')(answers.customIconName)
|
|
112
|
+
const camelCaseCustomName = plop.getHelper('camelCase')(iconName)
|
|
113
|
+
const customIconFileName = `${iconName}.tsx`
|
|
114
|
+
const importStatement = `import { ${iconName} } from './${iconName}'`
|
|
115
|
+
const customIconFilePath = path.join(
|
|
116
|
+
plop.getDestBasePath(),
|
|
117
|
+
'packages/ui/src/icons/' + customIconFileName,
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
// Add actions for '🔹 Create Custom SVG'
|
|
121
|
+
actions.push(
|
|
122
|
+
{
|
|
123
|
+
type: 'add',
|
|
124
|
+
path: customIconFilePath,
|
|
125
|
+
templateFile: 'templates/icon/icon-react.hbs',
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
type: 'modify',
|
|
129
|
+
path: '{{ turbo.paths.root }}/packages/ui/src/icons/index.tsx',
|
|
130
|
+
pattern: /(?=(import \{))(.+)(?=(\export type Icon = LucideIcon))/s,
|
|
131
|
+
template: `$2${importStatement}\n\n`,
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
type: 'modify',
|
|
135
|
+
path: '{{ turbo.paths.root }}/packages/ui/src/icons/index.tsx',
|
|
136
|
+
pattern: /(?<=(const \Icons \= \{))/s,
|
|
137
|
+
template: `\n ${camelCaseCustomName}: ${iconName},`,
|
|
138
|
+
},
|
|
139
|
+
)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (
|
|
143
|
+
answers &&
|
|
144
|
+
answers.iconSource ===
|
|
145
|
+
'🔸 Import Lucide React from "https://lucide.dev/icons/"'
|
|
146
|
+
) {
|
|
147
|
+
const importedIconName = answers.importedIconName
|
|
148
|
+
|
|
149
|
+
let pascalCaseImportedIconName: string
|
|
150
|
+
|
|
151
|
+
if (importedIconName.includes('-')) {
|
|
152
|
+
const splittedAnswer: string[] = answers.importedIconName.split('-') // ['air', 'vent']
|
|
153
|
+
|
|
154
|
+
pascalCaseImportedIconName = splittedAnswer.reduce<string>(
|
|
155
|
+
(acc, word) => {
|
|
156
|
+
return acc + word[0].toUpperCase() + word.slice(1)
|
|
157
|
+
},
|
|
158
|
+
'',
|
|
159
|
+
)
|
|
160
|
+
console.log(pascalCaseImportedIconName)
|
|
161
|
+
} else {
|
|
162
|
+
pascalCaseImportedIconName =
|
|
163
|
+
importedIconName[0].toUpperCase() + importedIconName.slice(1)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const importedIconFileName = `${importedIconName}.js`
|
|
167
|
+
const importedIconFilePath = path.join(
|
|
168
|
+
plop.getDestBasePath(),
|
|
169
|
+
'/node_modules/lucide-react/dist/esm/icons/' + importedIconFileName,
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
if (fs.existsSync(importedIconFilePath)) {
|
|
173
|
+
const importKey = `${pascalCaseImportedIconName[0].toLowerCase()}${pascalCaseImportedIconName.slice(
|
|
174
|
+
1,
|
|
175
|
+
)}`
|
|
176
|
+
// Add actions for '🔸 Import Lucide React since "https://lucide.dev/icons/"'
|
|
177
|
+
actions.push(
|
|
178
|
+
{
|
|
179
|
+
type: 'modify',
|
|
180
|
+
path: '{{ turbo.paths.root }}/packages/ui/src/icons/index.tsx',
|
|
181
|
+
pattern: /(?=(import \{))(.*?)(?=(\} from 'lucide-react'))/s,
|
|
182
|
+
template: `$2 ${pascalCaseImportedIconName},\n`,
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
type: 'modify',
|
|
186
|
+
path: '{{ turbo.paths.root }}/packages/ui/src/icons/index.tsx',
|
|
187
|
+
pattern: /(?<=(const \Icons \= \{))/s,
|
|
188
|
+
template: `\n ${importKey}: ${pascalCaseImportedIconName},`,
|
|
189
|
+
},
|
|
190
|
+
)
|
|
191
|
+
} else {
|
|
192
|
+
console.error(
|
|
193
|
+
`The file "${importedIconFileName}" doesn't exist in the specified path.`,
|
|
194
|
+
)
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return actions
|
|
199
|
+
},
|
|
200
|
+
})
|
|
201
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { RouteHandler } from 'fastify'
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
{{#each endpointActions}}
|
|
5
|
+
{{this.typeName}},
|
|
6
|
+
{{/each}}
|
|
7
|
+
} from './{{ getEntityFromPath modulePath}}.schema'
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
{{#each endpointActions}}
|
|
11
|
+
{{this.actionName}},
|
|
12
|
+
{{/each}}
|
|
13
|
+
} from './{{ getEntityFromPath modulePath}}.service'
|
|
14
|
+
|
|
15
|
+
import {
|
|
16
|
+
{{!-- Counting on prettier to format your code correctly and remove this if empty 🫠 --}}
|
|
17
|
+
{{#each endpointActions}}
|
|
18
|
+
{{#if this.isAParamRoute}}
|
|
19
|
+
{{ pascalCase this.entityName }}IdType,
|
|
20
|
+
{{/if}}
|
|
21
|
+
{{/each}}
|
|
22
|
+
} from '@pragma/common/server'
|
|
23
|
+
|
|
24
|
+
{{#each endpointActions}}
|
|
25
|
+
export const {{this.actionName}}Handler: RouteHandler<{
|
|
26
|
+
Reply: {{this.typeName}}
|
|
27
|
+
{{#if this.isAParamRoute}}
|
|
28
|
+
Params: {{ pascalCase this.entityName }}IdType
|
|
29
|
+
}> = (req, reply) => {
|
|
30
|
+
const {{this.entity}}Id = req.params.id
|
|
31
|
+
const { id, createdAt, updatedAt } = {{this.actionName}}({{this.entity}}Id)
|
|
32
|
+
|
|
33
|
+
reply.code({{this.responseCode}}).send({
|
|
34
|
+
id: id,
|
|
35
|
+
createdAt: createdAt,
|
|
36
|
+
updatedAt: updatedAt,
|
|
37
|
+
})
|
|
38
|
+
{{else}}
|
|
39
|
+
}> = (_, reply) => {
|
|
40
|
+
const payload = {{this.actionName}}()
|
|
41
|
+
|
|
42
|
+
reply.code({{this.responseCode}}).send(payload)
|
|
43
|
+
{{/if}}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
{{/each}}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { buildJsonSchemas } from '@pragma/common/server'
|
|
2
|
+
import { z } from 'zod'
|
|
3
|
+
|
|
4
|
+
{{#each endpointActions}}
|
|
5
|
+
{{#if this.isAParamRoute}}
|
|
6
|
+
const {{this.entityName}}IdSchema = z.object({
|
|
7
|
+
id: z.string({ description: '{{ pascalCase this.entityName }} id path parameter' }).uuid(),
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
export type {{ pascalCase this.entityName }}IdType = z.infer<typeof {{this.entityName}}IdSchema>
|
|
11
|
+
|
|
12
|
+
export const { schemas: {{this.entityName}}IdParamSchema, $ref: {{this.entityName}}ParamRef } =
|
|
13
|
+
buildJsonSchemas(
|
|
14
|
+
{
|
|
15
|
+
{{this.entityName}}IdSchema,
|
|
16
|
+
},
|
|
17
|
+
{ $id: '{{this.entityName}}_id' },
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
export const with{{ pascalCase this.entityName }}Param = {{this.entityName}}ParamRef('{{this.entityName}}IdSchema')
|
|
21
|
+
{{/if}}
|
|
22
|
+
{{/each}}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { FastifyPluginAsync } from 'fastify'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
{{#each endpointActions}}
|
|
5
|
+
{{this.actionName}}Handler,
|
|
6
|
+
{{/each}}
|
|
7
|
+
} from './{{ getEntityFromPath modulePath }}.controller'
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
{{#each endpointActions}}
|
|
11
|
+
{{this.fastifySchemaName}},
|
|
12
|
+
{{/each}}
|
|
13
|
+
} from './{{ getEntityFromPath modulePath}}.schema'
|
|
14
|
+
|
|
15
|
+
const {{ getEntityFromPath modulePath }}: FastifyPluginAsync = async (fastify): Promise<void> => {
|
|
16
|
+
{{#each endpointActions}}
|
|
17
|
+
fastify.{{this.verb}}(
|
|
18
|
+
'{{this.route}}',
|
|
19
|
+
{
|
|
20
|
+
schema: {{this.fastifySchemaName}},
|
|
21
|
+
config: { authorize: 'SUPER_ADMIN_ONLY' },
|
|
22
|
+
},
|
|
23
|
+
{{this.actionName}}Handler,
|
|
24
|
+
)
|
|
25
|
+
{{/each}}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default {{ getEntityFromPath modulePath }}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { FastifySchema } from 'fastify'
|
|
2
|
+
import { buildJsonSchemas } from '@pragma/common/server'
|
|
3
|
+
import z from 'zod'
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
{{!-- Counting on prettier to format your code correctly and remove this if empty 🫠 --}}
|
|
7
|
+
{{#each endpointActions}}
|
|
8
|
+
{{#if this.isAParamRoute}}
|
|
9
|
+
with{{pascalCase this.entityName}}Param,
|
|
10
|
+
{{/if}}
|
|
11
|
+
{{/each}}
|
|
12
|
+
} from '@pragma/common/server'
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
// import { bindExamples } from '@pragma/common/shared'
|
|
16
|
+
|
|
17
|
+
const {{ upperCase ( getEntityFromPath modulePath ) }}_TAG = { tags: ['{{ pascalCase ( getEntityFromPath modulePath ) }}'] }
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Zod elementary models definitions.
|
|
21
|
+
*/
|
|
22
|
+
{{#each endpointActions}}
|
|
23
|
+
const {{this.zodElementarySchemaDefinition}} = {
|
|
24
|
+
id: z.string({ description: '{{ pascalCase this.entityName }} ID' }).uuid(),
|
|
25
|
+
createdAt: z.date({ description: '{{ pascalCase this.entityName }} creation date in the DB' }),
|
|
26
|
+
updatedAt: z.date({ description: '{{ pascalCase this.entityName }} last update date in the DB' }),
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
{{/each}}
|
|
30
|
+
/**
|
|
31
|
+
* Zod schema definitions.
|
|
32
|
+
*/
|
|
33
|
+
{{#each endpointActions}}
|
|
34
|
+
export const {{ this.zodSchemaDefinitionName }} = {{#unless this.isAParamRoute}}z.array({{/unless}}z.object({{ this.zodElementarySchemaDefinition }}, {
|
|
35
|
+
description: '{{ pascalCase this.entityName }}',
|
|
36
|
+
}){{#unless this.isAParamRoute}}){{/unless}}
|
|
37
|
+
|
|
38
|
+
{{/each}}
|
|
39
|
+
/**
|
|
40
|
+
* Generate types from zod schemas.
|
|
41
|
+
*/
|
|
42
|
+
{{#each endpointActions}}
|
|
43
|
+
export type {{this.typeName}} = z.infer<typeof {{this.zodSchemaDefinitionName}}>
|
|
44
|
+
{{/each}}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Examples of schemas from types definitions.
|
|
48
|
+
*/
|
|
49
|
+
// const schemaExamples = {
|
|
50
|
+
{{#each endpointActions}}
|
|
51
|
+
// {{this.actionName}}SchemaExample,
|
|
52
|
+
{{/each}}
|
|
53
|
+
// }
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Generate JSON schemas from zod schemas.
|
|
57
|
+
*/
|
|
58
|
+
export const { schemas: {{ getEntityFromPath modulePath }}Schemas, $ref: {{ getEntityFromPath modulePath }}Ref } = buildJsonSchemas(
|
|
59
|
+
{
|
|
60
|
+
{{#each endpointActions}}
|
|
61
|
+
{{this.zodSchemaDefinitionName}},
|
|
62
|
+
{{/each}}
|
|
63
|
+
},
|
|
64
|
+
{ $id: '{{ getEntityFromPath modulePath }}Schemas' },
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Bind examples to JSON schemas.
|
|
69
|
+
*/
|
|
70
|
+
// bindExamples({{ getEntityFromPath modulePath }}Schemas, schemaExamples)
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Export Fastify schemas.
|
|
74
|
+
*/
|
|
75
|
+
{{#each endpointActions}}
|
|
76
|
+
export const {{this.fastifySchemaName}}: FastifySchema = {
|
|
77
|
+
...{{ upperCase ( getEntityFromPath ../this.modulePath ) }}_TAG,
|
|
78
|
+
description: '{{this.fastifyDescription}}',
|
|
79
|
+
summary: '{{this.fastifySummary}}',
|
|
80
|
+
operationId: '{{this.fastifyOperationId}}',
|
|
81
|
+
security: [{ apiKey: [] }],
|
|
82
|
+
hide: true,
|
|
83
|
+
response: {
|
|
84
|
+
{{this.responseCode}}: {{ getEntityFromPath ../this.modulePath }}Ref('{{this.zodSchemaDefinitionName}}'),
|
|
85
|
+
},
|
|
86
|
+
{{#if this.isAParamRoute}}
|
|
87
|
+
params: with{{pascalCase this.entityName}}Param,
|
|
88
|
+
{{/if}}
|
|
89
|
+
}
|
|
90
|
+
{{/each}}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import {
|
|
2
|
+
{{#each endpointActions}}
|
|
3
|
+
type {{this.typeName}},
|
|
4
|
+
{{/each}}
|
|
5
|
+
} from './{{ getEntityFromPath modulePath}}.schema'
|
|
6
|
+
|
|
7
|
+
import { faker } from '@faker-js/faker'
|
|
8
|
+
|
|
9
|
+
{{#each endpointActions}}
|
|
10
|
+
export function {{this.actionName}}(
|
|
11
|
+
{{#if this.isAParamRoute}}
|
|
12
|
+
id: string
|
|
13
|
+
{{/if}}
|
|
14
|
+
): {{this.typeName}} {
|
|
15
|
+
{{#if this.isAParamRoute}}
|
|
16
|
+
return {
|
|
17
|
+
id: id,
|
|
18
|
+
createdAt: new Date(),
|
|
19
|
+
updatedAt: new Date(),
|
|
20
|
+
}
|
|
21
|
+
{{else}}
|
|
22
|
+
return [
|
|
23
|
+
{
|
|
24
|
+
id: faker.string.uuid(),
|
|
25
|
+
createdAt: new Date(),
|
|
26
|
+
updatedAt: new Date(),
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
id: faker.string.uuid(),
|
|
30
|
+
createdAt: new Date(),
|
|
31
|
+
updatedAt: new Date(),
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: faker.string.uuid(),
|
|
35
|
+
createdAt: new Date(),
|
|
36
|
+
updatedAt: new Date(),
|
|
37
|
+
},
|
|
38
|
+
]
|
|
39
|
+
{{/if}}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
{{/each}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './{{pascalCase componentName}}'
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
interface {{pascalCase componentName}}Props {
|
|
4
|
+
/**
|
|
5
|
+
* TODO: Change this
|
|
6
|
+
*/
|
|
7
|
+
name?: 'change me'
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const {{pascalCase componentName}} = ({ name }: {{pascalCase componentName}}Props) => {
|
|
11
|
+
return <div>{name}</div>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export { {{pascalCase componentName}} }
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
|
|
4
|
+
import { {{pascalCase componentName}} } from './{{pascalCase componentName}}'
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof {{pascalCase componentName}}> = {
|
|
7
|
+
title: 'Components/{{pascalCase componentName}}', //Todo: Change the section name ex. 'Components/DataDisplay/componentName'
|
|
8
|
+
component: {{pascalCase componentName}},
|
|
9
|
+
decorators: [
|
|
10
|
+
(Story) => (
|
|
11
|
+
<div className="h-full w-full">
|
|
12
|
+
<Story />
|
|
13
|
+
</div>
|
|
14
|
+
),
|
|
15
|
+
],
|
|
16
|
+
}
|
|
17
|
+
export default meta
|
|
18
|
+
type Story = StoryObj<typeof {{pascalCase componentName}}>
|
|
19
|
+
export const Base: Story = {
|
|
20
|
+
args: {},
|
|
21
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import '@testing-library/jest-dom'
|
|
2
|
+
|
|
3
|
+
import { render, screen } from '@testing-library/react'
|
|
4
|
+
import React from 'react'
|
|
5
|
+
|
|
6
|
+
import { {{pascalCase componentName}} } from './{{pascalCase componentName}}'
|
|
7
|
+
|
|
8
|
+
describe('{{pascalCase componentName}} Component', () => {
|
|
9
|
+
test('should render the {{pascalCase componentName}} Component', () => {
|
|
10
|
+
render(<{{pascalCase componentName}} name="change me" />)
|
|
11
|
+
const component = screen.getByText('change me')
|
|
12
|
+
expect(component).toBeInTheDocument()
|
|
13
|
+
})
|
|
14
|
+
})
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
interface {{pascalCase customIconName}}Props extends React.SVGProps<SVGSVGElement> {
|
|
4
|
+
ref?: React.Ref<SVGSVGElement>;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const {{pascalCase customIconName}} =
|
|
8
|
+
({ ref, className, ...props }: {{pascalCase customIconName}}Props) => {
|
|
9
|
+
return (
|
|
10
|
+
<svg
|
|
11
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
12
|
+
width="24"
|
|
13
|
+
height="24"
|
|
14
|
+
viewBox="0 0 24 24"
|
|
15
|
+
fill="none"
|
|
16
|
+
stroke="#f62992"
|
|
17
|
+
strokeWidth="2"
|
|
18
|
+
strokeLinecap="round"
|
|
19
|
+
strokeLinejoin="round">
|
|
20
|
+
<path d="M18 6a4 4 0 0 0-4 4 7 7 0 0 0-7 7c0-5 4-5 4-10.5a4.5 4.5 0 1 0-9 0 2.5 2.5 0 0 0 5 0C7 10 3 11 3 17c0 2.8 2.2 5 5 5h10" />
|
|
21
|
+
<path d="M16 20c0-1.7 1.3-3 3-3h1a2 2 0 0 0 2-2v-2a4 4 0 0 0-4-4V4" />
|
|
22
|
+
<path d="M15.2 22a3 3 0 0 0-2.2-5" />
|
|
23
|
+
<path d="M18 13h.01" />
|
|
24
|
+
</svg>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* TODO: Then add in svg
|
|
29
|
+
* ref={ref}
|
|
30
|
+
* className={props.className}
|
|
31
|
+
* fill="currentColor"
|
|
32
|
+
*/
|
package/build/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|