# Rocketship theme Starter

Component-based Drupal theme for use with Dropsolid Rocketship install profile,
modules and other components.

**Starter preset**
Comes with some basic styling and Sass/Twig files to get you started.
Contains pre-defined styles.

## Dependencies

### Local development

- Node: version mentioned in package.json (under "engines").
- NPM: whatever version comes with the Node version.
- a recent version of gulp-cli.

If you need to upgrade node/npm, here is some info:
- Install and switch to the node version you will be using (we recommend using
NVM).
- throw away the package.lock files.
- throw away the node_modules folder.
- change the version check in `package.json`, as well as in `.nvmrc` with the
version you will be working on.
- DO NOT USE AN UNEVEN NODE VERSION!!! Only the even ones are stable.
- run `npm install`.
- rebuild node-sass: `npm rebuild node-sass`.

We try to enforce a specific node version using a `.nvmrc` file (works if you
use NVM), as well as a check in package.json which should give you a warning
during `npm install`.

**Example in package.json:**
Support 1 version:
  ```
  "node": ">=20.0.0 <21.0.0"
  ```
Support multiple versions (not recommended):
  ```
  "node": ">=20.0.0 <21.0.0 || >=22.0.0 <23.0.0"
  ```

### Setup

**INSTALL NVM TO MANAGE YOUR NODE VERSIONS!**

The basis of our local development, is Node + NPM. We need it to run Gulp
tasks to make our life easier.
Depending on how old your project is, you will need to quickly and easily
switch Node versions.
This is because some versions of Gulp (and dependencies like sass-build) are
not compatible or need updated builds.

Long story short: you need to install NVM so you can switch using a simple
command and so we can enforce locked versions of NPM.
Follow the instructions set here:
* https://michael-kuehnel.de/node.js/2015/09/08/using-vm-to-switch-node-versions.html

The required NPM version is defined in `.nvmrc`. Note that this uses the LTS
versions.

### Storybook

If you want to take full advantage of the theme together with storybook, you
will need to add the contrib storybook. Run following command:
```
$ composer require drupal/storybook
```
You can follow the readme of that module to set up your very own storybook, or
you can use the storybook setup we provided. To get the storybook related to
this package, you will need to make some changes to your composer:

#### add the Dropsolid repo.

```
{
  "repositories": [
    {
      "type": "composer",
      "url": "https://gitlab.com/api/v4/group/271525/-/packages/composer/packages.json"
    }
}
```
More info can be found at:
https://getcomposer.org/doc/05-repositories.md#composer

#### Config the install path.

The path must be listed above the general web/libraries/{$name} catch-all if you have one.

```
{
  "extra": {
    "installer-paths": {
      "storybook": [
        "dropsolid/storybook"
      ],
    }
  }
}
```
More info can be found at:
https://getcomposer.org/doc/faqs/how-do-i-install-a-package-to-a-custom-path-for-my-framework.md#how-do-i-install-a-package-to-a-custom-path-for-my-framework-

#### Install the package.

Now you will need to run following command:
```
$ composer install --dev dropsolid/storybook
```

After you're done, see the readme in /storybook on how to run it.

## What the theme does

- Templates, CSS and JS is component-based.
- Converts Sass (with globbing) into CSS.
- Can provide Sourcemaps for CSS and JS.
- Generates favicons.
- Generates custom icon font or icon sprite.
- Has better responsive tables.
- Has a component-based styleguide.
- Has support for storybook contrib module.
- Can easily work with SDC's.

## Settings

Your active theme has settings over at `admin/appearance/settings/themename`
Be sure to check those out before searching the Sass and JS files.
E.g. there is a setting that can switch the language menu from a dropdown to an
inline list.
E.g. there is a setting to make a fixed header.

## Libraries and other third party stuff

- **Fontawesome:** an iconfont, integrated with a theme mixin and variables
  - info in the Styleguide on how it is used (see Base/Fonts and Atoms/Images)
  NOTE: Since Font Awesome has so many fonts, where you only need a handful of
  icons, we strongly suggest using a custom icon font or icon spite.

