@aemonge-dev/pi-stardeck 0.5.0 → 0.7.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.
- package/README.md +3 -2
- package/docs/architecture.md +8 -5
- package/licenses/README.md +9 -7
- package/package.json +2 -2
- package/packages/footer/README.md +15 -0
- package/packages/footer/index.ts +37 -0
- package/packages/footer/package.json +32 -0
- package/packages/footer/src/protocol.ts +10 -0
- package/packages/footer/src/quota.ts +26 -0
- package/packages/footer/src/telemetry.ts +59 -0
- package/packages/pi-stardeck/README.md +7 -6
- package/packages/pi-stardeck/src/deck.ts +79 -44
- package/packages/status/package.json +1 -1
- package/src/health.ts +0 -1
- package/src/index.ts +3 -4
- package/licenses/pi-fancy-footer-LICENSE +0 -21
- package/packages/pi-fancy-footer-full-palette/LICENSE +0 -21
- package/packages/pi-fancy-footer-full-palette/LOCAL-CHANGES.md +0 -41
- package/packages/pi-fancy-footer-full-palette/README.md +0 -468
- package/packages/pi-fancy-footer-full-palette/package.json +0 -52
- package/packages/pi-fancy-footer-full-palette/src/api.ts +0 -204
- package/packages/pi-fancy-footer-full-palette/src/config-editor.ts +0 -634
- package/packages/pi-fancy-footer-full-palette/src/config.ts +0 -852
- package/packages/pi-fancy-footer-full-palette/src/data-widgets.ts +0 -259
- package/packages/pi-fancy-footer-full-palette/src/git.ts +0 -130
- package/packages/pi-fancy-footer-full-palette/src/index.ts +0 -479
- package/packages/pi-fancy-footer-full-palette/src/layout.ts +0 -309
- package/packages/pi-fancy-footer-full-palette/src/provider-status.ts +0 -1466
- package/packages/pi-fancy-footer-full-palette/src/render.ts +0 -1061
- package/packages/pi-fancy-footer-full-palette/src/shared.ts +0 -903
|
@@ -1,309 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
MAX_WIDGET_POSITION,
|
|
3
|
-
MAX_WIDGET_ROW,
|
|
4
|
-
clampInt,
|
|
5
|
-
type FooterConfigSnapshot,
|
|
6
|
-
type FooterWidgetAlign,
|
|
7
|
-
type FooterWidgetFill,
|
|
8
|
-
} from "./shared.ts";
|
|
9
|
-
import {
|
|
10
|
-
getWidgetOverride,
|
|
11
|
-
updateWidgetOverride,
|
|
12
|
-
type ConfigurableWidgetMeta,
|
|
13
|
-
} from "./config.ts";
|
|
14
|
-
|
|
15
|
-
export const WIDGET_ALIGNS: readonly FooterWidgetAlign[] = ["left", "middle", "right"];
|
|
16
|
-
|
|
17
|
-
export interface EffectivePlacement {
|
|
18
|
-
row: number;
|
|
19
|
-
position: number;
|
|
20
|
-
align: FooterWidgetAlign;
|
|
21
|
-
fill: FooterWidgetFill;
|
|
22
|
-
benched: boolean;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export interface LayoutChip {
|
|
26
|
-
widget: ConfigurableWidgetMeta;
|
|
27
|
-
placement: EffectivePlacement;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export interface LayoutRow {
|
|
31
|
-
row: number;
|
|
32
|
-
groups: Record<FooterWidgetAlign, LayoutChip[]>;
|
|
33
|
-
/** Visual order: left group, then middle, then right. */
|
|
34
|
-
ordered: LayoutChip[];
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export interface LayoutModel {
|
|
38
|
-
rows: LayoutRow[];
|
|
39
|
-
bench: LayoutChip[];
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export function effectivePlacement(
|
|
43
|
-
config: FooterConfigSnapshot,
|
|
44
|
-
widget: ConfigurableWidgetMeta,
|
|
45
|
-
): EffectivePlacement {
|
|
46
|
-
const override = getWidgetOverride(config, widget);
|
|
47
|
-
return {
|
|
48
|
-
row: clampInt(override?.row ?? widget.defaults.row, 0, MAX_WIDGET_ROW),
|
|
49
|
-
position: clampInt(
|
|
50
|
-
override?.position ?? widget.defaults.position,
|
|
51
|
-
0,
|
|
52
|
-
MAX_WIDGET_POSITION,
|
|
53
|
-
),
|
|
54
|
-
align: override?.align ?? widget.defaults.align,
|
|
55
|
-
fill: override?.fill ?? widget.defaults.fill,
|
|
56
|
-
benched: (override?.enabled ?? widget.defaults.enabled ?? true) === false,
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Widgets keep their base order (built-ins first, then extensions) and each
|
|
61
|
-
// group sorts by position with a stable sort, matching prepareWidgetGroup()
|
|
62
|
-
// in render.ts.
|
|
63
|
-
export function buildLayoutModel(
|
|
64
|
-
config: FooterConfigSnapshot,
|
|
65
|
-
widgets: readonly ConfigurableWidgetMeta[],
|
|
66
|
-
): LayoutModel {
|
|
67
|
-
const chips: LayoutChip[] = widgets.map((widget) => ({
|
|
68
|
-
widget,
|
|
69
|
-
placement: effectivePlacement(config, widget),
|
|
70
|
-
}));
|
|
71
|
-
|
|
72
|
-
const bench = chips.filter((chip) => chip.placement.benched);
|
|
73
|
-
const placed = chips.filter((chip) => !chip.placement.benched);
|
|
74
|
-
|
|
75
|
-
const highestRow = placed.reduce((acc, chip) => Math.max(acc, chip.placement.row), 1);
|
|
76
|
-
|
|
77
|
-
const rows: LayoutRow[] = [];
|
|
78
|
-
for (let row = 0; row <= highestRow; row++) {
|
|
79
|
-
const groups: Record<FooterWidgetAlign, LayoutChip[]> = {
|
|
80
|
-
left: [],
|
|
81
|
-
middle: [],
|
|
82
|
-
right: [],
|
|
83
|
-
};
|
|
84
|
-
for (const chip of placed) {
|
|
85
|
-
if (chip.placement.row === row) groups[chip.placement.align].push(chip);
|
|
86
|
-
}
|
|
87
|
-
for (const align of WIDGET_ALIGNS) {
|
|
88
|
-
groups[align].sort((a, b) => a.placement.position - b.placement.position);
|
|
89
|
-
}
|
|
90
|
-
rows.push({
|
|
91
|
-
row,
|
|
92
|
-
groups,
|
|
93
|
-
ordered: [...groups.left, ...groups.middle, ...groups.right],
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return { rows, bench };
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function findChip(model: LayoutModel, widgetId: string): LayoutChip | undefined {
|
|
101
|
-
for (const row of model.rows) {
|
|
102
|
-
const chip = row.ordered.find((entry) => entry.widget.id === widgetId);
|
|
103
|
-
if (chip) return chip;
|
|
104
|
-
}
|
|
105
|
-
return model.bench.find((entry) => entry.widget.id === widgetId);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// A widget's (row, align, position) triple is only removed from its override
|
|
109
|
-
// when all three equal its defaults: default positions are sparse and shared
|
|
110
|
-
// across widgets, so pruning a single key could reorder its group.
|
|
111
|
-
function setPlacement(
|
|
112
|
-
config: FooterConfigSnapshot,
|
|
113
|
-
widget: ConfigurableWidgetMeta,
|
|
114
|
-
placement: { row: number; align: FooterWidgetAlign; position: number },
|
|
115
|
-
): void {
|
|
116
|
-
updateWidgetOverride(config, widget, (override) => {
|
|
117
|
-
if (
|
|
118
|
-
placement.row === widget.defaults.row &&
|
|
119
|
-
placement.align === widget.defaults.align &&
|
|
120
|
-
placement.position === widget.defaults.position
|
|
121
|
-
) {
|
|
122
|
-
delete override.row;
|
|
123
|
-
delete override.align;
|
|
124
|
-
delete override.position;
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
override.row = placement.row;
|
|
128
|
-
override.align = placement.align;
|
|
129
|
-
override.position = placement.position;
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// When the group is exactly its default members in default order, restore
|
|
134
|
-
// the default (possibly sparse, non-zero-based) positions so setPlacement
|
|
135
|
-
// prunes the overrides and the config file stays minimal. Otherwise assign
|
|
136
|
-
// dense positions 0..n-1.
|
|
137
|
-
function renumberGroup(
|
|
138
|
-
config: FooterConfigSnapshot,
|
|
139
|
-
group: readonly LayoutChip[],
|
|
140
|
-
row: number,
|
|
141
|
-
align: FooterWidgetAlign,
|
|
142
|
-
): void {
|
|
143
|
-
const isDefaultGroup = group.every(
|
|
144
|
-
(chip, index) =>
|
|
145
|
-
chip.widget.defaults.row === row &&
|
|
146
|
-
chip.widget.defaults.align === align &&
|
|
147
|
-
(index === 0 ||
|
|
148
|
-
group[index - 1]!.widget.defaults.position < chip.widget.defaults.position),
|
|
149
|
-
);
|
|
150
|
-
|
|
151
|
-
for (const [index, chip] of group.entries()) {
|
|
152
|
-
setPlacement(config, chip.widget, {
|
|
153
|
-
row,
|
|
154
|
-
align,
|
|
155
|
-
position: isDefaultGroup ? chip.widget.defaults.position : index,
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
export function moveHorizontal(
|
|
161
|
-
config: FooterConfigSnapshot,
|
|
162
|
-
widgets: readonly ConfigurableWidgetMeta[],
|
|
163
|
-
widgetId: string,
|
|
164
|
-
direction: -1 | 1,
|
|
165
|
-
): void {
|
|
166
|
-
const model = buildLayoutModel(config, widgets);
|
|
167
|
-
const chip = findChip(model, widgetId);
|
|
168
|
-
if (!chip || chip.placement.benched) return;
|
|
169
|
-
|
|
170
|
-
const { row, align } = chip.placement;
|
|
171
|
-
const group = [...model.rows[row]!.groups[align]];
|
|
172
|
-
const index = group.findIndex((entry) => entry.widget.id === widgetId);
|
|
173
|
-
const target = index + direction;
|
|
174
|
-
|
|
175
|
-
if (target >= 0 && target < group.length) {
|
|
176
|
-
[group[index], group[target]] = [group[target]!, group[index]!];
|
|
177
|
-
renumberGroup(config, group, row, align);
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
const nextAlign = WIDGET_ALIGNS[WIDGET_ALIGNS.indexOf(align) + direction];
|
|
182
|
-
if (!nextAlign) return;
|
|
183
|
-
|
|
184
|
-
group.splice(index, 1);
|
|
185
|
-
renumberGroup(config, group, row, align);
|
|
186
|
-
|
|
187
|
-
const neighbor = [...model.rows[row]!.groups[nextAlign]];
|
|
188
|
-
if (direction === 1) neighbor.unshift(chip);
|
|
189
|
-
else neighbor.push(chip);
|
|
190
|
-
renumberGroup(config, neighbor, row, nextAlign);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
export function moveVertical(
|
|
194
|
-
config: FooterConfigSnapshot,
|
|
195
|
-
widgets: readonly ConfigurableWidgetMeta[],
|
|
196
|
-
widgetId: string,
|
|
197
|
-
direction: -1 | 1,
|
|
198
|
-
): void {
|
|
199
|
-
const model = buildLayoutModel(config, widgets);
|
|
200
|
-
const chip = findChip(model, widgetId);
|
|
201
|
-
if (!chip) return;
|
|
202
|
-
|
|
203
|
-
if (chip.placement.benched) {
|
|
204
|
-
if (direction === -1) unbenchToBottomRow(config, widgets, widgetId);
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
const { row, align } = chip.placement;
|
|
209
|
-
const bottomRow = model.rows.length - 1;
|
|
210
|
-
|
|
211
|
-
if (direction === 1 && row === bottomRow) {
|
|
212
|
-
setBenched(config, widgets, widgetId, true);
|
|
213
|
-
return;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
const targetRow = clampInt(row + direction, 0, MAX_WIDGET_ROW);
|
|
217
|
-
if (targetRow === row) return;
|
|
218
|
-
|
|
219
|
-
const source = model.rows[row]!.groups[align].filter(
|
|
220
|
-
(entry) => entry.widget.id !== widgetId,
|
|
221
|
-
);
|
|
222
|
-
renumberGroup(config, source, row, align);
|
|
223
|
-
|
|
224
|
-
const target = [...(model.rows[targetRow]?.groups[align] ?? []), chip];
|
|
225
|
-
renumberGroup(config, target, targetRow, align);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
export function cycleAlign(
|
|
229
|
-
config: FooterConfigSnapshot,
|
|
230
|
-
widgets: readonly ConfigurableWidgetMeta[],
|
|
231
|
-
widgetId: string,
|
|
232
|
-
): void {
|
|
233
|
-
const model = buildLayoutModel(config, widgets);
|
|
234
|
-
const chip = findChip(model, widgetId);
|
|
235
|
-
if (!chip || chip.placement.benched) return;
|
|
236
|
-
|
|
237
|
-
const { row, align } = chip.placement;
|
|
238
|
-
const nextAlign =
|
|
239
|
-
WIDGET_ALIGNS[(WIDGET_ALIGNS.indexOf(align) + 1) % WIDGET_ALIGNS.length]!;
|
|
240
|
-
|
|
241
|
-
const source = model.rows[row]!.groups[align].filter(
|
|
242
|
-
(entry) => entry.widget.id !== widgetId,
|
|
243
|
-
);
|
|
244
|
-
renumberGroup(config, source, row, align);
|
|
245
|
-
|
|
246
|
-
const target = [...model.rows[row]!.groups[nextAlign], chip];
|
|
247
|
-
renumberGroup(config, target, row, nextAlign);
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
export function toggleFill(
|
|
251
|
-
config: FooterConfigSnapshot,
|
|
252
|
-
widgets: readonly ConfigurableWidgetMeta[],
|
|
253
|
-
widgetId: string,
|
|
254
|
-
): void {
|
|
255
|
-
const widget = widgets.find((entry) => entry.id === widgetId);
|
|
256
|
-
if (!widget) return;
|
|
257
|
-
|
|
258
|
-
const current = effectivePlacement(config, widget).fill;
|
|
259
|
-
const next: FooterWidgetFill = current === "grow" ? "none" : "grow";
|
|
260
|
-
updateWidgetOverride(config, widget, (override) => {
|
|
261
|
-
if (next === widget.defaults.fill) delete override.fill;
|
|
262
|
-
else override.fill = next;
|
|
263
|
-
});
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
// Benching only touches `enabled`, so a bench round-trip restores the exact
|
|
267
|
-
// placement. The override is dropped when it matches the widget's default
|
|
268
|
-
// enabled state.
|
|
269
|
-
export function setBenched(
|
|
270
|
-
config: FooterConfigSnapshot,
|
|
271
|
-
widgets: readonly ConfigurableWidgetMeta[],
|
|
272
|
-
widgetId: string,
|
|
273
|
-
benched: boolean,
|
|
274
|
-
): void {
|
|
275
|
-
const widget = widgets.find((entry) => entry.id === widgetId);
|
|
276
|
-
if (!widget) return;
|
|
277
|
-
|
|
278
|
-
const defaultEnabled = widget.defaults.enabled ?? true;
|
|
279
|
-
updateWidgetOverride(config, widget, (override) => {
|
|
280
|
-
if (benched === !defaultEnabled) delete override.enabled;
|
|
281
|
-
else override.enabled = !benched;
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// "u" from the bench re-enables the widget on the bottom-most row so it
|
|
286
|
-
// reappears adjacent to the bench, at the end of its alignment group. A
|
|
287
|
-
// widget already stored on that row keeps its exact placement.
|
|
288
|
-
function unbenchToBottomRow(
|
|
289
|
-
config: FooterConfigSnapshot,
|
|
290
|
-
widgets: readonly ConfigurableWidgetMeta[],
|
|
291
|
-
widgetId: string,
|
|
292
|
-
): void {
|
|
293
|
-
setBenched(config, widgets, widgetId, false);
|
|
294
|
-
|
|
295
|
-
const model = buildLayoutModel(config, widgets);
|
|
296
|
-
const chip = findChip(model, widgetId);
|
|
297
|
-
if (!chip) return;
|
|
298
|
-
|
|
299
|
-
const bottomRow = model.rows.length - 1;
|
|
300
|
-
if (chip.placement.row === bottomRow) return;
|
|
301
|
-
|
|
302
|
-
const source = model.rows[chip.placement.row]!.groups[chip.placement.align].filter(
|
|
303
|
-
(entry) => entry.widget.id !== widgetId,
|
|
304
|
-
);
|
|
305
|
-
renumberGroup(config, source, chip.placement.row, chip.placement.align);
|
|
306
|
-
|
|
307
|
-
const target = [...model.rows[bottomRow]!.groups[chip.placement.align], chip];
|
|
308
|
-
renumberGroup(config, target, bottomRow, chip.placement.align);
|
|
309
|
-
}
|