create-buntui 0.1.0-alpha.1 → 0.1.0-alpha.3
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/dist/buntui.so +0 -0
- package/dist/index.js +7 -0
- package/package.json +12 -5
- package/templates/basic/README.md +17 -0
- package/templates/basic/package.json +12 -2
- package/templates/basic/scripts/build.ts +65 -0
- package/templates/basic/src/App.vue +29 -0
- package/templates/basic/src/dev.ts +27 -0
- package/templates/basic/src/main.ts +15 -0
- package/templates/basic/tsconfig.json +28 -0
- package/templates/full/README.md +39 -0
- package/templates/full/package.json +21 -0
- package/templates/full/scripts/build.ts +66 -0
- package/templates/full/src/App.vue +49 -0
- package/templates/full/src/components/BoxDemo.vue +80 -0
- package/templates/full/src/components/ButtonDemo.vue +32 -0
- package/templates/full/src/components/CheckboxDemo.vue +19 -0
- package/templates/full/src/components/InputDemo.vue +34 -0
- package/templates/full/src/components/ProgressDemo.vue +25 -0
- package/templates/full/src/components/RadioDemo.vue +23 -0
- package/templates/full/src/components/ScrollBoxDemo.vue +50 -0
- package/templates/full/src/components/SelectDemo.vue +41 -0
- package/templates/full/src/components/SwitchDemo.vue +19 -0
- package/templates/full/src/components/TableDemo.vue +33 -0
- package/templates/full/src/components/TextDemo.vue +66 -0
- package/templates/full/src/components/TextareaDemo.vue +38 -0
- package/templates/full/src/dev.ts +40 -0
- package/templates/full/src/main.ts +21 -0
- package/templates/full/tsconfig.json +28 -0
- package/templates/sfc/README.md +28 -0
- package/templates/sfc/package.json +21 -0
- package/templates/sfc/scripts/build.ts +66 -0
- package/templates/sfc/src/App.vue +42 -0
- package/templates/sfc/src/dev.ts +40 -0
- package/templates/sfc/src/main.ts +21 -0
- package/templates/sfc/tsconfig.json +28 -0
- package/src/index.ts +0 -10
- package/src/scaffold.ts +0 -25
- package/src/setup-ui.ts +0 -145
- package/templates/basic/index.ts +0 -30
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{name}}",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "bun --preload @buntui/compiler/vue-plugin src/dev.ts",
|
|
7
|
+
"build": "bun run ./scripts/build.ts"
|
|
8
|
+
},
|
|
9
|
+
"dependencies": {
|
|
10
|
+
"@buntui/core": "{{version}}",
|
|
11
|
+
"@buntui/compiler": "{{version}}",
|
|
12
|
+
"@buntui/native": "{{version}}",
|
|
13
|
+
"@buntui/extensions": "{{version}}",
|
|
14
|
+
"@vue/reactivity": "^3.5.34"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@types/bun": "latest",
|
|
18
|
+
"vue": "^3.5.34",
|
|
19
|
+
"vue-tsc": "^3.2.8"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import process from 'node:process';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import {compile, CORE_REGISTRY} from '@buntui/compiler';
|
|
5
|
+
import {getBinaryPath} from '@buntui/native';
|
|
6
|
+
|
|
7
|
+
const result = await Bun.build({
|
|
8
|
+
entrypoints: ['src/main.ts'],
|
|
9
|
+
outdir: 'dist',
|
|
10
|
+
target: 'bun',
|
|
11
|
+
minify: true,
|
|
12
|
+
plugins: [
|
|
13
|
+
{
|
|
14
|
+
name: 'buntui-vue',
|
|
15
|
+
setup(build) {
|
|
16
|
+
build.onLoad({filter: /\.vue$/v}, async args => {
|
|
17
|
+
const source = await Bun.file(args.path).text();
|
|
18
|
+
const compiled = compile(source, {
|
|
19
|
+
filename: args.path,
|
|
20
|
+
registry: CORE_REGISTRY,
|
|
21
|
+
codegen: {
|
|
22
|
+
coreModuleId: '@buntui/core',
|
|
23
|
+
reactivityModuleId: '@vue/reactivity',
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
return {contents: compiled.code, loader: 'ts'};
|
|
27
|
+
});
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
if (!result.success) {
|
|
34
|
+
for (const error of result.logs) {
|
|
35
|
+
console.error(error);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
for (const output of result.outputs) {
|
|
42
|
+
console.log(`Built: ${output.path} (${(output.size / 1024).toFixed(1)} KB)`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function getBinaryExt(): string {
|
|
46
|
+
if (process.platform === 'win32') return 'dll';
|
|
47
|
+
if (process.platform === 'darwin') return 'dylib';
|
|
48
|
+
return 'so';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const binaryName = `buntui.${getBinaryExt()}`;
|
|
52
|
+
const nativePath = getBinaryPath();
|
|
53
|
+
const dllSearchPaths = [
|
|
54
|
+
...(nativePath ? [nativePath] : []),
|
|
55
|
+
path.resolve(import.meta.dir, '..', 'node_modules', '@buntui', 'core', binaryName),
|
|
56
|
+
path.resolve(import.meta.dir, '..', binaryName),
|
|
57
|
+
];
|
|
58
|
+
|
|
59
|
+
for (const candidate of dllSearchPaths) {
|
|
60
|
+
if (fs.existsSync(candidate)) {
|
|
61
|
+
const dest = path.resolve(import.meta.dir, '..', 'dist', binaryName);
|
|
62
|
+
fs.copyFileSync(candidate, dest);
|
|
63
|
+
console.log(`Copied: ${binaryName} -> dist/`);
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<SelectButton :x="1" :y="2" :height="1" :options="tabOptions" v-model="currentTab" />
|
|
3
|
+
|
|
4
|
+
<BoxDemo v-if="currentTab === 'Box'" />
|
|
5
|
+
<ButtonDemo v-if="currentTab === 'Button'" />
|
|
6
|
+
<InputDemo v-if="currentTab === 'Input'" />
|
|
7
|
+
<TextDemo v-if="currentTab === 'Text'" />
|
|
8
|
+
<ProgressDemo v-if="currentTab === 'Progress'" />
|
|
9
|
+
<CheckboxDemo v-if="currentTab === 'Checkbox'" />
|
|
10
|
+
<SwitchDemo v-if="currentTab === 'Switch'" />
|
|
11
|
+
<RadioDemo v-if="currentTab === 'Radio'" />
|
|
12
|
+
<ScrollBoxDemo v-if="currentTab === 'ScrollBox'" />
|
|
13
|
+
<TextareaDemo v-if="currentTab === 'Textarea'" />
|
|
14
|
+
<TableDemo v-if="currentTab === 'Table'" />
|
|
15
|
+
<SelectDemo v-if="currentTab === 'Select'" />
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<script setup lang="ts">
|
|
19
|
+
import { ref } from '@vue/reactivity'
|
|
20
|
+
|
|
21
|
+
import BoxDemo from './components/BoxDemo.vue'
|
|
22
|
+
import ButtonDemo from './components/ButtonDemo.vue'
|
|
23
|
+
import InputDemo from './components/InputDemo.vue'
|
|
24
|
+
import TextDemo from './components/TextDemo.vue'
|
|
25
|
+
import ProgressDemo from './components/ProgressDemo.vue'
|
|
26
|
+
import CheckboxDemo from './components/CheckboxDemo.vue'
|
|
27
|
+
import SwitchDemo from './components/SwitchDemo.vue'
|
|
28
|
+
import RadioDemo from './components/RadioDemo.vue'
|
|
29
|
+
import ScrollBoxDemo from './components/ScrollBoxDemo.vue'
|
|
30
|
+
import TextareaDemo from './components/TextareaDemo.vue'
|
|
31
|
+
import TableDemo from './components/TableDemo.vue'
|
|
32
|
+
import SelectDemo from './components/SelectDemo.vue'
|
|
33
|
+
|
|
34
|
+
const tabOptions = ref([
|
|
35
|
+
'Box',
|
|
36
|
+
'Button',
|
|
37
|
+
'Input',
|
|
38
|
+
'Text',
|
|
39
|
+
'Progress',
|
|
40
|
+
'Checkbox',
|
|
41
|
+
'Switch',
|
|
42
|
+
'Radio',
|
|
43
|
+
'ScrollBox',
|
|
44
|
+
'Textarea',
|
|
45
|
+
'Table',
|
|
46
|
+
'Select',
|
|
47
|
+
])
|
|
48
|
+
const currentTab = ref(tabOptions.value[0]!)
|
|
49
|
+
</script>
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Text :x="1" :y="3" value="Box widget — layout container with borders, padding, alignment" />
|
|
3
|
+
|
|
4
|
+
<Box
|
|
5
|
+
:x="1"
|
|
6
|
+
:y="4"
|
|
7
|
+
:width="30"
|
|
8
|
+
:height="6"
|
|
9
|
+
borderColor="rgba(137,180,250,1)"
|
|
10
|
+
borderStyle="rounded"
|
|
11
|
+
direction="vertical"
|
|
12
|
+
:gap="1"
|
|
13
|
+
:paddingTop="1"
|
|
14
|
+
:paddingLeft="1"
|
|
15
|
+
>
|
|
16
|
+
<Text value="Rounded border" />
|
|
17
|
+
<Text value="With padding and gap" />
|
|
18
|
+
</Box>
|
|
19
|
+
|
|
20
|
+
<Box
|
|
21
|
+
:x="33"
|
|
22
|
+
:y="4"
|
|
23
|
+
:width="30"
|
|
24
|
+
:height="6"
|
|
25
|
+
borderColor="rgba(166,227,161,1)"
|
|
26
|
+
borderStyle="double"
|
|
27
|
+
direction="vertical"
|
|
28
|
+
:gap="1"
|
|
29
|
+
:paddingTop="1"
|
|
30
|
+
:paddingLeft="1"
|
|
31
|
+
>
|
|
32
|
+
<Text value="Double border" />
|
|
33
|
+
<Text value="Vertical layout" />
|
|
34
|
+
</Box>
|
|
35
|
+
|
|
36
|
+
<Box
|
|
37
|
+
:x="1"
|
|
38
|
+
:y="11"
|
|
39
|
+
:width="30"
|
|
40
|
+
:height="3"
|
|
41
|
+
borderColor="rgba(250,179,135,1)"
|
|
42
|
+
borderStyle="solid"
|
|
43
|
+
direction="horizontal"
|
|
44
|
+
:gap="2"
|
|
45
|
+
align="center"
|
|
46
|
+
>
|
|
47
|
+
<Text value="Horizontal" />
|
|
48
|
+
<Text value="center aligned" />
|
|
49
|
+
</Box>
|
|
50
|
+
|
|
51
|
+
<Box
|
|
52
|
+
:x="33"
|
|
53
|
+
:y="11"
|
|
54
|
+
:width="30"
|
|
55
|
+
:height="3"
|
|
56
|
+
borderColor="rgba(243,139,168,1)"
|
|
57
|
+
borderStyle="dashed"
|
|
58
|
+
direction="horizontal"
|
|
59
|
+
:gap="2"
|
|
60
|
+
align="center"
|
|
61
|
+
>
|
|
62
|
+
<Text value="Dashed border" />
|
|
63
|
+
<Text value="gap=2" />
|
|
64
|
+
</Box>
|
|
65
|
+
|
|
66
|
+
<Box
|
|
67
|
+
:draggable="true"
|
|
68
|
+
:x="1"
|
|
69
|
+
:y="15"
|
|
70
|
+
:width="20"
|
|
71
|
+
:height="3"
|
|
72
|
+
borderColor="rgba(203,166,245,1)"
|
|
73
|
+
borderStyle="rounded"
|
|
74
|
+
>
|
|
75
|
+
<Text value="Drag me!" />
|
|
76
|
+
</Box>
|
|
77
|
+
</template>
|
|
78
|
+
|
|
79
|
+
<script setup lang="ts">
|
|
80
|
+
</script>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Text :x="1" :y="3" value="Button widget — interactive clickable element" />
|
|
3
|
+
|
|
4
|
+
<Button :x="1" :y="4" :width="18" :height="3" value="Click me" @click="handleClick" />
|
|
5
|
+
<Text :x="21" :y="5" :value="log" />
|
|
6
|
+
|
|
7
|
+
<Text :x="1" :y="8" value="Border variants:" />
|
|
8
|
+
<Button :x="1" :y="9" :width="12" :height="3" value="Solid" borderStyleNormal="solid" @click="handleClick" />
|
|
9
|
+
<Button :x="15" :y="9" :width="12" :height="3" value="Rounded" borderStyleNormal="rounded" @click="handleClick" />
|
|
10
|
+
<Button :x="29" :y="9" :width="12" :height="3" value="Bold" borderStyleNormal="bold" @click="handleClick" />
|
|
11
|
+
<Button :x="43" :y="9" :width="12" :height="3" value="Double" borderStyleNormal="double" @click="handleClick" />
|
|
12
|
+
|
|
13
|
+
<Text :x="1" :y="13" value="States:" />
|
|
14
|
+
<Button :x="1" :y="14" :width="18" :height="3" value="Disabled" :disabled="disabled" />
|
|
15
|
+
<Button :x="21" :y="14" :width="18" :height="3" value="Toggle me" @click="toggleDisabled" />
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<script setup lang="ts">
|
|
19
|
+
import { ref } from '@vue/reactivity'
|
|
20
|
+
|
|
21
|
+
const log = ref('Click a button above')
|
|
22
|
+
const disabled = ref(false)
|
|
23
|
+
|
|
24
|
+
function handleClick() {
|
|
25
|
+
const now = new Date()
|
|
26
|
+
log.value = `Clicked at ${now.toLocaleTimeString()}`
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function toggleDisabled() {
|
|
30
|
+
disabled.value = !disabled.value
|
|
31
|
+
}
|
|
32
|
+
</script>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Text :x="1" :y="3" value="Checkbox widget — boolean toggle" />
|
|
3
|
+
|
|
4
|
+
<Checkbox :x="1" :y="4" label="Enable feature A" @change="handleChange('A', $event)" />
|
|
5
|
+
<Checkbox :x="1" :y="5" label="Enable feature B" @change="handleChange('B', $event)" />
|
|
6
|
+
<Checkbox :x="1" :y="6" label="Disabled option" :disabled="true" />
|
|
7
|
+
|
|
8
|
+
<Text :x="1" :y="8" :value="log" />
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script setup lang="ts">
|
|
12
|
+
import { ref } from '@vue/reactivity'
|
|
13
|
+
|
|
14
|
+
const log = ref('Toggle a checkbox above')
|
|
15
|
+
|
|
16
|
+
function handleChange(name: string, event: TuiCheckboxChangeEvent) {
|
|
17
|
+
log.value = `${name}: ${event.checked ? 'checked' : 'unchecked'}`
|
|
18
|
+
}
|
|
19
|
+
</script>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Text :x="1" :y="3" value="Input widget — text field with editing support" />
|
|
3
|
+
|
|
4
|
+
<Box
|
|
5
|
+
:x="1"
|
|
6
|
+
:y="4"
|
|
7
|
+
:width="50"
|
|
8
|
+
:height="8"
|
|
9
|
+
borderStyle="rounded"
|
|
10
|
+
direction="vertical"
|
|
11
|
+
:gap="1"
|
|
12
|
+
:paddingTop="1"
|
|
13
|
+
:paddingLeft="1"
|
|
14
|
+
>
|
|
15
|
+
<Text value="Type something and press Enter:" />
|
|
16
|
+
<Input
|
|
17
|
+
:width="46"
|
|
18
|
+
placeholder="Enter text here..."
|
|
19
|
+
@submit="handleSubmit"
|
|
20
|
+
/>
|
|
21
|
+
</Box>
|
|
22
|
+
|
|
23
|
+
<Text :x="1" :y="13" :value="submittedValue" />
|
|
24
|
+
</template>
|
|
25
|
+
|
|
26
|
+
<script setup lang="ts">
|
|
27
|
+
import { ref } from '@vue/reactivity'
|
|
28
|
+
|
|
29
|
+
const submittedValue = ref('Submit result appears here')
|
|
30
|
+
|
|
31
|
+
function handleSubmit(event: TuiSubmitEvent) {
|
|
32
|
+
submittedValue.value = `Submitted: "${event.value}"`
|
|
33
|
+
}
|
|
34
|
+
</script>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Text :x="1" :y="3" value="Progress widget — bar indicator" />
|
|
3
|
+
|
|
4
|
+
<Text :x="1" :y="4" value="Determinate:" />
|
|
5
|
+
<Progress :x="1" :y="5" :width="40" :height="1" :value="progress" />
|
|
6
|
+
|
|
7
|
+
<Text :x="1" :y="7" :value="`${Math.round(progress * 100)}%`" />
|
|
8
|
+
|
|
9
|
+
<Button :x="1" :y="9" :width="20" :height="3" value="Reset" @click="reset" />
|
|
10
|
+
<Button :x="23" :y="9" :width="20" :height="3" value="Set 75%" @click="set75" />
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<script setup lang="ts">
|
|
14
|
+
import { ref } from '@vue/reactivity'
|
|
15
|
+
|
|
16
|
+
const progress = ref(0.5)
|
|
17
|
+
|
|
18
|
+
function reset() {
|
|
19
|
+
progress.value = 0
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function set75() {
|
|
23
|
+
progress.value = 0.75
|
|
24
|
+
}
|
|
25
|
+
</script>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Text :x="1" :y="3" value="RadioGroup widget — single selection from options" />
|
|
3
|
+
|
|
4
|
+
<RadioGroup
|
|
5
|
+
:x="1"
|
|
6
|
+
:y="4"
|
|
7
|
+
:width="30"
|
|
8
|
+
:options="['Red', 'Green', 'Blue']"
|
|
9
|
+
@change="handleChange"
|
|
10
|
+
/>
|
|
11
|
+
|
|
12
|
+
<Text :x="1" :y="8" :value="log" />
|
|
13
|
+
</template>
|
|
14
|
+
|
|
15
|
+
<script setup lang="ts">
|
|
16
|
+
import { ref } from '@vue/reactivity'
|
|
17
|
+
|
|
18
|
+
const log = ref('Select a color above')
|
|
19
|
+
|
|
20
|
+
function handleChange(event: TuiRadioGroupChangeEvent) {
|
|
21
|
+
log.value = `Selected: ${event.label} (index ${event.value})`
|
|
22
|
+
}
|
|
23
|
+
</script>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Text :x="1" :y="3" value="ScrollBox widget — scrollable container" />
|
|
3
|
+
|
|
4
|
+
<ScrollBox
|
|
5
|
+
:x="1"
|
|
6
|
+
:y="4"
|
|
7
|
+
:width="40"
|
|
8
|
+
:height="8"
|
|
9
|
+
borderStyle="rounded"
|
|
10
|
+
:gap="1"
|
|
11
|
+
:paddingTop="1"
|
|
12
|
+
:paddingLeft="1"
|
|
13
|
+
:alwaysShowScrollbar="true"
|
|
14
|
+
>
|
|
15
|
+
<Text v-for="item in items" :key="item" :value="item" />
|
|
16
|
+
</ScrollBox>
|
|
17
|
+
|
|
18
|
+
<Box
|
|
19
|
+
:x="44"
|
|
20
|
+
:y="4"
|
|
21
|
+
:width="30"
|
|
22
|
+
:height="8"
|
|
23
|
+
borderStyle="rounded"
|
|
24
|
+
direction="vertical"
|
|
25
|
+
:gap="1"
|
|
26
|
+
:paddingTop="1"
|
|
27
|
+
:paddingLeft="1"
|
|
28
|
+
>
|
|
29
|
+
<Text value="Scroll with arrow keys" />
|
|
30
|
+
<Text value="Content overflows the visible area" />
|
|
31
|
+
<Text value="Scrollbar appears automatically" />
|
|
32
|
+
</Box>
|
|
33
|
+
</template>
|
|
34
|
+
|
|
35
|
+
<script setup lang="ts">
|
|
36
|
+
import { ref } from '@vue/reactivity'
|
|
37
|
+
|
|
38
|
+
const items = ref([
|
|
39
|
+
'Item 1 — Apple',
|
|
40
|
+
'Item 2 — Banana',
|
|
41
|
+
'Item 3 — Cherry',
|
|
42
|
+
'Item 4 — Date',
|
|
43
|
+
'Item 5 — Elderberry',
|
|
44
|
+
'Item 6 — Fig',
|
|
45
|
+
'Item 7 — Grape',
|
|
46
|
+
'Item 8 — Honeydew',
|
|
47
|
+
'Item 9 — Kiwi',
|
|
48
|
+
'Item 10 — Lemon',
|
|
49
|
+
])
|
|
50
|
+
</script>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Text :x="1" :y="3" value="Select widget — dropdown selection" />
|
|
3
|
+
|
|
4
|
+
<Box
|
|
5
|
+
:x="1"
|
|
6
|
+
:y="4"
|
|
7
|
+
:width="50"
|
|
8
|
+
:height="8"
|
|
9
|
+
borderStyle="rounded"
|
|
10
|
+
direction="vertical"
|
|
11
|
+
:gap="1"
|
|
12
|
+
:paddingTop="1"
|
|
13
|
+
:paddingLeft="1"
|
|
14
|
+
>
|
|
15
|
+
<Text value="Choose a framework:" />
|
|
16
|
+
<Select
|
|
17
|
+
:width="46"
|
|
18
|
+
:options="frameworks"
|
|
19
|
+
placeholder="Select a framework..."
|
|
20
|
+
@change="handleChange"
|
|
21
|
+
/>
|
|
22
|
+
</Box>
|
|
23
|
+
|
|
24
|
+
<Text :x="1" :y="13" :value="selected" />
|
|
25
|
+
</template>
|
|
26
|
+
|
|
27
|
+
<script setup lang="ts">
|
|
28
|
+
import { ref } from '@vue/reactivity'
|
|
29
|
+
|
|
30
|
+
const frameworks = ref([
|
|
31
|
+
{value: 'bun', label: 'Bun'},
|
|
32
|
+
{value: 'node', label: 'Node.js'},
|
|
33
|
+
{value: 'deno', label: 'Deno'},
|
|
34
|
+
])
|
|
35
|
+
|
|
36
|
+
const selected = ref('Select an option above')
|
|
37
|
+
|
|
38
|
+
function handleChange(event: TuiChangeEventData) {
|
|
39
|
+
selected.value = `Selected: ${String(event.value)}`
|
|
40
|
+
}
|
|
41
|
+
</script>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Text :x="1" :y="3" value="Switch widget — on/off toggle" />
|
|
3
|
+
|
|
4
|
+
<Switch :x="1" :y="4" label="Dark mode" @change="handleChange('Dark mode', $event)" />
|
|
5
|
+
<Switch :x="1" :y="5" label="Notifications" @change="handleChange('Notifications', $event)" />
|
|
6
|
+
<Switch :x="1" :y="6" label="Disabled" :disabled="true" />
|
|
7
|
+
|
|
8
|
+
<Text :x="1" :y="8" :value="log" />
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script setup lang="ts">
|
|
12
|
+
import { ref } from '@vue/reactivity'
|
|
13
|
+
|
|
14
|
+
const log = ref('Toggle a switch above')
|
|
15
|
+
|
|
16
|
+
function handleChange(name: string, event: TuiSwitchChangeEvent) {
|
|
17
|
+
log.value = `${name}: ${event.checked ? 'on' : 'off'}`
|
|
18
|
+
}
|
|
19
|
+
</script>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Text :x="1" :y="3" value="Table widget — structured data display with selection" />
|
|
3
|
+
|
|
4
|
+
<Table
|
|
5
|
+
:x="1"
|
|
6
|
+
:y="4"
|
|
7
|
+
:width="60"
|
|
8
|
+
:height="8"
|
|
9
|
+
borderStyle="rounded"
|
|
10
|
+
:columns="columns"
|
|
11
|
+
:rows="rows"
|
|
12
|
+
/>
|
|
13
|
+
|
|
14
|
+
<Text :x="1" :y="13" value="Use arrow keys to navigate rows" />
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<script setup lang="ts">
|
|
18
|
+
import { ref } from '@vue/reactivity'
|
|
19
|
+
|
|
20
|
+
const columns = ref([
|
|
21
|
+
{key: 'name', label: 'Name', width: 20},
|
|
22
|
+
{key: 'role', label: 'Role', width: 16},
|
|
23
|
+
{key: 'status', label: 'Status', width: 10},
|
|
24
|
+
])
|
|
25
|
+
|
|
26
|
+
const rows = ref([
|
|
27
|
+
{name: 'Alice', role: 'Engineer', status: 'Active'},
|
|
28
|
+
{name: 'Bob', role: 'Designer', status: 'Away'},
|
|
29
|
+
{name: 'Charlie', role: 'Manager', status: 'Active'},
|
|
30
|
+
{name: 'Diana', role: 'Engineer', status: 'Busy'},
|
|
31
|
+
{name: 'Eve', role: 'Analyst', status: 'Active'},
|
|
32
|
+
])
|
|
33
|
+
</script>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Text :x="1" :y="3" value="Text widget — display styled text" />
|
|
3
|
+
|
|
4
|
+
<Box
|
|
5
|
+
:x="1"
|
|
6
|
+
:y="4"
|
|
7
|
+
width="45%"
|
|
8
|
+
:height="8"
|
|
9
|
+
borderStyle="rounded"
|
|
10
|
+
direction="vertical"
|
|
11
|
+
:gap="1"
|
|
12
|
+
:paddingTop="1"
|
|
13
|
+
:paddingLeft="1"
|
|
14
|
+
>
|
|
15
|
+
<Text value="Font styles" />
|
|
16
|
+
<Text styleModifier="bold" value="Bold text" />
|
|
17
|
+
<Text styleModifier="italic" value="Italic text" />
|
|
18
|
+
</Box>
|
|
19
|
+
|
|
20
|
+
<Box
|
|
21
|
+
x="50%"
|
|
22
|
+
:y="4"
|
|
23
|
+
width="45%"
|
|
24
|
+
:height="10"
|
|
25
|
+
borderStyle="rounded"
|
|
26
|
+
direction="vertical"
|
|
27
|
+
:gap="1"
|
|
28
|
+
:paddingTop="1"
|
|
29
|
+
:paddingLeft="1"
|
|
30
|
+
>
|
|
31
|
+
<Text value="Colors" />
|
|
32
|
+
<Text colorFg="rgba(243,139,168,1)" value="Red " />
|
|
33
|
+
<Text colorFg="rgba(137,180,250,1)" value="Blue " />
|
|
34
|
+
<Text colorFg="rgba(166,227,161,1)" value="Green" />
|
|
35
|
+
</Box>
|
|
36
|
+
|
|
37
|
+
<Box
|
|
38
|
+
:x="1"
|
|
39
|
+
:y="15"
|
|
40
|
+
width="95%"
|
|
41
|
+
:height="6"
|
|
42
|
+
borderStyle="rounded"
|
|
43
|
+
direction="vertical"
|
|
44
|
+
:gap="1"
|
|
45
|
+
:paddingTop="1"
|
|
46
|
+
:paddingLeft="1"
|
|
47
|
+
>
|
|
48
|
+
<Text value="Dynamic clock:" />
|
|
49
|
+
<Text :value="clock" />
|
|
50
|
+
</Box>
|
|
51
|
+
</template>
|
|
52
|
+
|
|
53
|
+
<script setup lang="ts">
|
|
54
|
+
import { ref, computed } from '@vue/reactivity'
|
|
55
|
+
|
|
56
|
+
const elapsed = ref(0)
|
|
57
|
+
setInterval(() => {
|
|
58
|
+
elapsed.value += 1
|
|
59
|
+
}, 1000)
|
|
60
|
+
|
|
61
|
+
const clock = computed(() => {
|
|
62
|
+
elapsed.value
|
|
63
|
+
const now = new Date()
|
|
64
|
+
return now.toLocaleTimeString()
|
|
65
|
+
})
|
|
66
|
+
</script>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Text :x="1" :y="3" value="Textarea widget — multi-line text editor" />
|
|
3
|
+
|
|
4
|
+
<Box
|
|
5
|
+
:x="1"
|
|
6
|
+
:y="4"
|
|
7
|
+
:width="50"
|
|
8
|
+
:height="8"
|
|
9
|
+
borderStyle="rounded"
|
|
10
|
+
direction="vertical"
|
|
11
|
+
:gap="1"
|
|
12
|
+
:paddingTop="1"
|
|
13
|
+
:paddingLeft="1"
|
|
14
|
+
>
|
|
15
|
+
<Text :value="label" />
|
|
16
|
+
<Textarea
|
|
17
|
+
:width="46"
|
|
18
|
+
:height="3"
|
|
19
|
+
placeholder="Enter multi-line text..."
|
|
20
|
+
v-model="text"
|
|
21
|
+
/>
|
|
22
|
+
</Box>
|
|
23
|
+
|
|
24
|
+
<Text :x="1" :y="13" :value="preview" />
|
|
25
|
+
</template>
|
|
26
|
+
|
|
27
|
+
<script setup lang="ts">
|
|
28
|
+
import { ref, computed } from '@vue/reactivity'
|
|
29
|
+
|
|
30
|
+
const text = ref('')
|
|
31
|
+
|
|
32
|
+
const label = computed(() => text.value.length > 0 ? `Characters: ${text.value.length}` : 'Type something below:')
|
|
33
|
+
|
|
34
|
+
const preview = computed(() => {
|
|
35
|
+
const lines = text.value.split('\n')
|
|
36
|
+
return text.value.length > 0 ? `${lines.length} lines, ${text.value.length} chars` : 'Preview appears here'
|
|
37
|
+
})
|
|
38
|
+
</script>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import {createDevServer, CORE_REGISTRY, type DevServerOptions} from '@buntui/compiler';
|
|
4
|
+
import {mountHmrErrorOverlay, type HmrErrorOverlayHandle} from '@buntui/extensions/hmr-error-overlay';
|
|
5
|
+
import {ENTRY, run} from './main';
|
|
6
|
+
|
|
7
|
+
const DEV_DIR = path.join(import.meta.dir, '.dev');
|
|
8
|
+
fs.mkdirSync(DEV_DIR, {recursive: true});
|
|
9
|
+
|
|
10
|
+
const {scene} = run({logFilePath: DEV_DIR});
|
|
11
|
+
|
|
12
|
+
const VUE_FILE = path.join(import.meta.dir, ENTRY);
|
|
13
|
+
|
|
14
|
+
let errorOverlay: HmrErrorOverlayHandle | undefined;
|
|
15
|
+
|
|
16
|
+
createDevServer({
|
|
17
|
+
file: VUE_FILE,
|
|
18
|
+
tempDir: DEV_DIR,
|
|
19
|
+
compileOptions: {
|
|
20
|
+
registry: CORE_REGISTRY,
|
|
21
|
+
codegen: {
|
|
22
|
+
coreModuleId: '@buntui/core',
|
|
23
|
+
reactivityModuleId: '@vue/reactivity',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
onClear() {
|
|
27
|
+
errorOverlay?.dismiss();
|
|
28
|
+
errorOverlay = undefined;
|
|
29
|
+
scene.clearWidgets();
|
|
30
|
+
},
|
|
31
|
+
onReload(setupFn: (scene: unknown) => void) {
|
|
32
|
+
errorOverlay?.dismiss();
|
|
33
|
+
errorOverlay = undefined;
|
|
34
|
+
setupFn(scene);
|
|
35
|
+
},
|
|
36
|
+
onError(error: Error) {
|
|
37
|
+
errorOverlay?.dismiss();
|
|
38
|
+
errorOverlay = mountHmrErrorOverlay(scene, error);
|
|
39
|
+
},
|
|
40
|
+
} satisfies DevServerOptions);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {createApp} from '@buntui/core';
|
|
2
|
+
import App from './App.vue';
|
|
3
|
+
|
|
4
|
+
export const ENTRY = 'App.vue';
|
|
5
|
+
|
|
6
|
+
export function run(devOptions: {logFilePath?: string} = {}) {
|
|
7
|
+
const app = createApp({
|
|
8
|
+
logLevel: 'info',
|
|
9
|
+
clearLog: true,
|
|
10
|
+
tickRate: 60,
|
|
11
|
+
renderRate: 24,
|
|
12
|
+
...devOptions,
|
|
13
|
+
});
|
|
14
|
+
const scene = app.createScene(App, {bgHexRgb: 0x1A_1B_26, visible: true});
|
|
15
|
+
app.start();
|
|
16
|
+
return {app, scene};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (import.meta.main) {
|
|
20
|
+
run();
|
|
21
|
+
}
|