@inkbar/theme 0.10.0 → 0.12.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.
- package/README.md +20 -5
- package/package.json +1 -1
- package/theme.css +210 -1
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
---
|
|
22
22
|
|
|
23
|
-
`@inkbar/theme` styles the viewer, toolbar controls and note threads from `@inkbar/vue`, `@inkbar/react`, `@inkbar/svelte` and `createViewer` in `@inkbar/core`. Import it and ship, or override any part of it with your own CSS. If your app already defines shadcn tokens, the theme picks up your colours and radius.
|
|
23
|
+
`@inkbar/theme` styles the viewer and what it draws over pages (annotations, form fields, search matches), the toolbar controls and menus, sidebars and thumbnails, the find bar and search results, the signature dialog, note threads, and plugin cards and command buttons, from `@inkbar/vue`, `@inkbar/react`, `@inkbar/svelte` and `createViewer` in `@inkbar/core`. Import it and ship, or override any part of it with your own CSS. If your app already defines shadcn tokens, the theme picks up your colours and radius.
|
|
24
24
|
|
|
25
25
|
## Install
|
|
26
26
|
|
|
@@ -34,7 +34,7 @@ Import the stylesheet once in your app:
|
|
|
34
34
|
import '@inkbar/theme/theme.css'
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
Every rule sits in `@layer inkbar` and inside `:where()`, so each selector has zero specificity. Your unlayered CSS overrides it without `!important`.
|
|
37
|
+
Every rule sits in `@layer inkbar` and inside `:where()`, so each selector has zero specificity. Your unlayered CSS overrides it without `!important`. The one exception is the move cursor while an annotation is dragged (`[data-ink-dragging]`), which uses `!important` to show over every element's own cursor.
|
|
38
38
|
|
|
39
39
|
## Layer order
|
|
40
40
|
|
|
@@ -66,14 +66,15 @@ Set these variables on `[data-ink-root]` to change the default colour for new an
|
|
|
66
66
|
| `--ink-note`, `--ink-free-text` | Notes and text boxes |
|
|
67
67
|
| `--ink-shape`, `--ink-ink` | Shapes and freehand drawing |
|
|
68
68
|
| `--ink-redact`, `--ink-redact-fill` | Redaction outline and fill |
|
|
69
|
+
| `--ink-mask` | Masks |
|
|
69
70
|
|
|
70
|
-
Inkbar reads a colour when you create the annotation and stores it on the annotation, because the colour goes into the PDF. Changing a variable later affects new annotations only.
|
|
71
|
+
Inkbar reads a colour when you create the annotation and stores it on the annotation, because the colour goes into the PDF. Changing a variable later affects new annotations only. Write these as hex (`#f2c230`) or `rgb()`: Inkbar ignores other formats and uses its own default.
|
|
71
72
|
|
|
72
73
|
## Layout
|
|
73
74
|
|
|
74
75
|
The root and viewport fill their parent as a column, and the scroll area takes the remaining height. Give the parent a height and the document scrolls inside it.
|
|
75
76
|
|
|
76
|
-
The theme gives a toolbar a background and padding and styles the controls in it. You decide where the toolbar sits, how to group its controls and what separates it from the document. Set `--ink-control-size` on a toolbar to change the height of its buttons, fields and zoom select (default `2.25rem`), and `--ink-icon-size` to change the size of their icons (default `1.125rem`).
|
|
77
|
+
The theme gives a toolbar a background and padding and styles the controls in it. You decide where the toolbar sits, how to group its controls and what separates it from the document. Set `--ink-control-size` on a toolbar to change the height of its buttons, fields and zoom select (default `2.25rem`), and `--ink-icon-size` to change the size of their icons (default `1.125rem`). `--ink-control-size` also sizes the sidebar rail's buttons and any `ink-select`.
|
|
77
78
|
|
|
78
79
|
```css
|
|
79
80
|
.my-page-bar {
|
|
@@ -83,9 +84,23 @@ The theme gives a toolbar a background and padding and styles the controls in it
|
|
|
83
84
|
}
|
|
84
85
|
```
|
|
85
86
|
|
|
87
|
+
Sidebars and thumbnails have their own sizes:
|
|
88
|
+
|
|
89
|
+
| Variable | Default | Sets |
|
|
90
|
+
| -------------------------- | ------- | --------------------------------------------------- |
|
|
91
|
+
| `--ink-sidebar-width` | `320px` | An open sidebar's width; the sidebar sets it inline |
|
|
92
|
+
| `--ink-sidebar-rail-width` | `48px` | The width of a sidebar's icon rail |
|
|
93
|
+
| `--ink-thumbnail-width` | `120px` | The width of a page thumbnail |
|
|
94
|
+
|
|
95
|
+
The sidebar always sets `--ink-sidebar-width` inline, even when no width is saved, so a CSS override of it no longer applies. Pass the sidebar's `defaultWidth` instead. Style the handle with `.ink-sidebar-handle`. It draws a 2px `--ink-accent` line on hover, focus and while dragging.
|
|
96
|
+
|
|
97
|
+
## Search, form and link colours
|
|
98
|
+
|
|
99
|
+
`--ink-search-hit` and `--ink-search-current` colour search matches and the current match. `--ink-mark-selected-outline` outlines a plugin mark whose record is selected (default `2px solid #2740f5`). `--ink-form-field-bg`, `--ink-form-field-focus` and `--ink-form-field-invalid` colour form fields, the focused field and a field that fails its check. `--ink-link-hover` tints a link under the pointer (default `transparent`, so links show no box).
|
|
100
|
+
|
|
86
101
|
## Your own controls
|
|
87
102
|
|
|
88
|
-
|
|
103
|
+
Three classes give your own controls the look of the built-in ones. Add `ink-select` to a `<select>` to give it the zoom select's box and chevron. To put an icon in a field, wrap the input in `ink-input-group` and add an `ink-input-accessory` before it for an icon at the start, or after it for one at the end. The icon lets clicks through to the field, and the input makes room for it. The find bar and the search results field use this for their search icon.
|
|
89
104
|
|
|
90
105
|
```html
|
|
91
106
|
<select class="ink-select">
|
package/package.json
CHANGED
package/theme.css
CHANGED
|
@@ -37,12 +37,19 @@
|
|
|
37
37
|
/* Pages stay white in dark mode and the search layer multiplies, so these serve both. */
|
|
38
38
|
--ink-search-hit: #f1ffa0;
|
|
39
39
|
--ink-search-current: #e4ff4a;
|
|
40
|
+
/* A tint over a link under the pointer; off by default, as desktop readers show no box. */
|
|
41
|
+
--ink-link-hover: transparent;
|
|
40
42
|
/* The selected record's mark; pages stay white in dark mode, so this serves both. */
|
|
41
43
|
--ink-mark-selected-outline: 2px solid #2740f5;
|
|
42
44
|
/* Sidebars (createSidebar and the bindings' sidebar): the open sidebar and its rail. */
|
|
43
|
-
--ink-sidebar-width:
|
|
45
|
+
--ink-sidebar-width: 320px;
|
|
44
46
|
--ink-sidebar-rail-width: 48px;
|
|
45
47
|
--ink-thumbnail-width: 120px;
|
|
48
|
+
/* The outline (createOutline and the bindings' outline): indent per level, item height and
|
|
49
|
+
the current item's tint. */
|
|
50
|
+
--ink-outline-indent: 16px;
|
|
51
|
+
--ink-outline-item-height: 44px;
|
|
52
|
+
--ink-outline-current-bg: color-mix(in srgb, var(--ink-accent) 10%, transparent);
|
|
46
53
|
|
|
47
54
|
--ink-bg: var(--muted, #f1f2f5);
|
|
48
55
|
--ink-fg: var(--foreground, #151820);
|
|
@@ -351,6 +358,30 @@
|
|
|
351
358
|
border-radius: 50%;
|
|
352
359
|
}
|
|
353
360
|
|
|
361
|
+
/* Links: over the text layer, under the search matches, fields and annotations. They never
|
|
362
|
+
take the pointer (the viewer hit-tests links itself, so selection and tools work over
|
|
363
|
+
them), so they show only as a ring while focused from the keyboard, on every line of a
|
|
364
|
+
wrapped link, and as the hover tint the viewer turns on with data-ink-hover. */
|
|
365
|
+
:where(.ink-link-layer) {
|
|
366
|
+
z-index: 1;
|
|
367
|
+
pointer-events: none;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
:where(.ink-link) {
|
|
371
|
+
pointer-events: none;
|
|
372
|
+
border-radius: 2px;
|
|
373
|
+
outline: none;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
:where(.ink-link:focus-visible, .ink-link[data-ink-focused]) {
|
|
377
|
+
outline: 2px solid var(--ink-ring);
|
|
378
|
+
outline-offset: 1px;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
:where(.ink-link[data-ink-hover]) {
|
|
382
|
+
background: var(--ink-link-hover);
|
|
383
|
+
}
|
|
384
|
+
|
|
354
385
|
/* Search matches sit under the annotations: before the overlay in the page, same level. The
|
|
355
386
|
layer multiplies with the page, so dark text shows through as if the page were marked. */
|
|
356
387
|
:where(.ink-search-layer) {
|
|
@@ -837,6 +868,7 @@
|
|
|
837
868
|
* mirrors them.
|
|
838
869
|
*/
|
|
839
870
|
:where(.ink-sidebar) {
|
|
871
|
+
position: relative;
|
|
840
872
|
box-sizing: border-box;
|
|
841
873
|
display: flex;
|
|
842
874
|
flex-direction: column;
|
|
@@ -918,6 +950,58 @@
|
|
|
918
950
|
display: none;
|
|
919
951
|
}
|
|
920
952
|
|
|
953
|
+
/* The resize handle: a strip straddling the inner edge, wider for fingers. touch-action keeps
|
|
954
|
+
a touch drag from scrolling the page instead. */
|
|
955
|
+
:where(.ink-sidebar-handle) {
|
|
956
|
+
position: absolute;
|
|
957
|
+
top: 0;
|
|
958
|
+
bottom: 0;
|
|
959
|
+
right: -4px;
|
|
960
|
+
width: 8px;
|
|
961
|
+
cursor: col-resize;
|
|
962
|
+
touch-action: none;
|
|
963
|
+
z-index: 1;
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
:where(.ink-sidebar[data-side='right'] .ink-sidebar-handle) {
|
|
967
|
+
right: auto;
|
|
968
|
+
left: -4px;
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
@media (pointer: coarse) {
|
|
972
|
+
:where(.ink-sidebar-handle) {
|
|
973
|
+
right: -8px;
|
|
974
|
+
width: 16px;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
:where(.ink-sidebar[data-side='right'] .ink-sidebar-handle) {
|
|
978
|
+
right: auto;
|
|
979
|
+
left: -8px;
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
:where(.ink-sidebar-handle[hidden]) {
|
|
984
|
+
display: none;
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
:where(
|
|
988
|
+
.ink-sidebar-handle:hover,
|
|
989
|
+
.ink-sidebar-handle:focus-visible,
|
|
990
|
+
.ink-sidebar[data-resizing] .ink-sidebar-handle
|
|
991
|
+
) {
|
|
992
|
+
background: linear-gradient(
|
|
993
|
+
to right,
|
|
994
|
+
transparent calc(50% - 1px),
|
|
995
|
+
var(--ink-accent) calc(50% - 1px),
|
|
996
|
+
var(--ink-accent) calc(50% + 1px),
|
|
997
|
+
transparent calc(50% + 1px)
|
|
998
|
+
);
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
:where(.ink-sidebar[data-resizing]) {
|
|
1002
|
+
user-select: none;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
921
1005
|
/* Not visible: the whole sidebar goes, its state kept. After every display rule above. */
|
|
922
1006
|
:where(.ink-sidebar[hidden]) {
|
|
923
1007
|
display: none;
|
|
@@ -2150,6 +2234,127 @@
|
|
|
2150
2234
|
font-size: 0.875rem;
|
|
2151
2235
|
}
|
|
2152
2236
|
|
|
2237
|
+
/*
|
|
2238
|
+
* The outline (createOutline and the bindings' outline): a tree that fills its parent's height
|
|
2239
|
+
* and scrolls. Each item is indented by its level, which the renderer sets as
|
|
2240
|
+
* --ink-outline-level (0 at the top), and is at least 44px tall to stay easy to tap.
|
|
2241
|
+
*/
|
|
2242
|
+
:where(.ink-outline) {
|
|
2243
|
+
box-sizing: border-box;
|
|
2244
|
+
height: 100%;
|
|
2245
|
+
min-height: 0;
|
|
2246
|
+
overflow-x: hidden;
|
|
2247
|
+
overflow-y: auto;
|
|
2248
|
+
}
|
|
2249
|
+
|
|
2250
|
+
:where(.ink-outline-tree, .ink-outline-group) {
|
|
2251
|
+
margin: 0;
|
|
2252
|
+
padding: 0;
|
|
2253
|
+
list-style: none;
|
|
2254
|
+
}
|
|
2255
|
+
|
|
2256
|
+
:where(.ink-outline-tree) {
|
|
2257
|
+
padding: 0.5rem;
|
|
2258
|
+
}
|
|
2259
|
+
|
|
2260
|
+
:where(
|
|
2261
|
+
.ink-outline-tree[hidden],
|
|
2262
|
+
.ink-outline-group[hidden],
|
|
2263
|
+
.ink-outline-empty[hidden]
|
|
2264
|
+
) {
|
|
2265
|
+
display: none;
|
|
2266
|
+
}
|
|
2267
|
+
|
|
2268
|
+
/* The item holds its children's group, so what is the item's alone sits on its row. */
|
|
2269
|
+
:where(.ink-outline-item) {
|
|
2270
|
+
outline: none;
|
|
2271
|
+
}
|
|
2272
|
+
|
|
2273
|
+
:where(.ink-outline-row) {
|
|
2274
|
+
box-sizing: border-box;
|
|
2275
|
+
display: flex;
|
|
2276
|
+
align-items: center;
|
|
2277
|
+
gap: 0.25rem;
|
|
2278
|
+
min-height: var(--ink-outline-item-height, 44px);
|
|
2279
|
+
padding: 0 0.5rem 0
|
|
2280
|
+
calc(var(--ink-outline-level, 0) * var(--ink-outline-indent, 16px));
|
|
2281
|
+
border-radius: calc(var(--ink-radius) - 2px);
|
|
2282
|
+
font-size: 0.875rem;
|
|
2283
|
+
line-height: 1.3;
|
|
2284
|
+
cursor: pointer;
|
|
2285
|
+
}
|
|
2286
|
+
|
|
2287
|
+
:where(.ink-outline-row:hover) {
|
|
2288
|
+
background: color-mix(in srgb, var(--ink-fg) 6%, transparent);
|
|
2289
|
+
}
|
|
2290
|
+
|
|
2291
|
+
:where(.ink-outline-item:focus-visible > .ink-outline-row) {
|
|
2292
|
+
outline: 2px solid var(--ink-ring);
|
|
2293
|
+
outline-offset: -2px;
|
|
2294
|
+
}
|
|
2295
|
+
|
|
2296
|
+
:where(.ink-outline-item[aria-current='location'] > .ink-outline-row) {
|
|
2297
|
+
background: var(--ink-outline-current-bg);
|
|
2298
|
+
color: var(--ink-fg);
|
|
2299
|
+
box-shadow: inset 2px 0 0 var(--ink-accent);
|
|
2300
|
+
}
|
|
2301
|
+
|
|
2302
|
+
:where(.ink-outline-item[data-bold] > .ink-outline-row) {
|
|
2303
|
+
font-weight: 600;
|
|
2304
|
+
}
|
|
2305
|
+
|
|
2306
|
+
:where(.ink-outline-item[data-italic] > .ink-outline-row) {
|
|
2307
|
+
font-style: italic;
|
|
2308
|
+
}
|
|
2309
|
+
|
|
2310
|
+
/* Items Inkbar cannot follow (another file, an app, an unsafe URL) stay listed, greyed out. */
|
|
2311
|
+
:where(.ink-outline-item[aria-disabled='true'] > .ink-outline-row) {
|
|
2312
|
+
color: var(--ink-muted-fg);
|
|
2313
|
+
cursor: default;
|
|
2314
|
+
}
|
|
2315
|
+
|
|
2316
|
+
:where(.ink-outline-item[aria-disabled='true'] > .ink-outline-row:hover) {
|
|
2317
|
+
background: transparent;
|
|
2318
|
+
}
|
|
2319
|
+
|
|
2320
|
+
/* Touch can only expand an item by its chevron, and a near miss follows the item instead, so
|
|
2321
|
+
the chevron gets a full 44px column of the row. A leaf keeps the column empty, so titles
|
|
2322
|
+
line up. */
|
|
2323
|
+
:where(.ink-outline-toggle, .ink-outline-spacer) {
|
|
2324
|
+
display: inline-flex;
|
|
2325
|
+
flex: none;
|
|
2326
|
+
align-items: center;
|
|
2327
|
+
align-self: stretch;
|
|
2328
|
+
justify-content: center;
|
|
2329
|
+
width: 44px;
|
|
2330
|
+
min-height: 44px;
|
|
2331
|
+
color: var(--ink-muted-fg);
|
|
2332
|
+
}
|
|
2333
|
+
|
|
2334
|
+
:where(.ink-outline-toggle > svg) {
|
|
2335
|
+
width: 1rem;
|
|
2336
|
+
height: 1rem;
|
|
2337
|
+
}
|
|
2338
|
+
|
|
2339
|
+
:where(
|
|
2340
|
+
.ink-outline-item[aria-expanded='true'] > .ink-outline-row > .ink-outline-toggle > svg
|
|
2341
|
+
) {
|
|
2342
|
+
transform: rotate(90deg);
|
|
2343
|
+
}
|
|
2344
|
+
|
|
2345
|
+
:where(.ink-outline-title) {
|
|
2346
|
+
min-width: 0;
|
|
2347
|
+
padding-block: 0.375rem;
|
|
2348
|
+
overflow-wrap: anywhere;
|
|
2349
|
+
}
|
|
2350
|
+
|
|
2351
|
+
:where(.ink-outline-empty) {
|
|
2352
|
+
margin: 0;
|
|
2353
|
+
padding: 1rem 0.75rem;
|
|
2354
|
+
color: var(--ink-muted-fg);
|
|
2355
|
+
font-size: 0.875rem;
|
|
2356
|
+
}
|
|
2357
|
+
|
|
2153
2358
|
/*
|
|
2154
2359
|
* Search results frame their cards as the viewer frames its pages: the field on the surface
|
|
2155
2360
|
* at the top, the cards on the page canvas, and the count in a footer on the surface at the
|
|
@@ -2363,5 +2568,9 @@
|
|
|
2363
2568
|
:where(.ink-annotation) {
|
|
2364
2569
|
transition: outline-color 120ms ease;
|
|
2365
2570
|
}
|
|
2571
|
+
|
|
2572
|
+
:where(.ink-outline-toggle > svg) {
|
|
2573
|
+
transition: transform 120ms ease-out;
|
|
2574
|
+
}
|
|
2366
2575
|
}
|
|
2367
2576
|
}
|