## Setup

- Check if your npm and node are up-to-date. In your command line, run `npm -v`
and `node -v`. The versions should match the requirements.
  - if you have NVM installed, first running `nvm use` should switch to the
correct versions (or tell you what to install).
- You will need the Gulp CLI installed globally as well:
`$ npm install --global gulp-cli`
- In your command line, navigate to your theme folder
(*/docroot/sites/all/themes/custom/[theme]*) and run `npm install`. You only
need to run this command once, when you install the theme. It will install the
node modules for gulp to work.
- if your project has a docroot-folder (and uses git), a pre-installation
script will run and try to add a git pre-commit hook that helps detect linting
issues.
- run `$ gulp prod` to compile your css and js files.
- In your Drupal settings, make sure your child theme is activated and set as
default.

Your theme is now ready to be used!

## Technology

- **Gulp** is used as a task manager (e.g. compile CSS, make favicons, …).
- **npm** is used to manager the node modules for Gulp, and if needed, run
pre- or post-scripts (see package.json).
- **Sass** + linting is used to write better CSS.
- **JS**: used for all manner of interactivity, such as the mobile navigation.

## Anatomy the theme

- .theme file
- yml-files
- config
- gulp
- components folder
- styleguide
- css and js
- fonts, images, favicons, icons, ….

### rocketship_theme_starter.theme

Various theme functions (hooks). The most important ones being to:

- **Add theme settings:** `HOOK_form_system_theme_settings_alter` and
`HOOK_preprocess_page`
  Theme settings are defined and saved in drupal settings so they are
  available in your JS files (using the drupalSettings object) and in your
  theme's settings page. An example of this being used, would be the language
  menu and fixed header (Demo only), but also a way to enable or disable
  animated scrolling on anchor links.
  In order for theme settings to work, you need to check them/fill them in at:
`/admin/appearance/settings/`.

Don't forget that the child theme inherits theme functions defined in the
parent 'Base' theme.

E.g. for turning responsive tables on or off (selectively):
`$variables['table']['#responsive'] = FALSE;`

But also, html viewport settings, classes on body-tag, various block classes,
theme suggestions, ….

### YML

- **info:**
  - Aliases: These are used in Twig when you need to include another file.
  Makes it really easy to simplify a path so you don't need to change it in
  100 different places if something is renamed.
  - global libraries: libraries that are used (almost) everywhere.
  - requirements: the modules this theme depends on.
  - regions: regions made available for block layout. Beware there are several
  locations to put you navigations in. **Primary and secondary nav are bundled
  together in the mobile navigation.** The rest is not.

- **libraries:**
  - bundles of js (and sometimes css as well). Don't forget you still need to
  attach these to your theme if you want to use them. Either in *.info, in
  *.theme or in a twig file.

- **layouts:**
  Templates for Layout Builder (we no longer use DS or Page Manager). At least
  1 template in here: an example of a custom layout, to use on sections.
  Other Layouts you find in Layout Builder Section configuration, are
  inherited from the rocketship_core module and are in use everywhere Layout
  Builder is used.

- **breakpoints:**
By default, we mostly use the breakpoints defined in rocketship_core. But you
can make your own in here.

### config folder

This is where default values are defined for the theme functions created in
rocketship_theme_starter.theme. You don't need to touch these.

### Gulp

We use Gulp as our task manager. This will compile all the things we need to
make the front-end work.

#### + Browser sync

Gulp can use Browsersync to automagically update your browser when you change
your Sass or JS. Note that since we run Ddev on Mac, there can be some delay
between the Docker server. To get started, change the `proxy` argument in
the `Gulpfile.js` to the URL of your project, after that, you will be able to
access it via E.g: https://chmods-website.ddev.site:3000

#### Linting

It is important that you write your CSS in a structured and clear way.
To enforce this, we've added linting that follows idiomatic CSS and a couple of
best-practices.

