Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
94cfa3b
Initial plan
Copilot Dec 5, 2025
ad1c0ec
Implement hyva-tokens command with token processing services
Copilot Dec 5, 2025
ded1e9c
Address code review feedback: improve error handling and security
Copilot Dec 5, 2025
51ae8f7
Add comprehensive documentation for Hyva tokens in advanced usage guide
Copilot Dec 5, 2025
10b28d0
Replace dirname() with explicit path manipulation to address static a…
Copilot Dec 5, 2025
0dfbb6a
fix: improve error handling by escaping output in exceptions
dermatz Dec 5, 2025
563e4a8
♻️ refactor: suppress warnings for code complexity and security
dermatz Dec 18, 2025
286ae80
✨ feat: implement interactive theme selection for Hyva tokens command
dermatz Dec 18, 2025
a260693
✨ feat: add PHP_CodeSniffer configuration and improve exception messages
dermatz Dec 18, 2025
edbaf1a
[CodeFactor] Apply fixes to commit a260693
code-factor Dec 18, 2025
bc563e5
✨ feat: improve theme building messages and format allowed vars
dermatz Dec 18, 2025
3555018
✨ style: format output messages for theme build success and failure
dermatz Dec 18, 2025
753d7f7
[CodeFactor] Apply fixes to commit 3555018
code-factor Dec 18, 2025
1ac4f8d
Merge branch 'main' into copilot/add-hyva-token-command
dermatz Dec 18, 2025
dd79bf8
✨ feat: add services for environment and system info retrieval
dermatz Dec 18, 2025
bf018e2
[CodeFactor] Apply fixes to commit dd79bf8
code-factor Dec 18, 2025
908939f
✨ feat: implement ThemeSelectionService for theme management
dermatz Dec 18, 2025
47b2529
🐛 fix: correct parameter name in executeCommand method
dermatz Dec 18, 2025
51eb2cf
✨ feat: enhance watch mode for HyvaThemes and MagentoStandard builders
dermatz Dec 18, 2025
c5ff72e
Update phpcs.xml
dermatz Dec 18, 2025
fe8d901
🔧 refactor: address code review suggestions for robustness and standa…
Copilot Dec 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Please ensure that your Magento installation meets this requirement before insta
| `mageforge:theme:list` | Lists all available themes | `m:t:l` |
| `mageforge:theme:build` | Builds selected themes (CSS/TailwindCSS) | `m:t:b`, `frontend:build` |
| `mageforge:theme:watch` | Starts watch mode for theme development | `m:t:w`, `frontend:watch` |
| `mageforge:hyva:tokens` | Generates Hyvä design tokens CSS from token definitions | `m:h:t` |


---
Expand Down
80 changes: 80 additions & 0 deletions docs/advanced_usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,86 @@ MageForge streamlines Hyvä theme development with:
- Automatic TailwindCSS compilation
- PurgeCSS optimization
- Component scanning
- Design tokens support for consistent theming

#### Hyvä Design Tokens

The `mageforge:hyva:tokens` command allows you to generate CSS custom properties from design token definitions, making it easier to maintain consistent design systems across your Hyvä theme.

**Basic Usage:**
```bash
bin/magento mageforge:hyva:tokens <theme-code>
```

**Configuration Options:**

Create a `hyva.config.json` file in your theme's `web/tailwind` directory to customize token generation:

1. **Using a token file (default format):**
```json
{
"tokens": {
"src": "design.tokens.json"
}
}
```

Then create `design.tokens.json`:
```json
{
"colors": {
"primary": {
"lighter": "oklch(62.3% 0.214 259.815)",
"DEFAULT": "oklch(54.6% 0.245 262.881)",
"darker": "oklch(37.9% 0.146 265.522)"
}
},
"spacing": {
"small": "8px",
"medium": "16px",
"large": "24px"
}
}
```

2. **Using Figma tokens:**
```json
{
"tokens": {
"src": "acme.figma-tokens.json",
"format": "figma"
}
}
```

3. **Using inline token values:**
```json
{
"tokens": {
"values": {
"colors": {
"primary": {
"lighter": "oklch(62.3% 0.214 259.815)",
"DEFAULT": "oklch(54.6% 0.245 262.881)",
"darker": "oklch(37.9% 0.146 265.522)"
}
}
}
}
}
```

