purgetss 7.5.2 → 7.6.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/README.md +93 -11
- package/bin/purgetss +140 -1
- package/dist/purgetss.ui.js +65 -26
- package/dist/utilities.tss +21 -4
- package/experimental/completions2.js +1 -1
- package/lib/completions/titanium/completions-v3.json +62 -1
- package/lib/templates/purgetss.config.js.cjs +15 -1
- package/lib/templates/purgetss.ui.js.cjs +64 -25
- package/package.json +3 -1
- package/src/cli/commands/brand.js +69 -0
- package/src/cli/commands/create.js +11 -7
- package/src/cli/commands/fonts.js +9 -9
- package/src/cli/commands/icon-library.js +18 -16
- package/src/cli/commands/images.js +116 -0
- package/src/cli/commands/init.js +4 -0
- package/src/cli/commands/module.js +4 -2
- package/src/cli/commands/purge.js +77 -101
- package/src/cli/commands/semantic.js +180 -0
- package/src/cli/commands/shades.js +332 -13
- package/src/cli/utils/project-detection.js +4 -2
- package/src/core/analyzers/class-extractor.js +110 -3
- package/src/core/branding/brand-config.js +111 -0
- package/src/core/branding/branding-logger.js +40 -0
- package/src/core/branding/cleanup-legacy.js +220 -0
- package/src/core/branding/ensure-brand-section.js +80 -0
- package/src/core/branding/gen-android-adaptive.js +116 -0
- package/src/core/branding/gen-android-legacy.js +63 -0
- package/src/core/branding/gen-ic-launcher-xml.js +29 -0
- package/src/core/branding/gen-ios-dark.js +70 -0
- package/src/core/branding/gen-ios-tinted.js +55 -0
- package/src/core/branding/gen-ios.js +69 -0
- package/src/core/branding/gen-marketplace.js +71 -0
- package/src/core/branding/gen-notification.js +76 -0
- package/src/core/branding/gen-splash.js +64 -0
- package/src/core/branding/index.js +336 -0
- package/src/core/branding/post-gen-notes.js +145 -0
- package/src/core/branding/prepare-master.js +108 -0
- package/src/core/branding/tiapp-reader.js +110 -0
- package/src/core/builders/tailwind-helpers.js +1 -1
- package/src/core/images/ensure-images-section.js +57 -0
- package/src/core/images/gen-scales.js +181 -0
- package/src/core/images/index.js +171 -0
- package/src/shared/config-manager.js +46 -0
- package/src/shared/config-writer.js +84 -0
- package/src/shared/constants.js +3 -0
- package/src/shared/helpers/typography.js +38 -3
- package/src/shared/logger.js +69 -4
- package/src/shared/prompt.js +64 -0
- package/src/shared/svg-utils.js +80 -0
- package/src/shared/utils.js +8 -4
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
</div>
|
|
12
12
|
|
|
13
|
-
**PurgeTSS** is a toolkit for building mobile apps with the [Titanium framework](https://titaniumsdk.com). It provides utility classes, icon font support, an Animation module, a grid system, and
|
|
13
|
+
**PurgeTSS** is a toolkit for building mobile apps with the [Titanium framework](https://titaniumsdk.com). It provides utility classes, icon font support, an Animation module, a grid system, and color generation commands (`shades` for tonal palettes, `semantic` for Light/Dark mode semantic colors).
|
|
14
14
|
|
|
15
15
|
---
|
|
16
16
|
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
- Icon font support: Font Awesome, Material Icons, Material Symbols, Framework7-Icons
|
|
21
21
|
- `build-fonts` command generates `fonts.tss` with class definitions and fontFamily selectors
|
|
22
22
|
- `shades` command generates color shades from any hex color
|
|
23
|
+
- `semantic` command generates Titanium semantic colors (Light/Dark mode) — tonal palettes with mirror inversion, or single purpose-based colors with optional alpha
|
|
23
24
|
- Animation module for 2D matrix animations on views or arrays of views
|
|
24
25
|
- Grid system for aligning and distributing elements within views
|
|
25
26
|
|
|
@@ -240,6 +241,79 @@ Fallback defaults when not set: `swap`/`reorder`/`snapTo` → 200ms; `shake` →
|
|
|
240
241
|
|
|
241
242
|
See the full documentation at [purgetss.com/docs/animation-module/introduction](https://purgetss.com/docs/animation-module/introduction).
|
|
242
243
|
|
|
244
|
+
### Appearance management
|
|
245
|
+
|
|
246
|
+
Switch between Light, Dark, and System modes with automatic persistence:
|
|
247
|
+
|
|
248
|
+
```js
|
|
249
|
+
const { Appearance } = require('purgetss.ui')
|
|
250
|
+
|
|
251
|
+
// Call once at app startup (e.g., in index.js before opening the first window)
|
|
252
|
+
Appearance.init()
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
| Method | Description |
|
|
256
|
+
| ----------- | ------------------------------------------------------------ |
|
|
257
|
+
| `init()` | Restore the saved mode from `Ti.App.Properties` |
|
|
258
|
+
| `get()` | Returns the current mode string |
|
|
259
|
+
| `set(mode)` | Apply and persist a mode: `'system'`, `'light'`, or `'dark'` |
|
|
260
|
+
| `toggle()` | Switch between `'light'` and `'dark'` |
|
|
261
|
+
|
|
262
|
+
Use it from any controller to respond to user actions:
|
|
263
|
+
|
|
264
|
+
```js
|
|
265
|
+
const { Appearance } = require('purgetss.ui')
|
|
266
|
+
|
|
267
|
+
function selectDark() { Appearance.set('dark') }
|
|
268
|
+
function selectLight() { Appearance.set('light') }
|
|
269
|
+
function selectSystem() { Appearance.set('system') }
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Requires `semantic.colors.json` in `app/assets/` for views to respond to mode changes. Generate it with the `semantic` command instead of writing it by hand:
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
# Tonal palette (11 shades with mirror-by-index Light/Dark inversion)
|
|
276
|
+
purgetss semantic '#15803d' amazon
|
|
277
|
+
|
|
278
|
+
# Purpose-based single colors (auto-mapped to classes in config.cjs)
|
|
279
|
+
purgetss semantic --single '#F9FAFB' surfaceColor --dark '#0f172a'
|
|
280
|
+
purgetss semantic --single '#111827' textColor --dark '#f1f5f9'
|
|
281
|
+
purgetss semantic --single '#000000' overlayColor --alpha 50
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
See the [Semantic Colors guide](https://purgetss.com/docs/best-practices/semantic-colors) for the full workflow.
|
|
285
|
+
|
|
286
|
+
### Default font families
|
|
287
|
+
|
|
288
|
+
PurgeTSS generates `font-sans`, `font-serif`, and `font-mono` classes automatically with platform-appropriate values:
|
|
289
|
+
|
|
290
|
+
| Class | iOS | Android |
|
|
291
|
+
| ------------ | ---------------- | ------------ |
|
|
292
|
+
| `font-sans` | `Helvetica Neue` | `sans-serif` |
|
|
293
|
+
| `font-serif` | `Georgia` | `serif` |
|
|
294
|
+
| `font-mono` | `monospace` | `monospace` |
|
|
295
|
+
|
|
296
|
+
Override or add families in `config.cjs`:
|
|
297
|
+
|
|
298
|
+
```js
|
|
299
|
+
// theme.extend.fontFamily → adds to defaults
|
|
300
|
+
extend: {
|
|
301
|
+
fontFamily: {
|
|
302
|
+
display: 'AlfaSlabOne-Regular',
|
|
303
|
+
body: 'BarlowSemiCondensed-Regular'
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// theme.fontFamily → replaces defaults entirely
|
|
308
|
+
theme: {
|
|
309
|
+
fontFamily: {
|
|
310
|
+
sans: 'System',
|
|
311
|
+
mono: 'Courier',
|
|
312
|
+
display: 'AlfaSlabOne-Regular'
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
243
317
|
---
|
|
244
318
|
|
|
245
319
|
## Customizing default components
|
|
@@ -304,6 +378,9 @@ Button: {
|
|
|
304
378
|
|
|
305
379
|
- [Installation](https://purgetss.com/docs/installation)
|
|
306
380
|
- [Commands](https://purgetss.com/docs/commands)
|
|
381
|
+
- App Assets
|
|
382
|
+
- [App icons and branding](https://purgetss.com/docs/app-assets/app-icons-and-branding)
|
|
383
|
+
- [Multi-density images](https://purgetss.com/docs/app-assets/multi-density-images)
|
|
307
384
|
- Customization
|
|
308
385
|
- [The Config File](https://purgetss.com/docs/customization/the-config-file)
|
|
309
386
|
- [Custom Rules](https://purgetss.com/docs/customization/custom-rules)
|
|
@@ -312,14 +389,19 @@ Button: {
|
|
|
312
389
|
- [Arbitrary Values](https://purgetss.com/docs/customization/arbitrary-values)
|
|
313
390
|
- [Platform and Device Modifiers](https://purgetss.com/docs/customization/platform-and-device-modifiers)
|
|
314
391
|
- [Icon Fonts Libraries](https://purgetss.com/docs/customization/icon-fonts-libraries)
|
|
315
|
-
-
|
|
316
|
-
- [Introduction](https://purgetss.com/docs/
|
|
317
|
-
- [The `play` Method](https://purgetss.com/docs/
|
|
318
|
-
- [The `apply` Method](https://purgetss.com/docs/
|
|
319
|
-
- [The `open` and `close` Methods](https://purgetss.com/docs/
|
|
320
|
-
- [The `draggable` Method](https://purgetss.com/docs/
|
|
321
|
-
- [Complex UI Elements](https://purgetss.com/docs/
|
|
322
|
-
- [Additional Methods](https://purgetss.com/docs/
|
|
323
|
-
- [Available Utilities](https://purgetss.com/docs/
|
|
324
|
-
- [Implementation Rules](https://purgetss.com/docs/
|
|
392
|
+
- The UI Module
|
|
393
|
+
- [Introduction](https://purgetss.com/docs/purgetss-ui/introduction)
|
|
394
|
+
- [The `play` Method](https://purgetss.com/docs/purgetss-ui/the-play-method)
|
|
395
|
+
- [The `apply` Method](https://purgetss.com/docs/purgetss-ui/the-apply-method)
|
|
396
|
+
- [The `open` and `close` Methods](https://purgetss.com/docs/purgetss-ui/the-open-and-close-methods)
|
|
397
|
+
- [The `draggable` Method](https://purgetss.com/docs/purgetss-ui/the-draggable-method)
|
|
398
|
+
- [Complex UI Elements](https://purgetss.com/docs/purgetss-ui/complex-ui-elements)
|
|
399
|
+
- [Additional Methods](https://purgetss.com/docs/purgetss-ui/additional-methods)
|
|
400
|
+
- [Available Utilities](https://purgetss.com/docs/purgetss-ui/available-utilities)
|
|
401
|
+
- [Implementation Rules](https://purgetss.com/docs/purgetss-ui/implementation-rules)
|
|
402
|
+
- [Appearance](https://purgetss.com/docs/purgetss-ui/appearance)
|
|
403
|
+
- Best Practices
|
|
404
|
+
- [Appearance Setup](https://purgetss.com/docs/best-practices/appearance-setup)
|
|
405
|
+
- [Semantic Colors](https://purgetss.com/docs/best-practices/semantic-colors)
|
|
406
|
+
- [Large Titles on iOS](https://purgetss.com/docs/best-practices/large-titles-on-ios)
|
|
325
407
|
- [Grid System](https://purgetss.com/docs/grid-system)
|
package/bin/purgetss
CHANGED
|
@@ -17,8 +17,11 @@ import { copyModulesLibrary } from '../src/cli/commands/module.js'
|
|
|
17
17
|
import { dependencies } from '../src/cli/commands/dependencies.js'
|
|
18
18
|
import { init } from '../src/cli/commands/init.js'
|
|
19
19
|
import { shades, colorModule } from '../src/cli/commands/shades.js'
|
|
20
|
+
import { semantic } from '../src/cli/commands/semantic.js'
|
|
20
21
|
import { buildFonts } from '../src/cli/commands/fonts.js'
|
|
21
22
|
import { copyFonts } from '../src/cli/commands/icon-library.js'
|
|
23
|
+
import { brand } from '../src/cli/commands/brand.js'
|
|
24
|
+
import { images } from '../src/cli/commands/images.js'
|
|
22
25
|
|
|
23
26
|
// ESM equivalent of __dirname
|
|
24
27
|
const __filename = fileURLToPath(import.meta.url)
|
|
@@ -113,6 +116,8 @@ program.helpInformation = function () {
|
|
|
113
116
|
output.push(` ${chalk.cyan('init|i')} ${chalk.gray('[options]')} Create a ${chalk.yellow('config.cjs')} file for your project`)
|
|
114
117
|
output.push(` ${chalk.cyan('create|c')} ${chalk.gray('[options]')} ${chalk.gray('<name>')} Create a new Alloy project with ${chalk.green('PurgeTSS')}`)
|
|
115
118
|
output.push(` ${chalk.cyan('install-dependencies|id')} Install ${chalk.green('ESLint')} and ${chalk.green('Tailwind CSS')}`)
|
|
119
|
+
output.push(` ${chalk.cyan('brand')} ${chalk.gray('[options]')} ${chalk.gray('<logo>')} Generate Titanium app icons & splash from a logo SVG/PNG`)
|
|
120
|
+
output.push(` ${chalk.cyan('images')} ${chalk.gray('[options]')} ${chalk.gray('[source]')} Generate Titanium multi-density UI images (Alloy + Classic)`)
|
|
116
121
|
output.push('')
|
|
117
122
|
output.push(` ${chalk.green('Daily Development:')}`)
|
|
118
123
|
output.push(` ${chalk.cyan('build|b')} ${chalk.gray('[options]')} Generate ${chalk.yellow('utilities.tss')} file`)
|
|
@@ -126,6 +131,7 @@ program.helpInformation = function () {
|
|
|
126
131
|
output.push('')
|
|
127
132
|
output.push(` ${chalk.green('Utilities:')}`)
|
|
128
133
|
output.push(` ${chalk.cyan('shades|s')} ${chalk.gray('[options]')} ${chalk.gray('[hexcode]')} Generate color shades from a hex color`)
|
|
134
|
+
output.push(` ${chalk.cyan('semantic')} ${chalk.gray('[options]')} ${chalk.gray('[hexcode]')} Generate Titanium semantic colors (Light/Dark)`)
|
|
129
135
|
output.push('')
|
|
130
136
|
output.push(` ${chalk.green('Maintenance:')}`)
|
|
131
137
|
output.push(` ${chalk.cyan('update|u')} Update ${chalk.green('PurgeTSS')} to the latest version`)
|
|
@@ -248,6 +254,114 @@ program
|
|
|
248
254
|
}
|
|
249
255
|
})
|
|
250
256
|
|
|
257
|
+
// Brand command — generate Titanium app icons and splash assets
|
|
258
|
+
program
|
|
259
|
+
.command('brand [logo]')
|
|
260
|
+
.description(`Generate Titanium app icons & branding assets from a logo SVG/PNG`)
|
|
261
|
+
.addHelpText('after', `
|
|
262
|
+
Writes directly into the current project (Alloy or Classic — auto-detected).
|
|
263
|
+
Logos auto-discovered from ${chalk.cyan('purgetss/brand/')}:
|
|
264
|
+
${chalk.yellow('logo.{svg,png}')} required — main logo
|
|
265
|
+
${chalk.yellow('logo-mono.{svg,png}')} optional — monochrome layer + notifications
|
|
266
|
+
${chalk.yellow('logo-dark.{svg,png}')} optional — iOS 18+ dark variant
|
|
267
|
+
${chalk.yellow('logo-tinted.{svg,png}')} optional — iOS 18+ tinted variant
|
|
268
|
+
|
|
269
|
+
Defaults come from the ${chalk.cyan('brand:')} section in ${chalk.cyan('purgetss/config.cjs')}.
|
|
270
|
+
CLI flags always win over config values.
|
|
271
|
+
|
|
272
|
+
Generates:
|
|
273
|
+
${chalk.yellow('DefaultIcon.png')} / ${chalk.yellow('DefaultIcon-ios.png')} Root icons (alpha + flattened)
|
|
274
|
+
${chalk.yellow('DefaultIcon-Dark.png')} / ${chalk.yellow('DefaultIcon-Tinted.png')} iOS 18+ variants (Apple HIG specs)
|
|
275
|
+
${chalk.yellow('iTunesConnect.png')} / ${chalk.yellow('MarketplaceArtwork.png')} App Store + Play Store artwork
|
|
276
|
+
${chalk.yellow('mipmap-*/ic_launcher_{foreground,background,monochrome}.png')} Android adaptive × 5
|
|
277
|
+
${chalk.yellow('mipmap-*/ic_launcher.png')} Android legacy × 5
|
|
278
|
+
${chalk.yellow('mipmap-anydpi-v26/ic_launcher.xml')} Adaptive icon binder
|
|
279
|
+
|
|
280
|
+
Android dark/light mode is handled by the ${chalk.yellow('monochrome')} adaptive layer
|
|
281
|
+
(Android 13+ tints it from the wallpaper + theme). No separate dark file exists.
|
|
282
|
+
|
|
283
|
+
Examples:
|
|
284
|
+
${chalk.cyan('purgetss brand')} # uses purgetss/brand/logo.svg + config
|
|
285
|
+
${chalk.cyan('purgetss brand')} logo.svg # explicit logo path
|
|
286
|
+
${chalk.cyan('purgetss brand')} --bg-color "#0B1326" # override config bg
|
|
287
|
+
${chalk.cyan('purgetss brand')} --dark-bg-color "#1C1C1E" --no-tinted # customize dark, skip tinted
|
|
288
|
+
${chalk.cyan('purgetss brand')} --dry-run # preview without writing
|
|
289
|
+
${chalk.cyan('purgetss brand')} --cleanup-legacy --dry-run # preview legacy cleanup
|
|
290
|
+
`)
|
|
291
|
+
.option('--bg-color <hex>', 'Background color for Android adaptive + iOS flatten (default: #FFFFFF)')
|
|
292
|
+
.option('--padding <n>', 'Android safe-zone % (range 12-20, default: 15)', (v) => parseInt(v, 10))
|
|
293
|
+
.option('--ios-padding <n>', 'iOS aesthetic % (typical 2-6, default: 4)', (v) => parseInt(v, 10))
|
|
294
|
+
.option('--notification', 'Also generate ic_stat_notify.png × 5 densities')
|
|
295
|
+
.option('--splash', 'Also generate Android 12+ splash_icon.png × 5 densities')
|
|
296
|
+
.option('--monochrome-logo <path>', 'Override the monochrome logo (otherwise purgetss/brand/logo-mono.{svg,png})')
|
|
297
|
+
.option('--dark-bg-color <hex>', 'Opt into opaque dark bg for DefaultIcon-Dark.png (default: transparent per Apple HIG)')
|
|
298
|
+
.option('--dark-logo <path>', 'Override the dark logo (otherwise purgetss/brand/logo-dark.{svg,png})')
|
|
299
|
+
.option('--tinted-logo <path>', 'Override the tinted logo (otherwise purgetss/brand/logo-tinted.{svg,png})')
|
|
300
|
+
.option('--no-dark', 'Skip DefaultIcon-Dark.png generation')
|
|
301
|
+
.option('--no-tinted', 'Skip DefaultIcon-Tinted.png generation')
|
|
302
|
+
.option('--project <path>', 'Project root (default: cwd)')
|
|
303
|
+
.option('-o, --output <dir>', 'Stage to <dir> instead of writing in-place')
|
|
304
|
+
.option('--notes', 'Print full tiapp.xml snippets + tuning guide')
|
|
305
|
+
.option('--dry-run', 'Preview without writing any files')
|
|
306
|
+
.option('--cleanup-legacy', 'Remove legacy branding artifacts (reads tiapp.xml)')
|
|
307
|
+
.option('--aggressive', 'With --cleanup-legacy: also remove ldpi folders')
|
|
308
|
+
.option('-y, --yes', 'Skip the in-place confirmation prompt')
|
|
309
|
+
.option('--debug', 'Debug mode')
|
|
310
|
+
.action(async (logo, options) => {
|
|
311
|
+
try {
|
|
312
|
+
await brand(logo, options)
|
|
313
|
+
} catch (error) {
|
|
314
|
+
console.error(chalk.red('Error running brand:'), error.message)
|
|
315
|
+
process.exit(1)
|
|
316
|
+
}
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
// Images command — generate Titanium multi-density UI assets
|
|
320
|
+
program
|
|
321
|
+
.command('images [source]')
|
|
322
|
+
.description(`Generate Titanium multi-density UI images (Alloy & Classic)`)
|
|
323
|
+
.addHelpText('after', `
|
|
324
|
+
Scales UI images into all Titanium density variants in one pass:
|
|
325
|
+
${chalk.yellow('Android')} → ${chalk.gray('res-mdpi, res-hdpi, res-xhdpi, res-xxhdpi, res-xxxhdpi')} (5 densities)
|
|
326
|
+
${chalk.yellow('iPhone')} → ${chalk.gray('@1x, @2x, @3x')} (3 scales via filename suffix)
|
|
327
|
+
|
|
328
|
+
Sources auto-discovered from ${chalk.cyan('purgetss/images/')} (subdirectories preserved).
|
|
329
|
+
Pass a file or directory path to override auto-discovery.
|
|
330
|
+
|
|
331
|
+
Writes directly to the project (auto-detects Alloy vs Classic):
|
|
332
|
+
${chalk.yellow('Alloy')} → ${chalk.gray('app/assets/{android,iphone}/images/')}
|
|
333
|
+
${chalk.yellow('Classic')} → ${chalk.gray('Resources/{android,iphone}/images/')}
|
|
334
|
+
|
|
335
|
+
Defaults come from the ${chalk.cyan('images:')} section in ${chalk.cyan('purgetss/config.cjs')}.
|
|
336
|
+
CLI flags always win over config values.
|
|
337
|
+
|
|
338
|
+
Examples:
|
|
339
|
+
${chalk.cyan('purgetss images')} # uses purgetss/images/ + config
|
|
340
|
+
${chalk.cyan('purgetss images')} ./docs/screenshots # scope to one folder
|
|
341
|
+
${chalk.cyan('purgetss images')} logo.png # scope to one file
|
|
342
|
+
${chalk.cyan('purgetss images')} --android # Android densities only
|
|
343
|
+
${chalk.cyan('purgetss images')} --ios # iPhone scales only
|
|
344
|
+
${chalk.cyan('purgetss images')} --format webp # convert all outputs to WebP
|
|
345
|
+
${chalk.cyan('purgetss images')} --format png --quality 95
|
|
346
|
+
${chalk.cyan('purgetss images')} --dry-run
|
|
347
|
+
`)
|
|
348
|
+
.option('--android', 'Generate only Android density variants (skip iPhone)')
|
|
349
|
+
.option('--ios', 'Generate only iPhone scale variants (skip Android)')
|
|
350
|
+
.option('--format <ext>', 'Convert all outputs to this format: webp|jpeg|png|avif|gif|tiff')
|
|
351
|
+
.option('--quality <n>', 'JPEG/WebP/AVIF quality 0-100 (default: 85)', (v) => parseInt(v, 10))
|
|
352
|
+
.option('--project <path>', 'Project root (default: cwd)')
|
|
353
|
+
.option('--dry-run', 'Preview without writing any files')
|
|
354
|
+
.option('-y, --yes', 'Skip the overwrite confirmation prompt')
|
|
355
|
+
.option('--debug', 'Debug mode')
|
|
356
|
+
.action(async (source, options) => {
|
|
357
|
+
try {
|
|
358
|
+
await images(source, options)
|
|
359
|
+
} catch (error) {
|
|
360
|
+
console.error(chalk.red('Error running images:'), error.message)
|
|
361
|
+
process.exit(1)
|
|
362
|
+
}
|
|
363
|
+
})
|
|
364
|
+
|
|
251
365
|
// === DAILY DEVELOPMENT ===
|
|
252
366
|
|
|
253
367
|
// Build command
|
|
@@ -391,6 +505,31 @@ program
|
|
|
391
505
|
}
|
|
392
506
|
})
|
|
393
507
|
|
|
508
|
+
// Semantic command — generates Titanium semantic colors (Light/Dark mode)
|
|
509
|
+
program
|
|
510
|
+
.command('semantic [hexcode] [name]')
|
|
511
|
+
.description(`Generate Titanium semantic colors in ${chalk.yellow('app/assets/semantic.colors.json')}`)
|
|
512
|
+
.addHelpText('after', `\nWithout ${chalk.yellow('--single')}: one hex → 11-shade palette with Light/Dark inversion.\nWith ${chalk.yellow('--single')}: explicit light + dark + optional alpha → one purpose-based color.`)
|
|
513
|
+
.option('-s, --single', 'Generate a single purpose-based semantic color (requires explicit per-mode hex values)')
|
|
514
|
+
.option('-d, --dark <hex>', `With ${chalk.yellow('--single')}: dark-mode hex (defaults to the light value)`)
|
|
515
|
+
.option('-a, --alpha <value>', `With ${chalk.yellow('--single')}: wrap values as ${chalk.yellow('{ color, alpha }')} (range ${chalk.yellow('0-100')}, integer or float)`)
|
|
516
|
+
.option('-n, --name <name>', 'Specify the name of the color')
|
|
517
|
+
.option('-r, --random', 'Palette mode: use a random base color')
|
|
518
|
+
.option('-o, --override', `Place the mapping in ${chalk.yellow('theme.colors')} instead of ${chalk.yellow('theme.extend.colors')}`)
|
|
519
|
+
.option('-q, --quotes', `Keep double quotes in ${chalk.yellow('config.cjs')}`)
|
|
520
|
+
.option('-l, --log', 'Preview the JSON without writing any files')
|
|
521
|
+
.action(async (hexcode, name, options) => {
|
|
522
|
+
try {
|
|
523
|
+
const result = await semantic({ hexcode, name }, options)
|
|
524
|
+
if (!result) {
|
|
525
|
+
process.exit(1)
|
|
526
|
+
}
|
|
527
|
+
} catch (error) {
|
|
528
|
+
console.error(chalk.red('Error running semantic:'), error.message)
|
|
529
|
+
process.exit(1)
|
|
530
|
+
}
|
|
531
|
+
})
|
|
532
|
+
|
|
394
533
|
// === MAINTENANCE ===
|
|
395
534
|
|
|
396
535
|
// Update command
|
|
@@ -496,7 +635,7 @@ function findSimilarCommands(input, validCommands) {
|
|
|
496
635
|
// Validate arguments before parsing
|
|
497
636
|
const args = process.argv.slice(2)
|
|
498
637
|
if (args.length > 0) {
|
|
499
|
-
const validCommands = ['init', 'i', 'create', 'c', 'install-dependencies', 'id', 'build', 'b', 'watch', 'w', 'icon-library', 'il', 'build-fonts', 'bf', 'color-module', 'cm', 'shades', 's', 'module', 'm', 'update', 'u', 'sudo-update', 'su']
|
|
638
|
+
const validCommands = ['init', 'i', 'create', 'c', 'install-dependencies', 'id', 'brand', 'images', 'build', 'b', 'watch', 'w', 'icon-library', 'il', 'build-fonts', 'bf', 'color-module', 'cm', 'shades', 's', 'semantic', 'module', 'm', 'update', 'u', 'sudo-update', 'su']
|
|
500
639
|
const validFlags = ['-h', '--help', '-V', '--version', '--debug', '-a', '--all']
|
|
501
640
|
|
|
502
641
|
const firstArg = args[0]
|
package/dist/purgetss.ui.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// PurgeTSS v7.
|
|
1
|
+
// PurgeTSS v7.6.0
|
|
2
2
|
// Created by César Estrada
|
|
3
3
|
// https://purgetss.com
|
|
4
4
|
|
|
@@ -316,7 +316,13 @@ function Animation(args = {}) {
|
|
|
316
316
|
|
|
317
317
|
if (!layout) {
|
|
318
318
|
view.animate(Ti.UI.createAnimation({ ...args, zIndex: 0, opacity: 0 }), () => {
|
|
319
|
-
|
|
319
|
+
if (params.isIOS) {
|
|
320
|
+
// Preserve transform so next fade-in continues from last visual state
|
|
321
|
+
view.applyProperties({ zIndex: 0, opacity: 0, touchEnabled: false })
|
|
322
|
+
} else {
|
|
323
|
+
// Android: reset transform to avoid animator glitches on next fade-in
|
|
324
|
+
view.applyProperties({ zIndex: 0, opacity: 0, touchEnabled: false, transform: Ti.UI.createMatrix2D(), translation: { x: 0, y: 0 }, rotate: 0, scale: 1 })
|
|
325
|
+
}
|
|
320
326
|
})
|
|
321
327
|
return
|
|
322
328
|
}
|
|
@@ -343,7 +349,7 @@ function Animation(args = {}) {
|
|
|
343
349
|
if (layout.opacity !== undefined) animation.opacity = layout.opacity
|
|
344
350
|
|
|
345
351
|
view.animate(animation, () => {
|
|
346
|
-
const props = { transform, translation: { x: tx, y: ty }, rotate, scale, zIndex: layout.zIndex }
|
|
352
|
+
const props = { transform, translation: { x: tx, y: ty }, rotate, scale, zIndex: layout.zIndex, touchEnabled: true }
|
|
347
353
|
if (needsFadeIn) props.opacity = 1
|
|
348
354
|
view.applyProperties(props)
|
|
349
355
|
})
|
|
@@ -468,13 +474,6 @@ function Animation(args = {}) {
|
|
|
468
474
|
const target = directTarget ?? params.lastKnownTarget
|
|
469
475
|
logger(` -> collision check: ${draggableView.id} | direct: ${directTarget?.id ?? 'null'} | lastKnown: ${params.lastKnownTarget?.id ?? 'null'} | final: ${target?.id ?? 'null'}`)
|
|
470
476
|
if (target) {
|
|
471
|
-
// On Android, consolidate drag position before snap to avoid animation conflict
|
|
472
|
-
if (!params.isIOS) {
|
|
473
|
-
draggableView.applyProperties({
|
|
474
|
-
top: draggableView._visualTop ?? draggableView.top,
|
|
475
|
-
left: draggableView._visualLeft ?? draggableView.left
|
|
476
|
-
})
|
|
477
|
-
}
|
|
478
477
|
if (args.animationProperties?.snap?.center) {
|
|
479
478
|
logger(` -> snap-center: ${draggableView.id} to ${target.id}`)
|
|
480
479
|
animationView.snapTo(draggableView, [target])
|
|
@@ -486,14 +485,6 @@ function Animation(args = {}) {
|
|
|
486
485
|
} else if (!target && args.animationProperties?.snap?.back) {
|
|
487
486
|
logger(` -> bounce-back: ${draggableView.id} to (${draggableView._originTop}, ${draggableView._originLeft})`)
|
|
488
487
|
|
|
489
|
-
// On Android, consolidate drag position before bounce-back to avoid animation conflict
|
|
490
|
-
if (!params.isIOS) {
|
|
491
|
-
draggableView.applyProperties({
|
|
492
|
-
top: draggableView._visualTop ?? draggableView.top,
|
|
493
|
-
left: draggableView._visualLeft ?? draggableView.left
|
|
494
|
-
})
|
|
495
|
-
}
|
|
496
|
-
|
|
497
488
|
draggableView._bouncingBack = true
|
|
498
489
|
|
|
499
490
|
draggableView.animate({
|
|
@@ -582,8 +573,8 @@ function Animation(args = {}) {
|
|
|
582
573
|
draggableView.applyProperties({ duration: 0, transform: Ti.UI.createMatrix2D().translate(x, y) })
|
|
583
574
|
}
|
|
584
575
|
} else {
|
|
585
|
-
const r = draggableView.rotate ?? 0
|
|
586
576
|
const s = draggableView.scale ?? 1
|
|
577
|
+
const r = draggableView.rotate ?? 0
|
|
587
578
|
|
|
588
579
|
if (r !== 0 || s !== 1) {
|
|
589
580
|
// Delta-based drag for transformed views on Android
|
|
@@ -593,14 +584,20 @@ function Animation(args = {}) {
|
|
|
593
584
|
translation.x += deltaX
|
|
594
585
|
translation.y += deltaY
|
|
595
586
|
draggableView.animate(Ti.UI.createAnimation({
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
}))
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
draggableView.scale = s
|
|
587
|
+
duration: 0,
|
|
588
|
+
transform: Ti.UI.createMatrix2D().translate(translation.x, translation.y).rotate(r).scale(s)
|
|
589
|
+
}), () => {
|
|
590
|
+
draggableView.applyProperties({ translation: translation, rotate: r, scale: s })
|
|
591
|
+
})
|
|
602
592
|
} else {
|
|
603
|
-
|
|
593
|
+
// Transform-based (mirror of iOS Rama B) — keeps top/left untouched so snapTo/transition stay coherent
|
|
594
|
+
const { x, y } = calculateTranslation(draggableView, draggableView.parent.rect, left, top)
|
|
595
|
+
draggableView.animate(Ti.UI.createAnimation({
|
|
596
|
+
duration: 0,
|
|
597
|
+
transform: Ti.UI.createMatrix2D().translate(x, y)
|
|
598
|
+
}), () => {
|
|
599
|
+
draggableView.applyProperties({ translation: { x, y }, rotate: 0, scale: 1 })
|
|
600
|
+
})
|
|
604
601
|
}
|
|
605
602
|
}
|
|
606
603
|
|
|
@@ -906,3 +903,45 @@ function saveComponent({ source, directory = Ti.Filesystem.tempDirectory }) {
|
|
|
906
903
|
exports.saveComponent = saveComponent
|
|
907
904
|
|
|
908
905
|
exports.createAnimation = (args) => new Animation(args)
|
|
906
|
+
|
|
907
|
+
// --- Appearance Management (Light/Dark/System) ---
|
|
908
|
+
function Appearance() {
|
|
909
|
+
const PROP_KEY = 'userInterfaceStyle'
|
|
910
|
+
const STYLES = {
|
|
911
|
+
dark: Ti.UI.USER_INTERFACE_STYLE_DARK,
|
|
912
|
+
light: Ti.UI.USER_INTERFACE_STYLE_LIGHT,
|
|
913
|
+
system: Ti.UI.USER_INTERFACE_STYLE_UNSPECIFIED
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
let currentMode = 'system'
|
|
917
|
+
|
|
918
|
+
function applyMode(mode) {
|
|
919
|
+
currentMode = mode
|
|
920
|
+
Ti.UI.overrideUserInterfaceStyle = STYLES[mode]
|
|
921
|
+
Ti.App.Properties.setInt(PROP_KEY, STYLES[mode])
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
return {
|
|
925
|
+
init() {
|
|
926
|
+
const saved = Ti.App.Properties.getInt(PROP_KEY, STYLES.system)
|
|
927
|
+
currentMode = Object.keys(STYLES).find(key => STYLES[key] === saved) || 'system'
|
|
928
|
+
Ti.UI.overrideUserInterfaceStyle = saved
|
|
929
|
+
},
|
|
930
|
+
|
|
931
|
+
set(mode) {
|
|
932
|
+
if (!STYLES.hasOwnProperty(mode)) return
|
|
933
|
+
applyMode(mode)
|
|
934
|
+
},
|
|
935
|
+
|
|
936
|
+
get() {
|
|
937
|
+
return currentMode
|
|
938
|
+
},
|
|
939
|
+
|
|
940
|
+
toggle() {
|
|
941
|
+
const next = (currentMode === 'dark') ? 'light' : 'dark'
|
|
942
|
+
applyMode(next)
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
exports.Appearance = Appearance()
|
package/dist/utilities.tss
CHANGED
|
@@ -2250,9 +2250,6 @@
|
|
|
2250
2250
|
'.rounded-full-2.5': { width: 10, height: 10, borderRadius: 5 }
|
|
2251
2251
|
'.rounded-full-3.5': { width: 14, height: 14, borderRadius: 7 }
|
|
2252
2252
|
|
|
2253
|
-
// Property(ies): fontFamily
|
|
2254
|
-
// Component(s): Ti.UI.ActivityIndicator, Ti.UI.Button, Ti.UI.Label, Ti.UI.ListItem, Ti.UI.Picker, Ti.UI.PickerColumn, Ti.UI.PickerRow, Ti.UI.ProgressBar, Ti.UI.Switch, Ti.UI.TableViewRow, Ti.UI.TextArea, Ti.UI.TextField
|
|
2255
|
-
|
|
2256
2253
|
// Property(ies): fontSize
|
|
2257
2254
|
// Component(s): Ti.UI.ActivityIndicator, Ti.UI.Button, Ti.UI.Label, Ti.UI.ListItem, Ti.UI.Picker, Ti.UI.PickerColumn, Ti.UI.PickerRow, Ti.UI.ProgressBar, Ti.UI.Switch, Ti.UI.TableViewRow, Ti.UI.TextArea, Ti.UI.TextField
|
|
2258
2255
|
'.text-xs': { font: { fontSize: 12 } }
|
|
@@ -2281,6 +2278,14 @@
|
|
|
2281
2278
|
'.font-extrabold': { font: { fontWeight: 'bold' } }
|
|
2282
2279
|
'.font-black': { font: { fontWeight: 'bold' } }
|
|
2283
2280
|
|
|
2281
|
+
// Property(ies): fontFamily
|
|
2282
|
+
// Component(s): Ti.UI.ActivityIndicator, Ti.UI.Button, Ti.UI.Label, Ti.UI.ListItem, Ti.UI.Picker, Ti.UI.PickerColumn, Ti.UI.PickerRow, Ti.UI.ProgressBar, Ti.UI.Switch, Ti.UI.TableViewRow, Ti.UI.TextArea, Ti.UI.TextField
|
|
2283
|
+
'.font-mono': { font: { fontFamily: 'monospace' } }
|
|
2284
|
+
'.font-sans[platform=ios]': { font: { fontFamily: 'Helvetica Neue' } }
|
|
2285
|
+
'.font-serif[platform=ios]': { font: { fontFamily: 'Georgia' } }
|
|
2286
|
+
'.font-sans[platform=android]': { font: { fontFamily: 'sans-serif' } }
|
|
2287
|
+
'.font-serif[platform=android]': { font: { fontFamily: 'serif' } }
|
|
2288
|
+
|
|
2284
2289
|
// Property(ies): top, right, bottom, left - Gap for Grid System
|
|
2285
2290
|
// Component(s): Ti.UI.ActivityIndicator, Ti.UI.Animation, Ti.UI.View, Ti.UI.Window
|
|
2286
2291
|
'.gap-0': { top: 0, right: 0, bottom: 0, left: 0 }
|
|
@@ -6886,6 +6891,12 @@
|
|
|
6886
6891
|
'.left-11/12': { left: '91.666667%' }
|
|
6887
6892
|
'.left-full': { left: '100%' }
|
|
6888
6893
|
|
|
6894
|
+
// Property: keepHardwareMode
|
|
6895
|
+
// Description: A value indicating the render mode of the View
|
|
6896
|
+
// Component(s): Ti.UI.View, Ti.Media.VideoPlayer, Ti.UI.ActivityIndicator, Ti.UI.AlertDialog, Ti.UI.Android.CardView, Ti.UI.Android.CollapseToolbar, Ti.UI.Android.DrawerLayout, Ti.UI.Android.FloatingActionButton, Ti.UI.Android.ProgressIndicator, Ti.UI.Android.SearchView, Ti.UI.Android.Snackbar, Ti.UI.Button, Ti.UI.ButtonBar, Ti.UI.EmailDialog, Ti.UI.ImageView, Ti.UI.Label, Ti.UI.ListView, Ti.UI.MaskedImage, Ti.UI.NavigationWindow, Ti.UI.OptionBar, Ti.UI.OptionDialog, Ti.UI.Picker, Ti.UI.PickerColumn, Ti.UI.PickerRow, Ti.UI.ProgressBar, Ti.UI.ScrollView, Ti.UI.ScrollableView, Ti.UI.SearchBar, Ti.UI.Slider, Ti.UI.Switch, Ti.UI.Tab, Ti.UI.TabGroup, Ti.UI.TabbedBar, Ti.UI.TableView, Ti.UI.TableViewRow, Ti.UI.TextArea, Ti.UI.TextField, Ti.UI.Toolbar, Ti.UI.WebView, Ti.UI.Window
|
|
6897
|
+
'.keep-hardware-mode': { keepHardwareMode: true }
|
|
6898
|
+
'.keep-hardware-mode-false': { keepHardwareMode: false }
|
|
6899
|
+
|
|
6889
6900
|
// Property: layout
|
|
6890
6901
|
// Component(s): Ti.UI.View, Ti.Android.R, Ti.Media.VideoPlayer, Ti.UI.Android.CardView, Ti.UI.Android.DrawerLayout, Ti.UI.Android.SearchView, Ti.UI.Button, Ti.UI.ButtonBar, Ti.UI.DashboardView, Ti.UI.ImageView, Ti.UI.Label, Ti.UI.ListView, Ti.UI.MaskedImage, Ti.UI.NavigationWindow, Ti.UI.OptionBar, Ti.UI.PickerRow, Ti.UI.ProgressBar, Ti.UI.ScrollView, Ti.UI.ScrollableView, Ti.UI.SearchBar, Ti.UI.Slider, Ti.UI.Switch, Ti.UI.TabbedBar, Ti.UI.TableView, Ti.UI.TableViewRow, Ti.UI.TextArea, Ti.UI.TextField, Ti.UI.WebView, Ti.UI.Window, Ti.UI.iOS.BlurView, Ti.UI.iOS.CoverFlowView, Ti.UI.iOS.LivePhotoView, Ti.UI.iOS.SplitWindow, Ti.UI.iOS.Stepper
|
|
6891
6902
|
'.vertical': { layout: 'vertical' }
|
|
@@ -17330,7 +17341,7 @@
|
|
|
17330
17341
|
|
|
17331
17342
|
// Property: autoAdjustScrollViewInsets
|
|
17332
17343
|
// Description: Specifies whether or not the view controller should automatically adjust its scroll view insets.
|
|
17333
|
-
// Component(s): Ti.UI.NavigationWindow, Ti.UI.TabGroup, Ti.UI.Window, Ti.UI.iOS.SplitWindow
|
|
17344
|
+
// Component(s): Ti.UI.NavigationWindow, Ti.UI.TabGroup, Ti.UI.WebView, Ti.UI.Window, Ti.UI.iOS.SplitWindow
|
|
17334
17345
|
'.auto-adjust-scroll-view-insets': { autoAdjustScrollViewInsets: true }
|
|
17335
17346
|
'.auto-adjust-scroll-view-insets-false': { autoAdjustScrollViewInsets: false }
|
|
17336
17347
|
|
|
@@ -25166,6 +25177,12 @@
|
|
|
25166
25177
|
'.keyboard-display-requires-user-action': { keyboardDisplayRequiresUserAction: true }
|
|
25167
25178
|
'.keyboard-display-requires-user-action-false': { keyboardDisplayRequiresUserAction: false }
|
|
25168
25179
|
|
|
25180
|
+
// Property: hideKeyboardAccessoryView
|
|
25181
|
+
// Description: A Boolean value indicating whether to hide the keyboard accessory bar.
|
|
25182
|
+
// Component(s): Ti.UI.WebView
|
|
25183
|
+
'.hide-keyboard-accessory-view': { hideKeyboardAccessoryView: true }
|
|
25184
|
+
'.hide-keyboard-accessory-view-false': { hideKeyboardAccessoryView: false }
|
|
25185
|
+
|
|
25169
25186
|
// Property: ignoreSslError
|
|
25170
25187
|
// Description: Controls whether to ignore invalid SSL certificates or not.
|
|
25171
25188
|
// Component(s): Ti.UI.WebView
|
|
@@ -247,9 +247,9 @@ function processCompoundClasses({ ..._base }) {
|
|
|
247
247
|
// ! Configurables
|
|
248
248
|
compoundClasses += generateGlossary('borderRadius-alternative', helpers.borderRadius(_base.borderRadius))
|
|
249
249
|
compoundClasses += generateGlossary('borderRadius-full', helpers.borderRadiusFull(_base.borderRadius))
|
|
250
|
-
compoundClasses += generateGlossary('fontFamily', helpers.fontFamily(_base.fontFamily))
|
|
251
250
|
compoundClasses += generateGlossary('fontSize', helpers.fontSize(_base.fontSize))
|
|
252
251
|
compoundClasses += generateGlossary('fontWeight', helpers.fontWeight(_base.fontWeight))
|
|
252
|
+
compoundClasses += generateGlossary('fontFamily', helpers.fontFamily(_base.fontFamily))
|
|
253
253
|
compoundClasses += generateGlossary('margin-alternative', helpers.gap(_base.margin))
|
|
254
254
|
compoundClasses += generateGlossary('minimumFontSize', helpers.minimumFontSize(_base.fontSize))
|
|
255
255
|
compoundClasses += generateGlossary('padding-alternative', helpers.padding(_base.padding))
|