@maccesar/titools 2.9.0 → 2.10.1
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/lib/commands/update.js +4 -1
- package/package.json +1 -1
- package/skills/purgetss/SKILL.md +29 -6
- package/skills/purgetss/references/animation-advanced.md +0 -9
- package/skills/purgetss/references/app-branding.md +211 -49
- package/skills/purgetss/references/appearance-module.md +85 -27
- package/skills/purgetss/references/apply-directive.md +60 -0
- package/skills/purgetss/references/arbitrary-values.md +41 -0
- package/skills/purgetss/references/cli-commands.md +153 -28
- package/skills/purgetss/references/custom-rules.md +36 -19
- package/skills/purgetss/references/customization-deep-dive.md +49 -6
- package/skills/purgetss/references/grid-layout.md +45 -26
- package/skills/purgetss/references/icon-fonts.md +27 -25
- package/skills/purgetss/references/installation-setup.md +28 -2
- package/skills/purgetss/references/ios-large-titles.md +31 -15
- package/skills/purgetss/references/multi-density-images.md +57 -0
- package/skills/purgetss/references/opacity-modifier.md +11 -2
- package/skills/purgetss/references/semantic-colors.md +44 -1
- package/skills/purgetss/references/tikit-components.md +1 -3
- package/skills/purgetss/references/values-and-units.md +120 -0
|
@@ -2,15 +2,71 @@
|
|
|
2
2
|
|
|
3
3
|
The `Appearance` export from `purgetss.ui` (added in **v7.5.3**) handles Light / Dark / System mode switching and persists the user's choice across app restarts. It is a thin, deterministic wrapper around Titanium's native `Ti.UI.overrideUserInterfaceStyle` plus `Ti.App.Properties`, exposed as a singleton so every controller in the app reads and writes the same state.
|
|
4
4
|
|
|
5
|
-
This
|
|
5
|
+
This reference follows the same workflow-first / API-second split the official PurgeTSS documentation now uses:
|
|
6
|
+
|
|
7
|
+
- **Workflow** — initialize at startup, then build a Settings view that calls `Appearance.set(...)` (mirrors `best-practices/1-appearance-setup.md`).
|
|
8
|
+
- **API reference** — the four public methods, exact signatures, and lifecycle (mirrors `purgetss-ui/10-appearance.md`).
|
|
9
|
+
|
|
10
|
+
For the color wiring that actually makes the UI *respond* to mode changes, see [semantic-colors.md](./semantic-colors.md).
|
|
6
11
|
|
|
7
12
|
> **INFO**
|
|
8
13
|
>
|
|
9
14
|
> Requires PurgeTSS **>= 7.5.3**. On older versions the `Appearance` export does not exist — the `require('purgetss.ui')` call will succeed, but `Appearance` will be `undefined`. Run `purgetss --version` in the project root to confirm.
|
|
10
15
|
|
|
11
|
-
##
|
|
16
|
+
## How it fits together
|
|
17
|
+
|
|
18
|
+
The Appearance module sits between three moving parts: a JS singleton, the OS-level interface style, and the semantic colors generated by PurgeTSS. The diagram below shows how a single `Appearance.init()` call at startup wires them together, and what happens when the user later picks a mode in Settings.
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
┌─ app/lib/appearance.js (singleton from purgetss.ui) ─────────────────┐
|
|
22
|
+
│ │
|
|
23
|
+
│ Appearance.init() ────► reads 'userInterfaceStyle' │
|
|
24
|
+
│ from Ti.App.Properties │
|
|
25
|
+
│ applies Ti.UI.overrideUserInterfaceStyle │
|
|
26
|
+
│ │
|
|
27
|
+
│ Appearance.set(m) ────► writes Ti.App.Properties │
|
|
28
|
+
│ applies Ti.UI.overrideUserInterfaceStyle │
|
|
29
|
+
│ │
|
|
30
|
+
│ Appearance.get() ────► returns 'system' | 'light' | 'dark' │
|
|
31
|
+
│ Appearance.toggle()────► flips between 'light' and 'dark' │
|
|
32
|
+
│ │
|
|
33
|
+
└──────────────────────────────────────────────────────────────────────┘
|
|
34
|
+
│
|
|
35
|
+
▼
|
|
36
|
+
┌─ Ti.UI.semanticColorType (runtime) ──────────────────────────────────┐
|
|
37
|
+
│ │
|
|
38
|
+
│ Light mode ─► resolves bg-surface to surfaceColor.light │
|
|
39
|
+
│ resolves text-on-surface to textColor.light │
|
|
40
|
+
│ │
|
|
41
|
+
│ Dark mode ─► resolves bg-surface to surfaceColor.dark │
|
|
42
|
+
│ resolves text-on-surface to textColor.dark │
|
|
43
|
+
│ │
|
|
44
|
+
└──────────────────────────────────────────────────────────────────────┘
|
|
45
|
+
│
|
|
46
|
+
▼
|
|
47
|
+
┌─ Utility classes in views ───────────────────────────────────────────┐
|
|
48
|
+
│ │
|
|
49
|
+
│ bg-surface, text-on-surface, bg-border, bg-surface-high, ... │
|
|
50
|
+
│ Repaint instantly on every Appearance.set(...) call. │
|
|
51
|
+
│ │
|
|
52
|
+
└──────────────────────────────────────────────────────────────────────┘
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`Ti.App.Properties` is the persistence layer — the value written during `set(...)` is what `init()` reads on the next launch. Clearing app storage or reinstalling resets to `'system'`.
|
|
56
|
+
|
|
57
|
+
## Workflow
|
|
58
|
+
|
|
59
|
+
The fastest path from zero to a working Light / Dark toggle is three steps. Each one maps to one section of the official `best-practices/1-appearance-setup.md` guide.
|
|
12
60
|
|
|
13
|
-
|
|
61
|
+
### 1. Define semantic colors
|
|
62
|
+
|
|
63
|
+
Create `app/assets/semantic.colors.json` and register the color names under `theme.extend.colors` in `purgetss/config.cjs`. The class names you use in XML (`bg-surface`, `text-on-surface`, `bg-border`, ...) come from this mapping.
|
|
64
|
+
|
|
65
|
+
See [semantic-colors.md](./semantic-colors.md) for the JSON schema, the `config.cjs` mapping, nesting rules, and alpha transparency.
|
|
66
|
+
|
|
67
|
+
### 2. Initialize Appearance at startup
|
|
68
|
+
|
|
69
|
+
Call `Appearance.init()` **once** before opening the first window. The standard place is the top of `app/controllers/index.js`:
|
|
14
70
|
|
|
15
71
|
`app/controllers/index.js`
|
|
16
72
|
```js
|
|
@@ -27,22 +83,11 @@ $.navWin.open()
|
|
|
27
83
|
>
|
|
28
84
|
> Call `Appearance.init()` **before** `$.navWin.open()` (or whichever window you open first). If the window opens first, it will render once against the system default and then flicker to the saved mode when `init()` runs — a visible flash on cold launch.
|
|
29
85
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
| Method | Description |
|
|
33
|
-
| ------------ | --------------------------------------------------------------------------- |
|
|
34
|
-
| `init()` | Restore the saved mode from `Ti.App.Properties` and apply it via `Ti.UI.overrideUserInterfaceStyle`. Call once at app startup before opening the first window. |
|
|
35
|
-
| `set(mode)` | Apply and persist a mode. Accepts `'system'`, `'light'`, or `'dark'`. Any other value is silently ignored. |
|
|
36
|
-
| `get()` | Returns the current mode as a string: `'system'`, `'light'`, or `'dark'`. |
|
|
37
|
-
| `toggle()` | Switch between `'light'` and `'dark'`. Skips `'system'` — if current mode is `'system'` the next call produces `'dark'`. |
|
|
38
|
-
|
|
39
|
-
All four methods are **synchronous**. They do not fire events; if you need to react to a mode change, call your update logic right after `Appearance.set(...)`.
|
|
40
|
-
|
|
41
|
-
## Full Settings-view example
|
|
86
|
+
### 3. Build an Appearance toggle
|
|
42
87
|
|
|
43
|
-
|
|
88
|
+
Build a Settings view where users pick `System`, `Light`, or `Dark`. Tapping a row calls `Appearance.set(...)` and updates the check icons.
|
|
44
89
|
|
|
45
|
-
|
|
90
|
+
#### View
|
|
46
91
|
|
|
47
92
|
`app/views/settings.xml`
|
|
48
93
|
```xml
|
|
@@ -86,7 +131,7 @@ A three-row settings panel — System / Light / Dark — where each row shows a
|
|
|
86
131
|
</Alloy>
|
|
87
132
|
```
|
|
88
133
|
|
|
89
|
-
|
|
134
|
+
#### Controller
|
|
90
135
|
|
|
91
136
|
`app/controllers/settings.js`
|
|
92
137
|
```js
|
|
@@ -95,16 +140,16 @@ const { Appearance } = require('purgetss.ui')
|
|
|
95
140
|
// Sync check icons with the mode saved at app startup.
|
|
96
141
|
updateUI(Appearance.get())
|
|
97
142
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
143
|
+
function selectDark() { selectAppearance('dark') }
|
|
144
|
+
function selectLight() { selectAppearance('light') }
|
|
145
|
+
function selectSystem() { selectAppearance('system') }
|
|
101
146
|
|
|
102
|
-
|
|
147
|
+
function selectAppearance(value) {
|
|
103
148
|
Appearance.set(value)
|
|
104
149
|
updateUI(value)
|
|
105
150
|
}
|
|
106
151
|
|
|
107
|
-
|
|
152
|
+
function updateUI(value) {
|
|
108
153
|
$.themeDarkCheck.visible = (value === 'dark')
|
|
109
154
|
$.themeLightCheck.visible = (value === 'light')
|
|
110
155
|
$.themeSystemCheck.visible = (value === 'system')
|
|
@@ -113,9 +158,24 @@ const updateUI = (value) => {
|
|
|
113
158
|
|
|
114
159
|
The background, text, border, and icon colors in the XML come from semantic color classes (`bg-surface`, `bg-surface-high`, `text-on-surface`, `bg-border`, etc.) — see [semantic-colors.md](./semantic-colors.md) for how to wire those up so the whole view flips when `Appearance.set('dark')` fires.
|
|
115
160
|
|
|
116
|
-
|
|
161
|
+
> **Why named functions in Alloy controllers?** Alloy resolves `onClick="selectDark"` by looking up a top-level identifier on the controller scope. Named function declarations (`function selectDark() { ... }`) hoist and are reliably resolvable; arrow functions assigned to `const` are not hoisted and tend to bite you when an XML attribute fires before the binding has executed. The official setup guide uses named functions for this reason.
|
|
117
162
|
|
|
118
|
-
|
|
163
|
+
## API reference
|
|
164
|
+
|
|
165
|
+
### Methods
|
|
166
|
+
|
|
167
|
+
| Method | Description |
|
|
168
|
+
| ------------ | --------------------------------------------------------------------------- |
|
|
169
|
+
| `init()` | Restore the saved mode from `Ti.App.Properties` and apply it via `Ti.UI.overrideUserInterfaceStyle`. Call once at app startup before opening the first window. |
|
|
170
|
+
| `set(mode)` | Apply and persist a mode. Accepts `'system'`, `'light'`, or `'dark'`. Any other value is silently ignored. |
|
|
171
|
+
| `get()` | Returns the current mode as a string: `'system'`, `'light'`, or `'dark'`. |
|
|
172
|
+
| `toggle()` | Switch between `'light'` and `'dark'`. Skips `'system'` — if current mode is `'system'` the next call produces `'dark'`. |
|
|
173
|
+
|
|
174
|
+
All four methods are **synchronous**. They do not fire events; if you need to react to a mode change, call your update logic right after `Appearance.set(...)`.
|
|
175
|
+
|
|
176
|
+
### Lifecycle
|
|
177
|
+
|
|
178
|
+
How the four moving parts — `Appearance.init()`, `Ti.App.Properties`, `Ti.UI.overrideUserInterfaceStyle`, and semantic colors — cooperate during a typical session:
|
|
119
179
|
|
|
120
180
|
```
|
|
121
181
|
app startup
|
|
@@ -143,8 +203,6 @@ app startup
|
|
|
143
203
|
+-- Preference survives the next cold launch
|
|
144
204
|
```
|
|
145
205
|
|
|
146
|
-
`Ti.App.Properties` is the persistence layer — the value written during `set(...)` is what `init()` reads on the next launch. Clearing app storage or reinstalling resets to `'system'`.
|
|
147
|
-
|
|
148
206
|
> **INFO**
|
|
149
207
|
>
|
|
150
208
|
> `toggle()` intentionally skips `'system'`. If the current mode is `'system'`, calling `toggle()` produces `'dark'`. If you want a three-way cycle (System -> Light -> Dark -> System), build it in userland with `Appearance.get()` + `Appearance.set(...)`; do not expect `toggle()` to do it.
|
|
@@ -254,6 +254,66 @@ Window: { default: { apply: 'exit-on-close-false bg-blue-500' } }
|
|
|
254
254
|
|
|
255
255
|
Use the explicit `default:` wrapper when you also need platform blocks (`ios:`, `android:`) next to it. For the common case of one bundle of defaults, the shorthand reads better.
|
|
256
256
|
|
|
257
|
+
### Extend mode vs replace mode
|
|
258
|
+
|
|
259
|
+
> **HEADLINE CHANGE — v7.9.0**
|
|
260
|
+
> This is the headline change of PurgeTSS v7.9.0. Before v7.9.0, `theme.Window` / `theme.View` / `theme.ImageView` still had the framework defaults merged in, which caused gradient ghosting and other surprising overrides. v7.9.0 makes top-level (non-`extend`) configs behave as true replace mode.
|
|
261
|
+
>
|
|
262
|
+
> If you previously used `theme.Window` (no `extend`) and depended on the white background or the iOS `hires: true` / `Ti.UI.SIZE` defaults still being there, you will need to either move that config under `theme.extend.Window` (extend mode) or add the previously-implicit utilities back into your `apply` string.
|
|
263
|
+
|
|
264
|
+
PurgeTSS follows the Tailwind convention for the three Ti Elements that ship with framework defaults — `Window`, `View`, and `ImageView`:
|
|
265
|
+
|
|
266
|
+
- **Extend mode** — `theme.extend.Window`, `theme.extend.View`, `theme.extend.ImageView`. Your customization **merges** with the framework defaults. The white Window `backgroundColor`, `Ti.UI.SIZE` width/height on `View`, and iOS `hires: true` on `ImageView` stay in place unless you override them with `apply`. Use this when you want to add to the defaults, not replace them.
|
|
267
|
+
- **Replace mode** — `theme.Window`, `theme.View`, `theme.ImageView` (top level, no `extend`). Your config **replaces** the framework defaults entirely. The white Window background is omitted, the `Ti.UI.SIZE` width/height on `View` is omitted, and the iOS `hires: true` on `ImageView` is omitted. Your `apply` becomes the source of truth for that Ti Element.
|
|
268
|
+
|
|
269
|
+
Use replace mode when you want full control and do not want a preset mixed in. The canonical case is a Window declared at `theme.Window` with a `backgroundGradient`, where the previously-merged white `backgroundColor` would render on top of the gradient and produce a "ghost" white wash.
|
|
270
|
+
|
|
271
|
+
`./purgetss/config.cjs - replace mode (v7.9.0+)`
|
|
272
|
+
```javascript
|
|
273
|
+
module.exports = {
|
|
274
|
+
theme: {
|
|
275
|
+
Window: {
|
|
276
|
+
apply: 'bg-gradient-to-b from-blue-500 to-purple-600'
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
`./purgetss/styles/utilities.tss`
|
|
283
|
+
```tss
|
|
284
|
+
'Window': { backgroundGradient: { type: 'linear', colors: [...], startPoint: ..., endPoint: ... } }
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Note the missing `backgroundColor: '#FFFFFF'`. Replace mode skipped the framework default, so the gradient renders cleanly. Before v7.9.0 the same config produced:
|
|
288
|
+
|
|
289
|
+
```tss
|
|
290
|
+
/* Pre-v7.9.0 — ghost white background covering the gradient */
|
|
291
|
+
'Window': { backgroundColor: '#FFFFFF', backgroundGradient: { type: 'linear', colors: [...] } }
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
If you wanted the framework white background **and** something else on top, that is what extend mode is for:
|
|
295
|
+
|
|
296
|
+
`./purgetss/config.cjs - extend mode`
|
|
297
|
+
```javascript
|
|
298
|
+
module.exports = {
|
|
299
|
+
theme: {
|
|
300
|
+
extend: {
|
|
301
|
+
Window: {
|
|
302
|
+
apply: 'exit-on-close-false'
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
`./purgetss/styles/utilities.tss`
|
|
310
|
+
```tss
|
|
311
|
+
/* Framework default backgroundColor is preserved, exitOnClose merged in */
|
|
312
|
+
'Window': { backgroundColor: '#FFFFFF', exitOnClose: false }
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
The same extend-vs-replace distinction applies to `View` (`Ti.UI.SIZE` width/height defaults) and `ImageView` (iOS `hires: true` default).
|
|
316
|
+
|
|
257
317
|
### Apply Wins Over Static Defaults
|
|
258
318
|
|
|
259
319
|
If `apply` sets a property that the component already has as a built-in default, the applied value replaces the original instead of both ending up in the final TSS:
|
|
@@ -7,6 +7,47 @@ When you need a one-off value that is not in the defaults, use arbitrary values
|
|
|
7
7
|
>
|
|
8
8
|
> You cannot use square bracket notation like in Tailwind because Titanium handles platform and conditional statements in `.tss` files differently.
|
|
9
9
|
|
|
10
|
+
## Class syntax pre-validation
|
|
11
|
+
|
|
12
|
+
Starting with PurgeTSS v7.8.0, the build runs a pre-validation pass over class names found in XML views and JS controllers before purging. When it spots a malformed arbitrary-value utility, it stops and prints a structured `Class Syntax Error` block so the offending class can be fixed before any TSS is generated. If multiple errors are present, all of them are reported in the same run.
|
|
13
|
+
|
|
14
|
+
Each error block includes:
|
|
15
|
+
|
|
16
|
+
- The file path where the offending class lives
|
|
17
|
+
- The line number inside that file
|
|
18
|
+
- The offending class name (as authored)
|
|
19
|
+
- A `Fix:` suggestion with the corrected class name
|
|
20
|
+
|
|
21
|
+
Example shape:
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
Class Syntax Error
|
|
25
|
+
File: app/views/index.xml
|
|
26
|
+
Line: 12
|
|
27
|
+
Found: top-(-10)
|
|
28
|
+
Fix: -top-(10)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Detected patterns
|
|
32
|
+
|
|
33
|
+
The validator catches five narrow, actionable mistakes:
|
|
34
|
+
|
|
35
|
+
| Pattern | Offending input | Suggested fix | Notes |
|
|
36
|
+
| ----------------------------- | --------------- | ------------- | ---------------------------------------------------------------- |
|
|
37
|
+
| Inverted negative sign | `top-(-10)` | `-top-(10)` | The `-` prefix goes before the rule, not inside the value |
|
|
38
|
+
| Tailwind-style brackets | `top-[10px]` | `top-(10px)` | PurgeTSS uses parentheses, not square brackets, for arbitrary values |
|
|
39
|
+
| Empty parentheses | `wh-()` | (flagged, no auto-fix) | Add a value such as `wh-(10)` |
|
|
40
|
+
| Whitespace inside parentheses | `wh-( 200 )` | `wh-(200)` | No spaces allowed between `(`, the value, and `)` |
|
|
41
|
+
| Redundant `px` unit | `top-(10px)` | `top-(10)` | PurgeTSS treats unit-less arbitrary values as pixels |
|
|
42
|
+
|
|
43
|
+
### Unknown classes are still silently dropped
|
|
44
|
+
|
|
45
|
+
The pre-validator only fires on the five patterns above. Any other unknown class — typos, custom utilities not yet declared, vendor classes that are not enabled in `config.cjs` — is **not** reported as a `Class Syntax Error`. Those classes continue to flow into the `// Unused or unsupported classes` comment block in `app.tss`, exactly like before. This keeps the validator focused on actionable mistakes and avoids noise while you sketch out class names.
|
|
46
|
+
|
|
47
|
+
### v7.8.0 parser fix for negatives inside parentheses
|
|
48
|
+
|
|
49
|
+
Before v7.8.0, an inverted negative such as `top-(-10)` could be silently misparsed by the arbitrary-value pipeline (the `-` inside the parentheses confused the token matcher, producing wrong or missing TSS output without any warning). v7.8.0 hardens that path: the parser now correctly recognizes `top-(-10)` as authored, classifies it as an inverted-negative-sign error, and surfaces the `Class Syntax Error` block with the `-top-(10)` fix instead of producing silent garbage.
|
|
50
|
+
|
|
10
51
|
## Color Properties
|
|
11
52
|
|
|
12
53
|
You can set arbitrary color values for all available color properties using `hex`, `rgb`, or `rgba` values, directly in XML files or in `config.cjs`.
|
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
# PurgeTSS CLI Commands
|
|
2
2
|
|
|
3
|
-
> **Info: What's new in v7.5.3 / v7.6.0**
|
|
3
|
+
> **Info: What's new in v7.5.3 / v7.6.x / v7.7.0 / v7.8.0 / v7.9.0**
|
|
4
|
+
> - **Opacity modifiers on semantic colors (v7.9.0)** — writing `bg-surface/65` (or any opacity modifier on a class mapped to a name in `semantic.colors.json`) now produces a working rule with Light/Dark switching preserved. PurgeTSS auto-derives a `<originalKey>_<alphaPercent>` entry in `semantic.colors.json` with the original `light`/`dark` hex values plus the requested alpha for both modes, then emits the rule against the derived key. Re-runs are idempotent; manual edits with conflicting values halt the build with a `Conflict` error. New alpha entries require one full Titanium build to be picked up — Liveview hot-reload alone does not refresh `semantic.colors.json`.
|
|
5
|
+
> - **Gradient + Window/View/ImageView preset fixes (v7.9.0)** — `theme.Window` / `theme.View` / `theme.ImageView` no longer leak the framework presets (white background, `Ti.UI.SIZE`, iOS `hires: true`) when defined at the top level (replace mode), so a Window declared at `theme.Window` with a `backgroundGradient` no longer ghosts on top of a default `backgroundColor: '#FFFFFF'`. `theme.extend.Window` keeps merging with the defaults as before. Also fixed: tonal palette inversion bug, position-dependent `from`/`to` color ordering after `sort()`, and `bg-gradient-to-X` direction silently dropped when combined with `from-X to-Y` colors.
|
|
6
|
+
> - **Glossary path renamed (v7.9.0, breaking)** — the user-facing glossary output path was renamed from `purgetss/experimental/tailwind-classes/` to `purgetss/glossary/tailwind-classes/`. Tooling or CI that reads from the old path needs updating on upgrade — no transition shim. The `--glossary` flag and command surface are unchanged.
|
|
7
|
+
> - **`images --width <n>` flag (v7.8.0)** — pins Android `mdpi` (= iPhone `@1x`) to a specific pixel width, with larger scales deriving as ×1.5, ×2, ×3, ×4 from that base. Use it for SVG sources from vector editors with disproportionate viewBoxes (Affinity, Illustrator). CLI-only; there is no matching `images:` config property because the right width is per-asset. See [`images` Command](#images-command).
|
|
8
|
+
> - **Class syntax pre-validation (v7.8.0)** — `purgetss` now stops with a structured `Class Syntax Error` block (file + line + suggested fix) when it detects known class-name mistakes: inverted negative sign (`top-(-10)` → `-top-(10)`), Tailwind-style brackets (`top-[10px]` → `top-(10px)`), empty parentheses (`wh-()`), whitespace inside parentheses (`wh-( 200 )`), and redundant `px` unit (`top-(10px)` → `top-(10)`). All offenders are reported in one run. Generic unknown classes still flow into the `// Unused or unsupported classes` block in `app.tss`.
|
|
9
|
+
> - **Negative-values-in-parens parser fix (v7.8.0)** — classes like `top-(-10)`, `mt-(-5)`, and `origin-(-10,-20)` no longer crash with `Cannot read properties of null (reading 'pop')`. The parser now extracts the `(...)` portion first, so a `-` inside the value does not break the split.
|
|
10
|
+
> - **`brand:` config grouped (v7.7.0)** — the flat `brand:` block from v7.6.0 was reorganized into purpose-based sections: `brand.logos`, `brand.padding`, `brand.android`, `brand.ios`, and `brand.colors`. Old projects keep working — newly-generated configs use the grouped form.
|
|
11
|
+
> - **Separate Android brand inputs (v7.7.0)** — `brand` can now use one logo for the general brand set, another for Android launcher icons (`logos.androidLauncher` / `--icon-logo`), and another for Android 12+ splash artwork (`logos.androidSplash` / `--splash-logo`). Drop `logo-icon.*` and `logo-splash.*` into `purgetss/brand/` or set the paths in `config.cjs`.
|
|
12
|
+
> - **Legacy Android splash fallback (v7.7.0)** — `purgetss brand` now regenerates `app/assets/android/default.png` (Alloy) or `Resources/android/default.png` (Classic). `cleanup-legacy` no longer removes `default.png`.
|
|
13
|
+
> - **`semantic` works in Classic projects (v7.6.2)** — writes to `Resources/semantic.colors.json` for Classic, keeps writing to `app/assets/semantic.colors.json` for Alloy.
|
|
14
|
+
> - **Confirmation prompt for destructive writes (v7.6.1)** — `brand` and `images` ask `[y/N/a]` before overwriting (auto-skipped on non-TTY, with `-y`/`--yes`, or `PURGETSS_YES=1`).
|
|
4
15
|
> - **New `brand` command (v7.6.0)** — generates the complete Titanium branding set (launcher icons, adaptive icons, iOS 18+ Dark/Tinted variants, marketplace artwork, optional notification/splash) from a single SVG or PNG logo. See [`brand` Command](#brand-command) and the deep-dive [app-branding.md](./app-branding.md).
|
|
5
16
|
> - **New `images` command (v7.6.0)** — generates multi-density UI images (Android `res-*` densities + iPhone `@1x`/`@2x`/`@3x` scales) from sources in `./purgetss/images/`. See [`images` Command](#images-command) and the deep-dive [multi-density-images.md](./multi-density-images.md).
|
|
6
17
|
> - **New `semantic` command (v7.6.0)** — generates Titanium semantic colors (Light/Dark) into `app/assets/semantic.colors.json` with two modes (tonal palette vs. single purpose-based color). See [`semantic` Command](#semantic-command) and the deep-dive [semantic-colors.md](./semantic-colors.md).
|
|
@@ -68,12 +79,32 @@ module.exports = {
|
|
|
68
79
|
}
|
|
69
80
|
},
|
|
70
81
|
brand: {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
82
|
+
logos: {
|
|
83
|
+
// Optional overrides. If omitted, PurgeTSS auto-discovers files from purgetss/brand/:
|
|
84
|
+
// primary: './docs/logo.svg',
|
|
85
|
+
// androidLauncher: './docs/app-icon.svg',
|
|
86
|
+
// androidSplash: './docs/splash.svg',
|
|
87
|
+
// monochrome: './docs/logo-mono.svg',
|
|
88
|
+
// iosDark: './docs/logo-dark.svg',
|
|
89
|
+
// iosTinted: './docs/logo-tinted.svg'
|
|
90
|
+
},
|
|
91
|
+
padding: {
|
|
92
|
+
ios: '4%', // iOS aesthetic padding. Range 2-8%.
|
|
93
|
+
androidLegacy: '10%', // legacy ic_launcher.png padding %
|
|
94
|
+
androidAdaptive: '19%' // adaptive icon safe-zone %. Spec floor 19.44%.
|
|
95
|
+
},
|
|
96
|
+
android: {
|
|
97
|
+
splash: false, // also generate splash_icon.png × 5
|
|
98
|
+
notification: false // also generate ic_stat_notify.png × 5
|
|
99
|
+
},
|
|
100
|
+
ios: {
|
|
101
|
+
dark: true, // emit DefaultIcon-Dark.png (set false to skip)
|
|
102
|
+
tinted: true, // emit DefaultIcon-Tinted.png (set false to skip)
|
|
103
|
+
darkBackground: null // null = transparent per Apple HIG; set a hex like '#111111' for an opaque dark bg
|
|
104
|
+
},
|
|
105
|
+
colors: {
|
|
106
|
+
background: '#FFFFFF' // Android adaptive bg + iOS/marketplace flatten
|
|
107
|
+
},
|
|
77
108
|
confirmOverwrites: true // prompt before overwriting files (set false to skip)
|
|
78
109
|
},
|
|
79
110
|
images: {
|
|
@@ -164,7 +195,7 @@ Recommended VSCode extensions:
|
|
|
164
195
|
|
|
165
196
|
## `brand` Command
|
|
166
197
|
|
|
167
|
-
Introduced in v7.6.0. Generates the complete Titanium branding set (launcher icons, adaptive icons, iOS 18+ Dark/Tinted variants, marketplace artwork, optional notification/splash icons) from a single logo image. Alloy and Classic projects are auto-detected.
|
|
198
|
+
Introduced in v7.6.0, restructured in v7.7.0. Generates the complete Titanium branding set (launcher icons, adaptive icons, iOS 18+ Dark/Tinted variants, marketplace artwork, optional notification/splash icons) from a single logo image — with optional Android-specific logo overrides when you need them. Alloy and Classic projects are auto-detected.
|
|
168
199
|
|
|
169
200
|
> **Tip**
|
|
170
201
|
> This is a quick reference. See [app-branding.md](./app-branding.md) for the complete guide — workflow, padding guidance, Android dark mode, iOS 18+ variants, alpha channel handling, and troubleshooting.
|
|
@@ -176,25 +207,56 @@ purgetss brand path/to/logo.svg # positional logo path override
|
|
|
176
207
|
|
|
177
208
|
### Flags
|
|
178
209
|
|
|
210
|
+
**Project & output**
|
|
211
|
+
|
|
179
212
|
| Flag | Purpose |
|
|
180
213
|
| --- | --- |
|
|
181
214
|
| `--project <path>` | Project root (defaults to cwd). |
|
|
182
215
|
| `--dry-run` | Preview what would be generated without writing any files. |
|
|
183
216
|
| `--output <dir>` | Stage into `<dir>` instead of writing in place. |
|
|
184
217
|
| `-y, --yes` | Skip the overwrite confirmation prompt for this invocation. |
|
|
218
|
+
|
|
219
|
+
**Visual customization**
|
|
220
|
+
|
|
221
|
+
| Flag | Purpose |
|
|
222
|
+
| --- | --- |
|
|
185
223
|
| `--bg-color <hex>` | Background color for Android adaptive + iOS/marketplace flatten. |
|
|
186
|
-
| `--padding <n>` | Android
|
|
187
|
-
| `--
|
|
224
|
+
| `--padding <n>` | Shortcut: sets BOTH Android paddings to the same value for one run. |
|
|
225
|
+
| `--android-adaptive-padding <n>` | Adaptive icon safe-zone % (default `19`). |
|
|
226
|
+
| `--android-legacy-padding <n>` | Legacy `ic_launcher.png` padding % (default `10`). |
|
|
227
|
+
| `--ios-padding <n>` | iOS aesthetic padding % (range `2-8`, default `4`). |
|
|
228
|
+
|
|
229
|
+
**Optional asset types**
|
|
230
|
+
|
|
231
|
+
| Flag | Purpose |
|
|
232
|
+
| --- | --- |
|
|
188
233
|
| `--notification` | Also emit `ic_stat_notify.png × 5`. |
|
|
189
234
|
| `--splash` | Also emit `splash_icon.png × 5`. |
|
|
235
|
+
|
|
236
|
+
**Logo variants & overrides**
|
|
237
|
+
|
|
238
|
+
| Flag | Purpose |
|
|
239
|
+
| --- | --- |
|
|
240
|
+
| `--icon-logo <path>` | Override `purgetss/brand/logo-icon.{svg,png}` for Android launcher icons (square mark for non-square main logos). |
|
|
190
241
|
| `--monochrome-logo <path>` | Override `purgetss/brand/logo-mono.{svg,png}`. |
|
|
191
242
|
| `--dark-logo <path>` | Override `purgetss/brand/logo-dark.{svg,png}`. |
|
|
192
243
|
| `--dark-bg-color <hex>` | Opaque dark bg for `DefaultIcon-Dark.png` (default: transparent per Apple HIG). |
|
|
244
|
+
| `--splash-logo <path>` | Override `purgetss/brand/logo-splash.{svg,png}` for Android 12+ splash artwork. |
|
|
193
245
|
| `--tinted-logo <path>` | Override `purgetss/brand/logo-tinted.{svg,png}`. |
|
|
194
246
|
| `--no-dark` | Skip `DefaultIcon-Dark.png`. |
|
|
195
247
|
| `--no-tinted` | Skip `DefaultIcon-Tinted.png`. |
|
|
196
|
-
|
|
248
|
+
|
|
249
|
+
**Legacy cleanup**
|
|
250
|
+
|
|
251
|
+
| Flag | Purpose |
|
|
252
|
+
| --- | --- |
|
|
253
|
+
| `--cleanup-legacy` | Remove obsolete branding artifacts (reads `tiapp.xml` for safety rules). Keeps `default.png` on purpose. |
|
|
197
254
|
| `--aggressive` | With `--cleanup-legacy`, also remove `ldpi` density folders. |
|
|
255
|
+
|
|
256
|
+
**Diagnostics**
|
|
257
|
+
|
|
258
|
+
| Flag | Purpose |
|
|
259
|
+
| --- | --- |
|
|
198
260
|
| `--notes` | Print full `tiapp.xml` snippets + padding tuning guide. |
|
|
199
261
|
| `--debug` | Print extra diagnostics. |
|
|
200
262
|
|
|
@@ -202,22 +264,44 @@ purgetss brand path/to/logo.svg # positional logo path override
|
|
|
202
264
|
|
|
203
265
|
- `[logo-path]` (optional) — overrides auto-discovery of `purgetss/brand/logo.{svg,png}`.
|
|
204
266
|
|
|
205
|
-
### Config block
|
|
267
|
+
### Config block (v7.7.0 grouped structure)
|
|
206
268
|
|
|
207
269
|
Defaults live under `brand:` in `purgetss/config.cjs` and are injected automatically:
|
|
208
270
|
|
|
209
271
|
```javascript
|
|
210
272
|
brand: {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
273
|
+
logos: {
|
|
274
|
+
// Optional overrides. If omitted, PurgeTSS auto-discovers files from purgetss/brand/:
|
|
275
|
+
// primary: './docs/logo.svg',
|
|
276
|
+
// androidLauncher: './docs/app-icon.svg',
|
|
277
|
+
// androidSplash: './docs/splash.svg',
|
|
278
|
+
// monochrome: './docs/logo-mono.svg',
|
|
279
|
+
// iosDark: './docs/logo-dark.svg',
|
|
280
|
+
// iosTinted: './docs/logo-tinted.svg'
|
|
281
|
+
},
|
|
282
|
+
padding: {
|
|
283
|
+
ios: '4%', // iOS aesthetic padding. Range 2-8%.
|
|
284
|
+
androidLegacy: '10%', // legacy ic_launcher.png padding %
|
|
285
|
+
androidAdaptive: '19%' // adaptive icon safe-zone %. Spec floor 19.44%.
|
|
286
|
+
},
|
|
287
|
+
android: {
|
|
288
|
+
splash: false, // also generate splash_icon.png × 5
|
|
289
|
+
notification: false // also generate ic_stat_notify.png × 5
|
|
290
|
+
},
|
|
291
|
+
ios: {
|
|
292
|
+
dark: true, // emit DefaultIcon-Dark.png (set false to skip)
|
|
293
|
+
tinted: true, // emit DefaultIcon-Tinted.png (set false to skip)
|
|
294
|
+
darkBackground: null // null = transparent per Apple HIG; set a hex like '#111' for an opaque dark bg
|
|
295
|
+
},
|
|
296
|
+
colors: {
|
|
297
|
+
background: '#FFFFFF' // Android adaptive bg + iOS/marketplace flatten
|
|
298
|
+
},
|
|
217
299
|
confirmOverwrites: true // prompt before overwriting files
|
|
218
300
|
}
|
|
219
301
|
```
|
|
220
302
|
|
|
303
|
+
The recommended workflow is convention-first: drop files in `purgetss/brand/`, let auto-discovery pick them up. Treat `brand.logos.*` as optional overrides for one-off paths or when masters live outside `purgetss/brand/`.
|
|
304
|
+
|
|
221
305
|
### Confirmation prompt
|
|
222
306
|
|
|
223
307
|
`brand` writes in place, so it asks `Continue? [y/N/a]` before overwriting anything. Choose `a` (always) to write `confirmOverwrites: false` into `config.cjs` and silence the prompt on future runs. The prompt is skipped automatically when `stdin` is not a TTY (`alloy.jmk` hook, CI, pipes), when `-y`/`--yes` is passed, or when `PURGETSS_YES=1` is set.
|
|
@@ -225,14 +309,24 @@ brand: {
|
|
|
225
309
|
### Examples
|
|
226
310
|
|
|
227
311
|
```bash
|
|
228
|
-
purgetss brand
|
|
229
|
-
purgetss brand --bg-color "#0B1326"
|
|
230
|
-
purgetss brand --
|
|
231
|
-
purgetss brand --
|
|
232
|
-
purgetss brand --
|
|
233
|
-
purgetss brand --
|
|
312
|
+
purgetss brand # uses purgetss/brand/logo.svg + config
|
|
313
|
+
purgetss brand --bg-color "#0B1326" # override bg color
|
|
314
|
+
purgetss brand --icon-logo ./docs/app-icon.svg # dedicated square Android launcher mark
|
|
315
|
+
purgetss brand --splash --splash-logo ./docs/splash.svg # custom Android 12+ splash artwork
|
|
316
|
+
purgetss brand --notification --splash # add notification + splash
|
|
317
|
+
purgetss brand --no-tinted # skip iOS 18+ tinted variant
|
|
318
|
+
purgetss brand --dry-run # preview without writing
|
|
319
|
+
purgetss brand --cleanup-legacy --dry-run # preview legacy cleanup
|
|
234
320
|
```
|
|
235
321
|
|
|
322
|
+
### Android output groups
|
|
323
|
+
|
|
324
|
+
`brand` writes three Android-facing asset groups, each with a different job:
|
|
325
|
+
|
|
326
|
+
- `ic_launcher*` for the app icon and the default Android 12+ system splash path
|
|
327
|
+
- `splash_icon.png` when you pass `--splash` and want custom Android 12+ splash artwork
|
|
328
|
+
- `default.png` as the older Titanium Android splash fallback (regenerated since v7.7.0)
|
|
329
|
+
|
|
236
330
|
## `images` Command
|
|
237
331
|
|
|
238
332
|
Introduced in v7.6.0. Generates multi-density variants of your UI images (buttons, illustrations, logos, screen graphics) from a single high-resolution source per image. Alloy and Classic projects are auto-detected.
|
|
@@ -254,6 +348,7 @@ purgetss images background/ # re-process one subfolder
|
|
|
254
348
|
| `--ios` | Only emit iPhone scale variants. Mutually exclusive with `--android`. |
|
|
255
349
|
| `--format <ext>` | Convert all outputs to `webp`, `jpeg`, `png`, `avif`, `gif`, or `tiff`. Default: keep source format. |
|
|
256
350
|
| `--quality <n>` | Quality `0-100` for lossy formats. Default `85`. |
|
|
351
|
+
| `--width <n>` | (v7.8.0) Pin Android `mdpi` (= iPhone `@1x`) to `<n>` pixels wide. Larger scales derive as ×1.5, ×2, ×3, ×4 from that base; height stays proportional to the source's aspect ratio. Integer in `[1, 8192]`. |
|
|
257
352
|
| `--dry-run` | Preview without writing any files. |
|
|
258
353
|
| `--project <path>` | Project root (defaults to cwd). |
|
|
259
354
|
| `-y, --yes` | Skip the overwrite confirmation prompt. |
|
|
@@ -263,6 +358,12 @@ purgetss images background/ # re-process one subfolder
|
|
|
263
358
|
|
|
264
359
|
- `[source]` (optional) — path to override auto-discovery. Resolves first against `purgetss/images/` (short paths like `buttons/btn.png`), then against cwd.
|
|
265
360
|
|
|
361
|
+
### When to use `--width`
|
|
362
|
+
|
|
363
|
+
Use `--width <n>` for SVG sources from vector editors with disproportionate viewBoxes — common in Affinity, Illustrator, and other design tools where the viewBox does not match the intended display size. Without the flag, every scale derives from the source's natural pixel size as a 4× master, which can produce unexpected output sizes.
|
|
364
|
+
|
|
365
|
+
When you pass an SVG without `--width`, the command prints a one-time hint and falls back to the legacy 4× behavior. This is CLI-only; there is no matching `images:` config property because the right width is per-asset.
|
|
366
|
+
|
|
266
367
|
### Config block
|
|
267
368
|
|
|
268
369
|
Defaults live under `images:` in `purgetss/config.cjs`:
|
|
@@ -285,6 +386,7 @@ purgetss images background/pink-texture.png # re-process one file (sh
|
|
|
285
386
|
purgetss images background/ # re-process one subfolder
|
|
286
387
|
purgetss images --android # only Android densities
|
|
287
388
|
purgetss images --format webp --quality 90 # convert all outputs to WebP
|
|
389
|
+
purgetss images logo.svg --width 256 # pin SVG output to 256 px @1x/mdpi
|
|
288
390
|
purgetss images --dry-run # preview
|
|
289
391
|
```
|
|
290
392
|
|
|
@@ -322,6 +424,29 @@ purgetss semantic --single '#000000' overlayColor --alpha 50
|
|
|
322
424
|
|
|
323
425
|
When `--dark` is omitted, it defaults to the light hex — useful for overlays/glass surfaces where alpha is the only variation.
|
|
324
426
|
|
|
427
|
+
### Customizing the class name
|
|
428
|
+
|
|
429
|
+
The auto-mapping uses the most literal Titanium-style transform: strip `Color`, then kebab-case the rest (e.g. `surfaceColor` → `surface`, `textSecondaryColor` → `text-secondary`). If your design system prefers different names — for example `on-surface` instead of `text`, or nesting the surface family under `DEFAULT` / `high` — edit `config.cjs` after running the `--single` batch:
|
|
430
|
+
|
|
431
|
+
`./purgetss/config.cjs`
|
|
432
|
+
```javascript
|
|
433
|
+
theme: {
|
|
434
|
+
extend: {
|
|
435
|
+
colors: {
|
|
436
|
+
surface: { DEFAULT: 'surfaceColor', high: 'surfaceHighColor' },
|
|
437
|
+
'on-surface': 'textColor',
|
|
438
|
+
'on-surface-variant': 'textSecondaryColor',
|
|
439
|
+
muted: 'textMutedColor',
|
|
440
|
+
border: 'borderColor',
|
|
441
|
+
accent: 'accentColor',
|
|
442
|
+
overlay: 'overlayColor'
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
The next `purgetss build` picks up the renamed classes. Editing one generated mapping is faster than typing the whole structure from scratch. See [semantic-colors.md](./semantic-colors.md) for the full nested-vs-flat discussion (including the `[object Object]` pitfall when nesting without `DEFAULT`).
|
|
449
|
+
|
|
325
450
|
### Smart in-place updates
|
|
326
451
|
|
|
327
452
|
If a `--single` name matches an existing palette shade — e.g. `purgetss semantic --single '#000' amazon500` while palette `amazon` exists — PurgeTSS narrows the operation to an in-place JSON value edit. The entry stays in its original position, and `config.cjs` is left untouched (the palette already maps to that key).
|
|
@@ -392,10 +517,10 @@ After copying the fonts, you can use them in Buttons and Labels. For example, fo
|
|
|
392
517
|
|
|
393
518
|
### Available Font Classes
|
|
394
519
|
|
|
395
|
-
- [fontawesome.tss](https://github.com/macCesar/purgeTSS/blob/
|
|
396
|
-
- [materialicons.tss](https://github.com/macCesar/purgeTSS/blob/
|
|
397
|
-
- [materialsymbols.tss](https://github.com/macCesar/purgeTSS/blob/
|
|
398
|
-
- [framework7icons.tss](https://github.com/macCesar/purgeTSS/blob/
|
|
520
|
+
- [fontawesome.tss](https://github.com/macCesar/purgeTSS/blob/main/dist/fontawesome.tss)
|
|
521
|
+
- [materialicons.tss](https://github.com/macCesar/purgeTSS/blob/main/dist/materialicons.tss)
|
|
522
|
+
- [materialsymbols.tss](https://github.com/macCesar/purgeTSS/blob/main/dist/materialsymbols.tss)
|
|
523
|
+
- [framework7icons.tss](https://github.com/macCesar/purgeTSS/blob/main/dist/framework7icons.tss)
|
|
399
524
|
|
|
400
525
|
### Copying Specific Font Vendors
|
|
401
526
|
|