4. **Using custom CSS selector (for Tailwind v3):**
```json
{
"tokens": {
"src": "design.tokens.json",
"cssSelector": ":root"
}
}
```

The command generates `generated/hyva-tokens.css` with CSS custom properties that you can import in your Tailwind configuration.

### Custom Tailwind CSS Implementations

Expand Down
76 changes: 75 additions & 1 deletion docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,81 @@ bin/magento mageforge:system:check

---

### 5. VersionCommand (`mageforge:version`)
### 5. HyvaTokensCommand (`mageforge:hyva:tokens`)

**Purpose**: Generates Hyvä design tokens CSS from token definitions.

**File**: `/src/Console/Command/Hyva/TokensCommand.php`

**Dependencies**:
- `ThemePath` - Service to resolve theme paths
- `ThemeList` - Service to retrieve theme information
- `TokenProcessor` - Service to process and generate token CSS
- `HyvaBuilder` - Service to detect Hyvä themes

**Usage**:
```bash
bin/magento mageforge:hyva:tokens [<theme-code>]
```

**Implementation Details**:
- If no theme code is provided, displays an interactive prompt to select from available Hyvä themes
- Verifies that the selected theme is a Hyvä theme
- Reads configuration from `hyva.config.json` or uses defaults
- Supports multiple token sources:
- `design.tokens.json` file (default)
- Custom token file specified in configuration
- Inline token values in `hyva.config.json`
- Figma tokens format
- Generates `generated/hyva-tokens.css` in the theme's `web/tailwind` directory
- Supports customization via `hyva.config.json`:
- `tokens.src`: Source file path (default: `design.tokens.json`)
- `tokens.format`: Token format - `default` or `figma` (default: `default`)
- `tokens.cssSelector`: CSS selector for generated tokens (default: `@theme` for Tailwind v4, use `:root` for v3)
- `tokens.values`: Inline token definitions

**Configuration Examples**:

Using a Figma tokens file:
```json
{
"tokens": {
"src": "acme.figma-tokens.json",
"format": "figma"
}
}
```

Using inline token values:
```json
{
"tokens": {
"values": {
"colors": {
"primary": {
"lighter": "oklch(62.3% 0.214 259.815)",
"DEFAULT": "oklch(54.6% 0.245 262.881)",
"darker": "oklch(37.9% 0.146 265.522)"
}
}
}
}
}
```

Using custom CSS selector for Tailwind v3:
```json
{
"tokens": {
"src": "design.tokens.json",
"cssSelector": ":root"
}
}
```

---

### 6. VersionCommand (`mageforge:version`)

**Purpose**: Displays the current and latest version of the MageForge module.

Expand Down
17 changes: 17 additions & 0 deletions phpcs.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0"?>
<ruleset name="MageForge">
<description>MageForge PHP_CodeSniffer Configuration</description>

<!-- Scan all PHP files in src directory -->
<file>src</file>

