create-tinybase 0.1.0 → 0.1.2

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/cli.js CHANGED
@@ -1,359 +1,3 @@
1
1
  #!/usr/bin/env node
2
-
3
- import prompts from 'prompts';
4
- import { mkdir, writeFile } from 'fs/promises';
5
- import { join } from 'path';
6
-
7
- console.log('šŸŽ‰ Welcome to TinyBase!\n');
8
-
9
- const questions = [
10
- {
11
- type: 'text',
12
- name: 'projectName',
13
- message: 'Project name:',
14
- initial: 'my-tinybase-app',
15
- validate: (value) => value.length > 0 ? true : 'Project name is required'
16
- },
17
- {
18
- type: 'select',
19
- name: 'language',
20
- message: 'Language:',
21
- choices: [
22
- { title: 'TypeScript', value: 'typescript' },
23
- { title: 'JavaScript', value: 'javascript' }
24
- ],
25
- initial: 0
26
- },
27
- {
28
- type: 'select',
29
- name: 'framework',
30
- message: 'Framework:',
31
- choices: [
32
- { title: 'React', value: 'react' },
33
- { title: 'Vanilla', value: 'vanilla' }
34
- ],
35
- initial: 0
36
- },
37
- {
38
- type: 'select',
39
- name: 'persister',
40
- message: 'Persistence:',
41
- choices: [
42
- { title: 'None (in-memory only)', value: 'none' },
43
- { title: 'Local Storage', value: 'local-storage' },
44
- { title: 'SQLite', value: 'sqlite' },
45
- { title: 'PostgreSQL', value: 'postgres' }
46
- ],
47
- initial: 0
48
- },
49
- {
50
- type: 'confirm',
51
- name: 'sync',
52
- message: 'Include sync capabilities?',
53
- initial: false
54
- }
55
- ];
56
-
57
- async function main() {
58
- const answers = await prompts(questions, {
59
- onCancel: () => {
60
- console.log('\nāŒ Cancelled');
61
- process.exit(0);
62
- }
63
- });
64
-
65
- console.log('\nšŸ“¦ Creating your TinyBase app...\n');
66
-
67
- const projectPath = join(process.cwd(), answers.projectName);
68
-
69
- try {
70
- await createProject(projectPath, answers);
71
- console.log('āœ… Done!\n');
72
- console.log(`Next steps:`);
73
- console.log(` cd ${answers.projectName}`);
74
- console.log(` npm install`);
75
- console.log(` npm run dev`);
76
- } catch (error) {
77
- console.error('āŒ Error creating project:', error.message);
78
- process.exit(1);
79
- }
80
- }
81
-
82
- async function createProject(projectPath, config) {
83
- await mkdir(projectPath, { recursive: true });
84
- await mkdir(join(projectPath, 'src'), { recursive: true });
85
- await mkdir(join(projectPath, 'public'), { recursive: true });
86
-
87
- // Generate files based on config
88
- await generatePackageJson(projectPath, config);
89
- await generateIndexHtml(projectPath, config);
90
- await generateViteConfig(projectPath, config);
91
- await generateTsConfig(projectPath, config);
92
- await generateSourceFiles(projectPath, config);
93
- await generateReadme(projectPath, config);
94
- }
95
-
96
- async function generatePackageJson(projectPath, config) {
97
- const isTS = config.language === 'typescript';
98
- const isReact = config.framework === 'react';
99
-
100
- const pkg = {
101
- name: config.projectName,
102
- version: '0.1.0',
103
- type: 'module',
104
- scripts: {
105
- dev: 'vite',
106
- build: isTS ? 'tsc && vite build' : 'vite build',
107
- preview: 'vite preview'
108
- },
109
- dependencies: {
110
- tinybase: '^5.4.3'
111
- },
112
- devDependencies: {
113
- vite: '^5.4.11'
114
- }
115
- };
116
-
117
- if (isReact) {
118
- pkg.dependencies.react = '^18.3.1';
119
- pkg.dependencies['react-dom'] = '^18.3.1';
120
- pkg.devDependencies['@vitejs/plugin-react'] = '^4.3.4';
121
- }
122
-
123
- if (isTS) {
124
- pkg.devDependencies.typescript = '^5.6.3';
125
- }
126
-
127
- if (config.persister === 'sqlite') {
128
- pkg.dependencies['tinybase-sqlite-wasm'] = '^1.0.0';
129
- } else if (config.persister === 'postgres') {
130
- pkg.dependencies['pg'] = '^8.13.1';
131
- }
132
-
133
- if (config.sync) {
134
- pkg.dependencies['tinybase-ws-server'] = '^1.0.0';
135
- }
136
-
137
- await writeFile(
138
- join(projectPath, 'package.json'),
139
- JSON.stringify(pkg, null, 2)
140
- );
141
- }
142
-
143
- async function generateIndexHtml(projectPath, config) {
144
- const isTS = config.language === 'typescript';
145
- const ext = isTS ? 'tsx' : 'jsx';
146
-
147
- const html = `<!DOCTYPE html>
148
- <html lang="en">
149
- <head>
150
- <meta charset="UTF-8" />
151
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
152
- <title>${config.projectName}</title>
153
- </head>
154
- <body>
155
- <div id="app"></div>
156
- <script type="module" src="/src/index.${ext}"></script>
157
- </body>
158
- </html>
159
- `;
160
-
161
- await writeFile(join(projectPath, 'index.html'), html);
162
- }
163
-
164
- async function generateViteConfig(projectPath, config) {
165
- const isReact = config.framework === 'react';
166
- const isTS = config.language === 'typescript';
167
- const ext = isTS ? 'ts' : 'js';
168
-
169
- let content = `import { defineConfig } from 'vite';\n`;
170
-
171
- if (isReact) {
172
- content += `import react from '@vitejs/plugin-react';\n`;
173
- }
174
-
175
- content += `\nexport default defineConfig({\n`;
176
- content += ` plugins: [${isReact ? 'react()' : ''}],\n`;
177
- content += `});\n`;
178
-
179
- await writeFile(join(projectPath, `vite.config.${ext}`), content);
180
- }
181
-
182
- async function generateTsConfig(projectPath, config) {
183
- if (config.language !== 'typescript') return;
184
-
185
- const tsconfig = {
186
- compilerOptions: {
187
- target: 'ES2020',
188
- useDefineForClassFields: true,
189
- lib: ['ES2020', 'DOM', 'DOM.Iterable'],
190
- module: 'ESNext',
191
- skipLibCheck: true,
192
- moduleResolution: 'bundler',
193
- allowImportingTsExtensions: true,
194
- resolveJsonModule: true,
195
- isolatedModules: true,
196
- noEmit: true,
197
- jsx: config.framework === 'react' ? 'react-jsx' : undefined,
198
- strict: true,
199
- noUnusedLocals: true,
200
- noUnusedParameters: true,
201
- noFallthroughCasesInSwitch: true
202
- },
203
- include: ['src']
204
- };
205
-
206
- await writeFile(
207
- join(projectPath, 'tsconfig.json'),
208
- JSON.stringify(tsconfig, null, 2)
209
- );
210
- }
211
-
212
- async function generateSourceFiles(projectPath, config) {
213
- const isTS = config.language === 'typescript';
214
- const isReact = config.framework === 'react';
215
- const ext = isTS ? (isReact ? 'tsx' : 'ts') : (isReact ? 'jsx' : 'js');
216
-
217
- if (isReact) {
218
- await generateReactApp(projectPath, config, ext);
219
- } else {
220
- await generateVanillaApp(projectPath, config, ext);
221
- }
222
- }
223
-
224
- async function generateReactApp(projectPath, config, ext) {
225
- const isTS = config.language === 'typescript';
226
-
227
- // index file
228
- const indexContent = `import React from 'react';
229
- import ReactDOM from 'react-dom/client';
230
- import App from './App';
231
- import './index.css';
232
-
233
- ReactDOM.createRoot(document.getElementById('app')${isTS ? '!' : ''}).render(
234
- <React.StrictMode>
235
- <App />
236
- </React.StrictMode>
237
- );
238
- `;
239
-
240
- await writeFile(join(projectPath, 'src', `index.${ext}`), indexContent);
241
-
242
- // App component
243
- const appContent = `import { createStore } from 'tinybase';
244
- import { useCreateStore, useCell } from 'tinybase/ui-react';
245
-
246
- function App() {
247
- const store = useCreateStore(() => createStore().setCell('data', 'row1', 'count', 0));
248
-
249
- return (
250
- <div style={{ padding: '2rem', fontFamily: 'system-ui' }}>
251
- <h1>šŸŽ‰ TinyBase App</h1>
252
- <Counter store={store} />
253
- </div>
254
- );
255
- }
256
-
257
- function Counter({ store }${isTS ? ': { store: any }' : ''}) {
258
- const count = useCell('data', 'row1', 'count', store) ${isTS ? 'as number' : ''};
259
-
260
- return (
261
- <div>
262
- <p>Count: {count}</p>
263
- <button onClick={() => store.setCell('data', 'row1', 'count', count + 1)}>
264
- Increment
265
- </button>
266
- </div>
267
- );
268
- }
269
-
270
- export default App;
271
- `;
272
-
273
- await writeFile(join(projectPath, 'src', `App.${ext}`), appContent);
274
-
275
- // CSS
276
- const cssContent = `body {
277
- margin: 0;
278
- padding: 0;
279
- font-family: system-ui, -apple-system, sans-serif;
280
- }
281
-
282
- button {
283
- padding: 0.5rem 1rem;
284
- font-size: 1rem;
285
- cursor: pointer;
286
- background: #007bff;
287
- color: white;
288
- border: none;
289
- border-radius: 4px;
290
- }
291
-
292
- button:hover {
293
- background: #0056b3;
294
- }
295
- `;
296
-
297
- await writeFile(join(projectPath, 'src', 'index.css'), cssContent);
298
- }
299
-
300
- async function generateVanillaApp(projectPath, config, ext) {
301
- const content = `import { createStore } from 'tinybase';
302
-
303
- const store = createStore();
304
- store.setCell('data', 'row1', 'count', 0);
305
-
306
- const app = document.getElementById('app');
307
- app.innerHTML = \`
308
- <div style="padding: 2rem; font-family: system-ui">
309
- <h1>šŸŽ‰ TinyBase App</h1>
310
- <p>Count: <span id="count">0</span></p>
311
- <button id="increment">Increment</button>
312
- </div>
313
- \`;
314
-
315
- const countEl = document.getElementById('count');
316
- const button = document.getElementById('increment');
317
-
318
- store.addCellListener('data', 'row1', 'count', () => {
319
- countEl.textContent = store.getCell('data', 'row1', 'count');
320
- });
321
-
322
- button.addEventListener('click', () => {
323
- const current = store.getCell('data', 'row1', 'count');
324
- store.setCell('data', 'row1', 'count', current + 1);
325
- });
326
- `;
327
-
328
- await writeFile(join(projectPath, 'src', `index.${ext}`), content);
329
- }
330
-
331
- async function generateReadme(projectPath, config) {
332
- const readme = `# ${config.projectName}
333
-
334
- A TinyBase application scaffolded with \`tinybase-new\`.
335
-
336
- ## Configuration
337
-
338
- - Language: ${config.language}
339
- - Framework: ${config.framework}
340
- - Persistence: ${config.persister}
341
- - Sync: ${config.sync ? 'Yes' : 'No'}
342
-
343
- ## Getting Started
344
-
345
- \`\`\`bash
346
- npm install
347
- npm run dev
348
- \`\`\`
349
-
350
- ## Learn More
351
-
352
- - [TinyBase Documentation](https://tinybase.org/)
353
- - [TinyBase GitHub](https://github.com/tinyplex/tinybase)
354
- `;
355
-
356
- await writeFile(join(projectPath, 'README.md'), readme);
357
- }
358
-
359
- main();
2
+ import{dirname as c,join as p}from"path";import{createCLI as l}from"tinycreate";import{fileURLToPath as u}from"url";const m=c(u(import.meta.url)),g={welcomeMessage:`\u{1F389} Welcome to TinyBase!
3
+ `,questions:[{type:"text",name:"projectName",message:"Project name:",initial:"my-tinybase-app",validate:e=>e.length>0?!0:"Project name is required"},{type:"select",name:"language",message:"Language:",choices:[{title:"TypeScript",value:"typescript"},{title:"JavaScript",value:"javascript"}],initial:0},{type:"select",name:"framework",message:"Framework:",choices:[{title:"React",value:"react"},{title:"Vanilla",value:"vanilla"}],initial:0},{type:"confirm",name:"prettier",message:"Include Prettier?",initial:!1},{type:"confirm",name:"eslint",message:"Include ESLint?",initial:!1}],createContext:e=>{const{projectName:r,language:s,framework:i,prettier:n,eslint:a}=e,t=s==="typescript",o=i==="react";return{projectName:r,language:s,framework:i,prettier:n,eslint:a,typescript:t,react:o,ext:t?o?"tsx":"ts":o?"jsx":"js"}},createDirectories:async e=>{const{mkdir:r}=await import("fs/promises"),{join:s}=await import("path");await r(s(e,"src"),{recursive:!0}),await r(s(e,"public"),{recursive:!0})},getFiles:e=>{const{typescript:r,react:s,ext:i,prettier:n,eslint:a}=e,t=[{template:"base/package.json.hbs",output:"package.json",prettier:!0},{template:"base/index.html.hbs",output:"index.html",prettier:!0},{template:"base/README.md.hbs",output:"README.md",prettier:!0},{template:"src/index.css.hbs",output:"src/index.css",prettier:!0},{template:"src/index.tsx.hbs",output:`src/index.${i}`,prettier:!0,transpile:!0}];return n&&t.push({template:"base/.prettierrc.hbs",output:".prettierrc",prettier:!0}),a&&t.push({template:"base/eslint.config.js.hbs",output:"eslint.config.js",prettier:!0}),s&&t.push({template:"src/App.tsx.hbs",output:`src/App.${i}`,prettier:!0,transpile:!0},{template:"base/vite.config.js.hbs",output:"vite.config.js",prettier:!0}),r&&t.push({template:"base/tsconfig.json.hbs",output:"tsconfig.json",prettier:!0},{template:"base/tsconfig.node.json.hbs",output:"tsconfig.node.json",prettier:!0}),t},templateRoot:p(m,"templates"),onSuccess:e=>{console.log("Next steps:"),console.log(` cd ${e}`),console.log(" npm install"),console.log(" npm run dev")}};l(g).catch(e=>{console.error(e),process.exit(1)});
package/package.json CHANGED
@@ -1,8 +1,11 @@
1
1
  {
2
2
  "name": "create-tinybase",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "author": "jamesgpearce",
5
- "repository": "github:tinyplex/tinybase",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/tinyplex/tinybase.git"
8
+ },
6
9
  "license": "MIT",
