Browse Source

Scaffold JS behaviors entry point and prune unused .otf font files

Adds js/druid.behaviors.js with a heavily-commented Drupal.behaviors
skeleton, registered as the druid/behaviors always-on library (depends
on core/drupal and core/once). The IIFE is empty — ready for the first
behavior. CLAUDE.md gains a JavaScript section so future work has the
same self-documenting entry point as the CSS architecture.

Separately, removes 12 Adelle .otf source files that were committed
alongside their .woff2 web versions; only .woff2 is referenced from
css/fonts.css, so the .otf copies were ~1.4 MB of unreferenced bytes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
master
rdrew 2 weeks ago
parent
commit
54bd6cc847
  1. 7
      CLAUDE.md
  2. 1
      druid.info.yml
  3. 7
      druid.libraries.yml
  4. BIN
      fonts/adelle/Adelle_Bold.otf
  5. BIN
      fonts/adelle/Adelle_BoldItalic.otf
  6. BIN
      fonts/adelle/Adelle_ExtraBold.otf
  7. BIN
      fonts/adelle/Adelle_ExtraBoldItalic.otf
  8. BIN
      fonts/adelle/Adelle_Heavy.otf
  9. BIN
      fonts/adelle/Adelle_HeavyItalic.otf
  10. BIN
      fonts/adelle/Adelle_Italic.otf
  11. BIN
      fonts/adelle/Adelle_LightItalic.otf
  12. BIN
      fonts/adelle/Adelle_Reg.otf
  13. BIN
      fonts/adelle/Adelle_SemiBoldItalic.otf
  14. BIN
      fonts/adelle/Adelle_Semibold.otf
  15. BIN
      fonts/adelle/Adelle_light.otf
  16. 71
      js/druid.behaviors.js

7
CLAUDE.md

@ -53,6 +53,12 @@ All eight libraries are attached on every page via `druid.info.yml` `libraries:`
*Only when re-vendoring a new modern-normalize release — see the file header for the workflow.
## JavaScript
There's one JS file: `js/druid.behaviors.js`, registered as the `druid/behaviors` library with `core/drupal` + `core/once` as dependencies, attached on every page. It's currently empty inside its IIFE — a scaffold ready for the first behavior.
All theme JS should use Drupal's behaviors system rather than plain `DOMContentLoaded` listeners, because Drupal swaps DOM fragments at runtime (AJAX views, form errors, contextual links, modals) and `attach()` is what re-runs on each injected fragment. Use `once()` to prevent double-initialization. The file's own header comment is the detailed pattern reference; if you split JS into multiple files, either co-locate them in the `behaviors:` library entry or register new libraries for conditional loading via `libraries-extend`.
### Tokens / Open Props
`css/tokens.css` holds CSS custom properties on `:root`. We do **not** import the full Open Props library — instead, we cherry-pick individual tokens by copying their declarations into this file. The workflow is documented in the file's header comment; re-read it before adding tokens. The short version: browse https://open-props.style, copy the `--prop: value;` line, paste into the relevant section, preserve the Open Props name.
@ -68,6 +74,7 @@ All eight libraries are attached on every page via `druid.info.yml` `libraries:`
- **Cache clear**: required after any `.yml`, `.theme`, or template change — `drush cr` from the site root. CSS *content* edits do not require it; only adding/removing files or library entries does.
- **New component CSS**: create the file in `css/components/`, wrap its rules in `@layer components { … }`, register it under the `components:` library in `druid.libraries.yml` with `weight: -10`. If the styles should only load when a specific core library is in use, give it its own library and wire it via `libraries-extend` in `druid.info.yml` instead.
- **New JS behavior**: add it inside `js/druid.behaviors.js` following the `Drupal.behaviors.druidX = { attach(context) { once('druid-x', '.selector', context).forEach(…) } }` pattern. Always scope selectors to `context`, not `document`. For a separate file, register it in the `behaviors:` library (same dependencies) or define a new library if it should load conditionally.
- **New Twig override**: copy the upstream template from `core/themes/stable9/templates/…` (or the originating module) into the matching subdirectory here — don't write from scratch; the docblock comments document available variables and are worth keeping.
- **New preprocess hook**: follow the existing signature in `druid.theme` (`array &$variables`, `: void` return type, `/** Implements hook_X(). */` docblock).
- **Drupal core / contrib CSS is unlayered.** That means it wins against any `@layer components` rule you write — this is the one place the architecture leaks. Options: bump specificity for the override, or wrap the offending core CSS via a future `hook_css_alter` (not currently implemented). Don't reach for `!important` reflexively.