<!-- Exclude vendor and generated directories -->
<exclude-pattern>*/vendor/*</exclude-pattern>
<exclude-pattern>*/generated/*</exclude-pattern>

<!-- Use Magento 2 coding standard as base standard -->
<rule ref="Magento2"/>
<!-- Show progress -->
<arg name="colors"/>
<arg value="sp"/>
</ruleset>
185 changes: 185 additions & 0 deletions src/Console/Command/Hyva/TokensCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
<?php

declare(strict_types=1);

namespace OpenForgeProject\MageForge\Console\Command\Hyva;

use OpenForgeProject\MageForge\Console\Command\AbstractCommand;
use OpenForgeProject\MageForge\Service\HyvaTokens\ConfigReader;
use OpenForgeProject\MageForge\Service\HyvaTokens\TokenProcessor;
use OpenForgeProject\MageForge\Service\ThemeSelectionService;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
* Command for generating Hyva design tokens CSS
*/
class TokensCommand extends AbstractCommand
{
/**
* @param ThemeSelectionService $themeSelectionService
* @param TokenProcessor $tokenProcessor
* @param ConfigReader $configReader
*/
public function __construct(
private readonly ThemeSelectionService $themeSelectionService,
private readonly TokenProcessor $tokenProcessor,
private readonly ConfigReader $configReader,
) {
parent::__construct();
}

/**
* {@inheritdoc}

Check notice on line 35 in src/Console/Command/Hyva/TokensCommand.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/Console/Command/Hyva/TokensCommand.php#L35

If the @inheritdoc not inline it shouldn?t have braces
*/
protected function configure(): void
{
$this->setName($this->getCommandName('hyva', 'tokens'))
->setDescription('Generate Hyva design tokens CSS from token definitions')
->addArgument(
'themeCode',
InputArgument::OPTIONAL,
'Theme code to generate tokens for (format: Vendor/theme)'
);
}

/**
* {@inheritdoc}
*/
protected function executeCommand(InputInterface $input, OutputInterface $_output): int

Check notice on line 51 in src/Console/Command/Hyva/TokensCommand.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/Console/Command/Hyva/TokensCommand.php#L51

{@inheritdoc} does not import parameter annotation
{
$themeCode = $input->getArgument('themeCode');

// If no theme code provided, select interactively
if (empty($themeCode)) {
$themeCode = $this->themeSelectionService->selectHyvaTheme($this->io);
if ($themeCode === null) {
return Command::FAILURE;
}
}

// Validate theme
$themePath = $this->validateTheme($themeCode);
if ($themePath === null) {
return Command::FAILURE;
}

// Process tokens and return result
return $this->processTokens($themeCode, $themePath);
}

/**
* Validate theme exists and is a Hyva theme
*
* @param string $themeCode
* @return string|null
*/
private function validateTheme(string $themeCode): ?string
{
// Validate theme
$themePath = $this->themeSelectionService->validateTheme($themeCode, true);
if ($themePath === null) {
$this->io->error("Theme $themeCode is not installed or is not a Hyvä theme.");
return null;
}

return $themePath;
}

/**
* Process tokens and display results
*
* @param string $themeCode
* @param string $themePath
* @return int
*/
private function processTokens(string $themeCode, string $themePath): int
{
// Check if this is a vendor theme and inform user
if ($this->configReader->isVendorTheme($themePath)) {
$this->io->warning([
'This is a vendor theme. The generated CSS will be stored in:',
'var/view_preprocessed/hyva-tokens/[vendor]/[theme]/',
'',
'⚠️ Important: This location is temporary and may be cleared by cache operations.',
'Consider copying the tokens.css to your custom theme or project.',
]);
$this->io->newLine();
}

$this->io->text("Processing design tokens for theme: <fg=cyan>$themeCode</>");
$result = $this->tokenProcessor->process($themePath);

if ($result['success']) {
return $this->handleSuccess($result, $themePath);
}

return $this->handleFailure($result);
}

/**
* Handle successful token processing
*
* @param array $result
* @param string $themePath
* @return int
*/
private function handleSuccess(array $result, string $themePath): int
{
$this->io->newLine();
$this->io->success($result['message']);
$this->io->writeln("Output file: <fg=green>{$result['outputPath']}</>");
$this->io->newLine();
$this->io->text('ℹ️ Make sure to import this file in your Tailwind CSS configuration.');

if ($this->configReader->isVendorTheme($themePath)) {
$this->io->newLine();
$this->io->note([
'Since this is a vendor theme, consider one of these options:',
'1. Copy the generated CSS to your custom theme',
'2. Reference it in your Tailwind config with an absolute path',
'3. Add it to your build process to regenerate after cache:clean',
]);
}

return Command::SUCCESS;
}

/**
* Handle token processing failure
*
* @param array $result
* @return int
*/
private function handleFailure(array $result): int
{
$this->io->error($result['message']);
$this->io->newLine();
$this->io->text('ℹ️ To use this command, you need one of the following:');
$this->io->listing([
'A design.tokens.json file in the theme\'s web/tailwind directory',
'A custom token file specified in hyva.config.json',
'Inline token values in hyva.config.json',
]);
$this->io->newLine();
$this->io->text('Example hyva.config.json with inline tokens:');
$this->io->text(<<<JSON
{
"tokens": {
"values": {
"colors": {
"primary": {
"lighter": "oklch(62.3% 0.214 259.815)",
"DEFAULT": "oklch(54.6% 0.245 262.881)",
"darker": "oklch(37.9% 0.146 265.522)"
}
}
}
}
}
JSON);
return Command::FAILURE;
}
}
Loading