7
10
  "homepage": "https://tinybase.org",
8
11
  "description": "The CLI to build a new app using TinyBase, a reactive data store and sync engine.",
@@ -17,12 +20,16 @@
17
20
  ],
18
21
  "type": "module",
19
22
  "bin": {
20
- "create-tinybase": "./cli.js"
23
+ "create-tinybase": "cli.js"
21
24
  },
22
25
  "dependencies": {
23
- "prompts": "^2.4.2"
26
+ "tinycreate": "file:../tinycreate"
24
27
  },
25
28
  "engines": {
26
29
  "node": ">=18.0.0"
27
- }
30
+ },
31
+ "files": [
32
+ "cli.js",
33
+ "templates"
34
+ ]
28
35
  }
@@ -0,0 +1,5 @@
1
+ {
2
+ "bracketSpacing": false,
3
+ "singleQuote": true,
4
+ "trailingComma": "all"
5
+ }
@@ -0,0 +1,15 @@
1
+ # {{projectName}}
2
+
3
+ A TinyBase app built with {{#if typescript}}TypeScript{{else}}JavaScript{{/if}} and {{#if react}}React{{else}}Vanilla JS{{/if}}.
4
+
5
+ ## Getting Started
6
+
7
+ ```bash
8
+ npm install
9
+ npm run dev
10
+ ```
11
+
12
+ ## Learn More
13
+
14
+ - [TinyBase Documentation](https://tinybase.org)
15
+ - [TinyBase Examples](https://tinybase.org/demos/)
@@ -0,0 +1,38 @@
1
+ {{#if typescript}}
2
+ {{addImport "import tseslint from 'typescript-eslint';"}}
3
+ {{/if}}
4
+ {{#if react}}
5
+ {{addImport "import pluginReact from 'eslint-plugin-react';"}}
6
+ {{addImport "import pluginReactHooks from 'eslint-plugin-react-hooks';"}}
7
+ {{/if}}
8
+
9
+ export default [
10
+ {{#if typescript}}
11
+ ...tseslint.configs.recommended,
12
+ {{else}}
13
+ {
14
+ rules: {
15
+ 'no-unused-vars': 'warn',
16
+ 'no-undef': 'error',
17
+ },
18
+ },
19
+ {{/if}}
20
+
21
+ {{#if react}}
22
+ pluginReact.configs.flat.recommended,
23
+ {
24
+ plugins: {
25
+ 'react-hooks': pluginReactHooks,
26
+ },
27
+ rules: {
28
+ ...pluginReactHooks.configs.recommended.rules,
29
+ 'react/react-in-jsx-scope': 'off',
30
+ },
31
+ settings: {
32
+ react: {
33
+ version: 'detect',
34
+ },
35
+ },
36
+ },
37
+ {{/if}}
38
+ ];
@@ -0,0 +1,17 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>TinyBase</title>
8
+ </head>
9
+
10
+ <body>
11
+ {{#if react}}
12
+ <div id="app"></div>
13
+ {{/if}}
14
+ <script type="module" src="/src/index.{{ext}}"></script>
15
+ </body>
16
+
17
+ </html>
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "{{projectName}}",
3
+ "version": "1.0.0",
4
+ "scripts": {
5
+ {{#list}}
6
+ "dev": "vite"
7
+ {{#if typescript}}
8
+ "build": "tsc && vite build"
9
+ {{else}}
10
+ "build": "vite build"
11
+ {{/if}}
12
+ "preview": "vite preview"
13
+ {{#if prettier}}
14
+ "format": "prettier --write ."
15
+ "format:check": "prettier --check ."
16
+ {{/if}}
17
+ {{#if eslint}}
18
+ "lint": "eslint ."
19
+ {{/if}}
20
+ {{/list}}
21
+ },
22
+ "devDependencies": {
23
+ {{#list}}
24
+ "vite": "^7.1.3"
25
+ {{#if typescript}}
26
+ "typescript": "^5.9.3"
27
+ "@types/node": "^25.0.3"
28
+ {{#if react}}
29
+ "@types/react": "^18.3.18"
30
+ "@types/react-dom": "^18.3.5"
31
+ {{/if}}
32
+ {{/if}}
33
+ {{#if react}}
34
+ "@vitejs/plugin-react": "^4.3.4"
35
+ {{/if}}
36
+ {{#if prettier}}
37
+ "prettier": "^3.7.4"
38
+ {{/if}}
39
+ {{#if eslint}}
40
+ "eslint": "^9.39.2"
41
+ {{#if typescript}}
42
+ "typescript-eslint": "^8.51.0"
43
+ {{/if}}
44
+ {{#if react}}
45
+ "eslint-plugin-react": "^7.37.3"
46
+ "eslint-plugin-react-hooks": "^5.1.0"
47
+ {{/if}}
48
+ {{/if}}
49
+ {{/list}}
50
+ },
51
+ "dependencies": {
52
+ {{#list}}
53
+ "tinybase": "^6.6.0"
54
+ {{#if react}}
55
+ "react": "^18.3.1"
56
+ "react-dom": "^18.3.1"
57
+ {{/if}}
58
+ {{/list}}
59
+ }
60
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "useDefineForClassFields": true,
5
+ "module": "ESNext",
6
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
7
+ "skipLibCheck": true,
8
+ "moduleResolution": "bundler",
9
+ "allowImportingTsExtensions": true,
10
+ "isolatedModules": true,
11
+ "moduleDetection": "force",
12
+ "noEmit": true,
13
+ {{#if react}}
14
+ "jsx": "react-jsx",
15
+ {{/if}}
16
+ "strict": true,
17
+ "noUnusedLocals": true,
18
+ "noUnusedParameters": true,
19
+ "noFallthroughCasesInSwitch": true,
20
+ "noUncheckedSideEffectImports": true
21
+ },
22
+ "include": ["src"]
23
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "compilerOptions": {
3
+ "module": "ESNext",
4
+ "moduleResolution": "bundler",
5
+ "allowSyntheticDefaultImports": true,
6
+ "strict": true,
7
+ "skipLibCheck": true
8
+ }
9
+ }
@@ -0,0 +1,10 @@
1
+ {{addImport "import {defineConfig} from 'vite';"}}
2
+ {{#if isReact}}
3
+ {{addImport "import react from '@vitejs/plugin-react';"}}
4
+ {{/if}}
5
+
6
+ export default defineConfig({
7
+ {{#if isReact}}
8
+ plugins: [react()],
9
+ {{/if}}
10
+ });
@@ -0,0 +1,24 @@
1
+ {{addImport "import {createStore} from 'tinybase';"}}
2
+ {{addImport "import {Provider, useValue} from 'tinybase/ui-react';"}}
3
+
4
+ const store = createStore().setValue('count', 0);
5
+
6
+ export const App = () => (
7
+ <Provider store={store}>
8
+ <h1>TinyBase + React</h1>
9
+ <Counter />
10
+ </Provider>
11
+ );
12
+
13
+ const Counter = () => {
14
+ const count = useValue('count', store);
15
+
16
+ return (
17
+ <div>
18
+ <p>Count: {count}</p>
19
+ <button onClick={() => store.setValue('count', (c: number) => c + 1)}>
20
+ Increment
21
+ </button>
22
+ </div>
23
+ );
24
+ };
@@ -0,0 +1,110 @@
1
+ body {
2
+ color: #bbb;
3
+ background: #111;
4
+ font-family: 'Inter', sans-serif;
5
+ user-select: none;
6
+ }
7
+
8
+ #app {
9
+ max-width: 40rem;
10
+ margin: 2rem auto;
11
+ display: grid;
12
+ grid-template-columns: 1fr;
13
+ column-gap: 2rem;
14
+ align-items: start;
15
+ row-gap: 1rem;
16
+ }
17
+
18
+ a {
19
+ color: #bbb;
20
+ }
21
+
22
+ h1 {
23
+ font-weight: 600;
24
+ img {
25
+ margin-right: 1rem;
26
+ height: 2.5rem;
27
+ vertical-align: text-bottom;
28
+ }
29
+ }
30
+
31
+ h2 {
32
+ text-align: center;
33
+ font-weight: 800;
34
+ font-size: 1.3rem;
35
+ margin: 1rem 0 0;
36
+ }
37
+
38
+ #buttons {
39
+ border: solid #666;
40
+ border-width: 1px 0;
41
+ text-align: center;
42
+ }
43
+
44
+ #buttons button {
45
+ border: 1px solid #666;
46
+ border-radius: 0.25rem;
47
+ padding: 0.5rem 1rem;
48
+ background: #222;
49
+ color: #fff;
50
+ font-family: inherit;
51
+ font-weight: 800;
52
+ font-size: 0.8rem;
53
+ width: 10rem;
54
+ margin: 1rem;
55
+ }
56
+ #buttons button:hover {
57
+ border-color: #d81b60;
58
+ }
59
+
60
+ table {
61
+ border-collapse: collapse;
62
+ font-size: inherit;
63
+ line-height: inherit;
64
+ margin-top: 0.5rem;
65
+ table-layout: fixed;
66
+ width: 100%;
67
+ margin-bottom: 2rem;
68
+ caption-side: bottom;
69
+ }
70
+ table caption {
71
+ text-align: left;
72
+ button {
73
+ border: 0;
74
+ margin-right: 0.25rem;
75
+ }
76
+ }
77
+ table caption button {
78
+ line-height: 0.7rem;
79
+ margin: 0 0.25rem 0 0;
80
+ vertical-align: middle;
81
+ }
82
+ th,
83
+ td {
84
+ padding: 0.25rem 0.5rem 0.25rem 0;
85
+ text-align: left;
86
+ }
87
+ thead th,
88
+ thead td {
89
+ border: solid #999;
90
+ border-width: 1px 0;
91
+ }
92
+ tbody th,
93
+ tbody td {
94
+ border-bottom: 1px solid #333;
95
+ }
96
+
97
+ table.sortedTable thead th {
98
+ cursor: pointer;
99
+ }
100
+
101
+ @media (min-width: 40rem) {
102
+ #app {
103
+ grid-template-columns: 1fr 1fr;
104
+ }
105
+ header,
106
+ p,
107
+ #buttons {
108
+ grid-column: span 2;
109
+ }
110
+ }
@@ -0,0 +1,48 @@
1
+ {{addImport "import './index.css';"}}
2
+
3
+ {{#if react}}
4
+ {{addImport "import ReactDOM from 'react-dom/client';"}}
5
+ {{addImport "import {App} from './App';"}}
6
+
7
+ addEventListener('load', () =>
8
+ ReactDOM.createRoot(document.getElementById('app')!).render(<App />),
9
+ );
10
+
11
+ {{else}}
12
+ {{addImport "import {createStore} from 'tinybase';"}}
13
+
14
+ const onClick = (id: string, onClick: () => void) =>
15
+ document.getElementById(id)!.addEventListener('click', onClick);
16
+
17
+ const updateJson = (id: string, content: unknown) =>
18
+ (document.getElementById(id)!.innerText = JSON.stringify(content, null, 2));
19
+
20
+ const getRandom = (max = 100) => Math.floor(Math.random() * max);
21
+
22
+ addEventListener('load', () => {
23
+ const store = createStore();
24
+
25
+ onClick('countButton', () => store.setValue('counter', (value) => value + 1));
26
+ onClick('randomButton', () => store.setValue('random', getRandom()));
27
+ onClick('addPetButton', () =>
28
+ store.addRow('pets', {
29
+ name: ['fido', 'felix', 'bubbles', 'lowly', 'polly'][getRandom(5)],
30
+ species: store.getRowIds('species')[getRandom(5)],
31
+ }),
32
+ );
33
+
34
+ store.addValuesListener(() => updateJson('valuesJson', store.getValues()));
35
+ store.addTablesListener(() => updateJson('tablesJson', store.getTables()));
36
+
37
+ store
38
+ .setValue('counter', 0)
39
+ .setRow('pets', '0', {name: 'fido', species: 'dog'})
40
+ .setTable('species', {
41
+ dog: {price: 5},
42
+ cat: {price: 4},
43
+ fish: {price: 2},
44
+ worm: {price: 1},
45
+ parrot: {price: 3},
46
+ });
47
+ });
48
+ {{/if}}
package/README.md DELETED
@@ -1,17 +0,0 @@
1
- # create-tinybase
2
-
3
- CLI tool to scaffold a new TinyBase application.
4
-
5
- ## Usage
6
-
7
- ```bash
8
- npm init tinybase
9
- ```
10
-
11
- This will prompt you with questions to configure your new TinyBase app:
12
-
13
- - Project name
14
- - Language (TypeScript or JavaScript)
15
- - Framework (React or Vanilla)
16
- - Persistence option (None, Local Storage, SQLite, PostgreSQL)
17
- - Sync capabilities
package/cspell.json DELETED
@@ -1,8 +0,0 @@
1
- {
2
- "ignorePaths": [],
3
- "words": [
4
- "jamesgpearce",
5
- "tinybase",
6
- "tinyplex"
7
- ]
8
- }