plugin-gentleman 1.0.2 → 1.0.4
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/package.json +1 -1
- package/tui.tsx +81 -96
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "plugin-gentleman",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.4",
|
|
5
5
|
"description": "OpenCode TUI plugin featuring Mustachi - an animated ASCII mascot with eyes, mustache, and optional motivational phrases during busy states",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"exports": {
|
package/tui.tsx
CHANGED
|
@@ -6,60 +6,41 @@ import { createSignal, onCleanup, createEffect } from "solid-js"
|
|
|
6
6
|
|
|
7
7
|
const id = "gentleman"
|
|
8
8
|
|
|
9
|
-
// Premium Mustachi ASCII art -
|
|
9
|
+
// Premium Mustachi ASCII art - compact version for sidebar (25 chars wide)
|
|
10
10
|
// Base structure with eyes that will be replaced dynamically
|
|
11
11
|
const mustachiNeutralBase = [
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
" ██░░░░████████░░░░██ ██░░░░░░░░░░░░░░░░██",
|
|
18
|
-
" ██░░░░░░░░░░░░░░██ ██░░░░░░░░░░░░░░██",
|
|
19
|
-
" ██░░░░░░░░░░░░██ ██░░░░░░░░░░░░██",
|
|
20
|
-
" ████████████ ████████████",
|
|
12
|
+
" █████ █████",
|
|
13
|
+
" ██░░░░░██ ██░░░░░██",
|
|
14
|
+
" ██░░███░░██ ██░░░░░░░██",
|
|
15
|
+
" ██░░███░░██ ██░░░░░░░██",
|
|
16
|
+
"██ ██░░░░░██ ██░░░░░██ ██",
|
|
21
17
|
]
|
|
22
18
|
|
|
23
19
|
// Squinted eyes version for busy state
|
|
24
20
|
const mustachiSquintedBase = [
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
" ██░░░░░░░░░░░░░░░░██ ██░░░░░░░░░░░░░░░░██",
|
|
31
|
-
" ██░░░░░░░░░░░░░░██ ██░░░░░░░░░░░░░░██",
|
|
32
|
-
" ██░░░░░░░░░░░░██ ██░░░░░░░░░░░░██",
|
|
33
|
-
" ████████████ ████████████",
|
|
21
|
+
" █████ █████",
|
|
22
|
+
" ██░░░░░██ ██░░░░░██",
|
|
23
|
+
" ██░░███░░██ ██░░░░░░░██",
|
|
24
|
+
" █████████ █████████",
|
|
25
|
+
"██ █████ █████ ██",
|
|
34
26
|
]
|
|
35
27
|
|
|
36
|
-
// Mustache section (
|
|
28
|
+
// Mustache section (compact 25-char wide design)
|
|
37
29
|
const mustachiMustacheSection = [
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
" ███████████████████████████████████████████████████████████",
|
|
44
|
-
" ███████████████████████████████████████████████████████████",
|
|
45
|
-
" ███████████████████████████████████████████████████████████",
|
|
46
|
-
" █████████████████████████████████████████████████████████",
|
|
47
|
-
" ███████████████████████████████████████████████████████",
|
|
48
|
-
" ▓▓█████████████████████ █████████████████████▓▓",
|
|
49
|
-
" ▓▓▓███████████████ ███████████████▓▓▓",
|
|
50
|
-
" ▓▓▓█████████ █████████▓▓▓",
|
|
51
|
-
" ▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓",
|
|
30
|
+
"██████████ ████████",
|
|
31
|
+
"████████████ ██████████",
|
|
32
|
+
" █████████████████████████",
|
|
33
|
+
" ▓██████████ ██████████▓",
|
|
34
|
+
" ▓██████ ██████▓",
|
|
52
35
|
]
|
|
53
36
|
|
|
54
|
-
// Tongue animation frames (progressive)
|
|
37
|
+
// Tongue animation frames (progressive) - compact design
|
|
55
38
|
const tongueFrames = [
|
|
56
39
|
[], // no tongue
|
|
57
|
-
["
|
|
58
|
-
[" ███████", " █████"], // medium tongue
|
|
59
|
-
[" ███████", " █████", " ███"], // full tongue
|
|
40
|
+
[" ███", " █"], // tongue out
|
|
60
41
|
]
|
|
61
42
|
|
|
62
|
-
// Mustache-only ASCII art for home logo (
|
|
43
|
+
// Mustache-only ASCII art for home logo (original massive solid block design)
|
|
63
44
|
const mustachiMustacheOnly = [
|
|
64
45
|
"",
|
|
65
46
|
" ████████ ████████",
|
|
@@ -82,11 +63,12 @@ const mustachiMustacheOnly = [
|
|
|
82
63
|
// Left pupil positions for look-around animation (progressive)
|
|
83
64
|
// Modifies only the left eye (white sclera with dark pupil)
|
|
84
65
|
// Right eye is monocle/glass and remains static
|
|
66
|
+
// Pupil is on lines 2 and 3 (indices 2-3) of the 5-line eye array
|
|
85
67
|
const leftPupilPositions = [
|
|
86
|
-
"
|
|
87
|
-
"
|
|
88
|
-
"
|
|
89
|
-
"
|
|
68
|
+
"██░░███░░██", // center (line 2 of eyes)
|
|
69
|
+
"██████░░░██", // looking left
|
|
70
|
+
"██░░░██████", // looking right
|
|
71
|
+
"██░░███░░██", // center again
|
|
90
72
|
]
|
|
91
73
|
|
|
92
74
|
// Blink animation frames (progressive) - affects both eyes
|
|
@@ -96,30 +78,22 @@ const blinkFrames = [
|
|
|
96
78
|
// Half closed
|
|
97
79
|
{
|
|
98
80
|
left: [
|
|
99
|
-
"
|
|
100
|
-
"
|
|
101
|
-
"
|
|
102
|
-
"
|
|
103
|
-
"
|
|
104
|
-
" ██░░░░████████░░░░██ ██░░░░░░░░░░░░░░░░██",
|
|
105
|
-
" ██░░░░░░░░░░░░░░██ ██░░░░░░░░░░░░░░██",
|
|
106
|
-
" ██░░░░░░░░░░░░██ ██░░░░░░░░░░░░██",
|
|
107
|
-
" ████████████ ████████████",
|
|
81
|
+
" █████ █████",
|
|
82
|
+
" ██░░░░░██ ██░░░░░██",
|
|
83
|
+
" ██░░███░░██ ██░░░░░░░██",
|
|
84
|
+
" █████████ █████████",
|
|
85
|
+
"██ █████ █████ ██",
|
|
108
86
|
],
|
|
109
87
|
squinted: mustachiSquintedBase // squinted stays squinted during blink
|
|
110
88
|
},
|
|
111
89
|
// Fully closed
|
|
112
90
|
{
|
|
113
91
|
left: [
|
|
114
|
-
"
|
|
115
|
-
"
|
|
116
|
-
"
|
|
117
|
-
"
|
|
118
|
-
"
|
|
119
|
-
" ██░░████████████░░██ ██░░░░░░░░░░░░░░░░██",
|
|
120
|
-
" ██░░░░░░░░░░░░░░██ ██░░░░░░░░░░░░░░██",
|
|
121
|
-
" ██░░░░░░░░░░░░██ ██░░░░░░░░░░░░██",
|
|
122
|
-
" ████████████ ████████████",
|
|
92
|
+
" █████ █████",
|
|
93
|
+
" ██░░░░░██ ██░░░░░██",
|
|
94
|
+
" █████████ █████████",
|
|
95
|
+
" █████████ █████████",
|
|
96
|
+
"██ █████ █████ ██",
|
|
123
97
|
],
|
|
124
98
|
squinted: mustachiSquintedBase
|
|
125
99
|
},
|
|
@@ -235,31 +209,32 @@ const getProviders = (providers: ReadonlyArray<{ id: string; name: string }> | u
|
|
|
235
209
|
return Array.from(names).sort().join(", ")
|
|
236
210
|
}
|
|
237
211
|
|
|
238
|
-
// Home logo: Mustache-only (simple and prominent)
|
|
212
|
+
// Home logo: Mustache-only (simple and prominent) with grayscale gradient
|
|
239
213
|
const HomeLogo = (props: { theme: TuiThemeCurrent }) => {
|
|
240
|
-
|
|
241
|
-
const
|
|
242
|
-
const
|
|
214
|
+
// Grayscale palette for better TUI readability
|
|
215
|
+
const lightGray = "#C0C0C0" // Light gray for highlights
|
|
216
|
+
const midGray = "#808080" // Mid gray for main body
|
|
217
|
+
const darkGray = "#505050" // Dark gray for shadows
|
|
243
218
|
|
|
244
219
|
return (
|
|
245
220
|
<box flexDirection="column" alignItems="center">
|
|
246
|
-
{/* Mustache
|
|
221
|
+
{/* Mustache with grayscale gradient for depth */}
|
|
247
222
|
{mustachiMustacheOnly.map((line, idx) => {
|
|
248
223
|
const totalLines = mustachiMustacheOnly.length
|
|
249
|
-
let color =
|
|
224
|
+
let color = midGray
|
|
250
225
|
if (idx < totalLines / 3) {
|
|
251
|
-
color =
|
|
226
|
+
color = lightGray // Top highlight
|
|
252
227
|
} else if (idx >= (2 * totalLines) / 3) {
|
|
253
|
-
color =
|
|
228
|
+
color = darkGray // Bottom shadow
|
|
254
229
|
}
|
|
255
|
-
return <text fg={color}>{line}</text>
|
|
230
|
+
return <text fg={color}>{line.padEnd(61, " ")}</text>
|
|
256
231
|
})}
|
|
257
232
|
|
|
258
233
|
{/* OpenCode branding */}
|
|
259
|
-
<box flexDirection="row" gap={0}>
|
|
260
|
-
<text fg={props.theme.textMuted} dimColor={true}
|
|
261
|
-
<text fg={props.theme.primary}
|
|
262
|
-
<text fg={props.theme.textMuted} dimColor={true}
|
|
234
|
+
<box flexDirection="row" gap={0} marginTop={1}>
|
|
235
|
+
<text fg={props.theme.textMuted} dimColor={true}>╭ </text>
|
|
236
|
+
<text fg={props.theme.primary} bold={true}> O p e n C o d e </text>
|
|
237
|
+
<text fg={props.theme.textMuted} dimColor={true}> ╮</text>
|
|
263
238
|
</box>
|
|
264
239
|
|
|
265
240
|
<text> </text>
|
|
@@ -267,7 +242,7 @@ const HomeLogo = (props: { theme: TuiThemeCurrent }) => {
|
|
|
267
242
|
)
|
|
268
243
|
}
|
|
269
244
|
|
|
270
|
-
// Sidebar: Full Mustachi face with progressive animations
|
|
245
|
+
// Sidebar: Full Mustachi face with progressive animations (grayscale for clarity)
|
|
271
246
|
const SidebarMustachi = (props: { theme: TuiThemeCurrent; config: Cfg; isBusy?: boolean }) => {
|
|
272
247
|
const [pupilIndex, setPupilIndex] = createSignal(0)
|
|
273
248
|
const [blinkFrame, setBlinkFrame] = createSignal(0)
|
|
@@ -328,17 +303,17 @@ const SidebarMustachi = (props: { theme: TuiThemeCurrent; config: Cfg; isBusy?:
|
|
|
328
303
|
return
|
|
329
304
|
}
|
|
330
305
|
|
|
331
|
-
// Grow tongue progressively when entering busy state
|
|
306
|
+
// Grow tongue progressively when entering busy state (2 frames: hidden -> visible)
|
|
332
307
|
let currentFrame = 0
|
|
333
308
|
let tongueTimeoutId: NodeJS.Timeout | undefined
|
|
334
309
|
const growTongue = () => {
|
|
335
310
|
if (currentFrame < tongueFrames.length - 1) {
|
|
336
311
|
currentFrame++
|
|
337
312
|
setTongueFrame(currentFrame)
|
|
338
|
-
tongueTimeoutId = setTimeout(growTongue, 200)
|
|
339
313
|
}
|
|
340
314
|
}
|
|
341
|
-
|
|
315
|
+
// Show tongue immediately when busy
|
|
316
|
+
tongueTimeoutId = setTimeout(growTongue, 200)
|
|
342
317
|
|
|
343
318
|
// Rotate busy phrases
|
|
344
319
|
let phraseIdx = 0
|
|
@@ -371,12 +346,12 @@ const SidebarMustachi = (props: { theme: TuiThemeCurrent; config: Cfg; isBusy?:
|
|
|
371
346
|
: blinkFrames[blinkFrame()].left
|
|
372
347
|
}
|
|
373
348
|
|
|
374
|
-
// Add eyes with pupil position (modify line
|
|
349
|
+
// Add eyes with pupil position (modify line 2 for left eye pupil - index 2 in 5-line array)
|
|
375
350
|
eyeBase.forEach((line, idx) => {
|
|
376
|
-
if (idx ===
|
|
377
|
-
// Replace pupil in left eye (
|
|
351
|
+
if (idx === 2 && !props.isBusy && pupilIndex() >= 0) {
|
|
352
|
+
// Replace pupil in left eye (positions 2-12 of the line for the 25-char compact design)
|
|
378
353
|
const pupil = leftPupilPositions[pupilIndex()]
|
|
379
|
-
const modifiedLine = line.substring(0,
|
|
354
|
+
const modifiedLine = line.substring(0, 2) + pupil + line.substring(13)
|
|
380
355
|
lines.push(modifiedLine)
|
|
381
356
|
} else {
|
|
382
357
|
lines.push(line)
|
|
@@ -386,33 +361,43 @@ const SidebarMustachi = (props: { theme: TuiThemeCurrent; config: Cfg; isBusy?:
|
|
|
386
361
|
// Add mustache section
|
|
387
362
|
mustachiMustacheSection.forEach(line => lines.push(line))
|
|
388
363
|
|
|
389
|
-
// Add tongue if busy (progressive frames)
|
|
364
|
+
// Add tongue if busy (progressive frames) - mark as tongue for coloring
|
|
390
365
|
if (props.isBusy && tongueFrame() > 0) {
|
|
391
366
|
const tongueLines = tongueFrames[tongueFrame()]
|
|
392
|
-
tongueLines.forEach(line => lines.push(line))
|
|
367
|
+
tongueLines.forEach(line => lines.push(`TONGUE:${line}`))
|
|
393
368
|
}
|
|
394
369
|
|
|
395
370
|
return lines
|
|
396
371
|
}
|
|
397
372
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
const
|
|
401
|
-
const
|
|
402
|
-
const
|
|
373
|
+
// Grayscale palette for TUI clarity
|
|
374
|
+
const lightGray = "#C0C0C0" // Light gray for highlights
|
|
375
|
+
const midGray = "#808080" // Mid gray for main body
|
|
376
|
+
const darkGray = "#505050" // Dark gray for shadows
|
|
377
|
+
const tongueColor = "#FF4466" // Pink/Red for tongue
|
|
403
378
|
|
|
404
379
|
return (
|
|
405
380
|
<box flexDirection="column" alignItems="center">
|
|
406
|
-
{/* Full Mustachi face with
|
|
407
|
-
{
|
|
408
|
-
|
|
409
|
-
|
|
381
|
+
{/* Full Mustachi face with grayscale gradient + pink tongue */}
|
|
382
|
+
{buildFace().map((line, idx, arr) => {
|
|
383
|
+
// Check if this is a tongue line
|
|
384
|
+
const isTongue = line.startsWith("TONGUE:")
|
|
385
|
+
const displayLine = isTongue ? line.substring(7) : line
|
|
386
|
+
const paddedLine = displayLine.padEnd(25, " ")
|
|
387
|
+
|
|
388
|
+
if (isTongue) {
|
|
389
|
+
return <text fg={tongueColor}>{paddedLine}</text>
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Apply grayscale gradient to eyes and mustache
|
|
393
|
+
const totalLines = arr.length
|
|
394
|
+
let color = midGray
|
|
410
395
|
if (idx < totalLines / 3) {
|
|
411
|
-
color =
|
|
396
|
+
color = lightGray // Top highlight
|
|
412
397
|
} else if (idx >= (2 * totalLines) / 3) {
|
|
413
|
-
color =
|
|
398
|
+
color = darkGray // Bottom shadow
|
|
414
399
|
}
|
|
415
|
-
return <text fg={color}>{
|
|
400
|
+
return <text fg={color}>{paddedLine}</text>
|
|
416
401
|
})}
|
|
417
402
|
|
|
418
403
|
{/* Busy phrase if loading */}
|