From 684fd0de7784b1b9060e97871c70cc20651f5ab2 Mon Sep 17 00:00:00 2001 From: Zhongwei Li Date: Sun, 30 Nov 2025 08:45:16 +0800 Subject: [PATCH] Initial commit --- .claude-plugin/plugin.json | 11 + README.md | 3 + SKILL.md | 430 +++++++++++++ assets/theme-template/README.md | 63 ++ assets/theme-template/THEMENAME.info.yml | 40 ++ assets/theme-template/THEMENAME.libraries.yml | 19 + assets/theme-template/THEMENAME.theme | 39 ++ assets/theme-template/css/base/reset.css | 26 + assets/theme-template/js/custom.js | 16 + .../theme-template/templates/page.html.twig | 57 ++ plugin.lock.json | 77 +++ references/theming.md | 563 ++++++++++++++++++ 12 files changed, 1344 insertions(+) create mode 100644 .claude-plugin/plugin.json create mode 100644 README.md create mode 100644 SKILL.md create mode 100644 assets/theme-template/README.md create mode 100644 assets/theme-template/THEMENAME.info.yml create mode 100644 assets/theme-template/THEMENAME.libraries.yml create mode 100644 assets/theme-template/THEMENAME.theme create mode 100644 assets/theme-template/css/base/reset.css create mode 100644 assets/theme-template/js/custom.js create mode 100644 assets/theme-template/templates/page.html.twig create mode 100644 plugin.lock.json create mode 100644 references/theming.md diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000..2d07fd6 --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,11 @@ +{ + "name": "drupal-frontend", + "description": "Drupal Front End Specialist skill for theme development, Twig templates, and rendering system (Drupal 8-11+). Use when working with Drupal themes, Twig syntax, preprocessing, CSS/JS libraries, or template suggestions.", + "version": "1.0.0", + "author": { + "name": "Drupal Skills Team" + }, + "skills": [ + "./" + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..c2de937 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# drupal-frontend + +Drupal Front End Specialist skill for theme development, Twig templates, and rendering system (Drupal 8-11+). Use when working with Drupal themes, Twig syntax, preprocessing, CSS/JS libraries, or template suggestions. diff --git a/SKILL.md b/SKILL.md new file mode 100644 index 0000000..533b026 --- /dev/null +++ b/SKILL.md @@ -0,0 +1,430 @@ +--- +name: drupal-frontend +description: Drupal Front End Specialist skill for theme development, Twig templates, and rendering system (Drupal 8-11+). Use when working with Drupal themes, Twig syntax, preprocessing, CSS/JS libraries, or template suggestions. +--- + +# Drupal Front End Development + +## Overview + +Enable expert-level Drupal front end development capabilities. Provide comprehensive guidance for theme development, Twig templating, preprocessing, responsive design, and asset management for Drupal 8, 9, 10, and 11+. + +## When to Use This Skill + +Invoke this skill when working with: +- **Theme development**: Creating or customizing Drupal themes +- **Twig templates**: Writing or modifying .twig template files +- **Preprocessing**: Implementing preprocess functions for templates +- **Template suggestions**: Adding custom template naming patterns +- **CSS/JS libraries**: Managing theme assets and dependencies +- **Responsive design**: Implementing breakpoints and mobile-first design +- **Rendering system**: Understanding Drupal's rendering pipeline +- **Theme hooks**: Implementing theme-related hooks and alterations + +## Core Capabilities + +### 1. Theme Development + +Build complete, standards-compliant Drupal themes with proper structure: + +**Quick start workflow:** +1. Use theme template from `assets/theme-template/` as starting point +2. Replace `THEMENAME` with your theme's machine name +3. Replace `THEMELABEL` with human-readable name +4. Customize templates, CSS, JS, and libraries +5. Enable theme and configure via Appearance UI + +**Theme components:** +- `.info.yml` - Theme metadata and configuration +- `.libraries.yml` - CSS/JS library definitions +- `.theme` - Preprocess functions and theme logic +- `.breakpoints.yml` - Responsive breakpoints +- `templates/` - Twig template files +- `css/` - Stylesheets +- `js/` - JavaScript files + +**Reference documentation:** +- `references/theming.md` - Complete theming guide with examples + +### 2. Twig Template System + +Master Twig syntax and Drupal-specific extensions: + +**Twig fundamentals:** +- `{{ variable }}` - Print variables +- `{% if/for/set %}` - Control structures and logic +- `{# comment #}` - Comments and documentation +- `{{ var|filter }}` - Apply filters to variables +- `{% extends %}` - Template inheritance +- `{% block %}` - Define overridable sections + +**Drupal-specific Twig:** +- `{{ 'Text'|t }}` - Translate strings +- `{{ attach_library('theme/library') }}` - Load CSS/JS +- `{{ url('route.name') }}` - Generate URLs +- `{{ path('route.name') }}` - Generate paths +- `{{ file_url('public://image.jpg') }}` - File URLs +- `{{ content|without('field') }}` - Exclude fields + +**Common templates:** +- `page.html.twig` - Page layout structure +- `node.html.twig` - Node display +- `block.html.twig` - Block rendering +- `field.html.twig` - Field output +- `views-view.html.twig` - Views output + +### 3. Preprocessing Functions + +Modify template variables before rendering: + +**Preprocess pattern:** +```php +function THEMENAME_preprocess_HOOK(&$variables) { + // Add or modify variables + // Access entities, services, configuration + // Prepare data for templates +} +``` + +**Common preprocess hooks:** +- `hook_preprocess_page()` - Page-level variables +- `hook_preprocess_node()` - Node-specific data +- `hook_preprocess_block()` - Block modifications +- `hook_preprocess_field()` - Field alterations +- `hook_preprocess_html()` - HTML document + +**Best practices:** +- Keep logic in preprocess, markup in templates +- Use dependency injection when possible +- Cache properly with cache contexts/tags +- Document complex preprocessing + +### 4. Template Suggestions + +Provide specific templates for different contexts: + +**Suggestion patterns:** +``` +page--front.html.twig # Homepage +page--node--{nid}.html.twig # Specific node +page--node--{type}.html.twig # Content type +node--{type}--{viewmode}.html.twig # Type + view mode +block--{plugin-id}.html.twig # Specific block +field--{entity}--{field}.html.twig # Specific field +``` + +**Adding suggestions:** +```php +function THEMENAME_theme_suggestions_HOOK_alter(array &$suggestions, array $variables) { + // Add custom suggestions + $suggestions[] = 'custom__suggestion'; +} +``` + +### 5. CSS & JavaScript Management + +Organize and load theme assets efficiently: + +**Library definition:** +```yaml +# THEMENAME.libraries.yml +global-styling: + version: 1.0 + css: + base: + css/base/reset.css: {} + theme: + css/theme/styles.css: {} + js: + js/custom.js: {} + dependencies: + - core/drupal +``` + +**Loading libraries:** +- Global: Define in `.info.yml` +- Conditional: Use `attach_library()` in templates +- Preprocessed: Attach in preprocess functions + +**Best practices:** +- Separate CSS into layers (base, layout, component, theme) +- Use CSS aggregation in production +- Minimize JavaScript dependencies +- Leverage Drupal's asset library system + +### 6. Responsive Design + +Implement mobile-first, accessible designs: + +**Breakpoints definition:** +```yaml +# THEMENAME.breakpoints.yml +THEMENAME.mobile: + label: Mobile + mediaQuery: 'screen and (min-width: 0px)' + weight: 0 + +THEMENAME.tablet: + label: Tablet + mediaQuery: 'screen and (min-width: 768px)' + weight: 1 + +THEMENAME.desktop: + label: Desktop + mediaQuery: 'screen and (min-width: 1024px)' + weight: 2 +``` + +**Mobile-first approach:** +1. Design for smallest screens first +2. Enhance for larger viewports +3. Use responsive images +4. Test across devices +5. Follow accessibility standards (WCAG) + +## Development Workflow + +### Creating a New Theme + +1. **Scaffold the theme:** + ```bash + cp -r assets/theme-template/ /path/to/drupal/themes/custom/mytheme/ + cd /path/to/drupal/themes/custom/mytheme/ + + # Rename files + mv THEMENAME.info.yml mytheme.info.yml + mv THEMENAME.libraries.yml mytheme.libraries.yml + mv THEMENAME.theme mytheme.theme + ``` + +2. **Update theme configuration:** + - Edit `mytheme.info.yml` - Set name, regions, base theme + - Edit `mytheme.libraries.yml` - Define CSS/JS libraries + - Replace `THEMENAME` with your machine name + - Replace `THEMELABEL` with your label + +3. **Enable the theme:** + ```bash + ddev drush cr + # Enable via UI at /admin/appearance or: + ddev drush config:set system.theme default mytheme -y + ``` + +4. **Enable Twig debugging:** + - Copy `sites/default/default.services.yml` to `sites/default/services.yml` + - Set `twig.config.debug: true` + - Set `twig.config.auto_reload: true` + - Set `twig.config.cache: false` + - Run `ddev drush cr` + +5. **Develop and iterate:** + - Modify templates in `templates/` + - Update CSS in `css/` + - Clear cache frequently: `ddev drush cr` + - Check browser console for errors + +### Standard Development Workflow + +1. **Enable development settings** (Twig debug, disable CSS/JS aggregation) +2. **Create/modify templates** based on suggestions from Twig debug +3. **Implement preprocessing** in `.theme` file for complex data manipulation +4. **Add CSS/JS** via libraries system +5. **Test** across browsers and devices +6. **Clear cache** after changes: `ddev drush cr` + +### Finding Template Names + +With Twig debugging enabled, inspect HTML source: + +```html + +``` + +The `x` indicates the active template. Others are suggestions you can create. + +## Common Patterns + +### Adding Custom Variables in Preprocess + +```php +function mytheme_preprocess_page(&$variables) { + // Add site slogan + $variables['site_slogan'] = \Drupal::config('system.site')->get('slogan'); + + // Add current user + $variables['is_logged_in'] = \Drupal::currentUser()->isAuthenticated(); + + // Add custom class + $variables['attributes']['class'][] = 'custom-page-class'; +} +``` + +### Template Inheritance + +```twig +{# templates/page--article.html.twig #} +{% extends "page.html.twig" %} + +{% block content %} +
+ {{ parent() }} +
+{% endblock %} +``` + +### Conditional Library Loading + +```php +function mytheme_preprocess_node(&$variables) { + if ($variables['node']->bundle() == 'article') { + $variables['#attached']['library'][] = 'mytheme/article-styles'; + } +} +``` + +### Accessing Field Values in Twig + +```twig +{# Get field value #} +{{ node.field_custom.value }} + +{# Check if field has value #} +{% if node.field_image|render %} + {{ content.field_image }} +{% endif %} + +{# Loop through multi-value field #} +{% for item in node.field_tags %} + {{ item.entity.label }} +{% endfor %} +``` + +## Best Practices + +### Theme Development +1. **Base theme**: Choose appropriate base (Olivero, Claro, or none) +2. **Structure**: Organize CSS logically (base, layout, components, theme) +3. **Naming**: Use BEM or similar CSS methodology +4. **Comments**: Document complex Twig logic and preprocessing +5. **Performance**: Optimize images, minimize CSS/JS, lazy load when possible + +### Twig Templates +1. **Logic**: Keep complex logic in preprocess, not templates +2. **Filters**: Use appropriate filters (|t, |clean_class, |safe_join) +3. **Whitespace**: Use {% spaceless %} to control output +4. **Debugging**: Enable Twig debugging during development only +5. **Suggestions**: Use specific templates only when needed + +### Preprocessing +1. **Services**: Use dependency injection in theme service subscribers +2. **Caching**: Add proper cache contexts and tags +3. **Performance**: Avoid heavy operations in frequently-called preprocessors +4. **Organization**: Group related preprocessing logically + +### CSS & JavaScript +1. **Libraries**: Group related assets into logical libraries +2. **Dependencies**: Declare all library dependencies +3. **Loading**: Load globally only when necessary +4. **Aggregation**: Enable in production for performance + +### Accessibility +1. **Semantic HTML**: Use proper elements (header, nav, main, etc.) +2. **ARIA**: Add labels and roles when needed +3. **Keyboard**: Ensure keyboard navigation works +4. **Contrast**: Meet WCAG color contrast requirements +5. **Alt text**: Provide for all images + +### Responsive Design +1. **Mobile-first**: Design for small screens, enhance for large +2. **Breakpoints**: Define logical breakpoints +3. **Images**: Use responsive image styles +4. **Testing**: Test across devices and screen sizes +5. **Performance**: Optimize for mobile networks + +## Troubleshooting + +### Template Changes Not Showing +- Clear cache: `ddev drush cr` +- Verify file location and naming +- Check Twig debug for active template +- Ensure library is properly defined + +### CSS/JS Not Loading +- Check library definition in `.libraries.yml` +- Verify file paths are correct +- Ensure library is attached (globally or conditionally) +- Clear cache and check browser console + +### Variables Not Available in Template +- Check preprocess function naming +- Verify variables are being set correctly +- Use Twig debugging: `{{ dump() }}` +- Clear cache after preprocessing changes + +### Twig Debugging Not Working +- Verify `sites/default/services.yml` exists +- Check `twig.config.debug: true` is set +- Clear cache: `ddev drush cr` +- Check file permissions + +## Resources + +### Reference Documentation + +- **`references/theming.md`** - Comprehensive theming guide + - Twig syntax and filters + - Template suggestions + - Preprocessing patterns + - Library management + - Responsive design + - Best practices + +### Asset Templates + +- **`assets/theme-template/`** - Complete theme scaffold + - `.info.yml` with regions and configuration + - `.libraries.yml` with CSS/JS examples + - `.theme` with preprocess examples + - Page template + - CSS and JS starter files + +### Searching References + +```bash +# Find specific Twig filter +grep -r "clean_class" references/ + +# Find preprocessing examples +grep -r "preprocess_node" references/ + +# Find library patterns +grep -r "libraries.yml" references/ +``` + +## Version Compatibility + +### Drupal 8 vs 9 vs 10 vs 11 +- **Twig syntax**: Consistent across all versions +- **Base themes**: Some legacy themes removed in 10+ +- **Libraries**: Same structure across versions +- **jQuery**: Drupal 9+ doesn't load jQuery by default +- **Claro**: Admin theme standard in 9+ +- **Olivero**: Frontend theme standard in 10+ + +### Migration Notes +- When upgrading, check for deprecated base themes +- Review jQuery dependencies +- Test with current Twig version +- Check for removed core templates + +## See Also + +- **drupal-backend** - Module development, hooks, APIs +- **drupal-tooling** - DDEV and Drush development tools +- [Drupal Theming Guide](https://www.drupal.org/docs/theming-drupal) - Official documentation +- [Twig Documentation](https://twig.symfony.com/doc/) - Twig syntax reference diff --git a/assets/theme-template/README.md b/assets/theme-template/README.md new file mode 100644 index 0000000..0d887a0 --- /dev/null +++ b/assets/theme-template/README.md @@ -0,0 +1,63 @@ +# Theme Template + +This is a basic Drupal theme template. To use it: + +1. Copy this directory to your Drupal installation: `themes/custom/yourthemename/` +2. Rename files from `THEMENAME.*` to `yourthemename.*` +3. Replace all instances of `THEMENAME` with your theme's machine name (lowercase, underscores) +4. Replace all instances of `THEMELABEL` with your theme's human-readable name +5. Customize the theme as needed + +## Files Included + +- `THEMENAME.info.yml` - Theme metadata +- `THEMENAME.libraries.yml` - CSS/JS library definitions +- `THEMENAME.theme` - Theme functions and preprocessing +- `templates/page.html.twig` - Page template +- `css/base/reset.css` - Base CSS reset +- `js/custom.js` - Custom JavaScript + +## Directory Structure + +``` +THEMENAME/ +├── THEMENAME.info.yml +├── THEMENAME.libraries.yml +├── THEMENAME.theme +├── css/ +│ └── base/ +│ └── reset.css +├── js/ +│ └── custom.js +└── templates/ + └── page.html.twig +``` + +You can expand the CSS structure as needed: +``` +css/ +├── base/ +│ └── reset.css +├── layout/ +│ └── layout.css +├── components/ +│ └── components.css +└── theme/ + └── theme.css +``` + +## Next Steps + +After creating your theme: + +1. Clear cache: `ddev drush cr` +2. Enable your theme: Go to `/admin/appearance` +3. Set as default theme +4. Start customizing! + +## Development Tips + +- Enable Twig debugging in `sites/default/services.yml` +- Disable CSS/JS aggregation during development +- Clear cache frequently: `ddev drush cr` +- Use template suggestions for specific pages/content types diff --git a/assets/theme-template/THEMENAME.info.yml b/assets/theme-template/THEMENAME.info.yml new file mode 100644 index 0000000..a01e2be --- /dev/null +++ b/assets/theme-template/THEMENAME.info.yml @@ -0,0 +1,40 @@ +name: THEMELABEL +description: 'A custom Drupal theme.' +type: theme +core_version_requirement: ^9 || ^10 || ^11 +package: Custom + +# Base theme (uncomment one) +# base theme: stable9 +# base theme: claro +# base theme: olivero +base theme: false + +# Regions +regions: + header: Header + primary_menu: 'Primary menu' + secondary_menu: 'Secondary menu' + page_top: 'Page top' + page_bottom: 'Page bottom' + highlighted: Highlighted + breadcrumb: Breadcrumb + content: Content + sidebar_first: 'Sidebar first' + sidebar_second: 'Sidebar second' + footer: Footer + +# Libraries +libraries: + - THEMENAME/global-styling + - THEMENAME/global-scripts + +# Component libraries (optional) +# component-libraries: +# atoms: +# paths: +# - components/atoms + +# Logo and favicon +# logo: images/logo.svg +# favicon: images/favicon.ico diff --git a/assets/theme-template/THEMENAME.libraries.yml b/assets/theme-template/THEMENAME.libraries.yml new file mode 100644 index 0000000..1eac8b9 --- /dev/null +++ b/assets/theme-template/THEMENAME.libraries.yml @@ -0,0 +1,19 @@ +global-styling: + version: 1.0 + css: + base: + css/base/reset.css: {} + layout: + css/layout/layout.css: {} + component: + css/components/components.css: {} + theme: + css/theme/theme.css: {} + +global-scripts: + version: 1.0 + js: + js/custom.js: {} + dependencies: + - core/drupal + - core/drupalSettings diff --git a/assets/theme-template/THEMENAME.theme b/assets/theme-template/THEMENAME.theme new file mode 100644 index 0000000..1149342 --- /dev/null +++ b/assets/theme-template/THEMENAME.theme @@ -0,0 +1,39 @@ + + {% if page.header %} + + {% endif %} + + {% if page.primary_menu %} + + {% endif %} + + {% if page.breadcrumb %} + + {% endif %} + + {% if page.highlighted %} +
+ {{ page.highlighted }} +
+ {% endif %} + +
+ + +
+ {{ page.content }} +
+ + {% if page.sidebar_first %} + + {% endif %} + + {% if page.sidebar_second %} + + {% endif %} +
+ + {% if page.footer %} + + {% endif %} + diff --git a/plugin.lock.json b/plugin.lock.json new file mode 100644 index 0000000..2df9080 --- /dev/null +++ b/plugin.lock.json @@ -0,0 +1,77 @@ +{ + "$schema": "internal://schemas/plugin.lock.v1.json", + "pluginId": "gh:Omedia/drupal-skill:drupal-frontend", + "normalized": { + "repo": null, + "ref": "refs/tags/v20251128.0", + "commit": "41cbbcfc5b908d2a4c909c8ed3cf4bf346d8347d", + "treeHash": "246b3d55adff0aa493e95588c8d801d78afdbb17202b57bd7c53e8765536c031", + "generatedAt": "2025-11-28T10:12:18.414950Z", + "toolVersion": "publish_plugins.py@0.2.0" + }, + "origin": { + "remote": "git@github.com:zhongweili/42plugin-data.git", + "branch": "master", + "commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390", + "repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data" + }, + "manifest": { + "name": "drupal-frontend", + "description": "Drupal Front End Specialist skill for theme development, Twig templates, and rendering system (Drupal 8-11+). Use when working with Drupal themes, Twig syntax, preprocessing, CSS/JS libraries, or template suggestions.", + "version": "1.0.0" + }, + "content": { + "files": [ + { + "path": "README.md", + "sha256": "5e23c9576a6751990607cd10129f80a3a93456d7edefa59cd3e467d3337e9312" + }, + { + "path": "SKILL.md", + "sha256": "ff8d70723699a19b27030618b278f28ce8480489866e02de73ec889e5afd3791" + }, + { + "path": "references/theming.md", + "sha256": "2dc93f7f888dcf8f108dc034a59c5290dfb03b60d54fefc5e5224bc09767dd09" + }, + { + "path": ".claude-plugin/plugin.json", + "sha256": "a50e29c08f31276d4a3070447cbb2d42f17d6e90c15b86f5ec138e60832a8a5b" + }, + { + "path": "assets/theme-template/THEMENAME.libraries.yml", + "sha256": "e7348c8ee5729c458f1189aa4559398e5b92568b4b790c869eda020af5ca5bed" + }, + { + "path": "assets/theme-template/README.md", + "sha256": "6e45999798046e8bcfa6ce4d98a3a46f5902b7083af37319549403ed98f62825" + }, + { + "path": "assets/theme-template/THEMENAME.info.yml", + "sha256": "25a0760f6de46d0eed90d4b5a183404248b70a5f297bf28b4a92c6617c7465bd" + }, + { + "path": "assets/theme-template/THEMENAME.theme", + "sha256": "9219803ea44915d93d50f4c5ae813eb1c29cc35b7bcaa0a3e1514bb18435ba22" + }, + { + "path": "assets/theme-template/css/base/reset.css", + "sha256": "3a548377de02f63a2b44019f206200b368cfca5af624b6413aed879ac6bad628" + }, + { + "path": "assets/theme-template/js/custom.js", + "sha256": "edef32819f6f1f7682063f228ccd11f9ccaf920e602998806bad1f7541341010" + }, + { + "path": "assets/theme-template/templates/page.html.twig", + "sha256": "0bd1013051a32a702fe2fe8c494be3cb81721918ebff535fdc1eb1265943fec6" + } + ], + "dirSha256": "246b3d55adff0aa493e95588c8d801d78afdbb17202b57bd7c53e8765536c031" + }, + "security": { + "scannedAt": null, + "scannerVersion": null, + "flags": [] + } +} \ No newline at end of file diff --git a/references/theming.md b/references/theming.md new file mode 100644 index 0000000..2bba91f --- /dev/null +++ b/references/theming.md @@ -0,0 +1,563 @@ +# Drupal Theming Reference + +Comprehensive guide to Drupal theming for Drupal 8-11+. + +## Theme Structure + +``` +mytheme/ +├── mytheme.info.yml # Theme metadata (required) +├── mytheme.libraries.yml # CSS/JS libraries +├── mytheme.theme # Theme functions and preprocess +├── mytheme.breakpoints.yml # Responsive breakpoints +├── logo.svg # Theme logo +├── screenshot.png # Admin screenshot +├── composer.json # Composer dependencies +├── package.json # NPM dependencies (if using build tools) +├── config/ +│ ├── install/ # Default configuration +│ └── schema/ # Configuration schema +├── css/ +│ ├── base/ +│ ├── components/ +│ ├── layout/ +│ └── theme/ +├── js/ +│ └── custom.js +├── images/ +├── templates/ +│ ├── block/ +│ ├── content/ +│ ├── field/ +│ ├── layout/ +│ ├── navigation/ +│ ├── views/ +│ ├── page.html.twig +│ ├── node.html.twig +│ └── block.html.twig +└── src/ # Optional PHP classes + └── Plugin/ + └── Preprocess/ +``` + +## Theme Info File (mytheme.info.yml) + +```yaml +name: My Theme +type: theme +description: 'A custom Drupal theme' +core_version_requirement: ^9 || ^10 || ^11 +package: Custom + +# Base theme +base theme: stable9 +# Or for no base theme: +# base theme: false + +# Regions +regions: + header: Header + primary_menu: 'Primary menu' + secondary_menu: 'Secondary menu' + page_top: 'Page top' + page_bottom: 'Page bottom' + highlighted: Highlighted + breadcrumb: Breadcrumb + content: Content + sidebar_first: 'Sidebar first' + sidebar_second: 'Sidebar second' + footer: Footer + +# Libraries to load on all pages +libraries: + - mytheme/global-styling + - mytheme/global-scripts + +# Libraries to load only when certain conditions are met +libraries-override: + # Replace core library + core/drupal.dialog: + mytheme/custom-dialog: {} + +libraries-extend: + # Add to existing library + core/drupal.dialog: + - mytheme/dialog-extend + +# Remove libraries +libraries-override: + core/normalize: + css: + base: + assets/vendor/normalize-css/normalize.css: false + +# Component libraries (for single-directory components) +component-libraries: + atoms: + paths: + - components/atoms + molecules: + paths: + - components/molecules + +# Logo and favicon +logo: images/logo.svg +favicon: images/favicon.ico + +# Stylesheets to remove +stylesheets-remove: + - core/assets/vendor/normalize-css/normalize.css + - '@classy/css/components/tabs.css' + +# CKEditor stylesheet +ckeditor_stylesheets: + - css/ckeditor.css + +# Hidden theme (for base themes) +hidden: false +``` + +## Libraries (mytheme.libraries.yml) + +```yaml +global-styling: + version: 1.0 + css: + base: + css/base/reset.css: {} + layout: + css/layout/layout.css: {} + component: + css/components/button.css: {} + css/components/card.css: {} + theme: + css/theme/colors.css: {} + css/theme/typography.css: {} + +global-scripts: + version: 1.0 + js: + js/custom.js: {} + dependencies: + - core/drupal + - core/jquery + +# Conditional library (loaded via preprocess or template) +modal: + version: 1.0 + css: + component: + css/components/modal.css: {} + js: + js/modal.js: {} + dependencies: + - core/drupal + - core/drupalSettings + +# External library +fontawesome: + version: 6.0 + css: + theme: + https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css: { type: external, minified: true } + +# SCSS/SASS (requires compilation) +compiled-styles: + version: 1.0 + css: + theme: + dist/css/styles.css: {} + dependencies: + - core/normalize +``` + +## Theme Functions (mytheme.theme) + +```php +get('slogan'); + + // Add body classes + $variables['attributes']['class'][] = 'custom-page-class'; +} + +/** + * Implements hook_preprocess_HOOK() for node templates. + */ +function mytheme_preprocess_node(&$variables) { + /** @var \Drupal\node\NodeInterface $node */ + $node = $variables['node']; + + // Add custom variables + $variables['created_date'] = \Drupal::service('date.formatter')->format( + $node->getCreatedTime(), + 'custom', + 'F j, Y' + ); + + // Add template suggestions + $variables['theme_hook_suggestions'][] = 'node__' . $node->bundle() . '__' . $variables['view_mode']; +} + +/** + * Implements hook_preprocess_HOOK() for block templates. + */ +function mytheme_preprocess_block(&$variables) { + // Add block ID as class + if (isset($variables['elements']['#id'])) { + $variables['attributes']['class'][] = 'block-' . $variables['elements']['#id']; + } +} + +/** + * Implements hook_preprocess_HOOK() for field templates. + */ +function mytheme_preprocess_field(&$variables) { + $element = $variables['element']; + + // Custom preprocessing for specific fields + if ($element['#field_name'] == 'field_custom') { + $variables['custom_class'] = 'field-custom-class'; + } +} + +/** + * Implements hook_theme_suggestions_HOOK_alter() for page templates. + */ +function mytheme_theme_suggestions_page_alter(array &$suggestions, array $variables) { + // Add template suggestions based on current route + if ($node = \Drupal::routeMatch()->getParameter('node')) { + if ($node instanceof NodeInterface) { + $suggestions[] = 'page__node__' . $node->bundle(); + $suggestions[] = 'page__node__' . $node->id(); + } + } +} + +/** + * Implements hook_theme_suggestions_HOOK_alter() for node templates. + */ +function mytheme_theme_suggestions_node_alter(array &$suggestions, array $variables) { + /** @var \Drupal\node\NodeInterface $node */ + $node = $variables['elements']['#node']; + $view_mode = $variables['elements']['#view_mode']; + + // Add suggestion for bundle and view mode combination + $suggestions[] = 'node__' . $node->bundle() . '__' . $view_mode; +} + +/** + * Implements hook_form_alter(). + */ +function mytheme_form_alter(&$form, FormStateInterface $form_state, $form_id) { + // Add custom classes to forms + if ($form_id == 'search_block_form') { + $form['actions']['submit']['#attributes']['class'][] = 'custom-search-submit'; + } +} + +/** + * Implements hook_page_attachments_alter(). + */ +function mytheme_page_attachments_alter(array &$attachments) { + // Add custom meta tags + $meta_charset = [ + '#tag' => 'meta', + '#attributes' => [ + 'charset' => 'utf-8', + ], + ]; + $attachments['#attached']['html_head'][] = [$meta_charset, 'meta_charset']; +} + +/** + * Implements hook_library_info_alter(). + */ +function mytheme_library_info_alter(&$libraries, $extension) { + // Modify libraries from other modules + if ($extension == 'core' && isset($libraries['drupal.dialog'])) { + $libraries['drupal.dialog']['dependencies'][] = 'mytheme/custom-dialog'; + } +} +``` + +## Twig Templates + +### page.html.twig +```twig +
+
+ {{ page.header }} + {{ page.primary_menu }} +
+ + {{ page.breadcrumb }} + {{ page.highlighted }} + +
+ + +
+ {{ page.content }} +
+ + {% if page.sidebar_first %} + + {% endif %} + + {% if page.sidebar_second %} + + {% endif %} +
+ + {% if page.footer %} +
+ {{ page.footer }} +
+ {% endif %} +
+``` + +### node.html.twig +```twig + + + {{ title_prefix }} + {% if not page %} + + {{ label }} + + {% endif %} + {{ title_suffix }} + + {% if display_submitted %} +
+ {{ author_picture }} + + {% trans %}Submitted by {{ author_name }} on {{ date }}{% endtrans %} + + {{ metadata }} +
+ {% endif %} + + + {{ content }} + + + +``` + +### block.html.twig +```twig + + {{ title_prefix }} + {% if label %} + {{ label }} + {% endif %} + {{ title_suffix }} + + {% block content %} + {{ content }} + {% endblock %} + +``` + +### field.html.twig +```twig +{% if multiple %} + + {% if label %} + {{ label }} + {% endif %} +
+ {% for item in items %} + {{ item.content }}
+ {% endfor %} + + +{% else %} + {% for item in items %} + + {% if label %} + {{ label }} + {% endif %} + {{ item.content }} + + {% endfor %} +{% endif %} +``` + +## Twig Filters & Functions + +### Common Filters +```twig +{# Translate #} +{{ 'Hello World'|t }} + +{# Clean class name #} +{{ 'Field Name'|clean_class }} + +{# Format date #} +{{ node.created.value|date('F j, Y') }} + +{# Safe join #} +{{ items|safe_join(', ') }} + +{# Render #} +{{ content|render }} + +{# Without (remove array elements) #} +{{ content|without('field_image') }} + +{# Placeholder #} +{{ 'Hello @name'|t({'@name': name}) }} +``` + +### Common Functions +```twig +{# Attach library #} +{{ attach_library('mytheme/modal') }} + +{# URL #} +Link + +{# Path #} +Link + +{# File URL #} +{{ file_url('public://image.jpg') }} + +{# Create attribute #} +{% set attributes = create_attribute() %} +{{ attributes.addClass('custom-class') }} +``` + +## Breakpoints (mytheme.breakpoints.yml) + +```yaml +mytheme.mobile: + label: Mobile + mediaQuery: 'screen and (min-width: 0px)' + weight: 0 + multipliers: + - 1x + - 2x + +mytheme.tablet: + label: Tablet + mediaQuery: 'screen and (min-width: 768px)' + weight: 1 + multipliers: + - 1x + - 2x + +mytheme.desktop: + label: Desktop + mediaQuery: 'screen and (min-width: 1024px)' + weight: 2 + multipliers: + - 1x + - 2x + +mytheme.wide: + label: Wide + mediaQuery: 'screen and (min-width: 1440px)' + weight: 3 + multipliers: + - 1x +``` + +## Debug Mode + +Enable Twig debugging in development: + +**sites/default/services.yml** +```yaml +parameters: + twig.config: + debug: true + auto_reload: true + cache: false +``` + +Then clear cache: +```bash +ddev drush cr +``` + +## Theme Development Workflow + +1. **Enable development settings** + ```bash + # Copy and enable development settings + cp sites/example.settings.local.php sites/default/settings.local.php + ``` + +2. **Disable CSS/JS aggregation** + - Go to `/admin/config/development/performance` + - Uncheck "Aggregate CSS files" + - Uncheck "Aggregate JavaScript files" + +3. **Clear cache frequently** + ```bash + ddev drush cr + ``` + +4. **Use Twig debugging** + - Check HTML source for template suggestions + - Look for `` comments + +5. **Rebuild theme registry** + ```bash + ddev drush drush cr + ``` + +## Best Practices + +1. **BEM Methodology**: Use BEM for CSS class naming +2. **Component-based**: Build reusable components +3. **Accessibility**: Follow WCAG guidelines +4. **Performance**: Optimize images, minimize CSS/JS +5. **Mobile-first**: Design for mobile, enhance for desktop +6. **Semantic HTML**: Use proper HTML5 elements +7. **Template suggestions**: Use specific templates when needed +8. **Libraries**: Group related CSS/JS in libraries +9. **Preprocessing**: Keep logic in .theme file, not templates +10. **Documentation**: Comment complex template logic + +## Common Template Suggestions + +``` +page--front.html.twig # Front page +page--node--123.html.twig # Specific node +page--node--article.html.twig # Content type +node--article--full.html.twig # Bundle and view mode +node--123.html.twig # Specific node +block--system-branding-block.html.twig # Specific block +field--node--title--article.html.twig # Specific field +views-view--blog--page-1.html.twig # View and display +``` + +## Useful Resources + +- Theming Guide: https://www.drupal.org/docs/theming-drupal +- Twig Documentation: https://twig.symfony.com/doc/ +- Template Suggestions: https://www.drupal.org/docs/theming-drupal/twig-in-drupal/debugging-twig-templates