tensorgrid-ui 1.0.4 → 1.0.5

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.
Files changed (2) hide show
  1. package/lib/index.js +86 -0
  2. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -39,6 +39,64 @@ const FAVICON =
39
39
  BRAND_PATHS.map((d) => `<path d="${d}"/>`).join('') +
40
40
  '</svg>'
41
41
 
42
+ /**
43
+ * Иконка установленного приложения: знак на тёмной плашке.
44
+ *
45
+ * Отличается от фавиконки не прихотью. Фавиконка живёт на вкладке рядом с
46
+ * чужими и подстраивается под схему ОС; иконка приложения стоит в панели
47
+ * задач и меню «Пуск», где голый знак без фона выглядит потерянным.
48
+ *
49
+ * Здесь скругление рисуется прямо в SVG — в отличие от файла .ico, который
50
+ * проходит через конвертер и теряет прозрачность. Браузер получает SVG как
51
+ * есть, портить нечему.
52
+ */
53
+ const APP_ICON = (() => {
54
+ const size = 1024
55
+ const [vx, vy, vw, vh] = BRAND_VIEWBOX.split(' ').map(Number)
56
+ const padding = size * 0.16
57
+ const scale = (size - padding * 2) / vw
58
+ const shiftX = padding - vx * scale
59
+ const shiftY = (size - vh * scale) / 2 - vy * scale
60
+ return (
61
+ `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${size} ${size}" width="${size}" height="${size}" role="img" aria-label="TENSOR GRID">` +
62
+ `<rect width="${size}" height="${size}" rx="${Math.round(size * 0.22)}" fill="#0B0D12"/>` +
63
+ `<g transform="translate(${shiftX.toFixed(2)} ${shiftY.toFixed(2)}) scale(${scale.toFixed(5)})">` +
64
+ BRAND_PATHS.map((d) => `<path d="${d}" fill="#FFFFFF"/>`).join('') +
65
+ '</g></svg>'
66
+ )
67
+ })()
68
+
69
+ const APP_ICON_PATH = '/tensorgrid-icon.svg'
70
+
71
+ /**
72
+ * Веб-манифест. Он задаёт не только иконку, но и ИМЯ установленного
73
+ * приложения — то, что видно в панели задач, меню «Пуск» и заголовке окна.
74
+ * Поставочный называет продукт чужим именем, поэтому манифест свой.
75
+ *
76
+ * Поля id, start_url, scope и display повторяют поставочные: они определяют
77
+ * поведение установленного приложения, и менять их значило бы чинить не то.
78
+ */
79
+ const MANIFEST = JSON.stringify(
80
+ {
81
+ id: '/',
82
+ name: 'TENSOR GRID',
83
+ short_name: 'TENSOR GRID',
84
+ start_url: '/',
85
+ scope: '/',
86
+ display: 'fullscreen',
87
+ background_color: '#0B0D12',
88
+ theme_color: '#0B0D12',
89
+ icons: [
90
+ { src: APP_ICON_PATH, sizes: 'any', type: 'image/svg+xml', purpose: 'any' },
91
+ // maskable разрешает системе обрезать иконку под свою форму. Знак
92
+ // отступает от краёв на 16%, поэтому обрезка его не заденет.
93
+ { src: APP_ICON_PATH, sizes: 'any', type: 'image/svg+xml', purpose: 'maskable' },
94
+ ],
95
+ },
96
+ null,
97
+ 2,
98
+ )
99
+
42
100
  export const name = 'tensorgrid-ui'
43
101
 
44
102
  /**
@@ -63,6 +121,34 @@ export function apply(ctx) {
63
121
  }),
64
122
  )
65
123
 
124
+ web.effect(() =>
125
+ web.webServer.register({
126
+ kind: 'exact',
127
+ path: APP_ICON_PATH,
128
+ handler(_req, res) {
129
+ res.writeHead(200, {
130
+ 'content-type': 'image/svg+xml; charset=utf-8',
131
+ 'cache-control': 'no-cache',
132
+ })
133
+ res.end(APP_ICON)
134
+ },
135
+ }),
136
+ )
137
+
138
+ web.effect(() =>
139
+ web.webServer.register({
140
+ kind: 'exact',
141
+ path: '/manifest.webmanifest',
142
+ handler(_req, res) {
143
+ res.writeHead(200, {
144
+ 'content-type': 'application/manifest+json; charset=utf-8',
145
+ 'cache-control': 'no-cache',
146
+ })
147
+ res.end(MANIFEST)
148
+ },
149
+ }),
150
+ )
151
+
66
152
  // Состояние обновлений держим в памяти: проверка ходит в сеть и в git,
67
153
  // и дёргать её на каждый рендер настроек незачем.
68
154
  let cached = null
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tensorgrid-ui",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "TENSOR GRID — фирменный интерфейс поверх DeepSeek Harness: палитра, живой ambient-слой, айдентика и русский язык-пакет",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",