{"id":27553012,"url":"https://github.com/maccesar/purgetss","last_synced_at":"2026-04-30T03:02:29.185Z","repository":{"id":42019418,"uuid":"279669069","full_name":"macCesar/purgeTSS","owner":"macCesar","description":"PurgeTSS is a toolkit designed to make it easier for Titanium developers to create visually attractive mobile apps. It offers features like customizable utility classes, support for icon fonts, a basic animation module, a simple grid system, and a \"shades\" command for generating custom colors.","archived":false,"fork":false,"pushed_at":"2025-06-19T21:01:22.000Z","size":58563,"stargazers_count":25,"open_issues_count":0,"forks_count":4,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-06-19T21:30:55.334Z","etag":null,"topics":["alloy","android","appcelerator","cli","ios","javascript","nodejs","purgetss","titanium","titanium-module"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/macCesar.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"macCesar"}},"created_at":"2020-07-14T18:56:34.000Z","updated_at":"2025-06-12T18:14:52.000Z","dependencies_parsed_at":"2023-10-15T18:03:58.118Z","dependency_job_id":"64761e6b-cedb-481c-a537-e230c5b7f57c","html_url":"https://github.com/macCesar/purgeTSS","commit_stats":{"total_commits":1005,"total_committers":5,"mean_commits":201.0,"dds":0.007960199004975133,"last_synced_commit":"ea5fc8928fae7b6a2d849652c5d9df3a62c26f81"},"previous_names":[],"tags_count":90,"template":false,"template_full_name":null,"purl":"pkg:github/macCesar/purgeTSS","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/macCesar%2FpurgeTSS","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/macCesar%2FpurgeTSS/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/macCesar%2FpurgeTSS/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/macCesar%2FpurgeTSS/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/macCesar","download_url":"https://codeload.github.com/macCesar/purgeTSS/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/macCesar%2FpurgeTSS/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261494591,"owners_count":23167162,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["alloy","android","appcelerator","cli","ios","javascript","nodejs","purgetss","titanium","titanium-module"],"created_at":"2025-04-19T11:42:47.379Z","updated_at":"2026-04-30T03:02:29.178Z","avatar_url":"https://github.com/macCesar.png","language":"JavaScript","funding_links":["https://github.com/sponsors/macCesar"],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://codigomovil.mx/images/logotipo-purgetss-gris.svg\" height=\"230\" width=\"230\" alt=\"PurgeCSS logo\"/\u003e\n\u003c/p\u003e\n\n\u003cdiv align=\"center\"\u003e\n\n![npm](https://img.shields.io/npm/dm/purgetss)\n![npm](https://img.shields.io/npm/v/purgetss)\n![NPM](https://img.shields.io/npm/l/purgetss)\n\n\u003c/div\u003e\n\n**PurgeTSS** is a toolkit for building mobile apps with the [Titanium framework](https://titaniumsdk.com). It gives you 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).\n\n---\n\n- 23,300+ utility classes for styling Titanium views\n- Parses XML files to generate a clean `app.tss` with only the classes your project uses\n- Customizable defaults via `config.cjs`, with JIT classes for arbitrary values\n- `brand` command for Titanium icons and branding assets, focused on the modern Titanium icon pipeline: Android adaptive icons, iOS icon variants, optional Android 12+ splash artwork, and a minimal `default.png` compatibility fallback\n- Icon font support: Font Awesome, Material Icons, Material Symbols, Framework7-Icons\n- `build-fonts` command generates `fonts.tss` with class definitions and fontFamily selectors\n- `shades` command generates color shades from any hex color\n- `semantic` command generates Titanium semantic colors (Light/Dark mode) — tonal palettes with mirror inversion, or single purpose-based colors with optional alpha\n- Animation module for 2D matrix animations on views or arrays of views\n- Grid system for aligning and distributing elements within views\n\n---\n\n## Animation Module (`purgetss.ui.js`)\n\nInstall with `purgetss module` (or `purgetss m`). This places `purgetss.ui.js` in your project's `lib` folder.\n\n### Declaring an Animation object\n\n```xml\n\u003cAnimation id=\"myAnimation\" module=\"purgetss.ui\" class=\"opacity-0 duration-300 ease-in\" /\u003e\n```\n\nYou can use any position, size, color, opacity, or transformation class from `utilities.tss`.\n\n### Available methods\n\n| Method                                    | Description                                                                                                                                                                                                                                     |\n| ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `play(views, cb)` / `toggle(views, cb)`   | Animate views from current state to the animation state. Toggles `open`/`close` on each call.                                                                                                                                                   |\n| `open(views, cb)`                         | Explicitly run the `open` state animation.                                                                                                                                                                                                      |\n| `close(views, cb)`                        | Explicitly run the `close` state animation.                                                                                                                                                                                                     |\n| `apply(views, cb)`                        | Apply properties instantly without animation.                                                                                                                                                                                                   |\n| `draggable(views)`                        | Make a view or array of views draggable inside their parent.                                                                                                                                                                                    |\n| `undraggable(views)`                      | Remove draggable behavior and clean up all listeners.                                                                                                                                                                                           |\n| `detectCollisions(views, dragCB, dropCB)` | Enable collision detection on draggable views with hover and drop callbacks.                                                                                                                                                                    |\n| `swap(view1, view2)`                      | Animate two views exchanging positions. Auto-normalizes position from margins/right/center via `view.rect`. Inherits `duration`, `delay`, `curve`; fallback: 200ms.                                                                             |\n| `sequence(views, cb)`                     | Animate views one after another. Callback fires after the last view.                                                                                                                                                                            |\n| `shake(view, intensity)`                  | Bidirectional shake animation for error feedback. Inherits `duration`, `delay`; fallback: 400ms. Default intensity: 10px.                                                                                                                       |\n| `pulse(view, count)`                      | Scale-up-and-back pulse animation. Scale from Animation object (default 1.2x). Count: number of pulses (default 1).                                                                                                                             |\n| `snapTo(view, targets)`                   | Snap a view to the nearest target by center distance. Auto-normalizes target position. Inherits `duration`, `delay`, `curve`; fallback: 200ms.                                                                                                  |\n| `reorder(views, newOrder)`                | Animate views to new positions based on index mapping. Auto-normalizes positions. Inherits `duration`, `delay`, `curve`; fallback: 200ms.                                                                                                       |\n| `transition(views, layouts)`              | Multi-view layout transitions using `Matrix2D.translate().rotate().scale()`. Layout properties: `translation`, `rotate`, `scale`, `zIndex`. Compatible with TiDesigner presets. Views without a layout entry fade out; returning views fade in. |\n\n### Callback event object\n\nAll callbacks (`play`, `open`, `close`, `apply`) receive an enriched event object:\n\n```js\n{\n  type: String,         // event type ('complete' or 'applied')\n  bubbles: Boolean,\n  cancelBubble: Boolean,\n  action: String,       // 'play' or 'apply'\n  state: String,        // 'open' or 'close'\n  id: String,           // Animation object ID\n  targetId: String,     // ID of the animated view\n  index: Number,        // position in array (0-based)\n  total: Number,        // total views in array\n  getTarget: Function   // returns the animated view object\n}\n```\n\nWhen animating an **array of views**, the callback is called once per view with the corresponding `index` and `total` values.\n\n```js\n$.myAnimation.play([$.card1, $.card2, $.card3], (e) =\u003e {\n  console.log(`Animated ${e.index + 1} of ${e.total}`) // \"Animated 1 of 3\", etc.\n  if (e.index === e.total - 1) {\n    console.log('All done!')\n  }\n})\n```\n\n### Multi-state animations\n\nUse `open`, `close`, and `complete` modifiers inside `animationProperties` to define different states:\n\n```xml\n\u003cAnimation id=\"fadeToggle\" module=\"purgetss.ui\" class=\"duration-300\"\n  animationProperties=\"{\n    open: { opacity: 1 },\n    close: { opacity: 0 }\n  }\"\n/\u003e\n```\n\n### Draggable views\n\n```js\n$.myAnimation.draggable($.myView)\n// or with constraints:\n$.myAnimation.draggable([$.card1, $.card2])\n```\n\nUse `bounds` to restrict movement, and `drag`/`drop` modifiers for drag-state animations. Use `vertical-constraint` or `horizontal-constraint` classes to limit the drag axis.\n\n### Collision detection\n\nAfter calling `draggable()`, you can enable collision detection to know when a dragged view overlaps another:\n\n```js\n$.myAnimation.draggable(views)\n$.myAnimation.detectCollisions(views, onHover, onDrop)\n```\n\n**`dragCB(source, target)`** is called during drag:\n- `target` is the view under the drag center, or `null` when leaving all targets\n- Use this to show visual feedback (highlights, borders, scaling)\n\n**`dropCB(source, target)`** is called on drop:\n- `target` is the view where the source was released\n- If no target is found, the source automatically snaps back to its original position with a 200ms animation\n\n### Swap animation\n\nAnimate two views exchanging positions:\n\n```js\n$.myAnimation.swap(view1, view2)\n```\n\n- Inherits `duration`, `delay`, and `curve` from the Animation object's classes\n- Falls back to 200ms duration, 0ms delay, and ease-in-out curve if not set\n- Handles iOS transform reset automatically\n- Temporarily raises z-index so views animate above siblings\n- Updates internal `_originLeft`/`_originTop` for subsequent drag operations\n\n### Sequence animation\n\nAnimate views one after another (unlike `play(array)` which runs them in parallel):\n\n```js\n$.fadeIn.sequence([$.title, $.subtitle, $.button], () =\u003e {\n  console.log('All views animated')\n})\n```\n\n- Each view fully completes before the next starts\n- Callback fires once after the last view\n- Respects `open`/`close` state (set once for the entire sequence)\n\n### Shake animation\n\nQuick horizontal shake for error feedback, using native `autoreverse` + `repeat` for smooth performance:\n\n```js\n$.myAnimation.shake($.loginButton)        // default intensity: 10px\n$.myAnimation.shake($.input, 6)           // subtle: 6px\n$.myAnimation.shake($.errorLabel, 20)     // strong: 20px\n```\n\n### Snap to nearest target\n\nAfter dragging, snap a view to the closest target by center-to-center distance:\n\n```js\nconst matched = $.myAnimation.snapTo(draggedView, slotViews)\nif (matched) {\n  console.log('Snapped to:', matched.id)\n}\n```\n\n### Reorder animation\n\nAnimate an array of views to new positions based on index mapping:\n\n```js\n// Reverse order: view[0] goes to position of view[2], view[2] to position of view[0]\n$.myAnimation.reorder(cardViews, [2, 1, 0])\n```\n\n- All views animate simultaneously\n- Captures positions before animating to avoid conflicts\n\n### Removing draggable behavior\n\nRemove draggable behavior and clean up all event listeners:\n\n```js\n$.myAnimation.undraggable(cardViews)\n```\n\n### Property inheritance\n\nThe `swap`, `reorder`, `snapTo`, and `shake` methods inherit animation properties from the `\u003cAnimation\u003e` object's classes. This means you can configure behavior declaratively in XML:\n\n```xml\n\u003cAnimation id=\"myAnim\" module=\"purgetss.ui\" class=\"curve-animation-ease-out delay-100 duration-150\" /\u003e\n```\n\n| Property      | `play`/`toggle`/`open`/`close`/`sequence` | `swap`/`reorder`/`snapTo` |       `shake`       |\n| ------------- | :---------------------------------------: | :-----------------------: | :-----------------: |\n| `duration`    |                     ✅                     |             ✅             |       ✅ (÷6)        |\n| `delay`       |                     ✅                     |             ✅             |          ✅          |\n| `curve`       |                     ✅                     |             ✅             | fixed `EASE_IN_OUT` |\n| `autoreverse` |                     ✅                     |             —             |    fixed `true`     |\n| `repeat`      |                     ✅                     |             —             |      fixed `3`      |\n\nFallback defaults when not set: `swap`/`reorder`/`snapTo` → 200ms; `shake` → 400ms. All animation timing is controlled declaratively via the `\u003cAnimation\u003e` object's classes.\n\n- Removes touch and orientation listeners\n- Removes views from collision detection registry\n- Cleans up internal tracking properties\n\n### Utility classes for animations\n\n| Class pattern                                       | Description                   |\n| --------------------------------------------------- | ----------------------------- |\n| `duration-{n}`                                      | Animation duration in ms      |\n| `delay-{n}`                                         | Delay before animation starts |\n| `rotate-{n}`                                        | 2D rotation in degrees        |\n| `scale-{n}`                                         | Scale factor                  |\n| `repeat-{n}`                                        | Number of repeats             |\n| `ease-in`, `ease-out`, `ease-linear`, `ease-in-out` | Timing curve                  |\n| `zoom-in-{n}`, `zoom-out-{n}`                       | Zoom animations               |\n| `drag-apply`, `drag-animate`                        | Drag interaction style        |\n| `vertical-constraint`, `horizontal-constraint`      | Constrain drag axis           |\n\n### Utility functions\n\n| Function                               | Description                                                                                              |\n| -------------------------------------- | -------------------------------------------------------------------------------------------------------- |\n| `deviceInfo()`                         | Logs detailed platform and display information to the console. Works in both Alloy and Classic projects. |\n| `saveComponent({ source, directory })` | Saves a view snapshot as PNG to the photo gallery.                                                       |\n\nSee the full documentation at [purgetss.com/docs/animation-module/introduction](https://purgetss.com/docs/animation-module/introduction).\n\n### Appearance management\n\nSwitch between Light, Dark, and System modes with automatic persistence:\n\n```js\nconst { Appearance } = require('purgetss.ui')\n\n// Call once at app startup (e.g., in index.js before opening the first window)\nAppearance.init()\n```\n\n| Method      | Description                                                  |\n| ----------- | ------------------------------------------------------------ |\n| `init()`    | Restore the saved mode from `Ti.App.Properties`              |\n| `get()`     | Returns the current mode string                              |\n| `set(mode)` | Apply and persist a mode: `'system'`, `'light'`, or `'dark'` |\n| `toggle()`  | Switch between `'light'` and `'dark'`                        |\n\nUse it from any controller to respond to user actions:\n\n```js\nconst { Appearance } = require('purgetss.ui')\n\nfunction selectDark() { Appearance.set('dark') }\nfunction selectLight() { Appearance.set('light') }\nfunction selectSystem() { Appearance.set('system') }\n```\n\nRequires `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:\n\n```bash\n# Tonal palette (11 shades with mirror-by-index Light/Dark inversion)\npurgetss semantic '#15803d' amazon\n\n# Purpose-based single colors (auto-mapped to classes in config.cjs)\npurgetss semantic --single '#F9FAFB' surfaceColor --dark '#0f172a'\npurgetss semantic --single '#111827' textColor    --dark '#f1f5f9'\npurgetss semantic --single '#000000' overlayColor --alpha 50\n```\n\nSee the [Semantic Colors guide](https://purgetss.com/docs/best-practices/semantic-colors) for the full workflow.\n\n### Default font families\n\nPurgeTSS generates `font-sans`, `font-serif`, and `font-mono` classes automatically with platform-appropriate values:\n\n| Class        | iOS              | Android      |\n| ------------ | ---------------- | ------------ |\n| `font-sans`  | `Helvetica Neue` | `sans-serif` |\n| `font-serif` | `Georgia`        | `serif`      |\n| `font-mono`  | `monospace`      | `monospace`  |\n\nOverride or add families in `config.cjs`:\n\n```js\n// theme.extend.fontFamily → adds to defaults\nextend: {\n  fontFamily: {\n    display: 'AlfaSlabOne-Regular',\n    body: 'BarlowSemiCondensed-Regular'\n  }\n}\n\n// theme.fontFamily → replaces defaults entirely\ntheme: {\n  fontFamily: {\n    sans: 'System',\n    mono: 'Courier',\n    display: 'AlfaSlabOne-Regular'\n  }\n}\n```\n\n---\n\n## Customizing default components\n\nPurgeTSS sets defaults for three components out of the box:\n\n| Component   | Default                                 |\n| ----------- | --------------------------------------- |\n| `Window`    | `backgroundColor: '#FFFFFF'`            |\n| `View`      | `width: Ti.UI.SIZE, height: Ti.UI.SIZE` |\n| `ImageView` | `hires: true` (iOS only)                |\n\nOverride or extend them in `config.cjs` with `theme.extend`:\n\n```js\nmodule.exports = {\n  theme: {\n    extend: {\n      Window: {\n        apply: 'exit-on-close-false bg-surface'\n      }\n    }\n  }\n}\n```\n\nIf an applied class sets a property that already exists in the defaults (e.g., `bg-surface` vs `backgroundColor: '#FFFFFF'`), the applied value wins. Array-type properties like `extendEdges` and `orientationModes` use bracket notation (`[ ]`) in the generated output.\n\n### Shorthand and explicit forms\n\nBoth are equivalent:\n\n```js\n// Shorthand\nWindow: { apply: 'exit-on-close-false' }\n\n// Explicit\nWindow: { default: { apply: 'exit-on-close-false' } }\n```\n\nUse the explicit form when you need platform-specific variants:\n\n```js\nButton: {\n  default: { apply: 'text-xl' },\n  ios: { apply: 'font-bold' },\n  android: { apply: 'text-2xl font-semibold', color: 'red' }\n}\n```\n\n---\n\n### Visit the official documentation site at [purgetss.com](https://purgetss.com) to learn more.\n\n## Requirements\n\n- **Titanium SDK** (Compatible with all versions; 13.1.1.GA recommended for full property support)\n- **Alloy Framework** (for most commands)\n- **Node.js 20+** (required for the CLI tool)\n\n## Recent changes\n\n### v7.8.0\n\n- **`--width \u003cn\u003e` flag for `images`.** Pin Android `mdpi` / iPhone `@1x` to a specific width in pixels (e.g. `purgetss images logo.svg --width 256`); larger scales derive at ×1.5, ×2, ×3, ×4 with height staying proportional. Recommended when the source is an SVG export from Affinity / Illustrator with a disproportionate viewBox — the legacy 4× master convention produces unpredictable sizes there, and the new flag pins the result exactly. When you pass an SVG without `--width`, `images` now prints a one-time hint suggesting the flag, then falls back to the legacy behavior.\n- **Class syntax pre-validation.** `purgetss` now halts with a structured `Class Syntax Error` block (file + line + suggested fix) when it detects known authoring mistakes in your class names: 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)`).\n- All offenders are reported in a single run, so you can fix them in one pass.\n- Generic unknown classes (typos, vendor utilities not enabled, custom classes not yet declared) are NOT flagged by the validator — they continue to flow silently into the `// Unused or unsupported classes` block in `app.tss`, exactly as in previous versions.\n- **Arbitrary-value parser no longer crashes on negative values inside parentheses.** Classes like `top-(-10)`, `mt-(-5)`, or `origin-(-10,-20)` used to trigger a `Cannot read properties of null (reading 'pop')` exception. The parser was rewritten to extract the `(...)` portion first, so a `-` inside the value never breaks the split — and the new pre-validator catches the inverted-sign form before it gets that far.\n\n### v7.7.0\n\n- `brand` now uses grouped config sections: `brand.logos`, `brand.padding`, `brand.android`, `brand.ios`, and `brand.colors`.\n- `brand` supports separate Android artwork through `brand.logos.androidLauncher` / `--icon-logo` and `brand.logos.androidSplash` / `--splash-logo`.\n- `brand` regenerates `app/assets/android/default.png` in Alloy projects, or `Resources/android/default.png` in Classic projects, so older Android splash paths still have a fallback.\n- `cleanup-legacy` no longer removes `default.png`.\n- Branding help and docs now spell out the difference between Android launcher icons, Android 12+ `splash_icon.png`, and legacy Android splash assets.\n- `--notes` is explicit that `tiapp.xml` is not auto-edited and that apps with an existing custom Android theme should merge splash snippets into that theme instead of replacing it.\n- `brand` does not try to manage older Android splash theme assets such as `background.png` or `background.9.png`; if a project still depends on them, that remains manual by design.\n\nSee the full release notes in [CHANGELOG.md](./CHANGELOG.md).\n\n## Table of Content\n\n- [Installation](https://purgetss.com/docs/installation)\n- [Commands](https://purgetss.com/docs/commands)\n- App Assets\n  - [App icons and branding](https://purgetss.com/docs/app-assets/app-icons-and-branding)\n  - [Multi-density images](https://purgetss.com/docs/app-assets/multi-density-images)\n- Customization\n  - [The Config File](https://purgetss.com/docs/customization/the-config-file)\n  - [Custom Rules](https://purgetss.com/docs/customization/custom-rules)\n  - [The `apply` Directive](https://purgetss.com/docs/customization/the-apply-directive)\n  - [The `opacity` Modifier](https://purgetss.com/docs/customization/the-opacity-modifier)\n  - [Arbitrary Values](https://purgetss.com/docs/customization/arbitrary-values)\n  - [Platform and Device Modifiers](https://purgetss.com/docs/customization/platform-and-device-modifiers)\n  - [Icon Fonts Libraries](https://purgetss.com/docs/customization/icon-fonts-libraries)\n- The UI Module\n  - [Introduction](https://purgetss.com/docs/purgetss-ui/introduction)\n  - [The `play` Method](https://purgetss.com/docs/purgetss-ui/the-play-method)\n  - [The `apply` Method](https://purgetss.com/docs/purgetss-ui/the-apply-method)\n  - [The `open` and `close` Methods](https://purgetss.com/docs/purgetss-ui/the-open-and-close-methods)\n  - [The `draggable` Method](https://purgetss.com/docs/purgetss-ui/the-draggable-method)\n  - [Complex UI Elements](https://purgetss.com/docs/purgetss-ui/complex-ui-elements)\n  - [Additional Methods](https://purgetss.com/docs/purgetss-ui/additional-methods)\n  - [Available Utilities](https://purgetss.com/docs/purgetss-ui/available-utilities)\n  - [Implementation Rules](https://purgetss.com/docs/purgetss-ui/implementation-rules)\n  - [Appearance](https://purgetss.com/docs/purgetss-ui/appearance)\n- Best Practices\n  - [Appearance Setup](https://purgetss.com/docs/best-practices/appearance-setup)\n  - [Semantic Colors](https://purgetss.com/docs/best-practices/semantic-colors)\n  - [Large Titles on iOS](https://purgetss.com/docs/best-practices/large-titles-on-ios)\n- [Grid System](https://purgetss.com/docs/grid-system)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaccesar%2Fpurgetss","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmaccesar%2Fpurgetss","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaccesar%2Fpurgetss/lists"}