create-asciitorium 0.1.34 → 0.1.35
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/README.md +4 -4
- package/dist/templates/base/index.html +1 -1
- package/dist/templates/base/package.json +1 -1
- package/dist/templates/base/public/art/ART-DESIGN-SPEC.md +375 -0
- package/dist/templates/base/public/art/README.md +115 -0
- package/dist/templates/base/public/art/asciitorium.art +111 -0
- package/dist/templates/base/public/art/borders/bubbles.art +16 -0
- package/dist/templates/base/public/art/borders/dna.art +9 -0
- package/dist/templates/base/public/art/castle.art +4 -0
- package/dist/templates/base/public/art/computer.art +17 -0
- package/dist/templates/base/public/art/font/pencil.art +168 -0
- package/dist/templates/base/public/art/maps/README.md +251 -0
- package/dist/templates/base/public/art/maps/example/README.md +62 -0
- package/dist/templates/base/public/art/maps/example/legend.json +29 -0
- package/dist/templates/base/public/art/maps/example/map.art +21 -0
- package/dist/templates/base/public/art/materials/README.md +279 -0
- package/dist/templates/base/public/art/materials/bone.art +11 -0
- package/dist/templates/base/public/art/materials/door-wooden.art +154 -0
- package/dist/templates/base/public/art/materials/wall-brick.art +128 -0
- package/dist/templates/base/public/art/materials/wall-wireframe.art +128 -0
- package/dist/templates/base/public/art/mazes/example.art +21 -0
- package/dist/templates/base/public/art/sounds/door-close.mp3 +0 -0
- package/dist/templates/base/public/art/sounds/door-open.mp3 +0 -0
- package/dist/templates/base/public/art/sounds/taps.mp3 +0 -0
- package/dist/templates/base/public/art/sprites/asciitorium.art +6 -0
- package/dist/templates/base/public/art/sprites/balloon.art +126 -0
- package/dist/templates/base/public/art/sprites/beating-heart.art +49 -0
- package/dist/templates/base/public/art/sprites/castle.art +4 -0
- package/dist/templates/base/public/art/sprites/component-icon.art +6 -0
- package/dist/templates/base/public/art/sprites/eyes.art +61 -0
- package/dist/templates/base/public/art/sprites/firework.art +58 -0
- package/dist/templates/base/public/art/sprites/heart.art +5 -0
- package/dist/templates/base/public/art/sprites/multi-select-test.art +6 -0
- package/dist/templates/base/public/art/sprites/nav-basics.art +5 -0
- package/dist/templates/base/public/art/sprites/pyramid.art +5 -0
- package/dist/templates/base/public/art/sprites/tatooene.art +5 -0
- package/dist/templates/base/public/art/sprites/welcome.art +7 -0
- package/dist/templates/base/public/art/tatooene.txt +5 -0
- package/dist/templates/base/public/index.css +41 -0
- package/dist/templates/base/public/logo.png +0 -0
- package/dist/templates/base/scripts/gen-figlet-art.js +2 -2
- package/dist/templates/base/scripts/map-builder.js +294 -0
- package/dist/templates/base/src/main.tsx +22 -79
- package/package.json +1 -1
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import fs from 'fs/promises'
|
|
2
|
+
import process from 'process'
|
|
3
|
+
import path from 'path'
|
|
4
|
+
|
|
5
|
+
function parseArgs() {
|
|
6
|
+
const args = process.argv.slice(2)
|
|
7
|
+
|
|
8
|
+
// Check for flags
|
|
9
|
+
let smooth = false
|
|
10
|
+
let filteredArgs = []
|
|
11
|
+
|
|
12
|
+
for (let i = 0; i < args.length; i++) {
|
|
13
|
+
if (args[i] === '--smooth' || args[i] === '--unicode') {
|
|
14
|
+
smooth = true
|
|
15
|
+
} else {
|
|
16
|
+
filteredArgs.push(args[i])
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (filteredArgs.length !== 3) {
|
|
21
|
+
console.error('Usage: node map-builder.js <width> <height> <directory-name> [--smooth]')
|
|
22
|
+
console.error('Example: node map-builder.js 10 10 dungeon-level-1 --smooth')
|
|
23
|
+
console.error('Maps will be saved to public/art/maps/<directory-name>/map.art')
|
|
24
|
+
console.error('Use --smooth flag to enable Unicode box drawing characters')
|
|
25
|
+
process.exit(1)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const width = parseInt(filteredArgs[0])
|
|
29
|
+
const height = parseInt(filteredArgs[1])
|
|
30
|
+
const directoryName = filteredArgs[2]
|
|
31
|
+
|
|
32
|
+
if (isNaN(width) || width <= 0) {
|
|
33
|
+
console.error('Width must be a positive integer')
|
|
34
|
+
process.exit(1)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (isNaN(height) || height <= 0) {
|
|
38
|
+
console.error('Height must be a positive integer')
|
|
39
|
+
process.exit(1)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Construct the full path to the map directory
|
|
43
|
+
const mapDir = path.join(process.cwd(), '../public/art/maps', directoryName)
|
|
44
|
+
const fullPath = path.join(mapDir, 'map.art')
|
|
45
|
+
|
|
46
|
+
return { width, height, filename: fullPath, mapDir, smooth }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
class MapBuilder {
|
|
50
|
+
// Map is a 2D array of chars.
|
|
51
|
+
// example 10x10 grid = [
|
|
52
|
+
// 0123456789012345678
|
|
53
|
+
// 0'+-0-+---+---+---+---+',
|
|
54
|
+
// 1'0 1 2 3 4 5 6 7 8 9 |',
|
|
55
|
+
// 2'+-2-+---+---+---+---+',
|
|
56
|
+
// 3'| 3 | | |',
|
|
57
|
+
// 4'+-4-+ + + + +',
|
|
58
|
+
// 5'| 5 | | | |',
|
|
59
|
+
// 6'+-6-+ +---+ + +',
|
|
60
|
+
// 7'| 7 | | | |',
|
|
61
|
+
// 8'+-8-+ + +---+ +',
|
|
62
|
+
// 9'| 9 | | |',
|
|
63
|
+
// '+---+---+---+---+---+',
|
|
64
|
+
// ]
|
|
65
|
+
// is actually a 11x19 2d array
|
|
66
|
+
// conversion: y = y, x = x*2
|
|
67
|
+
// only place items and creatures on odd values of y and x
|
|
68
|
+
|
|
69
|
+
constructor(width, height, fileName, mapDir, smooth = false) {
|
|
70
|
+
this.fileName = fileName
|
|
71
|
+
this.mapDir = mapDir
|
|
72
|
+
this.width = width
|
|
73
|
+
this.height = height
|
|
74
|
+
this.smooth = smooth
|
|
75
|
+
this.map = []
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async build() {
|
|
79
|
+
console.log(`--- building Map (${this.width}x${this.height}) ---`)
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
this.map = this.createMap()
|
|
83
|
+
console.log(' - created base Map')
|
|
84
|
+
|
|
85
|
+
// Add rooms
|
|
86
|
+
this.addRooms()
|
|
87
|
+
console.log(' - added rooms')
|
|
88
|
+
|
|
89
|
+
// Smooth the Map with Unicode box drawing characters (if requested)
|
|
90
|
+
if (this.smooth) {
|
|
91
|
+
this.mapUpdate(this.map)
|
|
92
|
+
console.log(' - smoothed Map appearance with Unicode characters')
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Save the Map to text file
|
|
96
|
+
await this.saveToText()
|
|
97
|
+
console.log('--- Map build complete ---')
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.error(`Error building Map: ${error.message}`)
|
|
100
|
+
console.error(error)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async saveToText() {
|
|
105
|
+
try {
|
|
106
|
+
// Ensure the map directory exists
|
|
107
|
+
await fs.mkdir(this.mapDir, { recursive: true })
|
|
108
|
+
|
|
109
|
+
// Join the map array with newlines to create plain text
|
|
110
|
+
const textOutput = this.map.join('\n')
|
|
111
|
+
|
|
112
|
+
await fs.writeFile(this.fileName, textOutput, 'utf-8')
|
|
113
|
+
console.log(` - successfully wrote map data to ${this.fileName}`)
|
|
114
|
+
} catch (error) {
|
|
115
|
+
console.error(`Error writing text to file: ${error.message}`)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
xOffset(x) {
|
|
120
|
+
return x * 4 + 2
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
yOffset(y) {
|
|
124
|
+
return y * 2 + 1
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Doors are placed at all dead ends with openings to the north and south.
|
|
128
|
+
addRooms() {
|
|
129
|
+
for (let y = 0; y < this.height; y++) {
|
|
130
|
+
const yPos = this.yOffset(y)
|
|
131
|
+
for (let x = 0; x < this.width; x++) {
|
|
132
|
+
const xPos = this.xOffset(x)
|
|
133
|
+
this.replaceSpacesWithDoors(xPos, yPos)
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// identify dead ends to the north or south.
|
|
139
|
+
// If there is a dead end to the north or south, then specify the x and y position of the opening.
|
|
140
|
+
replaceSpacesWithDoors(xPos, yPos) {
|
|
141
|
+
if (this.map[yPos][xPos] != ' ') return
|
|
142
|
+
const wallDirections = []
|
|
143
|
+
if (this.map[yPos][xPos - 2] != ' ' && this.map[yPos][xPos - 2] != 'o') wallDirections.push('west')
|
|
144
|
+
if (this.map[yPos][xPos + 2] != ' ' && this.map[yPos][xPos + 2] != 'o') wallDirections.push('east')
|
|
145
|
+
if (this.map[yPos - 1][xPos] != ' ' && this.map[yPos - 1][xPos] != 'o') wallDirections.push('north')
|
|
146
|
+
if (this.map[yPos + 1][xPos] != ' ' && this.map[yPos + 1][xPos] != 'o') wallDirections.push('south')
|
|
147
|
+
if (wallDirections.length == 3) {
|
|
148
|
+
if (wallDirections.includes('north') && !wallDirections.includes('south')) {
|
|
149
|
+
this.map[yPos + 1] = this.replaceAt(this.map[yPos + 1], xPos - 1, '-')
|
|
150
|
+
this.map[yPos + 1] = this.replaceAt(this.map[yPos + 1], xPos, 'o')
|
|
151
|
+
this.map[yPos + 1] = this.replaceAt(this.map[yPos + 1], xPos + 1, '-')
|
|
152
|
+
} else if (!wallDirections.includes('north') && wallDirections.includes('south')) {
|
|
153
|
+
this.map[yPos - 1] = this.replaceAt(this.map[yPos - 1], xPos - 1, '-')
|
|
154
|
+
this.map[yPos - 1] = this.replaceAt(this.map[yPos - 1], xPos, 'o')
|
|
155
|
+
this.map[yPos - 1] = this.replaceAt(this.map[yPos - 1], xPos + 1, '-')
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
replaceAt(string, index, replacement) {
|
|
161
|
+
return string.substr(0, index) + replacement + string.substr(index + replacement.length)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
mapUpdate(map) {
|
|
165
|
+
const copy = [...map]
|
|
166
|
+
for (let y = 0; y < copy.length; y++) {
|
|
167
|
+
for (let x = 0; x < copy[y].length; x++) {
|
|
168
|
+
if (copy[y][x] === '-') copy[y] = copy[y].substring(0, x) + '─' + copy[y].substring(x + 1)
|
|
169
|
+
if (copy[y][x] === '|') copy[y] = copy[y].substring(0, x) + '│' + copy[y].substring(x + 1)
|
|
170
|
+
if (copy[y][x] === '+') {
|
|
171
|
+
let north = y > 0 && copy[y - 1][x] !== ' '
|
|
172
|
+
let south = y < copy.length - 1 && copy[y + 1][x] !== ' '
|
|
173
|
+
let west = x > 0 && copy[y][x - 1] !== ' '
|
|
174
|
+
let east = x < copy[y].length - 1 && copy[y][x + 1] !== ' '
|
|
175
|
+
if (north && south && west && east) copy[y] = copy[y].substring(0, x) + '┼' + copy[y].substring(x + 1)
|
|
176
|
+
else if (north && south && west) copy[y] = copy[y].substring(0, x) + '┤' + copy[y].substring(x + 1)
|
|
177
|
+
else if (north && south && east) copy[y] = copy[y].substring(0, x) + '├' + copy[y].substring(x + 1)
|
|
178
|
+
else if (north && east && west) copy[y] = copy[y].substring(0, x) + '┴' + copy[y].substring(x + 1)
|
|
179
|
+
else if (south && east && west) copy[y] = copy[y].substring(0, x) + '┬' + copy[y].substring(x + 1)
|
|
180
|
+
else if (north && south) copy[y] = copy[y].substring(0, x) + '│' + copy[y].substring(x + 1)
|
|
181
|
+
else if (west && east) copy[y] = copy[y].substring(0, x) + '─' + copy[y].substring(x + 1)
|
|
182
|
+
else if (north && east) copy[y] = copy[y].substring(0, x) + '╰' + copy[y].substring(x + 1)
|
|
183
|
+
else if (north && west) copy[y] = copy[y].substring(0, x) + '╯' + copy[y].substring(x + 1)
|
|
184
|
+
else if (south && east) copy[y] = copy[y].substring(0, x) + '╭' + copy[y].substring(x + 1)
|
|
185
|
+
else if (south && west) copy[y] = copy[y].substring(0, x) + '╮' + copy[y].substring(x + 1)
|
|
186
|
+
else if (east) copy[y] = copy[y].substring(0, x) + '╶' + copy[y].substring(x + 1)
|
|
187
|
+
else if (west) copy[y] = copy[y].substring(0, x) + '╴' + copy[y].substring(x + 1)
|
|
188
|
+
else if (north) copy[y] = copy[y].substring(0, x) + '╵' + copy[y].substring(x + 1)
|
|
189
|
+
else if (south) copy[y] = copy[y].substring(0, x) + '╷' + copy[y].substring(x + 1)
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
this.map = copy
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
createMap() {
|
|
197
|
+
// Establish variables and starting grid
|
|
198
|
+
const totalCells = this.height * this.width
|
|
199
|
+
const unvisited = [] // cells that are unvisited.
|
|
200
|
+
const map = []
|
|
201
|
+
for (let y = 0; y < this.height; y++) {
|
|
202
|
+
unvisited[y] = []
|
|
203
|
+
map[y * 2] = ''
|
|
204
|
+
map[y * 2 + 1] = ''
|
|
205
|
+
for (let x = 0; x < this.width; x++) {
|
|
206
|
+
map[y * 2] += '+---'
|
|
207
|
+
map[y * 2 + 1] += '| '
|
|
208
|
+
unvisited[y][x] = true
|
|
209
|
+
}
|
|
210
|
+
map[y * 2] += '+'
|
|
211
|
+
map[y * 2 + 1] += '|'
|
|
212
|
+
}
|
|
213
|
+
map[this.height * 2] = ''
|
|
214
|
+
for (let x = 0; x < this.width; x++) {
|
|
215
|
+
map[this.height * 2] += '+---'
|
|
216
|
+
}
|
|
217
|
+
map[this.height * 2] += '+'
|
|
218
|
+
|
|
219
|
+
// Set a random position to start from
|
|
220
|
+
let current = [Math.floor(Math.random() * this.height), Math.floor(Math.random() * this.width)]
|
|
221
|
+
const path = [current]
|
|
222
|
+
unvisited[current[0]][current[1]] = false
|
|
223
|
+
let visited = 1
|
|
224
|
+
|
|
225
|
+
// // Loop through all available cell positions (given walls take up half the cells, we divide the total by two)
|
|
226
|
+
while (visited < totalCells) {
|
|
227
|
+
// Determine neighboring cells (0,1) and pathways to them (2,3)
|
|
228
|
+
const south = [current[0] - 1, current[1], 'north']
|
|
229
|
+
const north = [current[0] + 1, current[1], 'south']
|
|
230
|
+
const east = [current[0], current[1] - 1, 'west']
|
|
231
|
+
const west = [current[0], current[1] + 1, 'east']
|
|
232
|
+
const possibleNeighbors = [south, north, east, west]
|
|
233
|
+
const neighbors = []
|
|
234
|
+
|
|
235
|
+
// Determine if each neighboring cell is in game grid, and whether it has already been checked
|
|
236
|
+
for (let i = 0; i < possibleNeighbors.length; i++) {
|
|
237
|
+
if (
|
|
238
|
+
possibleNeighbors[i][0] > -1 &&
|
|
239
|
+
possibleNeighbors[i][0] < this.height &&
|
|
240
|
+
possibleNeighbors[i][1] > -1 &&
|
|
241
|
+
possibleNeighbors[i][1] < this.width &&
|
|
242
|
+
unvisited[possibleNeighbors[i][0]][possibleNeighbors[i][1]] == true
|
|
243
|
+
) {
|
|
244
|
+
neighbors.push(possibleNeighbors[i])
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// If at least one active neighboring cell has been found
|
|
249
|
+
if (neighbors.length > 0) {
|
|
250
|
+
// Choose one of the neighbors at random
|
|
251
|
+
const next = neighbors[Math.floor(Math.random() * neighbors.length)]
|
|
252
|
+
|
|
253
|
+
// Remove the wall between the current cell and the chosen neighboring cell in the map view.
|
|
254
|
+
// split map
|
|
255
|
+
let xBorderToRemove = 0
|
|
256
|
+
let yBorderToRemove = 0
|
|
257
|
+
if (next[2] == 'south') {
|
|
258
|
+
yBorderToRemove = this.yOffset(next[0]) - 1
|
|
259
|
+
xBorderToRemove = this.xOffset(next[1])
|
|
260
|
+
map[yBorderToRemove] = this.replaceAt(map[yBorderToRemove], xBorderToRemove - 1, ' ')
|
|
261
|
+
map[yBorderToRemove] = this.replaceAt(map[yBorderToRemove], xBorderToRemove + 1, ' ')
|
|
262
|
+
} else if (next[2] == 'north') {
|
|
263
|
+
yBorderToRemove = this.yOffset(next[0]) + 1
|
|
264
|
+
xBorderToRemove = this.xOffset(next[1])
|
|
265
|
+
map[yBorderToRemove] = this.replaceAt(map[yBorderToRemove], xBorderToRemove - 1, ' ')
|
|
266
|
+
map[yBorderToRemove] = this.replaceAt(map[yBorderToRemove], xBorderToRemove + 1, ' ')
|
|
267
|
+
} else if (next[2] == 'east') {
|
|
268
|
+
yBorderToRemove = this.yOffset(next[0])
|
|
269
|
+
xBorderToRemove = this.xOffset(next[1]) - 2
|
|
270
|
+
} else if (next[2] == 'west') {
|
|
271
|
+
yBorderToRemove = this.yOffset(next[0])
|
|
272
|
+
xBorderToRemove = this.xOffset(next[1]) + 2
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
map[yBorderToRemove] = this.replaceAt(map[yBorderToRemove], xBorderToRemove, ' ')
|
|
276
|
+
|
|
277
|
+
// Mark the neighbor as visited, and set it as the current cell
|
|
278
|
+
current = next
|
|
279
|
+
unvisited[current[0]][current[1]] = false
|
|
280
|
+
visited++
|
|
281
|
+
path.push(current)
|
|
282
|
+
}
|
|
283
|
+
// Otherwise go back up a step and keep going
|
|
284
|
+
else {
|
|
285
|
+
current = path.pop()
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return map
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const { width, height, filename, mapDir, smooth } = parseArgs()
|
|
293
|
+
const builder = new MapBuilder(width, height, filename, mapDir, smooth)
|
|
294
|
+
builder.build()
|
|
@@ -1,101 +1,44 @@
|
|
|
1
1
|
import {
|
|
2
2
|
App,
|
|
3
3
|
Art,
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
Row,
|
|
4
|
+
Button,
|
|
5
|
+
Column,
|
|
7
6
|
Text,
|
|
8
7
|
PerfMonitor,
|
|
9
8
|
State,
|
|
10
9
|
Keybind,
|
|
11
10
|
} from 'asciitorium';
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
CelticBorderExample,
|
|
16
|
-
FormExample,
|
|
17
|
-
MultiSelectExample,
|
|
18
|
-
LayoutSizingExample,
|
|
19
|
-
ModalExample,
|
|
20
|
-
TabsExample,
|
|
21
|
-
ArtExample,
|
|
22
|
-
SlidersExample,
|
|
23
|
-
ScrollableTextExample,
|
|
24
|
-
MazeExample,
|
|
25
|
-
} from 'asciitorium/examples';
|
|
26
|
-
|
|
27
|
-
// Main state for component selection with persistence
|
|
28
|
-
const selectedComponent = new State('Art');
|
|
12
|
+
// State for counter demo
|
|
13
|
+
const count = new State(0);
|
|
29
14
|
|
|
30
|
-
// State for PerfMonitor visibility
|
|
15
|
+
// State for PerfMonitor visibility toggle
|
|
31
16
|
const showPerfMonitor = new State(false);
|
|
32
17
|
|
|
33
|
-
//
|
|
34
|
-
const componentList = [
|
|
35
|
-
'Art',
|
|
36
|
-
'Button',
|
|
37
|
-
'CelticBorder',
|
|
38
|
-
'Form',
|
|
39
|
-
'Modal',
|
|
40
|
-
'Maze',
|
|
41
|
-
'MultiSelect',
|
|
42
|
-
'LayoutSizing',
|
|
43
|
-
'ScrollableText',
|
|
44
|
-
'Sliders',
|
|
45
|
-
'Tabs',
|
|
46
|
-
];
|
|
47
|
-
|
|
48
|
-
// Component mapping for dynamic content
|
|
49
|
-
const examples = {
|
|
50
|
-
Art: ArtExample,
|
|
51
|
-
Button: ButtonExample,
|
|
52
|
-
CelticBorder: CelticBorderExample,
|
|
53
|
-
Form: FormExample,
|
|
54
|
-
Modal: ModalExample,
|
|
55
|
-
Maze: MazeExample,
|
|
56
|
-
MultiSelect: MultiSelectExample,
|
|
57
|
-
LayoutSizing: LayoutSizingExample,
|
|
58
|
-
ScrollableText: ScrollableTextExample,
|
|
59
|
-
Sliders: SlidersExample,
|
|
60
|
-
Tabs: TabsExample,
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
// toggle PerfMonitor with "P" key
|
|
18
|
+
// toggle PerfMonitor
|
|
64
19
|
const togglePerfMonitor = () => {
|
|
65
20
|
showPerfMonitor.value = !showPerfMonitor.value;
|
|
66
21
|
};
|
|
67
22
|
|
|
68
23
|
const app = (
|
|
69
24
|
<App>
|
|
70
|
-
<Keybind keyBinding="p" action={togglePerfMonitor}
|
|
25
|
+
<Keybind keyBinding="p" action={togglePerfMonitor} />
|
|
26
|
+
|
|
27
|
+
<Column style={{ align: 'center', gap: 1, width: '100%' }}>
|
|
28
|
+
<Art font="pencil" text="Welcome to" align="center" />
|
|
29
|
+
<Art src="asciitorium" align="center" />
|
|
30
|
+
|
|
31
|
+
<Text style={{ align: 'center', gap: 1 }}>
|
|
32
|
+
Edit src/main.tsx and save to reload.
|
|
33
|
+
</Text>
|
|
34
|
+
|
|
35
|
+
<Art src="beating-heart" width={20} align="center" />
|
|
36
|
+
|
|
37
|
+
<Text style={{ align: 'center', gap: 1 }}>
|
|
38
|
+
Press [P] to toggle performance monitor
|
|
39
|
+
</Text>
|
|
40
|
+
</Column>
|
|
71
41
|
|
|
72
|
-
<Art
|
|
73
|
-
src={'./art/asciitorium.txt'}
|
|
74
|
-
style={{ align: 'center', gap: { bottom: 2 } }}
|
|
75
|
-
/>
|
|
76
|
-
<Row style={{ height: 'fill' }}>
|
|
77
|
-
<Select
|
|
78
|
-
label="Components"
|
|
79
|
-
style={{
|
|
80
|
-
width: '30%',
|
|
81
|
-
height: 'fill',
|
|
82
|
-
}}
|
|
83
|
-
items={componentList}
|
|
84
|
-
selectedItem={selectedComponent}
|
|
85
|
-
/>
|
|
86
|
-
<Switch
|
|
87
|
-
style={{
|
|
88
|
-
width: 'fill',
|
|
89
|
-
height: 'fill',
|
|
90
|
-
}}
|
|
91
|
-
selectedKey={selectedComponent}
|
|
92
|
-
componentMap={examples}
|
|
93
|
-
/>
|
|
94
|
-
</Row>
|
|
95
|
-
<Text
|
|
96
|
-
content="Navigation: ↑↓ • [Space]/[Enter] to select • [Tab]/[Tab+Shift] to switch focus • [P] toggles performance monitor"
|
|
97
|
-
style={{ align: 'center', gap: 1 }}
|
|
98
|
-
/>
|
|
99
42
|
<PerfMonitor visible={showPerfMonitor} />
|
|
100
43
|
</App>
|
|
101
44
|
);
|