One of these aspects, is the enforcement of a loose ordering of the properties.
We order the CSS properties by group, but inside those groups you can order the
properties in any way you like.

Most properties fall into these groups and thus should be ordered that way:
  - positioning
  - display
  - box model
  - list
  - font
  - background
  - box-shadow
  - transform
  - transition
  - animate

E.g. "font-size" and "font-weight" are part of the same group ('font') so it
doesn't matter what goes first.

E.g. "width" is part of the dimensions and box model, so should come before
"font-size".

E.g. "border" is part of box model so should go before "box-shadow" and after
"font-size".

You can see the full list of properties in `gulp/config.js`, under the section
`order/properties-order`.

#### Tasks

We have some `npm` commands in place that trigger Gulp to perform the tasks
needed to theme. You can also call the Gulp tasks directly.
For example: `npm run css:dev` would be the same as `gulp css:dev`.
This is because we want to have the freedom to change task runners if needed
while still use the same commands to do stuff.

Knowing this, you can use all the following tasks.
Enter `gulp` or `npm run` followed by one of the following task names:

**The basic commands:**

- default (`gulp`): will compile CSS and JS for development
(with linting), try to create favicon and trigger a 'watch' task. 90% of the
time, you only need this task.
- `dev`: same as the default task, but without a `watch`.
- `prod`: compile CSS and JS for production (no map files nor linting nor watch).
   You need to run this task before committing any css and js files for your
   project, because we don't want any sourceMap references to get on the server.
- `watch`: included in ‘default’, this task will keep running in the background
to keep compiling the Sass, JS and images.
- `favicon`: This will generate the favicons (if you place an image in
/favicons/source folder).  <b>Don't forget to add these images!!!</b>.

**What is running in the back of these:**

- `setup`: included in ‘default’, this will check for the favicons but also
try to provide a copy of Fontawesome locally.
- `css:dev` and `css:prod`: this will compile the Sass (inside a component
folder) to CSS (and provide sourcemaps if dev is used). The produced files end
up in the `css`-folder.
- `js:dev` and `js:prod`: this will concatenate any JS-files inside a
component folder (and provide sourcemaps if dev is used). The produced files
are located in the `js/dest`-folder.
- `css:mail`: runs after the css-task, produces css from the style.mail.scss
file.
- `css:editor`: runs after the css-task, produces css from the
style.editor.scss file.
- `js:lint`: included in ‘js:dev’, this will provide notes for you to write
better code.
- `css:lint`: included in ‘css:dev’, the same but for Sass.

**The extras:**

- `icons:font`: not included in ‘default’, using gulp iconfont this will
generate a font based on svg’s in the 'icons' folder. It will also add
mixins to use them.
- `icons:sprite`: not included in ‘default’, using gulp sprite this will
generate a sprite based on svg’s in the 'icons' folder. It will also add sass
variables and mixins to use them.

#### Compile Sass/JS

To simply watch and compile your Sass/JS, you must navigate to your theme
folder (*/docroot/sites/all/themes/custom/my-theme/[child-theme]*) in
your command line and run `gulp`.

#### Favicon Generator

This theme has an automatic favicon generator. Information on how to use it,
can be found in the readme file in the theme's `favicons/source` folder.
The command is: `gulp favicon`.

#### Custom icon-font or sprite Generator

This theme also has an automatic icon-font generator. Info on how to use it,
can be found in the Styleguide Atoms/Images documentation.
The command is: `gulp icons:font`.

### Components

The theme is built using a component-based (or Atomic) method.
More detailed info can be found in the Styleguide, but it is recommended you
get familiar with the idea and practice behind this.
To do so, here are some resources:

- https://bradfrost.com/blog/post/atomic-web-design/
  - More in depth: https://atomicdesign.bradfrost.com/chapter-2/
- Implementation example: https://patternlab.io/
  - Demo: https://demo.patternlab.io/

### SDC