1
druid.info.yml

@ -25,6 +25,7 @@ libraries:
- druid/layout
- druid/components
- druid/utilities
- druid/behaviors
- druid/messages
libraries-extend:
user/drupal.user:

7
druid.libraries.yml

@ -61,6 +61,13 @@ utilities:
theme:
css/utilities.css:
weight: -50
behaviors:
version: VERSION
js:
js/druid.behaviors.js: {}
dependencies:
- core/drupal
- core/once
components:
version: VERSION
css:

BIN
fonts/adelle/Adelle_Bold.otf

Binary file not shown.

BIN
fonts/adelle/Adelle_BoldItalic.otf

Binary file not shown.

BIN
fonts/adelle/Adelle_ExtraBold.otf

Binary file not shown.

BIN
fonts/adelle/Adelle_ExtraBoldItalic.otf

Binary file not shown.

BIN
fonts/adelle/Adelle_Heavy.otf

Binary file not shown.

BIN
fonts/adelle/Adelle_HeavyItalic.otf

Binary file not shown.

BIN
fonts/adelle/Adelle_Italic.otf

Binary file not shown.

BIN
fonts/adelle/Adelle_LightItalic.otf

Binary file not shown.

BIN
fonts/adelle/Adelle_Reg.otf

Binary file not shown.

BIN
fonts/adelle/Adelle_SemiBoldItalic.otf

Binary file not shown.

BIN
fonts/adelle/Adelle_Semibold.otf

Binary file not shown.

BIN
fonts/adelle/Adelle_light.otf

Binary file not shown.

71
js/druid.behaviors.js

@ -0,0 +1,71 @@
/**
* @file
* JavaScript behaviors for the druid theme.
*
*
* What Drupal.behaviors solves
*
*
* Drupal swaps DOM fragments at runtime form errors, AJAX-loaded views,
* contextual links, modal dialogs, and inline edits all inject new HTML
* into the page after the initial load. A plain `DOMContentLoaded` handler
* runs once and misses everything that arrives later.
*
* The behaviors system runs your `attach()` on every fragment Drupal
* inserts (including the initial document), so the same code initializes
* new content automatically. Use `once()` to make sure an element is only
* initialized one time even if `attach()` is invoked repeatedly.
*
*
* Pattern
*
*
* Drupal.behaviors.druidSomething = {
* attach(context, settings) {
* once('druid-something', '.selector', context).forEach((el) => {
* // initialize el — add listeners, hydrate state, etc.
* });
* },
* detach(context, settings, trigger) {
* // OPTIONAL — clean up listeners/observers when Drupal removes the
* // fragment. Skip if you don't allocate anything that leaks.
* },
* };
*
* - `context` is the DOM subtree being attached. On the initial page load
* it's `document`; on AJAX updates it's just the newly inserted fragment.
* Always scope queries to `context`, never to `document`, or you'll
* re-initialize the whole page.
* - The first arg to `once()` is a unique string ID for this behavior. The
* second is a CSS selector. `once()` returns an array of elements that
* haven't been initialized yet (it marks them with a data attribute so
* subsequent calls skip them).
* - `settings` is the JS object Drupal exposes via `drupalSettings` use
* it to read PHP-side configuration (`drupalSettings.druid.someValue`).
*
* Naming: prefix behavior keys with `druid` so they don't collide with
* core/contrib behaviors. The `once()` ID should match the behavior name
* minus the prefix, lowercased and kebab-case.
*
* Library wiring: this file is registered in druid.libraries.yml under the
* `behaviors` library, with `core/drupal` and `core/once` as dependencies.
* If you split JS into multiple files, either add them under the same
* library or define new libraries and attach them via `libraries-extend`
* (for conditional loading) or the always-on list in druid.info.yml.
*
* Reference: https://www.drupal.org/docs/develop/standards/javascript
*/
((Drupal, once) => {
// Behaviors go here. Example skeleton — uncomment and adapt:
//
// Drupal.behaviors.druidExample = {
// attach(context) {
// once('druid-example', '[data-druid-example]', context).forEach((el) => {
// el.addEventListener('click', () => {
// el.classList.toggle('is-active');
// });
// });
// },
// };
})(Drupal, once);
Loading…
Cancel
Save