Skip to content

Commit f01cb33

Browse files
committed
docs(templates/community): add creation tutorial
1 parent 7f387a6 commit f01cb33

File tree

1 file changed

+155
-19
lines changed

1 file changed

+155
-19
lines changed

source/templates/community/README.md

Lines changed: 155 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -54,24 +54,6 @@ Some templates may accept additional custom parameters that can be passed throug
5454
}
5555
```
5656

57-
## 📪 Creating community templates
58-
59-
To create a new template, start a new repository and create a new folder in `/source/templates` with the same file structure as in [lowlighter/metrics](https://github.com/lowlighter/metrics) templates:
60-
61-
* `/source/templates`
62-
* `{template-name}`
63-
* `README.md`,
64-
* `metadata.yml`,
65-
* `image.svg`
66-
* `partials/`
67-
* `_.json`
68-
* `*.ejs`
69-
70-
Then use HTML, CSS, and [EJS](https://github.com/mde/ejs) to create something awesome!
71-
Do not hesitate to share it on [GitHub discussions](https://github.com/lowlighter/metrics/discussions)!
72-
73-
For more information, see [contribution guide](/CONTRIBUTING.md).
74-
7557
## ℹ️ Examples workflows
7658

7759
<!--examples-->
@@ -93,4 +75,158 @@ with:
9375
setup_community_templates: lowlighter/metrics@master:terminal+trust
9476

9577
```
96-
<!--/examples-->
78+
<!--/examples-->
79+
80+
## 📪 Creating community templates
81+
82+
Templates creation requires you to be comfortable with HTML, CSS and JavaScript ([EJS](https://github.com/mde/ejs) flavored).
83+
84+
To create a new template, clone and setup this repository first:
85+
```shell
86+
git clone https://github.com/lowlighter/metrics.git
87+
cd metrics/
88+
npm install
89+
```
90+
91+
Find a cool name for your new template and run the following:
92+
```shell
93+
npm run quickstart template <template_name>
94+
```
95+
96+
It will create a new directory in `/source/templates` with the following file structure:
97+
* `/source/templates/{template-name}`
98+
* `README.md`,
99+
* `metadata.yml`,
100+
* `image.svg`
101+
* `partials/`
102+
* `_.json`
103+
* `*.ejs`
104+
105+
Templates are auto-loaded based on their folder existence, so there's no need to register them somewhere.
106+
107+
### 💬 Understanding `image.svg`
108+
109+
Usually `image.svg` doesn't need to be edited too much, but let's explain it how it works.
110+
111+
```html
112+
<svg xmlns="http://www.w3.org/2000/svg" width="480" height="99999" class="<%= !animated ? 'no-animations' : '' %>">
113+
114+
<defs><style><%= fonts %></style></defs>
115+
<style data-optimizable="true"><%= style %></style>
116+
117+
<foreignObject x="0" y="0" width="100%" height="100%">
118+
<div xmlns="http://www.w3.org/1999/xhtml" xmlns:xlink="http://www.w3.org/1999/xlink">
119+
<% for (const partial of [...partials]) { %>
120+
<%- await include(`partials/${partial}.ejs`) %>
121+
<% } %>
122+
123+
<div id="metrics-end"></div>
124+
</div>
125+
</foreignObject>
126+
127+
</svg>
128+
```
129+
130+
#### EJS syntax
131+
132+
[EJS](https://github.com/mde/ejs) framework is used to programmatically create content through the help of templating tags (`<% %>`).
133+
134+
#### Styling
135+
136+
`fonts` and `style` variables are respectively populated with `fonts.css` and `styles.css` files content (or will fallback to those of `classic` template inexistent).
137+
138+
These will define the global design of the output.
139+
140+
`data-optimizable="true"` tells that a `style` tag can be safely minified and purged by CSS post-processors.
141+
142+
#### Partials
143+
144+
`partials` variable is populated with `partials/_.json` file content and define which files should be included along with default ordering.
145+
146+
The loop iterates over this array to include all defined partials. Each partial should handle whether it should be displayed by itself.
147+
148+
### `#metrics-end` tag
149+
150+
`#metrics-end` is a special HTML tag which must remain at the bottom of SVG template.
151+
152+
It is used to compute height dynamically through a [puppeteer](https://github.com/puppeteer/puppeteer) headless instance. Initial height should remain a high number so it doesn't get cropped accidentally while [puppeteer](https://github.com/puppeteer/puppeteer) compute [element.getBoundingClientRect()](https://developer.mozilla.org/fr/docs/Web/API/Element/getBoundingClientRect).
153+
154+
### 💬 Filling `metadata.yml`
155+
156+
`metadata.yml` is a file which describes supported account types, output formats, scopes, etc.
157+
158+
```yaml
159+
name: "🖼️ Template name"
160+
extends: classic
161+
description: Short description
162+
examples:
163+
default: https://via.placeholder.com/468x60?text=No%20preview%20available
164+
supports:
165+
- user
166+
- organization
167+
- repository
168+
formats:
169+
- svg
170+
- png
171+
- jpeg
172+
- json
173+
- markdown
174+
- markdown-pdf
175+
```
176+
177+
[`🧱 core`](/source/plugins/core/README.md) plugin will automatically check user inputs with your defined supported `supports` and `formats` key and throw an error in case of incompatibility.
178+
179+
`name`, `description` and `examples` are used to auto-generate documentation in the `README.md` by replacing the following:
180+
181+
```markdown
182+
<!--header-->
183+
<!--/header-->
184+
```
185+
186+
`extends` is used to define upon which template it should inherits its `template.mjs` when it is not trusted by user.
187+
188+
### 💬 Filling `examples.yml`
189+
190+
Workflow examples from `examples.yml` are used to auto-generate documentation in the `README.md` by replacing the following:
191+
192+
```markdown
193+
#### ℹ️ Examples workflows
194+
195+
<!--examples-->
196+
<!--/examples-->
197+
```
198+
199+
### 💬 Creating partials
200+
201+
Just create a new `.ejs` file in `partials` folder, and reference it into `partials/_.json`.
202+
203+
It should be able to handle gracefully plugins state and errors.
204+
205+
Below is a minimal snippet of a partial:
206+
```ejs
207+
<% if (plugins.gists) { %>
208+
<% if (plugins.gists.error) { %>
209+
<%= plugins.gists.error.message %>
210+
<% } else { %>
211+
<%# content %>
212+
<% } %>
213+
<% } %>
214+
```
215+
216+
Partials should have the match the same name as plugin handles, as they're used to display plugin compatibility in auto-generated header.
217+
218+
### 💬 Adding custom fonts
219+
220+
> ⚠️ This significantly increases rendered metrics filesize and thus not recommended. You should restrict charset when using this feature
221+
222+
Here's a quick step-by-step tutorial to create base64 encoded fonts:
223+
- 1. Find a font on [fonts.google.com](https://fonts.google.com)
224+
- Select regular, bold, italic and bold+italic fonts
225+
- Open `embed` tab and extract `href`
226+
- 2. Open extracted `href` in a browser and append `&text=` parameter with list of used characters
227+
- e.g. `&text=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`
228+
- 3. Download each font file from urls present in generated stylesheet
229+
- 4. Convert them into base64 with `woff` format on [transfonter.org](https://transfonter.org)
230+
- 5. Download archive and extract it
231+
- 6. Copy content of generated stylesheet to `fonts.css`
232+
- 7. Update `style.css` to use the new font

0 commit comments

Comments
 (0)