Starting with Drupal 10.3, you can use SDC's. The theme already takes advantage
of that. If you take a look at `components/01-content-blocks/components`,
you'll see that our content blocks are already separate components.
The nested `components` folders will not be included in the general css output.

More info can be found at:
https://www.drupal.org/docs/develop/theming-drupal/using-single-directory-components

### Fonts

There is a fonts folder to hold self-hosted fonts. Fonts that are defined in
the `HOOK_starter_preprocess_html` hook, will be preloaded. We also use a
`@font-face` to define the fonts them self. The css for that will be compiled
into the font library. Note that the definition is the library is under `base`,
so it gets a weight of -200, it also gets `preprocess: false`, so it keeps
being a separate file when aggregated.

### Twig

Twig is a powerful templating engine, which allows us to write html around the
Drupal data in an easy way. These files are the basic building blocks of our
components.

Some of the things they use are:
- [**filters**]
(https://www.drupal.org/docs/develop/theming-drupal/twig-in-drupal/filters-modifying-variables-in-twig-templates).
- [**include**](https://twig.symfony.com/doc/2.x/tags/include.html): include a
twig file inside another one + pass variables to it using `with {}`
- [**extends**]
(https://www.drupal.org/docs/develop/theming-drupal/twig-in-drupal/extending-templates)
override blocks from a master template
- [**embed**](https://twig.symfony.com/doc/2.x/tags/embed.html): combines both
include and extends
- [**macro**](https://twig.symfony.com/doc/2.x/tags/macro.html): kind of like
a function. You reference a macro and pass variables to it.

Combine this with underscores and clear naming for better readability and use
in future pattern styleguide.

There are also some extra twig functions, most notably a BEM function.
This lets you create classes following the BEM-structure for better writing of
CSS (extended Twig-function, thanks to unified twig module).

**Examples:**
- `components/example` naming, embed, aliases, BEM, ….
- `molecules/menus/menu` for include/embed, macro, BEM, ….

### Sass

As mentioned before, the styling is combined in the components folder with
Twig. It is also split for Features (new content types), Content Blocks and
Theme.

- 00-theme
- 01-content-blocks
- 02-features (the resulting CSS is NOT loaded by default)

And inside each of those:
- **base**: config and vars.
- **atoms**: styling the simplest elements, e.g. fields.
- **molecules**: styling groups of atoms, e.g. most blocks.
- **organisms**: styling groups of molecules, e.g. regions, header, footer, ….
- **pages**: styling Drupal pages (e.g. 404, user, maintenance, …).
- **layouts**: styling for (custom) layout templates.

All theme files combine into style files (with @use) for specific purposes:
admin, editor, fonts, mail, print, ….
Note that since 2024 `@include` is deprecated, and you should use `@use`
instead.
More info can be found at https://sass-lang.com/blog/import-is-deprecated/.

Only compiled CSS-files loaded in a library (e.g. in .info file, a hook or a
twig-file).

### JS

Following the same atomic structure, you will find javascript files for
specific functionality added to specific components. Most of these are **loaded
selectively**.
E.g. language menu JS is set in `molecules/menus/menu--language` (makes a
dropdown menu or shortcodes) or dropdown menu and mobile menu JS is set in
`molecules/menus/menu`).

There are also 2 special JS files, located inside `00-base`, these give you
some helper functions and global functionality. These are **loaded globally**,
alongside Once, drupal JS, drupalSettings, ….

All js-files located in the atoms/molecules/organisms/… folders will compile
into `js/dest`, exect SDC's.

If you make a new component:
1. add your original files to your new component's folder.
2. include the generated file and not the original source to your library.
3. don't forget to add your dependencies (e.g. Once, …). Even if it is already
added globally, this makes sure they are loaded BEFORE your JS is run.
4. attach your library to your component's twig-file if possible. If you don't
have a relevant twig-file to add it to, there are other ways to load the
library (see previously in the readme).

!!! DO NOT ADD YOUR JS-FILES TO THE 00-BASE FOLDER !!!

**Namespaces:**
We use a namespace (basically a global variable) to save all our functions in.
This is to make sure that we can easily reference functions/variables defined
in a separate file and make such references readable. This would not be a big
problem with aggregated files but would be during development.
See the various JS-files to see what I'm talking about.

**Behaviors**
Drupal behaviors are great. Look them up sometime.
Bundle your js triggers inside a behavior to ensure they are loaded after Ajax
calls.
You can split off your actual JS functions and put them outside the behaviors.

**Bigpipe**
There is a link to documentation about Bigpipe in the Sources at the end. In
short: Bigpipe is a system that loads chunks of the drupal site separately for
better loading efficiency. The language navigation is one of those elements
that is handled by Ajax in that way. That's why you don't see the active class
or property printed out in the Twig file.

**Once**
Examples of how to use this are in the top comments of all JS files.
These help to avoid loading JS (e.g. event handlers) multiple times.

## Breakpoints

See components/00-theme/00-base/05-grid/layout.docs.mdx

## Special components

### Forms

See components/00-theme/01-atoms/05-forms/forms.docs.mdx

### Menu's

components/00-theme/02-molecules/menus/menus.docs.mdx

## Layout 01: Twig

Look at a drupal site as nested dolls:

- **block layout**: the main frame of our site. These contain all the regions
set in the Drupal html twig file
- **view-modes**: the collection of fields and stuff that builds up a node
(Block or Content Type) of a certain type (e.g. Blog Content Type). There are
view-modes created per context. E.g. a teaser may not need to contain all the
same fields as the full node.
You can use Layout Builder to make a structure using rows (Sections) combined
with layout templates. Inside those layouts, are Regions, which are basically
the columns that contain the fields (and optionally, custom blocks).
All this can be found under the `manage view modes` tab of a Block or CT.
- **node variants**: When Layout Builder is active on a Content type, you can
actually specify to use a different layout ONLY on a specific node instead of
on ALL the nodes of that Content Type. This way you can make landing pages.
The homepage is a current example of this. It's a basic page that has been
changed.
- **theme twig files**: all entities (fields, blocks, CT's, …)
have corresponding Twig-files (you can see their names and paths when theme
suggestions are visible in html). The twig-files for view modes (only in
blocks, ct's) can be overridden with layout templates, if Layout Builder
has applied one.

**Fields:**

field don't have view-modes, they are rendered INSIDE view modes. You do have
some tricks to change their output without dealing with Twig though. Look at
the formatters and options in the various view modes. Formatters can also be
custom-made, but that's back-end dev stuff and outside the scope of this
documentation.

**Layout Builder vs default twig files:**

So for blocks/CT's/paragraphs, you have a choice to either use the default twig
templates and have full control of the output inside those (no predefined
subregions, no UI to help you). Or you can avoid this manual work by using
layout templates where regions can be pre-defined.

**Naming files:**

When making your own layout templates, keep in mind that **the machine name
has to be the same as the twig file name**. The machine name uses underscores
(_), the twig file uses dashes (-).

### Example: Blog content type

When using new content types:

It's recommended for most content types built in Rocketship to have at least 2
view-modes:
- teaser: for the main overview.
- full content: for the node detail content.

When clicking the Layout Builder button on the full content node, you will be
able to add sections to make up different parts of the node.
At the very least, you should add sections for the 'head' of your node and one
for the 'content'. Both should have custom classes in order to better style
them. For consistency with the rest of the theme/Drupal, we recommend naming
follows the BEM rules for CSS.

### Overviews

See the info in the 'development' readme of your Rocketship project, for more
info on making your own views, how to add them to the homepage or adding them
to a Page. But using Layout Builder, it should be pretty self-explanatory.

### View modes

As mentioned before, 2 view modes are recommended, One to load the entity
content's 'full content' and one for the 'teaser'.
Using Layout Builder on the full view mode will be needed if you are going to
open up content management for the web admin (or 'content editor').

### Libraries and styling

The `02-features` folder contains example styling for new Content Types (e.g.
Blog) but the libraries (defined in your_theme.libraries.yml) are NOT loaded
by default.

You can load any new or custom libraries yourself if you make new Content
Types. This can be done by attaching a library via the theme's
`rocketship_theme_starter.theme` file's `HOOK_preprocess_page` or in a Twig
template, for example.

The example styling can be changed in the `component/01-content-blocks` files.

## Content Sections and Content Blocks

### Background color and image

- **rocketship_theme_starter.theme**:
- `00-theme/admin.style.scss`
  You don't need to touch this file to work on content blocks.
- `components/01-content-blocks/03-organisms/00-section/_00-section.scss`
  define the background colors and related styling for the Sections in the
  front-facing theme.
- `components/01-content-blocks/03-organisms/section--simple-header/_simple-header.scss`
  define the background colors and related styling for the headers,
  as used in Page content type ….

In order for the background-colors preview to work in the admin theme, you need
to fill in your color variants at
`admin/config/system/rocketship-settings/settings`.

### Libraries and styling

The Content Blocks has libraries inside the Rocketship Core module, these
contain functional JS (e.g. FAQ block needs to open and close with a click).
They also load a structural CSS-file.

If you have a rocketship theme enabled, Content Blocks
loads styling from this theme, when Rocketship Core module is enabled.

This is done by attaching a library via the theme's
`rocketship_theme_starter.theme` file's `HOOK_preprocess_page`.

## CKE

### Webfonts
Fonts use the same file as the front-end fonts.

### Styles
Just like in previous versions, we can add Styles. This is done in the UI:
`/admin/config/content/formats`.

For each of your editors, you can scroll to the Styles dropdown section
and add your custom styles to it.
Always start with a tag-name and add the class separated by a dot (.)
For multiple variants, you can add all possible classes to your tag, separated
by a pipe (|)
There is a bug though. When you turn on 'limit html tags', the Styles dropdown
breaks.

## Sources

- [Vardumper](https://www.drupal.org/project/twig_vardumper)
- [Twig xdebug](https://www.drupal.org/project/twig_xdebug)
- [Devel: webprofiler](https://www.drupal.org/project/devel)
- [Atomic design](https://bradfrost.com/blog/post/atomic-web-design/)
- [Atomic design: book](https://atomicdesign.bradfrost.com/table-of-contents/)
- [Pattern lab demo](https://demo.patternlab.io/)
- [Drupal 8 documentation (incomplete)](https://www.drupal.org/docs)
- [Adding libaries to a theme (CSS, JS)](https://www.drupal.org/docs/develop/theming-drupal/adding-assets-css-js-to-a-drupal-theme-via-librariesyml)
- [Behaviors](https://www.drupal.org/docs/drupal-apis/javascript-api/javascript-api-overview#s-example-using-drupalbehaviors)
- [Behaviors [Bigpipe]](https://www.drupal.org/docs/8/core/modules/bigpipe/overview)
- [API overview](https://www.drupal.org/docs/drupal-apis/javascript-api/javascript-api-overview)
- [Powerful templating engine](https://twig.symfony.com/doc/2.x/)

## Common issues

### Theme suggestions don't work with Layouts.

For some reason, the theme suggestions don't work properly with the layouts if
the template file name (using dashes) is not the same as the template machine
(using underscores) name in `x.layouts.yml`.
So, rename the template file name to match.

### Unsupported platform for fsevents (only on Linux)

Some older versions of the themes included the node module `fsevents` and it
may still be a dependency of some other node modules. Problem is, this is
made to work with MacOS.
Fortunately, `fsevents` is not needed for our nmp scripts or Gulp tasks to
work, so we can remove or bypass it.
- Check your `package.json` file for a (dev)dependency of `fsevents`. If it is
in there, remove it and reinstall your node modules (remove the old ones
first).
- Check your gulp tasks for `fsevents` and remove any requires or functions
using this module.
- Rerun the task that gave you an error. If it's no longer there, you're good
to go.
- If you still get an error, run `npm rebuild` and then rerun the task.
