tackl 1.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.
Files changed (3) hide show
  1. package/README.md +75 -0
  2. package/bin/tackl.js +248 -0
  3. package/package.json +45 -0
package/README.md ADDED
@@ -0,0 +1,75 @@
1
+ # Tackl CLI
2
+
3
+ The ultimate Next.js starter kit with Waffl Grid system.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g tackl
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```bash
14
+ tackl my-app
15
+ ```
16
+
17
+ ### Options
18
+
19
+ - `--ref <branch>` - Template ref (branch or tag) (default: main)
20
+ - `--no-install` - Skip dependency installation
21
+ - `--no-git` - Skip git initialization
22
+ - `--help` - Show help message
23
+
24
+ ### Examples
25
+
26
+ ```bash
27
+ # Create a new project
28
+ tackl my-app
29
+
30
+ # Create with specific branch
31
+ tackl my-app --ref develop
32
+
33
+ # Skip installation and git
34
+ tackl my-app --no-install --no-git
35
+ ```
36
+
37
+ ## What's Included
38
+
39
+ - ⚡ **Next.js 15** with App Router
40
+ - 🎨 **Waffl Grid System** - Responsive grid with smart breakpoint inheritance
41
+ - 🎭 **Styled Components** - CSS-in-JS with TypeScript
42
+ - 🎬 **GSAP** - Professional animations
43
+ - 📱 **Responsive Design** - Mobile-first approach
44
+ - 🔧 **TypeScript** - Full type safety
45
+ - 🎯 **Performance** - Optimized for speed
46
+ - 📦 **Modern Tooling** - ESLint, Prettier, Husky
47
+
48
+ ## Features
49
+
50
+ ### Waffl Grid System
51
+
52
+ - Smart breakpoint inheritance (only specify what changes!)
53
+ - Responsive grid columns
54
+ - Semantic components
55
+ - CSS custom properties
56
+
57
+ ### Example Usage
58
+
59
+ ```jsx
60
+ <Waffl>
61
+ <Section $s='1/-1' $l='3/9'>
62
+ // Mobile: full width, Desktop: 3/9 // Tablet inherits mobile (full
63
+ width) Content
64
+ </Section>
65
+ </Waffl>
66
+ ```
67
+
68
+ ## Repository
69
+
70
+ - **GitHub**: https://github.com/12-studio/tackl
71
+ - **Issues**: https://github.com/12-studio/tackl/issues
72
+
73
+ ## License
74
+
75
+ MIT
package/bin/tackl.js ADDED
@@ -0,0 +1,248 @@
1
+ #!/usr/bin/env node
2
+ import { execSync } from 'child_process';
3
+ import fs from 'fs';
4
+ import os from 'os';
5
+ import path from 'path';
6
+ import pc from 'picocolors';
7
+ import prompts from 'prompts';
8
+ import * as tar from 'tar';
9
+ import { fileURLToPath } from 'url';
10
+
11
+ const __filename = fileURLToPath(import.meta.url);
12
+ const __dirname = path.dirname(__filename);
13
+
14
+ const OWNER = 'joebentaylor1995';
15
+ const REPO = 'tackl';
16
+ const DEFAULT_REF = 'main';
17
+
18
+ const log = {
19
+ info: m => console.log(pc.cyan('•'), m),
20
+ ok: m => console.log(pc.green('✔'), m),
21
+ warn: m => console.log(pc.yellow('▲'), m),
22
+ error: m => console.log(pc.red('✖'), m),
23
+ };
24
+
25
+ async function main() {
26
+ const args = process.argv.slice(2);
27
+
28
+ // Handle help flag
29
+ if (args.includes('--help') || args.includes('-h')) {
30
+ console.log(`
31
+ ${pc.bold('Tackl CLI')} - The ultimate Next.js starter kit
32
+
33
+ ${pc.bold('Usage:')}
34
+ tackl [project-name] [options]
35
+
36
+ ${pc.bold('Options:')}
37
+ --ref <branch> Template ref (branch or tag) (default: main)
38
+ --no-install Skip dependency installation
39
+ --no-git Skip git initialization
40
+ -h, --help Show this help message
41
+
42
+ ${pc.bold('Examples:')}
43
+ tackl my-app
44
+ tackl my-app --ref develop
45
+ tackl my-app --no-install --no-git
46
+
47
+ ${pc.bold('Repository:')} https://github.com/12-studio/tackl
48
+ `);
49
+ process.exit(0);
50
+ }
51
+
52
+ const argName = args.find(a => !a.startsWith('-'));
53
+ const getFlagVal = (key, fallback) => {
54
+ const idx = args.findIndex(a => a === key);
55
+ return idx >= 0 && args[idx + 1] && !args[idx + 1].startsWith('-')
56
+ ? args[idx + 1]
57
+ : fallback;
58
+ };
59
+
60
+ const initial = {
61
+ name: argName,
62
+ ref: getFlagVal('--ref', DEFAULT_REF),
63
+ install: !args.includes('--no-install'),
64
+ git: !args.includes('--no-git'),
65
+ };
66
+
67
+ // Filter out null prompts
68
+ const promptQuestions = [
69
+ {
70
+ type: initial.name ? null : 'text',
71
+ name: 'name',
72
+ message: 'Project directory',
73
+ initial: 'my-tackl-app',
74
+ validate: v =>
75
+ /^[a-z0-9\-._]+$/.test(v)
76
+ ? true
77
+ : 'Use lowercase letters, numbers, - . _',
78
+ },
79
+ {
80
+ type: 'text',
81
+ name: 'ref',
82
+ message: 'Template ref (branch or tag)',
83
+ initial: initial.ref,
84
+ },
85
+ {
86
+ type: 'toggle',
87
+ name: 'install',
88
+ message: 'Install dependencies?',
89
+ initial: initial.install,
90
+ active: 'yes',
91
+ inactive: 'no',
92
+ },
93
+ {
94
+ type: 'toggle',
95
+ name: 'git',
96
+ message: 'Initialize git?',
97
+ initial: initial.git,
98
+ active: 'yes',
99
+ inactive: 'no',
100
+ },
101
+ ].filter(q => q.type !== null);
102
+
103
+ const answers = await prompts(promptQuestions, {
104
+ onCancel: () => {
105
+ log.warn('Cancelled.');
106
+ process.exit(1);
107
+ },
108
+ onSubmit: () => {
109
+ // Clean up terminal
110
+ process.stdout.write('\x1b[?25h');
111
+ },
112
+ });
113
+
114
+ const projectName = (answers.name || initial.name).trim();
115
+ const ref = (answers.ref || initial.ref).trim();
116
+ const doInstall = answers.install;
117
+ const doGit = answers.git;
118
+
119
+ // Validate project name
120
+ if (!projectName) {
121
+ log.error('Project name is required.');
122
+ process.exit(1);
123
+ }
124
+
125
+ const targetDir = path.resolve(process.cwd(), projectName);
126
+ if (fs.existsSync(targetDir) && fs.readdirSync(targetDir).length > 0) {
127
+ log.error(
128
+ `Directory "${projectName}" already exists and is not empty.`
129
+ );
130
+ process.exit(1);
131
+ }
132
+ fs.mkdirSync(targetDir, { recursive: true });
133
+
134
+ log.info(
135
+ `Scaffolding ${pc.bold(projectName)} from ${OWNER}/${REPO}@${ref} ...`
136
+ );
137
+
138
+ const tarUrl = `https://codeload.github.com/${OWNER}/${REPO}/tar.gz/${encodeURIComponent(ref)}`;
139
+ const tmpTar = path.join(os.tmpdir(), `tackl-${Date.now()}.tgz`);
140
+
141
+ try {
142
+ const res = await fetch(tarUrl);
143
+ if (!res.ok)
144
+ throw new Error(`Download failed: ${res.status} ${res.statusText}`);
145
+ const out = fs.createWriteStream(tmpTar);
146
+ await new Promise((resolve, reject) => {
147
+ res.body.pipe(out);
148
+ res.body.on('error', reject);
149
+ out.on('finish', resolve);
150
+ });
151
+ log.ok('Downloaded template.');
152
+ } catch (e) {
153
+ log.error(e.message);
154
+ process.exit(1);
155
+ }
156
+
157
+ try {
158
+ await tar.x({ file: tmpTar, cwd: targetDir, strip: 1 });
159
+ log.ok('Extracted files.');
160
+ } catch (e) {
161
+ log.error(`Extraction failed: ${e.message}`);
162
+ process.exit(1);
163
+ } finally {
164
+ try {
165
+ fs.unlinkSync(tmpTar);
166
+ } catch {}
167
+ }
168
+
169
+ // Remove template .git if present
170
+ try {
171
+ const gitPath = path.join(targetDir, '.git');
172
+ if (fs.existsSync(gitPath))
173
+ fs.rmSync(gitPath, { recursive: true, force: true });
174
+ } catch {}
175
+
176
+ // Patch package name
177
+ const pkg = path.join(targetDir, 'package.json');
178
+ if (fs.existsSync(pkg)) {
179
+ try {
180
+ const json = JSON.parse(fs.readFileSync(pkg, 'utf8'));
181
+ json.name = projectName.toLowerCase();
182
+ fs.writeFileSync(pkg, JSON.stringify(json, null, 2));
183
+ log.ok('Updated package.json name.');
184
+ } catch (e) {
185
+ log.warn(`Could not update package.json: ${e.message}`);
186
+ }
187
+ }
188
+
189
+ if (doGit) {
190
+ try {
191
+ execSync('git init', { cwd: targetDir, stdio: 'ignore' });
192
+ execSync('git add -A', { cwd: targetDir, stdio: 'ignore' });
193
+ execSync('git commit -m "chore: scaffold with tackl"', {
194
+ cwd: targetDir,
195
+ stdio: 'ignore',
196
+ });
197
+ log.ok('Initialized git repository.');
198
+ } catch (e) {
199
+ log.warn(`Git init failed: ${e.message}`);
200
+ }
201
+ }
202
+
203
+ if (doInstall) {
204
+ try {
205
+ const pm = detectPM();
206
+ log.info(`Installing dependencies with ${pm} ...`);
207
+ execSync(
208
+ pm === 'pnpm'
209
+ ? 'pnpm install'
210
+ : pm === 'yarn'
211
+ ? 'yarn'
212
+ : 'npm install',
213
+ { cwd: targetDir, stdio: 'inherit' }
214
+ );
215
+ log.ok('Dependencies installed.');
216
+ } catch (e) {
217
+ log.warn(`Install failed: ${e.message}`);
218
+ }
219
+ } else {
220
+ log.info('Skipped dependency install.');
221
+ }
222
+
223
+ const rel = path.relative(process.cwd(), targetDir) || '.';
224
+ console.log(
225
+ '\n' + pc.bold(pc.green('Success!')) + ' Project scaffolded.\n'
226
+ );
227
+ console.log(` Next steps:`);
228
+ console.log(` 1) cd ${rel}`);
229
+ if (!doInstall) console.log(` 2) npm install (or pnpm/yarn)`);
230
+ console.log(` ${doInstall ? '2' : '3'}) npm run dev`);
231
+ }
232
+
233
+ function detectPM() {
234
+ try {
235
+ execSync('pnpm --version', { stdio: 'ignore' });
236
+ return 'pnpm';
237
+ } catch {}
238
+ try {
239
+ execSync('yarn --version', { stdio: 'ignore' });
240
+ return 'yarn';
241
+ } catch {}
242
+ return 'npm';
243
+ }
244
+
245
+ main().catch(e => {
246
+ console.error(e);
247
+ process.exit(1);
248
+ });
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "tackl",
3
+ "version": "1.0.0",
4
+ "description": "The ultimate Next.js starter kit with Waffl Grid system",
5
+ "type": "module",
6
+ "bin": {
7
+ "tackl": "./bin/tackl.js"
8
+ },
9
+ "main": "index.js",
10
+ "scripts": {
11
+ "test": "echo \"Error: no test specified\" && exit 1"
12
+ },
13
+ "keywords": [
14
+ "nextjs",
15
+ "react",
16
+ "starter",
17
+ "template",
18
+ "grid",
19
+ "css",
20
+ "styled-components",
21
+ "typescript"
22
+ ],
23
+ "author": "joebentaylor1995",
24
+ "license": "MIT",
25
+ "engines": {
26
+ "node": ">=20.0.0"
27
+ },
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "https://github.com/12-studio/tackl"
31
+ },
32
+ "homepage": "https://github.com/12-studio/tackl",
33
+ "bugs": {
34
+ "url": "https://github.com/12-studio/tackl/issues"
35
+ },
36
+ "files": [
37
+ "bin/",
38
+ "README.md"
39
+ ],
40
+ "dependencies": {
41
+ "picocolors": "^1.1.1",
42
+ "prompts": "^2.4.2",
43
+ "tar": "^7.5.1"
44
+ }
45
+ }