its-swiss 0.7.2 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +49 -0
- data/README.md +81 -2
- data/app/assets/javascripts/its_swiss/live_search_controller.js +31 -0
- data/app/assets/stylesheets/its_swiss/components.css +248 -0
- data/app/assets/stylesheets/its_swiss/tokens.css +8 -0
- data/app/assets/stylesheets/its_swiss/type.css +15 -2
- data/app/helpers/its_swiss/application_helper.rb +84 -0
- data/app/views/its_swiss/specimen/_filters.html.erb +38 -0
- data/app/views/its_swiss/specimen/_masthead.html.erb +21 -2
- data/app/views/its_swiss/specimen/_page_head.html.erb +15 -0
- data/app/views/its_swiss/specimen/_take.html.erb +2 -0
- data/app/views/layouts/its_swiss/shell.html.erb +5 -0
- data/config/importmap.rb +6 -4
- data/lib/its_swiss/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 609e2de8676ac502b9fd59c7c0eb8fa4a57e2c6ba5a0a7ab37b618f81b3203b4
|
|
4
|
+
data.tar.gz: 7fced9860618baa6456eb521f4b2a1e6fecb667f8adc3c9f550c990d067669c7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0fc7073ab2bf1bc8f39db1a2124b08e746d3811f71fbf38e0573af7fb6e59912e776e3f6bddce62802b08d9ae6528f5eb51d15d147904e0d4516f69db738df9c
|
|
7
|
+
data.tar.gz: 914e4ea3dee558b14821e3a0b3ce134220520b7be6d9d5d10727d2f8f6b173d025868aa30c4316b81e523ff7bfb8fb5a2563a2219a33b2686f9be2b8b0753fca
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,55 @@
|
|
|
2
2
|
|
|
3
3
|
Semver. Consumers pin `~> 0.1`.
|
|
4
4
|
|
|
5
|
+
## 0.8.0 — 2026-09-07
|
|
6
|
+
|
|
7
|
+
The third consumer, and what it and the second found in common.
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **A page head.** `page_head(title, lede:) { actions }` writes the one
|
|
12
|
+
shape every page opens with: the title in the page-title register, its
|
|
13
|
+
lede when it has one, and the actions in a run beside them, wrapping
|
|
14
|
+
under the title when the page is narrow. Pandatone, Stripeclub and
|
|
15
|
+
Badger had each drawn their own, and no two agreed on the size of the
|
|
16
|
+
title or where the buttons went. The document is titled from it unless
|
|
17
|
+
the view has titled itself.
|
|
18
|
+
|
|
19
|
+
- **Filters.** A block of registers that narrow a list, each a quiet label
|
|
20
|
+
and then the choices, in the same two positions every time — a search, a
|
|
21
|
+
tag, an order, a size are the same kind of control, and are built the
|
|
22
|
+
same way. `filter_register(label, choices, name:)` writes one; the choice
|
|
23
|
+
in force carries `aria-current`, which the CSS colours and weights, for
|
|
24
|
+
the reason the nav says it twice. `search_form(url, frame:, keep:)`
|
|
25
|
+
writes the first register: a search that narrows the list as you type,
|
|
26
|
+
into the Turbo Frame named, carrying the other choices so a search does
|
|
27
|
+
not drop them. Two slots go with it: `--filter-label`, the column the
|
|
28
|
+
labels occupy, and `--card`.
|
|
29
|
+
|
|
30
|
+
- **Cards.** `.cards` on a `.grid` lays a list out on the page's own
|
|
31
|
+
fields, each item `--card` fields wide, two lines between the rows.
|
|
32
|
+
`.card__link`, `.card__figure`, `.card__name`, `.card__meta` are the
|
|
33
|
+
parts. No box: the picture is the only filled area a card has.
|
|
34
|
+
|
|
35
|
+
- **A menu in the nav, and a subnav under the masthead.** `nav_menu(label,
|
|
36
|
+
current:) { links }` is a destination that opens into destinations — a
|
|
37
|
+
details element, so it opens with no script — and carries the accent and
|
|
38
|
+
the weight when where you are is inside it. The shell renders `:subnav`,
|
|
39
|
+
when an application fills it, as a shaded band under the masthead: a
|
|
40
|
+
second layer of destinations, inside the one you are in. A host that
|
|
41
|
+
carries several tools puts the tools in the menu and each tool's own
|
|
42
|
+
sections in the band.
|
|
43
|
+
|
|
44
|
+
- **A live search controller.** `its_swiss/live_search_controller.js`,
|
|
45
|
+
pinned by the engine like the clipboard, submits a search form as you
|
|
46
|
+
type and takes away the button it makes redundant. The host registers it
|
|
47
|
+
as `its-swiss-live-search`, beside the clipboard.
|
|
48
|
+
|
|
49
|
+
### Changed
|
|
50
|
+
|
|
51
|
+
- The micro register and the quiet colour take `.filter__label` and
|
|
52
|
+
`.card__meta`.
|
|
53
|
+
|
|
5
54
|
## 0.7.2 — 2026-09-04
|
|
6
55
|
|
|
7
56
|
### Changed
|
data/README.md
CHANGED
|
@@ -34,7 +34,7 @@ current one at `/<version>.html` for anything that needs to pin.
|
|
|
34
34
|
| In the gem | Stays in the application |
|
|
35
35
|
| --- | --- |
|
|
36
36
|
| Tokens, reset, base typography | The grid itself — which blocks span which fields |
|
|
37
|
-
| Masthead, nav, footer, table, form, button, definition list, pagination | Domain components |
|
|
37
|
+
| Masthead, nav, page head, footer, table, form, button, definition list, pagination, filters, cards | Domain components |
|
|
38
38
|
| A base layout shell with `content_for` slots | Page layouts beyond the shell |
|
|
39
39
|
| View transition names and durations | Which pages transition to which |
|
|
40
40
|
| The value scale and the accent slot | Any hue, any palette knowledge |
|
|
@@ -71,6 +71,8 @@ holding all of them. Nothing here has a default the gem could pick honestly.
|
|
|
71
71
|
| `--columns`, `--gutter` | How many fields this problem has |
|
|
72
72
|
| `--line` | The baseline: the interval everything vertical registers to |
|
|
73
73
|
| `--ratio` | A picture's aspect ratio, per figure — the library cannot read one |
|
|
74
|
+
| `--card` | How many fields a card takes, and at which widths |
|
|
75
|
+
| `--filter-label` | The column a filter's label occupies, so every register's choices start on one line |
|
|
74
76
|
| `--face-150`, `--face-200`, `--face-100` | Read, not set: the face a register names for its ratio of leading to size |
|
|
75
77
|
|
|
76
78
|
### The baseline
|
|
@@ -313,6 +315,59 @@ it stops on a field line:
|
|
|
313
315
|
--measure: calc(var(--field) * 3 + var(--gutter) * 2);
|
|
314
316
|
```
|
|
315
317
|
|
|
318
|
+
### The page head
|
|
319
|
+
|
|
320
|
+
What a page is and what can be done to it, in one shape on every page: the
|
|
321
|
+
title in the page-title register, its lede when it has one, and the actions in
|
|
322
|
+
a run beside them, wrapping under the title when the page is narrow.
|
|
323
|
+
|
|
324
|
+
```erb
|
|
325
|
+
<%= page_head "Palettes", lede: "Every palette in the library." do %>
|
|
326
|
+
<%= link_to "New palette", new_palette_path, class: "button button--primary" %>
|
|
327
|
+
<% end %>
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
The document is titled from it unless the view has already set `:title`.
|
|
331
|
+
|
|
332
|
+
### Filters and cards
|
|
333
|
+
|
|
334
|
+
What narrows a list, and the list. A search that filters as you type, and a
|
|
335
|
+
register for each other way of narrowing it — a tag, an order, a size — in the
|
|
336
|
+
same two positions every time: a quiet label, then the choices, the one in
|
|
337
|
+
force carrying `aria-current`, which the CSS colours and weights.
|
|
338
|
+
|
|
339
|
+
```erb
|
|
340
|
+
<div class="filters">
|
|
341
|
+
<%= search_form palettes_path, frame: "palettes", keep: { tag: params[:tag], sort: params[:sort] } %>
|
|
342
|
+
<%= filter_register "Tagged", [ [ "All", palettes_path, params[:tag].blank? ],
|
|
343
|
+
*tags.map { |t| [ t, palettes_path(tag: t), params[:tag] == t ] } ],
|
|
344
|
+
name: "tag" %>
|
|
345
|
+
</div>
|
|
346
|
+
|
|
347
|
+
<%= turbo_frame_tag "palettes", target: "_top" do %>
|
|
348
|
+
<ul class="grid cards">
|
|
349
|
+
<li class="card">
|
|
350
|
+
<a class="card__link" href="…">
|
|
351
|
+
<figure class="card__figure figure" style="--ratio: 1.5"><img src="…" alt=""></figure>
|
|
352
|
+
<span class="card__name">Brand Core</span>
|
|
353
|
+
</a>
|
|
354
|
+
<span class="card__meta">4 swatches</span>
|
|
355
|
+
</li>
|
|
356
|
+
</ul>
|
|
357
|
+
<% end %>
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
The search form belongs outside the frame it fills, so only the results are
|
|
361
|
+
replaced and the field keeps its cursor. `keep:` carries the other choices as
|
|
362
|
+
hidden fields, so a search does not drop the tag or the order you were reading
|
|
363
|
+
in. The button is there for a browser that runs no script; the controller
|
|
364
|
+
takes it away once it has connected.
|
|
365
|
+
|
|
366
|
+
A card is `--card` fields wide on the page's own grid — say how many once, and
|
|
367
|
+
again at each width that changes it. The picture is a `.figure` with its
|
|
368
|
+
`--ratio` declared, so its box is whole lines at any width and the name under
|
|
369
|
+
it stays on the grid.
|
|
370
|
+
|
|
316
371
|
## The layout shell
|
|
317
372
|
|
|
318
373
|
The installer writes `app/views/layouts/application.html.erb` as a layout
|
|
@@ -345,6 +400,7 @@ Slots, all optional:
|
|
|
345
400
|
| `:head` | Anything else that belongs in `<head>` |
|
|
346
401
|
| `:mark` | The wordmark. No mark and no nav means no masthead at all |
|
|
347
402
|
| `:nav` | The destinations |
|
|
403
|
+
| `:subnav` | A second layer of destinations, inside the one you are in: a shaded band under the masthead |
|
|
348
404
|
| `:main_class` | What the page's main region is, if it is a grid |
|
|
349
405
|
| `:footer` | Whatever belongs after the page |
|
|
350
406
|
|
|
@@ -359,9 +415,13 @@ beyond the shell is the application's, for the same reason its grid is.
|
|
|
359
415
|
| `its_swiss_stylesheet_tags` | The seven links, tracked for Turbo |
|
|
360
416
|
| `its_swiss_typeface(regular:, bold:)` | The application's typeface, declared under the library's face names |
|
|
361
417
|
| `nav_link_to(name, url, current:)` | A destination, with `aria-current` when you are at it |
|
|
418
|
+
| `nav_menu(label, current:) { links }` | A destination that opens into destinations, with no script |
|
|
362
419
|
| `copy_button(value)` | A value that copies itself |
|
|
363
420
|
| `its_swiss_form_with(...)` | `form_with`, already holding the library's builder |
|
|
364
421
|
| `its_swiss_page_numbers(page, pages)` | Which numbers a run of them shows, elided |
|
|
422
|
+
| `page_head(title, lede:) { actions }` | The one shape every page opens with |
|
|
423
|
+
| `filter_register(label, choices, name:)` | One register of a filter block |
|
|
424
|
+
| `search_form(url, frame:, keep:)` | A search that narrows a list as you type |
|
|
365
425
|
|
|
366
426
|
### Pagination
|
|
367
427
|
|
|
@@ -376,6 +436,24 @@ a page, a total, and something that turns a number into a URL:
|
|
|
376
436
|
Long runs are elided around the current page. `window:` (default 2) sets how
|
|
377
437
|
many neighbours show; `label:` names the `<nav>` for a screen reader.
|
|
378
438
|
|
|
439
|
+
### JavaScript
|
|
440
|
+
|
|
441
|
+
Two Stimulus controllers, pinned by the engine so an application that upgrades
|
|
442
|
+
the gem gets the new file without touching its importmap. They are outside
|
|
443
|
+
`controllers/`, so an application registers them by hand, once:
|
|
444
|
+
|
|
445
|
+
```js
|
|
446
|
+
// app/javascript/controllers/index.js
|
|
447
|
+
import ItsSwissClipboardController from "its_swiss/clipboard_controller"
|
|
448
|
+
import ItsSwissLiveSearchController from "its_swiss/live_search_controller"
|
|
449
|
+
application.register("its-swiss-clipboard", ItsSwissClipboardController)
|
|
450
|
+
application.register("its-swiss-live-search", ItsSwissLiveSearchController)
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
`copy_button` and `search_form` write the `data-controller` attributes; a page
|
|
454
|
+
without the registrations still works, with the value selectable and the
|
|
455
|
+
search's button on the page.
|
|
456
|
+
|
|
379
457
|
## The form builder
|
|
380
458
|
|
|
381
459
|
One shape for every field: a label, a control, and — when there is something to
|
|
@@ -464,7 +542,8 @@ ladder; the names are the library's rather than the application's.
|
|
|
464
542
|
| `.masthead__nav` | `.nav` |
|
|
465
543
|
| `.channels` | `.pairs` |
|
|
466
544
|
| `.form`, `.field`, `.button*`, `.copy`, `.errors`, `.hint`, `.empty` | unchanged |
|
|
467
|
-
|
|
|
545
|
+
| `.tag*`, `.filter*`, `.page-head`, `live-search` | `.filter*`, `.page-head`, `.cards`, `its-swiss-live-search` — in the gem since 0.8.0 |
|
|
546
|
+
| `--columns-dense`, `--card-wide`, `.swatch*` | stay in Pandatone |
|
|
468
547
|
|
|
469
548
|
Two behavioural differences to know about:
|
|
470
549
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
|
2
|
+
|
|
3
|
+
// Submits a search form as you type, into the Turbo Frame it targets.
|
|
4
|
+
//
|
|
5
|
+
// The filtering stays on the server, in the same scope the button uses: one
|
|
6
|
+
// definition of what a search matches, not a Ruby one and a drifting
|
|
7
|
+
// JavaScript copy. The form sits outside its frame so only the results are
|
|
8
|
+
// replaced and the field keeps its focus and its cursor.
|
|
9
|
+
//
|
|
10
|
+
// The button goes when this connects, because from that moment it is a second
|
|
11
|
+
// way to do the thing that has just been done. It is hidden here rather than
|
|
12
|
+
// left out of the markup for the browser that never runs this: without the
|
|
13
|
+
// controller the button is the only way to search, so it has to be on the
|
|
14
|
+
// page for the page to work.
|
|
15
|
+
export default class extends Controller {
|
|
16
|
+
static targets = [ "submit" ]
|
|
17
|
+
static values = { delay: { type: Number, default: 200 } }
|
|
18
|
+
|
|
19
|
+
connect() {
|
|
20
|
+
if (this.hasSubmitTarget) this.submitTarget.hidden = true
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
search() {
|
|
24
|
+
clearTimeout(this.timeout)
|
|
25
|
+
this.timeout = setTimeout(() => this.element.requestSubmit(), this.delayValue)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
disconnect() {
|
|
29
|
+
clearTimeout(this.timeout)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -70,6 +70,91 @@
|
|
|
70
70
|
font-weight: 700;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
/* A menu in the nav: a destination that opens into destinations. A
|
|
74
|
+
details element, so it opens and closes with no script, and a summary
|
|
75
|
+
set like the other destinations with a small mark that says it opens.
|
|
76
|
+
The list floats under it on paper with a keyline, the one floating box
|
|
77
|
+
in the style — a menu that pushed the page down would not be a menu. */
|
|
78
|
+
.menu {
|
|
79
|
+
position: relative;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.menu > summary {
|
|
83
|
+
list-style: none;
|
|
84
|
+
cursor: pointer;
|
|
85
|
+
white-space: nowrap;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.menu > summary::-webkit-details-marker { display: none; }
|
|
89
|
+
|
|
90
|
+
.menu > summary::after {
|
|
91
|
+
content: " \25BE";
|
|
92
|
+
color: var(--ink-quiet);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.menu > summary:hover,
|
|
96
|
+
.menu[open] > summary { color: var(--ink); }
|
|
97
|
+
|
|
98
|
+
/* Where you are, when where you are is inside the menu: said twice, the
|
|
99
|
+
way the nav says it. */
|
|
100
|
+
.menu--current > summary {
|
|
101
|
+
color: var(--accent);
|
|
102
|
+
font-weight: 700;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* Out of the flow, but still on the grid: a line of padding above and
|
|
106
|
+
below, and the keyline drawn inside, so every link in it sits on a
|
|
107
|
+
line of the page under it. */
|
|
108
|
+
.menu__list {
|
|
109
|
+
position: absolute;
|
|
110
|
+
inset-inline-start: calc(-1 * var(--space-2));
|
|
111
|
+
top: 100%;
|
|
112
|
+
z-index: 1;
|
|
113
|
+
display: flex;
|
|
114
|
+
flex-direction: column;
|
|
115
|
+
min-width: max-content;
|
|
116
|
+
padding: var(--line) var(--space-2);
|
|
117
|
+
background: var(--paper);
|
|
118
|
+
box-shadow: inset 0 0 0 var(--rule-hair) var(--rule);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.menu__list a {
|
|
122
|
+
display: block;
|
|
123
|
+
text-decoration: none;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.menu__list a:hover { color: var(--ink); }
|
|
127
|
+
|
|
128
|
+
/* --- Subnav -------------------------------------------------------------
|
|
129
|
+
A second layer of destinations, inside the one you are in: what a tool
|
|
130
|
+
has beside what the application has. A shaded band under the masthead,
|
|
131
|
+
three lines tall the way the masthead is, with the same run of links
|
|
132
|
+
the nav has and the same marking of where you are. Rendered by the
|
|
133
|
+
shell when the application fills :subnav, and not at all otherwise. */
|
|
134
|
+
/* The rule is drawn inside the band rather than under it, so the band and
|
|
135
|
+
the page inside it are both three whole lines. */
|
|
136
|
+
.subnav {
|
|
137
|
+
background: var(--paper-shaded);
|
|
138
|
+
box-shadow: inset 0 calc(-1 * var(--rule-hair)) 0 var(--rule);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.subnav > .page {
|
|
142
|
+
display: flex;
|
|
143
|
+
flex-wrap: wrap;
|
|
144
|
+
align-items: end;
|
|
145
|
+
gap: var(--line) var(--space-3);
|
|
146
|
+
padding-block: var(--line);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.subnav a { text-decoration: none; }
|
|
150
|
+
|
|
151
|
+
.subnav a:hover { color: var(--ink); }
|
|
152
|
+
|
|
153
|
+
.subnav [aria-current="page"] {
|
|
154
|
+
color: var(--accent);
|
|
155
|
+
font-weight: 700;
|
|
156
|
+
}
|
|
157
|
+
|
|
73
158
|
/* --- Footer -------------------------------------------------------------
|
|
74
159
|
A hairline, the micro register, and whatever the application has to say
|
|
75
160
|
after the page. It carries no links of its own: what belongs down there
|
|
@@ -89,6 +174,38 @@
|
|
|
89
174
|
line-height: var(--line);
|
|
90
175
|
}
|
|
91
176
|
|
|
177
|
+
/* --- Page head ----------------------------------------------------------
|
|
178
|
+
What a page is and what can be done to it. The title and, when it has
|
|
179
|
+
one, its lede on the left; the actions on the right, wrapping under
|
|
180
|
+
the title when the page is narrow. Everything after it starts two
|
|
181
|
+
lines down, which is the gap a section gets.
|
|
182
|
+
|
|
183
|
+
One shape for every page, so a reader arriving from another application
|
|
184
|
+
set in this style already knows where the name is and where the buttons
|
|
185
|
+
are. The title is the page-title register: a page has one, and it is
|
|
186
|
+
the largest thing on it. */
|
|
187
|
+
|
|
188
|
+
.page-head {
|
|
189
|
+
display: flex;
|
|
190
|
+
flex-wrap: wrap;
|
|
191
|
+
justify-content: space-between;
|
|
192
|
+
align-items: flex-start;
|
|
193
|
+
gap: var(--line) var(--space-3);
|
|
194
|
+
margin-block-end: var(--line-2);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/* The title takes the measure and the actions take what they need. A
|
|
198
|
+
basis rather than a share, so a long name wraps inside the measure
|
|
199
|
+
instead of pushing the actions off the line. */
|
|
200
|
+
.page-head__title {
|
|
201
|
+
flex: 1 1 var(--measure);
|
|
202
|
+
min-width: 0;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/* The actions shrink to their widest button and wrap inside it, rather
|
|
206
|
+
than holding their one-line width and pushing a phone's page sideways. */
|
|
207
|
+
.page-head__actions { flex: 0 1 auto; }
|
|
208
|
+
|
|
92
209
|
/* --- Rules --------------------------------------------------------------
|
|
93
210
|
The one horizontal mark in the style, at the two weights tokens.css
|
|
94
211
|
declares. */
|
|
@@ -490,6 +607,137 @@
|
|
|
490
607
|
|
|
491
608
|
.pagination__gap { color: var(--ink-quiet); }
|
|
492
609
|
|
|
610
|
+
/* --- Filters ------------------------------------------------------------
|
|
611
|
+
What narrows a list. One shape for every way of narrowing it — a
|
|
612
|
+
search, a tag, an order, a size — because they are the same kind of
|
|
613
|
+
control: pick one of a handful. A register is a quiet label and then
|
|
614
|
+
the choices, in the same two positions every time, so filtering and
|
|
615
|
+
ordering read as the registers they are rather than as two rows of
|
|
616
|
+
identical words. Ruled above and below: the block belongs to the list
|
|
617
|
+
under it, not to the page head above. */
|
|
618
|
+
|
|
619
|
+
.filters {
|
|
620
|
+
display: flex;
|
|
621
|
+
flex-wrap: wrap;
|
|
622
|
+
align-items: flex-start;
|
|
623
|
+
gap: var(--line) var(--space-3);
|
|
624
|
+
/* The rules are drawn inside the box, so the block stays whole lines. */
|
|
625
|
+
padding-block: calc(var(--line) - var(--rule-hair));
|
|
626
|
+
border-block: var(--rule-hair) solid var(--rule);
|
|
627
|
+
margin-block-end: var(--line);
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
.filter {
|
|
631
|
+
display: flex;
|
|
632
|
+
flex-wrap: wrap;
|
|
633
|
+
align-items: flex-start;
|
|
634
|
+
flex-basis: 100%;
|
|
635
|
+
gap: var(--line) var(--space-2);
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
/* The label column. A width off the ladder, so every register's choices
|
|
639
|
+
start on the same line down the page rather than a few pixels apart
|
|
640
|
+
because one word is longer than another. An application with longer
|
|
641
|
+
labels sets --filter-label once. */
|
|
642
|
+
.filter__label,
|
|
643
|
+
.filters .form--inline label { min-width: var(--filter-label); }
|
|
644
|
+
|
|
645
|
+
.filter__choices {
|
|
646
|
+
display: flex;
|
|
647
|
+
flex-wrap: wrap;
|
|
648
|
+
gap: var(--line) var(--space-2);
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
/* The choices are the flex items themselves, the way the nav's
|
|
652
|
+
destinations are: blockified, so each is a line box that is the tap
|
|
653
|
+
target and can be trimmed where the faces are not honoured. A list
|
|
654
|
+
item between them would be a second box to correct. */
|
|
655
|
+
.filter__choices a {
|
|
656
|
+
color: var(--ink-quiet);
|
|
657
|
+
text-decoration: none;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
.filter__choices a:hover { color: var(--ink); }
|
|
661
|
+
|
|
662
|
+
/* Which one is chosen, said twice, for the reason the nav says it twice. */
|
|
663
|
+
.filter__choices [aria-current] {
|
|
664
|
+
color: var(--accent);
|
|
665
|
+
font-weight: 700;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/* The search is the first register, built like the others rather than as
|
|
669
|
+
a stacked field above them: the label in the label column, the control
|
|
670
|
+
where the choices start. Label and control meet on the under edge — the
|
|
671
|
+
label's baseline is its under edge, and the control's text stands on
|
|
672
|
+
the rule that closes it — so the two read as one line. The button is
|
|
673
|
+
there for a browser that runs no script and wraps under the field at a
|
|
674
|
+
phone's width; it goes when the live search connects, because from then
|
|
675
|
+
on typing has already done what it does. */
|
|
676
|
+
.filters .form--inline {
|
|
677
|
+
flex: 1 1 var(--measure);
|
|
678
|
+
max-width: var(--measure);
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
.filters .form--inline .field--inline {
|
|
682
|
+
flex: 1 1 auto;
|
|
683
|
+
align-items: flex-end;
|
|
684
|
+
min-width: 0;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
/* A basis of nothing, so the control takes what the row has left rather
|
|
688
|
+
than the twenty characters a browser gives a text control by default. */
|
|
689
|
+
.filters .form--inline .field--inline input {
|
|
690
|
+
flex: 1 1 0;
|
|
691
|
+
width: auto;
|
|
692
|
+
min-width: 0;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
/* --- Cards --------------------------------------------------------------
|
|
696
|
+
A list of things, each a picture over its name and a line about it,
|
|
697
|
+
laid out on the page's own fields: a card is --card fields wide, and
|
|
698
|
+
the application says how many, once, at each width it cares about. Two
|
|
699
|
+
lines between the rows, because a row of cards is a row of sections.
|
|
700
|
+
|
|
701
|
+
No box. A card is the thing itself, and the picture is the only filled
|
|
702
|
+
area it has; what separates one from the next is the gutter. */
|
|
703
|
+
|
|
704
|
+
.cards { row-gap: var(--line-2); }
|
|
705
|
+
|
|
706
|
+
.cards > * {
|
|
707
|
+
--span: var(--card);
|
|
708
|
+
min-width: 0;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
/* The picture and the name are one link, so a card costs one tab stop and
|
|
712
|
+
announces its destination once. */
|
|
713
|
+
.card__link {
|
|
714
|
+
display: block;
|
|
715
|
+
color: inherit;
|
|
716
|
+
text-decoration: none;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
.card__link:hover .card__name {
|
|
720
|
+
text-decoration: underline;
|
|
721
|
+
text-underline-offset: 0.2em;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
/* The picture is a .figure with its --ratio declared, so its box is a
|
|
725
|
+
whole number of lines at any width and the name under it stays on the
|
|
726
|
+
grid; what this adds is the line between them. */
|
|
727
|
+
.card__figure { margin-block-end: var(--line); }
|
|
728
|
+
|
|
729
|
+
/* Blocks, so each is a line of its own and can be trimmed where the faces
|
|
730
|
+
are not honoured. */
|
|
731
|
+
.card__name,
|
|
732
|
+
.card__meta { display: block; }
|
|
733
|
+
|
|
734
|
+
.card__name {
|
|
735
|
+
font-family: var(--face-150), var(--font-family);
|
|
736
|
+
font-size: var(--size-2);
|
|
737
|
+
line-height: var(--line);
|
|
738
|
+
font-weight: 700;
|
|
739
|
+
}
|
|
740
|
+
|
|
493
741
|
/* --- What a page has to say --------------------------------------------
|
|
494
742
|
Three registers: it worked, it was refused, there is nothing here. The
|
|
495
743
|
refusal is the only one that interrupts, and it interrupts with a rule
|
|
@@ -181,6 +181,14 @@
|
|
|
181
181
|
);
|
|
182
182
|
--measure: calc(var(--field) * 3 + var(--gutter) * 2);
|
|
183
183
|
|
|
184
|
+
/* --- Lists -------------------------------------------------------------
|
|
185
|
+
Two more slots an index fills. How many fields a card takes, which is
|
|
186
|
+
the application's to say and to change at each width it cares about;
|
|
187
|
+
and the column a filter's label occupies, so the choices of every
|
|
188
|
+
register start on one line down the page. */
|
|
189
|
+
--card: 1;
|
|
190
|
+
--filter-label: var(--space-8);
|
|
191
|
+
|
|
184
192
|
/* --- Transitions -------------------------------------------------------
|
|
185
193
|
The page crossfade is short enough to read as a replacement rather than
|
|
186
194
|
an animation. A morph runs longer, because the thing travelling has to
|
|
@@ -81,7 +81,9 @@
|
|
|
81
81
|
caption,
|
|
82
82
|
legend,
|
|
83
83
|
label,
|
|
84
|
-
.field label
|
|
84
|
+
.field label,
|
|
85
|
+
.filter__label,
|
|
86
|
+
.card__meta {
|
|
85
87
|
font-family: var(--face-200), var(--font-family);
|
|
86
88
|
font-size: var(--size-1);
|
|
87
89
|
line-height: var(--line);
|
|
@@ -93,7 +95,11 @@
|
|
|
93
95
|
picking a gray. */
|
|
94
96
|
.quiet,
|
|
95
97
|
.hint,
|
|
98
|
+
.filter__label,
|
|
99
|
+
.card__meta,
|
|
96
100
|
.nav a,
|
|
101
|
+
.menu > summary,
|
|
102
|
+
.subnav a,
|
|
97
103
|
.footer,
|
|
98
104
|
.pairs dt,
|
|
99
105
|
.button--quiet,
|
|
@@ -119,6 +125,8 @@
|
|
|
119
125
|
inherited, because a button does not inherit a font and a nav may sit
|
|
120
126
|
inside a register that is not the body's. */
|
|
121
127
|
.nav a,
|
|
128
|
+
.menu > summary,
|
|
129
|
+
.subnav a,
|
|
122
130
|
.button {
|
|
123
131
|
font-family: var(--face-150), var(--font-family);
|
|
124
132
|
font-size: var(--size-2);
|
|
@@ -220,11 +228,16 @@
|
|
|
220
228
|
.page-title,
|
|
221
229
|
h1, h2, h3, h4,
|
|
222
230
|
p, dt, th, td, figcaption, caption, legend, label,
|
|
223
|
-
li:not(:has(> :is(p, ul, ol, dl, div, figure, table, pre, blockquote))),
|
|
231
|
+
li:not(:has(> :is(p, ul, ol, dl, div, figure, table, pre, blockquote, .card__link))),
|
|
224
232
|
dd:not(:has(> :is(p, ul, ol, dl, div, figure, table, pre, blockquote))),
|
|
225
233
|
.micro, .hint, .lede, .empty, .masthead__mark, .field__error, .errors__title,
|
|
234
|
+
.filter__label, .card__name, .card__meta,
|
|
226
235
|
/* Flex items are blockified, so the text in a row is trimmable too. */
|
|
227
236
|
.nav a,
|
|
237
|
+
.menu > summary,
|
|
238
|
+
.menu__list a,
|
|
239
|
+
.subnav a,
|
|
240
|
+
.filter__choices a,
|
|
228
241
|
.pagination a,
|
|
229
242
|
.pagination [aria-current],
|
|
230
243
|
.pagination__gap,
|
|
@@ -80,6 +80,21 @@ module ItsSwiss
|
|
|
80
80
|
link_to(name, url, **options, &block)
|
|
81
81
|
end
|
|
82
82
|
|
|
83
|
+
# A destination in the nav that opens into destinations: a details
|
|
84
|
+
# element with the label as its summary and the block as its list, so it
|
|
85
|
+
# opens and closes with no script. current: when one of the destinations
|
|
86
|
+
# inside is where you are, the summary carries the accent and the weight
|
|
87
|
+
# the way a current link does.
|
|
88
|
+
#
|
|
89
|
+
# <%= nav_menu "Tools", current: in_a_tool? do %>
|
|
90
|
+
# <%= nav_link_to "Pandatone", "/pandatone", current: in_engine?(pandatone) %>
|
|
91
|
+
# <% end %>
|
|
92
|
+
def nav_menu(label, current: false, &block)
|
|
93
|
+
tag.details(class: token_list("menu", ("menu--current" if current))) do
|
|
94
|
+
safe_join([ tag.summary(label), tag.div(capture(&block), class: "menu__list") ])
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
83
98
|
# A value on screen exists to be taken somewhere else, so it is a button
|
|
84
99
|
# that copies itself. The value stays visible text inside it, which is
|
|
85
100
|
# what keeps it usable when the clipboard is not available at all.
|
|
@@ -133,6 +148,75 @@ module ItsSwiss
|
|
|
133
148
|
end
|
|
134
149
|
private :its_swiss_face
|
|
135
150
|
|
|
151
|
+
# What a page is and what can be done to it: the title, a lede when the
|
|
152
|
+
# page has one, and the actions in the block. One shape for every page,
|
|
153
|
+
# and the document is titled from it unless the view has titled itself.
|
|
154
|
+
#
|
|
155
|
+
# <%= page_head "Palettes", lede: "Every palette in the library." do %>
|
|
156
|
+
# <%= link_to "New palette", new_palette_path, class: "button button--primary" %>
|
|
157
|
+
# <% end %>
|
|
158
|
+
def page_head(title, lede: nil, &block)
|
|
159
|
+
content_for(:title, strip_tags(title.to_s)) unless content_for?(:title)
|
|
160
|
+
actions = capture(&block) if block
|
|
161
|
+
|
|
162
|
+
tag.header(class: "page-head") do
|
|
163
|
+
safe_join([
|
|
164
|
+
tag.div(class: "page-head__title") do
|
|
165
|
+
safe_join([ tag.h1(title, class: "page-title"), (tag.p(lede, class: "lede") if lede) ].compact)
|
|
166
|
+
end,
|
|
167
|
+
(tag.div(actions, class: "page-head__actions run") if actions.present?)
|
|
168
|
+
].compact)
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# One register of a filter block: a quiet label, then the choices, each
|
|
173
|
+
# a name, a URL and whether it is the one in force. Filtering and
|
|
174
|
+
# ordering are the same kind of control — pick one of a handful — so
|
|
175
|
+
# they are built the same way and told apart by their label.
|
|
176
|
+
#
|
|
177
|
+
# <%= filter_register "Tagged", [ [ "All", colors_path, params[:tag].blank? ],
|
|
178
|
+
# *tags.map { |t| [ t, colors_path(tag: t), params[:tag] == t ] } ],
|
|
179
|
+
# name: "tag" %>
|
|
180
|
+
#
|
|
181
|
+
# The one in force carries aria-current, which the CSS colours and
|
|
182
|
+
# weights, and a test can find without reading a class.
|
|
183
|
+
def filter_register(label, choices, name: nil)
|
|
184
|
+
tag.div(class: "filter", data: { filter: name }) do
|
|
185
|
+
safe_join([
|
|
186
|
+
tag.span(label, class: "filter__label"),
|
|
187
|
+
tag.div(class: "filter__choices") do
|
|
188
|
+
safe_join(choices.map { |text, url, current| link_to(text, url, aria: { current: ("true" if current) }) })
|
|
189
|
+
end
|
|
190
|
+
])
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# A search that narrows a list as you type, into the Turbo Frame named.
|
|
195
|
+
# The form belongs outside that frame, so only the results are replaced
|
|
196
|
+
# and the field keeps its cursor; the button is for a browser that runs
|
|
197
|
+
# no script, and the controller takes it away once it has connected.
|
|
198
|
+
#
|
|
199
|
+
# <%= search_form palettes_path, frame: "palettes", keep: { tag: params[:tag], sort: params[:sort] } %>
|
|
200
|
+
#
|
|
201
|
+
# keep: the other choices on the page, carried as hidden fields so a
|
|
202
|
+
# search does not drop the tag or the order you were reading in. The
|
|
203
|
+
# host registers the controller as its-swiss-live-search.
|
|
204
|
+
def search_form(url, frame:, param: :q, label: "Search", value: nil, keep: {}, delay: nil, **options)
|
|
205
|
+
value = params[param] if value.nil? && respond_to?(:params)
|
|
206
|
+
data = { controller: "its-swiss-live-search", action: "input->its-swiss-live-search#search",
|
|
207
|
+
turbo_frame: frame, its_swiss_live_search_delay_value: delay }.compact
|
|
208
|
+
|
|
209
|
+
form_with(url: url, method: :get, class: token_list("form form--inline", options[:class]), data: data) do
|
|
210
|
+
safe_join([
|
|
211
|
+
*keep.compact_blank.map { |name, kept| hidden_field_tag(name, kept, id: nil) },
|
|
212
|
+
tag.div(class: "field field--inline") do
|
|
213
|
+
safe_join([ label_tag(param, label), search_field_tag(param, value, autocomplete: "off") ])
|
|
214
|
+
end,
|
|
215
|
+
submit_tag(label, name: nil, class: "button", data: { its_swiss_live_search_target: "submit" })
|
|
216
|
+
])
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
136
220
|
# form_with, already holding the library's builder. An application that
|
|
137
221
|
# wants its own builder still can; this is the shorthand for the case
|
|
138
222
|
# where it does not.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<section data-specimen="filters">
|
|
2
|
+
<h3>Filters and cards</h3>
|
|
3
|
+
<p class="hint">
|
|
4
|
+
What narrows a list, and the list. A search that filters as you type, and
|
|
5
|
+
a register for each other way of narrowing it: the same two positions
|
|
6
|
+
every time, a quiet label and the choices, the one in force carrying the
|
|
7
|
+
accent and the weight. Under it, cards on the page's own fields — this
|
|
8
|
+
page says a card is two fields wide.
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<div class="filters">
|
|
12
|
+
<%= search_form "#filters", frame: "specimen-results", value: "", keep: { tag: "print" } %>
|
|
13
|
+
<%= filter_register "Tagged",
|
|
14
|
+
[ [ "All", "#filters", false ], [ "print", "#filters", true ], [ "screen", "#filters", false ] ],
|
|
15
|
+
name: "tag" %>
|
|
16
|
+
<%= filter_register "Sort by",
|
|
17
|
+
[ [ "Name", "#filters", true ], [ "Newest", "#filters", false ], [ "Most used", "#filters", false ] ],
|
|
18
|
+
name: "sort" %>
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<p class="hint">3 of 12 palettes</p>
|
|
22
|
+
|
|
23
|
+
<ul class="grid cards" style="--card: 2">
|
|
24
|
+
<% [ [ "Brand Core", "4 swatches", 1 ], [ "Press", "6 swatches", 2 ], [ "Screen", "3 swatches", 3 ] ].each do |name, meta, value| %>
|
|
25
|
+
<li class="card">
|
|
26
|
+
<a class="card__link" href="#filters">
|
|
27
|
+
<figure class="card__figure figure" style="--ratio: 1.5">
|
|
28
|
+
<svg viewBox="0 0 3 2" role="img" aria-label="A block of value <%= value %>">
|
|
29
|
+
<rect width="3" height="2" fill="var(--value-<%= value %>)"/>
|
|
30
|
+
</svg>
|
|
31
|
+
</figure>
|
|
32
|
+
<span class="card__name"><%= name %></span>
|
|
33
|
+
</a>
|
|
34
|
+
<span class="card__meta"><%= meta %></span>
|
|
35
|
+
</li>
|
|
36
|
+
<% end %>
|
|
37
|
+
</ul>
|
|
38
|
+
</section>
|
|
@@ -5,11 +5,30 @@
|
|
|
5
5
|
<nav class="nav">
|
|
6
6
|
<a href="#masthead" aria-current="page">Where you are</a>
|
|
7
7
|
<a href="#masthead">Somewhere else</a>
|
|
8
|
-
|
|
8
|
+
<%= nav_menu "A menu", current: false do %>
|
|
9
|
+
<a href="#masthead">One of several</a>
|
|
10
|
+
<a href="#masthead">Another of them</a>
|
|
11
|
+
<a href="#masthead">And a third</a>
|
|
12
|
+
<% end %>
|
|
13
|
+
<%= nav_menu "Where you also are", current: true do %>
|
|
14
|
+
<a href="#masthead" aria-current="page">Inside the menu</a>
|
|
15
|
+
<a href="#masthead">Beside it</a>
|
|
16
|
+
<% end %>
|
|
9
17
|
</nav>
|
|
10
18
|
</header>
|
|
19
|
+
<nav class="subnav" aria-label="Inside this section">
|
|
20
|
+
<div class="page">
|
|
21
|
+
<a href="#masthead">The section's mark</a>
|
|
22
|
+
<a href="#masthead" aria-current="page">Where you are in it</a>
|
|
23
|
+
<a href="#masthead">Elsewhere in it</a>
|
|
24
|
+
</div>
|
|
25
|
+
</nav>
|
|
11
26
|
<p class="hint">
|
|
12
27
|
The current destination carries the accent and the weight. Two signals,
|
|
13
|
-
because colour alone is not one.
|
|
28
|
+
because colour alone is not one. A menu is a destination that opens into
|
|
29
|
+
destinations, and carries both when where you are is inside it. The
|
|
30
|
+
subnav is a second layer, inside the one you are in: a shaded band under
|
|
31
|
+
the masthead, rendered by the shell when the application fills
|
|
32
|
+
<code>:subnav</code>.
|
|
14
33
|
</p>
|
|
15
34
|
</section>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<section data-specimen="page-head">
|
|
2
|
+
<h3>Page head</h3>
|
|
3
|
+
<p class="hint">
|
|
4
|
+
What a page is and what can be done to it: the title and its lede on the
|
|
5
|
+
left, the actions on the right, wrapping under when the page is narrow.
|
|
6
|
+
One shape for every page, so the name and the buttons are always where
|
|
7
|
+
they were on the last one.
|
|
8
|
+
</p>
|
|
9
|
+
<%= page_head "Palettes", lede: "Every palette in the library, including the ones no colour has claimed yet." do %>
|
|
10
|
+
<a href="#page-head" class="button button--primary">New palette</a>
|
|
11
|
+
<a href="#page-head" class="button">Import from a file</a>
|
|
12
|
+
<a href="#page-head" class="button">New from this</a>
|
|
13
|
+
<a href="#page-head" class="button button--danger">Delete palette</a>
|
|
14
|
+
<% end %>
|
|
15
|
+
</section>
|
|
@@ -9,11 +9,13 @@
|
|
|
9
9
|
<%= render "its_swiss/specimen/type" %>
|
|
10
10
|
<%= render "its_swiss/specimen/grid" %>
|
|
11
11
|
<%= render "its_swiss/specimen/masthead" %>
|
|
12
|
+
<%= render "its_swiss/specimen/page_head" %>
|
|
12
13
|
<%= render "its_swiss/specimen/buttons" %>
|
|
13
14
|
<%= render "its_swiss/specimen/form" %>
|
|
14
15
|
<%= render "its_swiss/specimen/figure" %>
|
|
15
16
|
<%= render "its_swiss/specimen/table" %>
|
|
16
17
|
<%= render "its_swiss/specimen/pairs" %>
|
|
18
|
+
<%= render "its_swiss/specimen/filters" %>
|
|
17
19
|
<%= render "its_swiss/specimen/pagination" %>
|
|
18
20
|
<%= render "its_swiss/specimen/messages" %>
|
|
19
21
|
<%= render "its_swiss/specimen/footer" %>
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
:head anything else that belongs in <head>
|
|
10
10
|
:mark the wordmark. No mark and no nav means no masthead at all
|
|
11
11
|
:nav the destinations
|
|
12
|
+
:subnav a second layer of destinations, inside the one you are in
|
|
12
13
|
:main_class what the page's main region is, if it is a grid
|
|
13
14
|
:footer whatever belongs after the page
|
|
14
15
|
|
|
@@ -48,6 +49,10 @@
|
|
|
48
49
|
|
|
49
50
|
<%= render "its_swiss/shared/masthead" %>
|
|
50
51
|
|
|
52
|
+
<% if content_for?(:subnav) %>
|
|
53
|
+
<nav class="subnav" aria-label="Inside this section"><div class="page"><%= content_for(:subnav) %></div></nav>
|
|
54
|
+
<% end %>
|
|
55
|
+
|
|
51
56
|
<main id="main" class="page <%= content_for(:main_class) %>">
|
|
52
57
|
<%= render "its_swiss/shared/flash" %>
|
|
53
58
|
<%= yield %>
|
data/config/importmap.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
# The library's whole JavaScript surface. A typographic
|
|
2
|
-
# script to set type;
|
|
3
|
-
# somewhere else should be a button that copies
|
|
4
|
-
#
|
|
1
|
+
# The library's whole JavaScript surface: two controllers. A typographic
|
|
2
|
+
# system does not need script to set type; these are here because a value
|
|
3
|
+
# that exists to be taken somewhere else should be a button that copies
|
|
4
|
+
# itself, and a search should narrow the list as you type, and neither can
|
|
5
|
+
# be done in CSS.
|
|
5
6
|
pin "its_swiss/clipboard_controller", to: "its_swiss/clipboard_controller.js"
|
|
7
|
+
pin "its_swiss/live_search_controller", to: "its_swiss/live_search_controller.js"
|
data/lib/its_swiss/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: its-swiss
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Bobby Meyer
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-09-
|
|
11
|
+
date: 2026-09-07 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: railties
|
|
@@ -105,6 +105,7 @@ files:
|
|
|
105
105
|
- LICENSE
|
|
106
106
|
- README.md
|
|
107
107
|
- app/assets/javascripts/its_swiss/clipboard_controller.js
|
|
108
|
+
- app/assets/javascripts/its_swiss/live_search_controller.js
|
|
108
109
|
- app/assets/stylesheets/its-swiss.css
|
|
109
110
|
- app/assets/stylesheets/its_swiss/components.css
|
|
110
111
|
- app/assets/stylesheets/its_swiss/faces.css
|
|
@@ -122,11 +123,13 @@ files:
|
|
|
122
123
|
- app/views/its_swiss/shared/_pagination.html.erb
|
|
123
124
|
- app/views/its_swiss/specimen/_buttons.html.erb
|
|
124
125
|
- app/views/its_swiss/specimen/_figure.html.erb
|
|
126
|
+
- app/views/its_swiss/specimen/_filters.html.erb
|
|
125
127
|
- app/views/its_swiss/specimen/_footer.html.erb
|
|
126
128
|
- app/views/its_swiss/specimen/_form.html.erb
|
|
127
129
|
- app/views/its_swiss/specimen/_grid.html.erb
|
|
128
130
|
- app/views/its_swiss/specimen/_masthead.html.erb
|
|
129
131
|
- app/views/its_swiss/specimen/_messages.html.erb
|
|
132
|
+
- app/views/its_swiss/specimen/_page_head.html.erb
|
|
130
133
|
- app/views/its_swiss/specimen/_pagination.html.erb
|
|
131
134
|
- app/views/its_swiss/specimen/_pairs.html.erb
|
|
132
135
|
- app/views/its_swiss/specimen/_table.html.erb
|