Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
15 changes: 9 additions & 6 deletions .github/prompts/gemini-scheduled-triage.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
You are a GitHub Issue Triage Assistant. Your goal is to analyze a list of GitHub issues and select the most appropriate labels for each one.

## Inputs

- **Issues to Triage:** {{ ISSUES_TO_TRIAGE }}
- *Note:* This should be a JSON string. If it looks like a placeholder, run `printenv ISSUES_TO_TRIAGE`.
- _Note:_ This should be a JSON string. If it looks like a placeholder, run `printenv ISSUES_TO_TRIAGE`.
- **Available Labels:** {{ AVAILABLE_LABELS }}
- *Note:* If placeholder, run `printenv AVAILABLE_LABELS`.
- _Note:_ If placeholder, run `printenv AVAILABLE_LABELS`.

## Instructions

1. **Parse** the list of issues.
2. **Analyze** each issue to understand its intent.
3. **Select** matching labels from the "Available Labels" list for each issue.
Expand All @@ -21,10 +23,11 @@ You are a GitHub Issue Triage Assistant. Your goal is to analyze a list of GitHu
]
```
5. **Action:** Set the `TRIAGED_ISSUES` environment variable.
* Method: `run_shell_command` -> `echo "TRIAGED_ISSUES=..." >> $GITHUB_ENV`
* **Crucial:** Escape the JSON string correctly for bash.
* Example: `echo 'TRIAGED_ISSUES=[{"issue_number":1,"labels_to_set":["bug"]}]' >> $GITHUB_ENV`
- Method: `run_shell_command` -> `echo "TRIAGED_ISSUES=..." >> $GITHUB_ENV`
- **Crucial:** Escape the JSON string correctly for bash.
- Example: `echo 'TRIAGED_ISSUES=[{"issue_number":1,"labels_to_set":["bug"]}]' >> $GITHUB_ENV`

## Constraints

- Only use provided labels.
- Return valid JSON.
- Return valid JSON.
21 changes: 12 additions & 9 deletions .github/prompts/gemini-triage.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
You are a GitHub Issue Triage Assistant. Your goal is to analyze a GitHub issue and select the most appropriate labels from a predefined list.

## Inputs

The following inputs are provided. If they appear as placeholders (e.g. `{{ ... }}`), use the `run_shell_command` tool to retrieve the values from the environment variables.

- **Issue Title:** {{ ISSUE_TITLE }}
- *Fallback:* `echo "$ISSUE_TITLE"`
- _Fallback:_ `echo "$ISSUE_TITLE"`
- **Issue Body:** {{ ISSUE_BODY }}
- *Fallback:* `echo "$ISSUE_BODY"`
- _Fallback:_ `echo "$ISSUE_BODY"`
- **Available Labels:** {{ AVAILABLE_LABELS }}
- *Fallback:* `echo "$AVAILABLE_LABELS"`
- _Fallback:_ `echo "$AVAILABLE_LABELS"`

## Instructions

1. **Analyze** the issue title and body.
2. **Review** the "Available Labels" list.
3. **Select** the labels that best categorize this issue.
* If it's a bug, use `bug` (if available).
* If it's a feature request, use `enhancement` (if available).
* Do not invent new labels.
- If it's a bug, use `bug` (if available).
- If it's a feature request, use `enhancement` (if available).
- Do not invent new labels.
4. **Action:** Set the `SELECTED_LABELS` environment variable.
* Format: Comma-separated list (e.g., `bug,high-priority`).
* Method: `run_shell_command` -> `echo "SELECTED_LABELS=label1,label2" >> $GITHUB_ENV`
- Format: Comma-separated list (e.g., `bug,high-priority`).
- Method: `run_shell_command` -> `echo "SELECTED_LABELS=label1,label2" >> $GITHUB_ENV`

## Constraints
- If no labels fit well, do not set the variable.

- If no labels fit well, do not set the variable.
60 changes: 33 additions & 27 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,12 @@ const SUPPORTED_BLOCKS = [
### Animation Types (17 total)

**Entry Animations:**

- `none`, `fade-in`, `slide-in-left`, `slide-in-right`, `slide-in-up`, `slide-in-down`
- `scale-up`, `rotate-in`, `blur-in`, `rotate-3d-in`, `circle-reveal`, `curtain-reveal`

**In-and-Out Animations:**

- `fade-in-out`, `slide-up-in-out`, `scale-in-out`, `rotate-in-out`, `rotate-3d-in-out`

### Animation Timing Presets
Expand All @@ -127,20 +129,21 @@ const SUPPORTED_BLOCKS = [

Each supported block gains these attributes:

| Attribute | Type | Default | Description |
|-----------|------|---------|-------------|
| `animationType` | string | `'none'` | Selected animation type |
| `animationRange` | string | `'default'` | Timing preset |
| `animationEntryStart` | number | `20` | Custom entry start (%) |
| `animationEntryEnd` | number | `100` | Custom entry end (%) |
| `animationExitStart` | number | `0` | Custom exit start (%) |
| `animationExitEnd` | number | `100` | Custom exit end (%) |
| `parallaxEnabled` | boolean | `false` | Enable parallax effect |
| `parallaxStrength` | number | `50` | Parallax displacement strength |
| Attribute | Type | Default | Description |
| --------------------- | ------- | ----------- | ------------------------------ |
| `animationType` | string | `'none'` | Selected animation type |
| `animationRange` | string | `'default'` | Timing preset |
| `animationEntryStart` | number | `20` | Custom entry start (%) |
| `animationEntryEnd` | number | `100` | Custom entry end (%) |
| `animationExitStart` | number | `0` | Custom exit start (%) |
| `animationExitEnd` | number | `100` | Custom exit end (%) |
| `parallaxEnabled` | boolean | `false` | Enable parallax effect |
| `parallaxStrength` | number | `50` | Parallax displacement strength |

### CSS Classes & Data Attributes

**Frontend output:**

- Class: `scroll-anim-block` - Main animation class
- Class: `scroll-anim-{type}` - Specific animation type (e.g., `scroll-anim-fade-in`)
- Attribute: `data-scroll-anim="1"` - Animation marker
Expand All @@ -149,16 +152,16 @@ Each supported block gains these attributes:

## Key Files & Their Roles

| File | Purpose |
|------|---------|
| `my-scroll-block.php` | Plugin entry; enqueues assets; `render_block` filter for frontend class injection |
| `src/index.js` | Block filters; attribute registration; UI controls; markup manipulation |
| `src/style.css` | CSS scroll timeline rules for all animation types |
| `src/editor.css` | Editor UI styles (animation indicator badge) |
| `src/progress-block/` | Reading Progress Bar custom block |
| `tests/scroll-block.spec.ts` | Main e2e tests for editor and frontend |
| `tests/reduced-motion.spec.ts` | Accessibility tests for reduced motion |
| `tests/global-setup.ts` | WordPress Playground startup with plugin mounting |
| File | Purpose |
| ------------------------------ | --------------------------------------------------------------------------------- |
| `my-scroll-block.php` | Plugin entry; enqueues assets; `render_block` filter for frontend class injection |
| `src/index.js` | Block filters; attribute registration; UI controls; markup manipulation |
| `src/style.css` | CSS scroll timeline rules for all animation types |
| `src/editor.css` | Editor UI styles (animation indicator badge) |
| `src/progress-block/` | Reading Progress Bar custom block |
| `tests/scroll-block.spec.ts` | Main e2e tests for editor and frontend |
| `tests/reduced-motion.spec.ts` | Accessibility tests for reduced motion |
| `tests/global-setup.ts` | WordPress Playground startup with plugin mounting |

## Testing Architecture

Expand Down Expand Up @@ -238,27 +241,30 @@ npx playwright test -g "test-name-pattern" # Run specific test

## Debugging

| Issue | Solution |
|-------|----------|
| Editor issues | Check browser console; WordPress error logs |
| Rendering issues | Run `npm run lint:js` and `npm run typecheck` |
| Test failures | Run `npm run test:headed` or `npm run test:debug` |
| Build errors | Check `npm run build` output; verify imports |
| Port 9400 in use | Kill with `pkill -f "wp-playground"` |
| Issue | Solution |
| ---------------- | ------------------------------------------------- |
| Editor issues | Check browser console; WordPress error logs |
| Rendering issues | Run `npm run lint:js` and `npm run typecheck` |
| Test failures | Run `npm run test:headed` or `npm run test:debug` |
| Build errors | Check `npm run build` output; verify imports |
| Port 9400 in use | Kill with `pkill -f "wp-playground"` |

## CI/CD Workflows

### playwright.yml

- Runs on: push to main/master, PRs
- Runs e2e tests with Chromium
- Uploads HTML report on failure

### build-plugin.yml

- Runs on: push, PR, release, manual
- Lints JS/CSS, builds assets, creates zip
- Auto-uploads to releases on release events

### pr-preview.yml

- Generates WordPress Playground preview links for PRs

## WordPress Playground Testing
Expand Down
99 changes: 68 additions & 31 deletions my-scroll-block.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,59 +99,96 @@ function my_scroll_block_register_assets() {
return $block_content;
}
$attrs = $block['attrs'];
if ( isset( $attrs['animationType'] ) && 'none' !== $attrs['animationType'] ) {

$has_animation = isset( $attrs['animationType'] ) && 'none' !== $attrs['animationType'];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 This condition is crucial for determining whether to apply scroll animation or parallax effects. A brief comment explaining its purpose would enhance code clarity.

$parallax_enabled = isset( $attrs['parallaxEnabled'] ) && $attrs['parallaxEnabled'];

if ( $has_animation || $parallax_enabled ) {
if ( wp_style_is( 'my-scroll-block-style', 'registered' ) ) {
wp_enqueue_style( 'my-scroll-block-style' );
}
// No view script on frontend when relying on CSS scroll timelines.

// Also ensure outer wrapper receives classes and attributes if missing (covers dynamic blocks).
if ( is_string( $block_content ) && $block_content !== '' && strpos( $block_content, 'scroll-anim-block' ) === false ) {
$animation_type = sanitize_key( (string) $attrs['animationType'] );
$animation_range = isset( $attrs['animationRange'] ) ? sanitize_key( (string) $attrs['animationRange'] ) : 'default';

$add_classes = sprintf( 'scroll-anim-block scroll-anim-%s', strtolower( str_replace( ' ', '-', $animation_type ) ) );

// Build data attributes
$data_attrs = ' data-scroll-anim="1" data-anim-range="' . esc_attr( $animation_range ) . '"';

// Add custom range values if using custom range
if ( $animation_range === 'custom' ) {
if ( isset( $attrs['animationEntryStart'] ) ) {
$data_attrs .= ' data-entry-start="' . absint( $attrs['animationEntryStart'] ) . '"';
}
if ( isset( $attrs['animationEntryEnd'] ) ) {
$data_attrs .= ' data-entry-end="' . absint( $attrs['animationEntryEnd'] ) . '"';
}
// Add exit range for in-out animations
if ( strpos( $animation_type, 'in-out' ) !== false ) {
if ( isset( $attrs['animationExitStart'] ) ) {
$data_attrs .= ' data-exit-start="' . absint( $attrs['animationExitStart'] ) . '"';
$needs_injection = is_string( $block_content ) && $block_content !== '';
$missing_anim = $has_animation && strpos( $block_content, 'scroll-anim-block' ) === false;
$missing_parallax = $parallax_enabled && strpos( $block_content, 'data-parallax' ) === false;

if ( $needs_injection && ( $missing_anim || $missing_parallax ) ) {
$add_classes = '';
$data_attrs = '';
$style_attr = '';

// Handle animation classes and data attributes
if ( $has_animation && $missing_anim ) {
$animation_type = sanitize_key( (string) $attrs['animationType'] );
$animation_range = isset( $attrs['animationRange'] ) ? sanitize_key( (string) $attrs['animationRange'] ) : 'default';

$add_classes = sprintf( 'scroll-anim-block scroll-anim-%s', strtolower( str_replace( ' ', '-', $animation_type ) ) );

// Build data attributes
$data_attrs = ' data-scroll-anim="1" data-anim-range="' . esc_attr( $animation_range ) . '"';

// Add custom range values if using custom range
if ( $animation_range === 'custom' ) {
if ( isset( $attrs['animationEntryStart'] ) ) {
$data_attrs .= ' data-entry-start="' . absint( $attrs['animationEntryStart'] ) . '"';
}
if ( isset( $attrs['animationEntryEnd'] ) ) {
$data_attrs .= ' data-entry-end="' . absint( $attrs['animationEntryEnd'] ) . '"';
}
if ( isset( $attrs['animationExitEnd'] ) ) {
$data_attrs .= ' data-exit-end="' . absint( $attrs['animationExitEnd'] ) . '"';
// Add exit range for in-out animations
if ( strpos( $animation_type, 'in-out' ) !== false ) {
if ( isset( $attrs['animationExitStart'] ) ) {
$data_attrs .= ' data-exit-start="' . absint( $attrs['animationExitStart'] ) . '"';
}
if ( isset( $attrs['animationExitEnd'] ) ) {
$data_attrs .= ' data-exit-end="' . absint( $attrs['animationExitEnd'] ) . '"';
}
}
}
}

// Handle parallax data attributes and styles
if ( $parallax_enabled && $missing_parallax ) {
$parallax_strength = isset( $attrs['parallaxStrength'] ) ? absint( $attrs['parallaxStrength'] ) : 50;
$data_attrs .= ' data-parallax="1" data-parallax-strength="' . $parallax_strength . '"';
$style_attr = '--parallax-strength: ' . $parallax_strength . 'px;';
}

// Inject into first element tag.
if ( preg_match( '/^\s*<([a-zA-Z0-9:-]+)([^>]*)>/', $block_content, $m, PREG_OFFSET_CAPTURE ) ) {
$full = $m[0][0];
$attrsStr = $m[2][0];
$updated = $attrsStr;

if ( preg_match( '/\sclass\s*=\s*"([^"]*)"/i', $attrsStr, $cm ) ) {
$newClass = trim( $cm[1] . ' ' . $add_classes );
$updated = preg_replace( '/\sclass\s*=\s*"([^"]*)"/i', ' class="' . esc_attr( $newClass ) . '"', $updated, 1 );
} else {
$updated .= ' class="' . esc_attr( $add_classes ) . '"';
// Add or merge classes
if ( $add_classes ) {
if ( preg_match( '/\sclass\s*=\s*"([^"]*)"/i', $attrsStr, $cm ) ) {
$newClass = trim( $cm[1] . ' ' . $add_classes );
$updated = preg_replace( '/\sclass\s*=\s*"([^"]*)"/i', ' class="' . esc_attr( $newClass ) . '"', $updated, 1 );
} else {
$updated .= ' class="' . esc_attr( $add_classes ) . '"';
}
}

if ( strpos( $updated, 'data-scroll-anim' ) === false ) {
// Add data attributes
if ( $data_attrs && strpos( $updated, 'data-scroll-anim' ) === false && strpos( $updated, 'data-parallax' ) === false ) {
$updated .= $data_attrs;
}

$newOpen = '<' . $m[1][0] . $updated . '>';
// Add or merge style attribute for parallax
if ( $style_attr ) {
if ( preg_match( '/\sstyle\s*=\s*"([^"]*)"/i', $attrsStr, $sm ) ) {
$existing_style = rtrim( $sm[1], '; ' );
$new_style = $existing_style . '; ' . $style_attr;
$updated = preg_replace( '/\sstyle\s*=\s*"([^"]*)"/i', ' style="' . esc_attr( $new_style ) . '"', $updated, 1 );
} else {
$updated .= ' style="' . esc_attr( $style_attr ) . '"';
}
}

$newOpen = '<' . $m[1][0] . $updated . '>';
$block_content = substr_replace( $block_content, $newOpen, $m[0][1], strlen( $full ) );
}
}
Expand Down
Loading
Loading