armonia


Namearmonia JSON
Version 1.0.1 PyPI version JSON
download
home_pageNone
SummaryA Python library for theming facilities
upload_time2025-11-01 14:35:43
maintainerNone
docs_urlNone
authorJesús Alonso Abad
requires_python>=3.11
licenseMIT
keywords color-management colors polychromos theme theming
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Armonia

> **ἁρμονία**
>
> _Ancient Greek; noun_
>
> The principle of order and beauty through balanced relationships.
>
> A joining, joint; harmony, agreement, concord.

A Python library for elegant color theme management with dynamic computed colors and powerful transformation functions.

[![Python Version](https://img.shields.io/badge/python-3.11%2B-blue)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

## Overview

**Armonia** provides a sophisticated yet simple system for managing color themes in Python applications.

Built on top of [polychromos](https://pypi.org/project/polychromos/), it offers:

- **Centralized Theme Management**: Define all your colors in one place
- **Dynamic Computed Colors**: Colors that automatically update when base colors change
- **Color Functions**: Comprehensive transformation library (lighter, darker, mix, contrast, etc.)
- **Palette System**: Organize colors into named collections
- **Serialization Support**: Save and load themes from JSON/YAML
- **Safety First**: Recursion protection and conflict detection
- **Type-Safe**: Full type hints and mypy compatibility

## Installation

```bash
pip install armonia
```

Or using `uv`:

```bash
uv add armonia
```

## Quick Start

```python
from armonia import Theme
from armonia import colorfunctions as cf
from polychromos.color import HSLColor

# Create a theme
theme = Theme()

# Set base colors
theme.set_color("primary", HSLColor.from_hex("#2563eb"))
theme.set_color("background", HSLColor.from_hex("#ffffff"))
theme.set_color("text", HSLColor.from_hex("#1f2937"))

# Create computed colors that automatically derive from base colors
theme.set_computed_color("primary_light", cf.lighter("primary", 0.2))
theme.set_computed_color("primary_dark", cf.darker("primary", 0.2))
theme.set_computed_color("text_muted", cf.mix("text", "background", 0.4))
theme.set_computed_color("on_primary", cf.contrast("primary"))

# Get colors - they resolve automatically
print(theme.get_color("primary_light").to_css_hex())  # #6b95f1

# Change the base color - computed colors update automatically!
theme.set_color("primary", HSLColor.from_hex("#7c3aed"))
print(theme.get_color("primary_light").to_css_hex())  # Now reflects new primary color
```

## Key Features

### 1. Dynamic Color Computation

Computed colors are functions that derive their values from other colors in the theme. When you change a base color, all computed colors update automatically:

```python
# Define once
theme.set_color("brand", HSLColor.from_hex("#ff6b6b"))
theme.set_computed_color("brand_hover", cf.darker("brand", 0.1))
theme.set_computed_color("brand_subtle", cf.alpha("brand", 0.3))

# Update anywhere - computed colors follow
theme.set_color("brand", HSLColor.from_hex("#4ecdc4"))
# brand_hover and brand_subtle automatically reflect the new brand color
```

### 2. Comprehensive Color Functions

Over 40 built-in transformation functions organized by purpose:

#### Lightness & Darkness
```python
cf.lighter("color", 0.2)      # Increase lightness
cf.darker("color", 0.2)       # Decrease lightness
cf.brighten("color", 0.3)     # Significantly lighter
cf.dim("color", 0.3)          # Significantly darker
```

#### Saturation
```python
cf.saturate("color", 0.2)     # More vivid
cf.desaturate("color", 0.2)   # More gray
cf.muted("color", 0.4)        # Significantly less saturated
cf.grayscale("color")         # Complete desaturation
```

#### Mixing & Blending
```python
cf.mix("color1", "color2", 0.5)           # Blend two colors
cf.tint("color", 0.2)                     # Mix with white
cf.shade("color", 0.2)                    # Mix with black
cf.tone("color", 0.2)                     # Mix with gray
cf.softer("color", "background", 0.3)     # Shift toward background
```

#### Opacity
```python
cf.alpha("color", 0.5)        # Set opacity
cf.fade("color", 0.3)         # Fade (alias for alpha)
```

#### Advanced Transformations
```python
cf.rotate_hue("color", 180)                # Rotate hue by degrees
cf.complementary("color")                  # Opposite on color wheel
cf.invert("color")                         # Invert lightness
cf.contrast("color")                       # Choose black or white for contrast
cf.alias("color")                          # Reference another color
```

#### Scaling Functions
```python
# Multiply mode (direct multiplication)
cf.scale_lightness("color", 0.7)          # new = old * 0.7
cf.scale_saturation("color", 0.5)         # new = old * 0.5

# Screen mode (gentler, preserves more original color)
cf.screen_lightness("color", 0.6)         # new = 1 - (1-old) * 0.6
cf.screen_saturation("color", 0.4)        # new = 1 - (1-old) * 0.4
```

#### Multi-Step Transformations
```python
# Chain multiple transformations
theme.set_computed_color(
    "accent_complex",
    cf.multi(
        "accent",
        lambda c: c.delta(0, 0, 0.1),    # Lighter
        lambda c: c.delta(0, -0.2, 0),   # Less saturated
    )
)
```

### 3. Color Palettes

Organize related colors into named palettes:

```python
# Define a palette
theme.set_palette("primary_scale", [
    "primary_dark",
    "primary",
    "primary_light",
    "primary_bright"
])

# Get all colors in the palette
colors = theme.get_palette("primary_scale")  # Returns List[HSLColor]

# Use for UI scales, gradients, etc.
theme.set_palette("grays", ["gray_900", "gray_700", "gray_500", "gray_300", "gray_100"])
```

### 4. Get All Colors

Retrieve and sort all theme colors:

```python
# Get all colors sorted by name (alphabetically)
colors = theme.get_all_colors(sort_by="name")

# Sort by hue (color wheel order)
colors = theme.get_all_colors(sort_by="hue")

# Sort by saturation (most vivid to most muted)
colors = theme.get_all_colors(sort_by="saturation", reverse=True)

# Sort by lightness (dark to light)
colors = theme.get_all_colors(sort_by="lightness")

# Each entry includes name, color, and source
for entry in colors:
    print(f"{entry.name}: {entry.color.to_css_hex()} ({entry.source})")
    # Example: "primary: #2563eb (manual)"
    # Example: "primary_light: #6b95f1 (computed)"
```

### 5. Flexible Color Resolution

The `get_color()` method resolves colors with a smart fallback chain:

```python
# 1. Theme colors (highest priority)
theme.set_color("brand", HSLColor.from_hex("#ff6b6b"))
theme.get_color("brand")

# 2. Computed colors
theme.set_computed_color("brand_light", cf.lighter("brand"))
theme.get_color("brand_light")

# 3. Web colors (CSS/HTML standard colors)
theme.get_color("tomato")      # Falls back to web color
theme.get_color("skyblue")

# 4. Hex colors (direct parsing)
theme.get_color("#3498db")     # Parses as hex
```

### 6. Serialization Support

Save and load themes from dictionaries (compatible with JSON/YAML):

```python
# Export theme to dictionary
theme_dict = {
    "colors": {
        "primary": "#2563eb",
        "secondary": "#7c3aed"
    },
    "computed_colors": {
        "primary_light": {
            "function": "lighter",
            "args": ["primary", 0.15]
        }
    },
    "palettes": {
        "primary_scale": ["primary_dark", "primary", "primary_light"]
    }
}

# Load from dictionary
theme = Theme.from_dict(theme_dict)

# Or load from JSON
import json

with open("theme.json", "r") as f:
    theme = Theme.from_dict(json.load(f))
```

### 7. Safety & Validation

Armonia protects against common errors:

```python
# Prevents naming conflicts
theme.set_color("red", ...)          # Error: 'red' is a web color
theme.set_color("primary", ...)
theme.set_computed_color("primary", ...) # Error: already exists as manual color

# Detects circular dependencies
theme.set_computed_color("a", cf.lighter("b"))
theme.set_computed_color("b", cf.darker("a"))
theme.get_color("a")  # Raises ColorRecursionError

# Clear error messages
theme.get_color("nonexistent")  # ColorNotFoundError with helpful message
```

## Complete Example

Here's a complete example of a modern design system:

```python
from armonia import Theme
from armonia import colorfunctions as cf
from polychromos.color import HSLColor

# Create theme
theme = Theme()

# Base colors
theme.set_color("primary", HSLColor.from_hex("#2563eb"))
theme.set_color("secondary", HSLColor.from_hex("#7c3aed"))
theme.set_color("accent", HSLColor.from_hex("#f59e0b"))
theme.set_color("background", HSLColor.from_hex("#ffffff"))
theme.set_color("surface", HSLColor.from_hex("#f3f4f6"))
theme.set_color("text", HSLColor.from_hex("#1f2937"))

# Primary variations
theme.set_computed_color("primary_light", cf.lighter("primary", 0.15))
theme.set_computed_color("primary_dark", cf.darker("primary", 0.15))
theme.set_computed_color("primary_muted", cf.muted("primary", 0.4))
theme.set_computed_color("primary_vivid", cf.saturate("primary", 0.2))

# Semantic colors
theme.set_computed_color("on_primary", cf.contrast("primary"))
theme.set_computed_color("on_secondary", cf.contrast("secondary"))
theme.set_computed_color("on_accent", cf.contrast("accent"))

# Surface variations
theme.set_computed_color("surface_light", cf.lighter("surface", 0.05))
theme.set_computed_color("surface_dark", cf.darker("surface", 0.05))

# Text hierarchy
theme.set_computed_color("text_muted", cf.mix("text", "background", 0.4))
theme.set_computed_color("text_subtle", cf.alpha("text", 0.6))

# Define palettes
theme.set_palette("primary_scale", [
    "primary_dark",
    "primary",
    "primary_light",
    "primary_vivid"
])

theme.set_palette("surfaces", [
    "background",
    "surface",
    "surface_light",
    "surface_dark"
])

theme.set_palette("text_hierarchy", [
    "text",
    "text_muted",
    "text_subtle"
])

# Use colors
print(f"Primary: {theme.get_color('primary').to_css_hex()}")
print(f"Primary Light: {theme.get_color('primary_light').to_css_hex()}")
print(f"Text on Primary: {theme.get_color('on_primary').to_css_hex()}")

# Get a palette
primary_colors = theme.get_palette("primary_scale")
for i, color in enumerate(primary_colors):
    print(f"  {i}: {color.to_css_hex()}")
```

## Integration Examples

### Flask/Django (CSS Custom Properties)

```python
from armonia import Theme
from polychromos.color import HSLColor

theme = Theme()
# ... setup theme ...

def generate_css():
    """Generate CSS custom properties from theme."""
    css_vars = [":root {"]

    for entry in theme.get_all_colors():
        css_name = entry.name.replace("_", "-")
        css_value = entry.color.to_css_hex()
        css_vars.append(f"  --color-{css_name}: {css_value};")

    css_vars.append("}")
    return "\n".join(css_vars)

# In your Flask/Django view
@app.route('/theme.css')
def theme_css():
    return generate_css(), 200, {'Content-Type': 'text/css'}
```

### TailwindCSS Integration

```python
import json

def generate_tailwind_colors(theme):
    """Generate Tailwind color configuration."""
    colors = {}
    for entry in theme.get_all_colors():
        colors[entry.name] = entry.color.to_css_hex()

    config = {
        "theme": {
            "extend": {
                "colors": colors
            }
        }
    }

    with open("tailwind.theme.json", "w") as f:
        json.dump(config, f, indent=2)
```

### Terminal/CLI Applications

```python
from armonia import Theme
from polychromos.color import HSLColor

theme = Theme()
# ... setup theme ...

# Get ANSI color codes for terminal output
def color_text(text, color_name):
    color = theme.get_color(color_name)
    r, g, b = color.rgb
    return f"\033[38;2;{r};{g};{b}m{text}\033[0m"

print(color_text("Success!", "success"))
print(color_text("Warning!", "warning"))
```

## Live Example

Check out the interactive example in `examples/color-showcase.py`:

```bash
cd examples
uv run color-showcase.py
```

Then open http://localhost:5000 to see a live demonstration with:
- Interactive color pickers
- Real-time computed color updates
- Light/dark theme switching
- All colors panel with sorting options

## Development

This project uses `uv` for dependency management.

### Setup

```bash
# Clone the repository
git clone https://gitlab.com/Kencho1/armonia.git
cd armonia

# Install dependencies
uv sync

# Install with test dependencies
uv sync --extra test
```

### Testing

```bash
# Run tests
uv run pytest

# Run with coverage
uv run pytest --cov=armonia

# Type checking
uv run mypy armonia

# Linting
uv run ruff check armonia
```

## License

MIT License - see [LICENSE](LICENSE) file for details.

## Links

- **Repository**: https://gitlab.com/Kencho1/armonia
- **Issues**: https://gitlab.com/Kencho1/armonia/-/issues
- **Changelog**: [CHANGELOG.md](CHANGELOG.md)

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "armonia",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.11",
    "maintainer_email": null,
    "keywords": "color-management, colors, polychromos, theme, theming",
    "author": "Jes\u00fas Alonso Abad",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/32/05/5a6ae8958a11965ed1c5e576d6d3278db3d786585c4e740550d6e1bd4bdb/armonia-1.0.1.tar.gz",
    "platform": null,
    "description": "# Armonia\n\n> **\u1f01\u03c1\u03bc\u03bf\u03bd\u03af\u03b1**\n>\n> _Ancient Greek; noun_\n>\n> The principle of order and beauty through balanced relationships.\n>\n> A joining, joint; harmony, agreement, concord.\n\nA Python library for elegant color theme management with dynamic computed colors and powerful transformation functions.\n\n[![Python Version](https://img.shields.io/badge/python-3.11%2B-blue)](https://www.python.org/downloads/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n\n## Overview\n\n**Armonia** provides a sophisticated yet simple system for managing color themes in Python applications.\n\nBuilt on top of [polychromos](https://pypi.org/project/polychromos/), it offers:\n\n- **Centralized Theme Management**: Define all your colors in one place\n- **Dynamic Computed Colors**: Colors that automatically update when base colors change\n- **Color Functions**: Comprehensive transformation library (lighter, darker, mix, contrast, etc.)\n- **Palette System**: Organize colors into named collections\n- **Serialization Support**: Save and load themes from JSON/YAML\n- **Safety First**: Recursion protection and conflict detection\n- **Type-Safe**: Full type hints and mypy compatibility\n\n## Installation\n\n```bash\npip install armonia\n```\n\nOr using `uv`:\n\n```bash\nuv add armonia\n```\n\n## Quick Start\n\n```python\nfrom armonia import Theme\nfrom armonia import colorfunctions as cf\nfrom polychromos.color import HSLColor\n\n# Create a theme\ntheme = Theme()\n\n# Set base colors\ntheme.set_color(\"primary\", HSLColor.from_hex(\"#2563eb\"))\ntheme.set_color(\"background\", HSLColor.from_hex(\"#ffffff\"))\ntheme.set_color(\"text\", HSLColor.from_hex(\"#1f2937\"))\n\n# Create computed colors that automatically derive from base colors\ntheme.set_computed_color(\"primary_light\", cf.lighter(\"primary\", 0.2))\ntheme.set_computed_color(\"primary_dark\", cf.darker(\"primary\", 0.2))\ntheme.set_computed_color(\"text_muted\", cf.mix(\"text\", \"background\", 0.4))\ntheme.set_computed_color(\"on_primary\", cf.contrast(\"primary\"))\n\n# Get colors - they resolve automatically\nprint(theme.get_color(\"primary_light\").to_css_hex())  # #6b95f1\n\n# Change the base color - computed colors update automatically!\ntheme.set_color(\"primary\", HSLColor.from_hex(\"#7c3aed\"))\nprint(theme.get_color(\"primary_light\").to_css_hex())  # Now reflects new primary color\n```\n\n## Key Features\n\n### 1. Dynamic Color Computation\n\nComputed colors are functions that derive their values from other colors in the theme. When you change a base color, all computed colors update automatically:\n\n```python\n# Define once\ntheme.set_color(\"brand\", HSLColor.from_hex(\"#ff6b6b\"))\ntheme.set_computed_color(\"brand_hover\", cf.darker(\"brand\", 0.1))\ntheme.set_computed_color(\"brand_subtle\", cf.alpha(\"brand\", 0.3))\n\n# Update anywhere - computed colors follow\ntheme.set_color(\"brand\", HSLColor.from_hex(\"#4ecdc4\"))\n# brand_hover and brand_subtle automatically reflect the new brand color\n```\n\n### 2. Comprehensive Color Functions\n\nOver 40 built-in transformation functions organized by purpose:\n\n#### Lightness & Darkness\n```python\ncf.lighter(\"color\", 0.2)      # Increase lightness\ncf.darker(\"color\", 0.2)       # Decrease lightness\ncf.brighten(\"color\", 0.3)     # Significantly lighter\ncf.dim(\"color\", 0.3)          # Significantly darker\n```\n\n#### Saturation\n```python\ncf.saturate(\"color\", 0.2)     # More vivid\ncf.desaturate(\"color\", 0.2)   # More gray\ncf.muted(\"color\", 0.4)        # Significantly less saturated\ncf.grayscale(\"color\")         # Complete desaturation\n```\n\n#### Mixing & Blending\n```python\ncf.mix(\"color1\", \"color2\", 0.5)           # Blend two colors\ncf.tint(\"color\", 0.2)                     # Mix with white\ncf.shade(\"color\", 0.2)                    # Mix with black\ncf.tone(\"color\", 0.2)                     # Mix with gray\ncf.softer(\"color\", \"background\", 0.3)     # Shift toward background\n```\n\n#### Opacity\n```python\ncf.alpha(\"color\", 0.5)        # Set opacity\ncf.fade(\"color\", 0.3)         # Fade (alias for alpha)\n```\n\n#### Advanced Transformations\n```python\ncf.rotate_hue(\"color\", 180)                # Rotate hue by degrees\ncf.complementary(\"color\")                  # Opposite on color wheel\ncf.invert(\"color\")                         # Invert lightness\ncf.contrast(\"color\")                       # Choose black or white for contrast\ncf.alias(\"color\")                          # Reference another color\n```\n\n#### Scaling Functions\n```python\n# Multiply mode (direct multiplication)\ncf.scale_lightness(\"color\", 0.7)          # new = old * 0.7\ncf.scale_saturation(\"color\", 0.5)         # new = old * 0.5\n\n# Screen mode (gentler, preserves more original color)\ncf.screen_lightness(\"color\", 0.6)         # new = 1 - (1-old) * 0.6\ncf.screen_saturation(\"color\", 0.4)        # new = 1 - (1-old) * 0.4\n```\n\n#### Multi-Step Transformations\n```python\n# Chain multiple transformations\ntheme.set_computed_color(\n    \"accent_complex\",\n    cf.multi(\n        \"accent\",\n        lambda c: c.delta(0, 0, 0.1),    # Lighter\n        lambda c: c.delta(0, -0.2, 0),   # Less saturated\n    )\n)\n```\n\n### 3. Color Palettes\n\nOrganize related colors into named palettes:\n\n```python\n# Define a palette\ntheme.set_palette(\"primary_scale\", [\n    \"primary_dark\",\n    \"primary\",\n    \"primary_light\",\n    \"primary_bright\"\n])\n\n# Get all colors in the palette\ncolors = theme.get_palette(\"primary_scale\")  # Returns List[HSLColor]\n\n# Use for UI scales, gradients, etc.\ntheme.set_palette(\"grays\", [\"gray_900\", \"gray_700\", \"gray_500\", \"gray_300\", \"gray_100\"])\n```\n\n### 4. Get All Colors\n\nRetrieve and sort all theme colors:\n\n```python\n# Get all colors sorted by name (alphabetically)\ncolors = theme.get_all_colors(sort_by=\"name\")\n\n# Sort by hue (color wheel order)\ncolors = theme.get_all_colors(sort_by=\"hue\")\n\n# Sort by saturation (most vivid to most muted)\ncolors = theme.get_all_colors(sort_by=\"saturation\", reverse=True)\n\n# Sort by lightness (dark to light)\ncolors = theme.get_all_colors(sort_by=\"lightness\")\n\n# Each entry includes name, color, and source\nfor entry in colors:\n    print(f\"{entry.name}: {entry.color.to_css_hex()} ({entry.source})\")\n    # Example: \"primary: #2563eb (manual)\"\n    # Example: \"primary_light: #6b95f1 (computed)\"\n```\n\n### 5. Flexible Color Resolution\n\nThe `get_color()` method resolves colors with a smart fallback chain:\n\n```python\n# 1. Theme colors (highest priority)\ntheme.set_color(\"brand\", HSLColor.from_hex(\"#ff6b6b\"))\ntheme.get_color(\"brand\")\n\n# 2. Computed colors\ntheme.set_computed_color(\"brand_light\", cf.lighter(\"brand\"))\ntheme.get_color(\"brand_light\")\n\n# 3. Web colors (CSS/HTML standard colors)\ntheme.get_color(\"tomato\")      # Falls back to web color\ntheme.get_color(\"skyblue\")\n\n# 4. Hex colors (direct parsing)\ntheme.get_color(\"#3498db\")     # Parses as hex\n```\n\n### 6. Serialization Support\n\nSave and load themes from dictionaries (compatible with JSON/YAML):\n\n```python\n# Export theme to dictionary\ntheme_dict = {\n    \"colors\": {\n        \"primary\": \"#2563eb\",\n        \"secondary\": \"#7c3aed\"\n    },\n    \"computed_colors\": {\n        \"primary_light\": {\n            \"function\": \"lighter\",\n            \"args\": [\"primary\", 0.15]\n        }\n    },\n    \"palettes\": {\n        \"primary_scale\": [\"primary_dark\", \"primary\", \"primary_light\"]\n    }\n}\n\n# Load from dictionary\ntheme = Theme.from_dict(theme_dict)\n\n# Or load from JSON\nimport json\n\nwith open(\"theme.json\", \"r\") as f:\n    theme = Theme.from_dict(json.load(f))\n```\n\n### 7. Safety & Validation\n\nArmonia protects against common errors:\n\n```python\n# Prevents naming conflicts\ntheme.set_color(\"red\", ...)          # Error: 'red' is a web color\ntheme.set_color(\"primary\", ...)\ntheme.set_computed_color(\"primary\", ...) # Error: already exists as manual color\n\n# Detects circular dependencies\ntheme.set_computed_color(\"a\", cf.lighter(\"b\"))\ntheme.set_computed_color(\"b\", cf.darker(\"a\"))\ntheme.get_color(\"a\")  # Raises ColorRecursionError\n\n# Clear error messages\ntheme.get_color(\"nonexistent\")  # ColorNotFoundError with helpful message\n```\n\n## Complete Example\n\nHere's a complete example of a modern design system:\n\n```python\nfrom armonia import Theme\nfrom armonia import colorfunctions as cf\nfrom polychromos.color import HSLColor\n\n# Create theme\ntheme = Theme()\n\n# Base colors\ntheme.set_color(\"primary\", HSLColor.from_hex(\"#2563eb\"))\ntheme.set_color(\"secondary\", HSLColor.from_hex(\"#7c3aed\"))\ntheme.set_color(\"accent\", HSLColor.from_hex(\"#f59e0b\"))\ntheme.set_color(\"background\", HSLColor.from_hex(\"#ffffff\"))\ntheme.set_color(\"surface\", HSLColor.from_hex(\"#f3f4f6\"))\ntheme.set_color(\"text\", HSLColor.from_hex(\"#1f2937\"))\n\n# Primary variations\ntheme.set_computed_color(\"primary_light\", cf.lighter(\"primary\", 0.15))\ntheme.set_computed_color(\"primary_dark\", cf.darker(\"primary\", 0.15))\ntheme.set_computed_color(\"primary_muted\", cf.muted(\"primary\", 0.4))\ntheme.set_computed_color(\"primary_vivid\", cf.saturate(\"primary\", 0.2))\n\n# Semantic colors\ntheme.set_computed_color(\"on_primary\", cf.contrast(\"primary\"))\ntheme.set_computed_color(\"on_secondary\", cf.contrast(\"secondary\"))\ntheme.set_computed_color(\"on_accent\", cf.contrast(\"accent\"))\n\n# Surface variations\ntheme.set_computed_color(\"surface_light\", cf.lighter(\"surface\", 0.05))\ntheme.set_computed_color(\"surface_dark\", cf.darker(\"surface\", 0.05))\n\n# Text hierarchy\ntheme.set_computed_color(\"text_muted\", cf.mix(\"text\", \"background\", 0.4))\ntheme.set_computed_color(\"text_subtle\", cf.alpha(\"text\", 0.6))\n\n# Define palettes\ntheme.set_palette(\"primary_scale\", [\n    \"primary_dark\",\n    \"primary\",\n    \"primary_light\",\n    \"primary_vivid\"\n])\n\ntheme.set_palette(\"surfaces\", [\n    \"background\",\n    \"surface\",\n    \"surface_light\",\n    \"surface_dark\"\n])\n\ntheme.set_palette(\"text_hierarchy\", [\n    \"text\",\n    \"text_muted\",\n    \"text_subtle\"\n])\n\n# Use colors\nprint(f\"Primary: {theme.get_color('primary').to_css_hex()}\")\nprint(f\"Primary Light: {theme.get_color('primary_light').to_css_hex()}\")\nprint(f\"Text on Primary: {theme.get_color('on_primary').to_css_hex()}\")\n\n# Get a palette\nprimary_colors = theme.get_palette(\"primary_scale\")\nfor i, color in enumerate(primary_colors):\n    print(f\"  {i}: {color.to_css_hex()}\")\n```\n\n## Integration Examples\n\n### Flask/Django (CSS Custom Properties)\n\n```python\nfrom armonia import Theme\nfrom polychromos.color import HSLColor\n\ntheme = Theme()\n# ... setup theme ...\n\ndef generate_css():\n    \"\"\"Generate CSS custom properties from theme.\"\"\"\n    css_vars = [\":root {\"]\n\n    for entry in theme.get_all_colors():\n        css_name = entry.name.replace(\"_\", \"-\")\n        css_value = entry.color.to_css_hex()\n        css_vars.append(f\"  --color-{css_name}: {css_value};\")\n\n    css_vars.append(\"}\")\n    return \"\\n\".join(css_vars)\n\n# In your Flask/Django view\n@app.route('/theme.css')\ndef theme_css():\n    return generate_css(), 200, {'Content-Type': 'text/css'}\n```\n\n### TailwindCSS Integration\n\n```python\nimport json\n\ndef generate_tailwind_colors(theme):\n    \"\"\"Generate Tailwind color configuration.\"\"\"\n    colors = {}\n    for entry in theme.get_all_colors():\n        colors[entry.name] = entry.color.to_css_hex()\n\n    config = {\n        \"theme\": {\n            \"extend\": {\n                \"colors\": colors\n            }\n        }\n    }\n\n    with open(\"tailwind.theme.json\", \"w\") as f:\n        json.dump(config, f, indent=2)\n```\n\n### Terminal/CLI Applications\n\n```python\nfrom armonia import Theme\nfrom polychromos.color import HSLColor\n\ntheme = Theme()\n# ... setup theme ...\n\n# Get ANSI color codes for terminal output\ndef color_text(text, color_name):\n    color = theme.get_color(color_name)\n    r, g, b = color.rgb\n    return f\"\\033[38;2;{r};{g};{b}m{text}\\033[0m\"\n\nprint(color_text(\"Success!\", \"success\"))\nprint(color_text(\"Warning!\", \"warning\"))\n```\n\n## Live Example\n\nCheck out the interactive example in `examples/color-showcase.py`:\n\n```bash\ncd examples\nuv run color-showcase.py\n```\n\nThen open http://localhost:5000 to see a live demonstration with:\n- Interactive color pickers\n- Real-time computed color updates\n- Light/dark theme switching\n- All colors panel with sorting options\n\n## Development\n\nThis project uses `uv` for dependency management.\n\n### Setup\n\n```bash\n# Clone the repository\ngit clone https://gitlab.com/Kencho1/armonia.git\ncd armonia\n\n# Install dependencies\nuv sync\n\n# Install with test dependencies\nuv sync --extra test\n```\n\n### Testing\n\n```bash\n# Run tests\nuv run pytest\n\n# Run with coverage\nuv run pytest --cov=armonia\n\n# Type checking\nuv run mypy armonia\n\n# Linting\nuv run ruff check armonia\n```\n\n## License\n\nMIT License - see [LICENSE](LICENSE) file for details.\n\n## Links\n\n- **Repository**: https://gitlab.com/Kencho1/armonia\n- **Issues**: https://gitlab.com/Kencho1/armonia/-/issues\n- **Changelog**: [CHANGELOG.md](CHANGELOG.md)\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A Python library for theming facilities",
    "version": "1.0.1",
    "project_urls": {
        "Homepage": "https://gitlab.com/Kencho1/armonia",
        "Issues": "https://gitlab.com/Kencho1/armonia/-/issues",
        "Repository": "https://gitlab.com/Kencho1/armonia.git"
    },
    "split_keywords": [
        "color-management",
        " colors",
        " polychromos",
        " theme",
        " theming"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "d5d6cf55e9486fa0c98f7386652b8ebc64c3a54bd1843527d56c3f243b6c8365",
                "md5": "949ca11c9de5fca0aee725c8aab1db7f",
                "sha256": "2e6cd932ae5805c7cc8a0a39fdea4e3b7f36fc8b57db7cc9c8917f4335063b70"
            },
            "downloads": -1,
            "filename": "armonia-1.0.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "949ca11c9de5fca0aee725c8aab1db7f",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.11",
            "size": 15611,
            "upload_time": "2025-11-01T14:35:42",
            "upload_time_iso_8601": "2025-11-01T14:35:42.161697Z",
            "url": "https://files.pythonhosted.org/packages/d5/d6/cf55e9486fa0c98f7386652b8ebc64c3a54bd1843527d56c3f243b6c8365/armonia-1.0.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "32055a6ae8958a11965ed1c5e576d6d3278db3d786585c4e740550d6e1bd4bdb",
                "md5": "2c64b60e6ec320e314d3b8d1046fcac8",
                "sha256": "2c95a5be793c63e30d952abbbffbb33fe626d3539f41a137818b0083c9a8c820"
            },
            "downloads": -1,
            "filename": "armonia-1.0.1.tar.gz",
            "has_sig": false,
            "md5_digest": "2c64b60e6ec320e314d3b8d1046fcac8",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.11",
            "size": 13332,
            "upload_time": "2025-11-01T14:35:43",
            "upload_time_iso_8601": "2025-11-01T14:35:43.002894Z",
            "url": "https://files.pythonhosted.org/packages/32/05/5a6ae8958a11965ed1c5e576d6d3278db3d786585c4e740550d6e1bd4bdb/armonia-1.0.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-11-01 14:35:43",
    "github": false,
    "gitlab": true,
    "bitbucket": false,
    "codeberg": false,
    "gitlab_user": "Kencho1",
    "gitlab_project": "armonia",
    "lcname": "armonia"
}
        
Elapsed time: 4.66890s