active_admin_theme 3.1.0 → 3.2.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/README.md +187 -36
- data/app/assets/javascripts/wigu/all.js +10 -0
- data/app/assets/javascripts/wigu/scrollbar_width.js +72 -0
- data/app/assets/javascripts/wigu/server_clock.js +171 -0
- data/app/assets/javascripts/wigu/table_crisscross.js +49 -0
- data/app/assets/stylesheets/wigu/active_admin_theme.scss +511 -39
- data/lib/active_admin_theme/version.rb +1 -1
- data/lib/active_admin_theme.rb +127 -1
- metadata +5 -1
|
@@ -55,6 +55,9 @@ $skinTitleBarBorderColor: $skinMainSecondColor!default;
|
|
|
55
55
|
$skinTitleBarBorderWidth: 0!default;
|
|
56
56
|
$skinTitleBarButtonPaddingY: 6px!default; // action button vertical padding
|
|
57
57
|
$skinTitleBarButtonPaddingX: 10px!default; // action button horizontal padding
|
|
58
|
+
// Minimum bar height — raise it alongside the button paddings above if your
|
|
59
|
+
// buttons outgrow the default band (the bar still grows to fit its content).
|
|
60
|
+
$skinTitleBarHeight: 37px!default;
|
|
58
61
|
|
|
59
62
|
// Panel/section headers + tabs accent (the blue bar on panel headers and the
|
|
60
63
|
// inactive tabs). $skinPanelHeaderColor is the base/light value;
|
|
@@ -130,7 +133,7 @@ $skinInactiveTabTextColor: #5e6469!default;
|
|
|
130
133
|
$skinInactiveTabTextColorDark: #b0b8c2!default;
|
|
131
134
|
// Index-table column header text, one colour for sortable and plain headers.
|
|
132
135
|
$skinTableHeaderTextColor: $skinTextColor!default;
|
|
133
|
-
$skinTableHeaderTextColorDark:
|
|
136
|
+
$skinTableHeaderTextColorDark: $skinTextColorDark!default;
|
|
134
137
|
|
|
135
138
|
// Status tags. The label is the same on every filled tag in both modes. The
|
|
136
139
|
// fills below are dark enough to carry a white one: every one of the five is
|
|
@@ -214,6 +217,20 @@ $skinStatusTagErrorColor: #ce483b!default; // error / errored / red
|
|
|
214
217
|
--aa-active-tab-text: #{$skinActiveTabTextColor};
|
|
215
218
|
--aa-inactive-tab-text: #{$skinInactiveTabTextColor};
|
|
216
219
|
--aa-delete-link: #{$skinDeleteLinkColor};
|
|
220
|
+
|
|
221
|
+
// Bridge for the companion active_admin_datetimepicker plugin: feed its
|
|
222
|
+
// --aa-datetimepicker-* inputs from this theme's palette, so the xdsoft picker
|
|
223
|
+
// is themed (light + dark) automatically with no per-app override. These point
|
|
224
|
+
// at the --aa-* vars, which are themselves redefined per mode, so a single set
|
|
225
|
+
// here covers both. Harmless no-op when the plugin isn't installed (nothing
|
|
226
|
+
// reads these). A host can still override any of them downstream.
|
|
227
|
+
--aa-datetimepicker-accent: var(--aa-accent);
|
|
228
|
+
--aa-datetimepicker-surface: var(--aa-surface);
|
|
229
|
+
--aa-datetimepicker-surface-2: var(--aa-surface-2);
|
|
230
|
+
--aa-datetimepicker-text: var(--aa-text);
|
|
231
|
+
--aa-datetimepicker-text-muted: var(--aa-text-muted);
|
|
232
|
+
--aa-datetimepicker-border: var(--aa-border);
|
|
233
|
+
--aa-datetimepicker-hover: var(--aa-surface-hover);
|
|
217
234
|
}
|
|
218
235
|
// OS preference, unless the user explicitly chose light
|
|
219
236
|
@media (prefers-color-scheme: dark) {
|
|
@@ -233,13 +250,27 @@ html[data-theme="dark"] { @include aa-dark-palette; }
|
|
|
233
250
|
html[data-theme="dark"] { @content; }
|
|
234
251
|
}
|
|
235
252
|
|
|
236
|
-
//
|
|
237
|
-
//
|
|
238
|
-
//
|
|
253
|
+
// Sort markers. Three shapes rather than one at two opacities: ActiveAdmin's
|
|
254
|
+
// sprite draws a double arrow for sortable-but-unsorted, and reusing the
|
|
255
|
+
// descending triangle for it leaves the two states indistinguishable on a
|
|
256
|
+
// freshly loaded index. Masked, like the theme switch icons, so they take
|
|
257
|
+
// currentColor and follow the heading into dark mode.
|
|
258
|
+
$sort-icon-none: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 12'%3E%3Cpath d='M4.5 0 9 5H0z'/%3E%3Cpath d='M4.5 12 0 7h9z'/%3E%3C/svg%3E")!default;
|
|
259
|
+
$sort-icon-asc: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 12'%3E%3Cpath d='M4.5 2 9 8H0z'/%3E%3C/svg%3E")!default;
|
|
260
|
+
$sort-icon-desc: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 12'%3E%3Cpath d='M4.5 10 0 4h9z'/%3E%3C/svg%3E")!default;
|
|
261
|
+
|
|
262
|
+
// Theme switch icons. Inline, because the gem ships no image files, and as a
|
|
263
|
+
// mask rather than a coloured SVG: a mask takes currentColor and so follows
|
|
264
|
+
// $skinMenuTextColor on its own. Half circle = auto, sun = light, moon = dark.
|
|
239
265
|
$theme-icon-auto: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='6.6' fill='none' stroke='black' stroke-width='1.4'/%3E%3Cpath d='M8 2.6a5.4 5.4 0 0 1 0 10.8z'/%3E%3C/svg%3E")!default;
|
|
240
266
|
$theme-icon-light: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.4' stroke-linecap='round'%3E%3Ccircle cx='8' cy='8' r='3.1'/%3E%3Cpath d='M8 .9v1.8M8 13.3v1.8M.9 8h1.8M13.3 8h1.8M2.9 2.9l1.3 1.3M11.8 11.8l1.3 1.3M13.1 2.9l-1.3 1.3M4.2 11.8l-1.3 1.3'/%3E%3C/svg%3E")!default;
|
|
241
267
|
$theme-icon-dark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M13.4 9.6A5.9 5.9 0 0 1 6.4 2.6a5.9 5.9 0 1 0 7 7z'/%3E%3C/svg%3E")!default;
|
|
242
268
|
|
|
269
|
+
// Logout drawn as a sign-out glyph instead of the word "Logout", so it matches
|
|
270
|
+
// the icon toggle beside it. Masked like the theme icons above, so it takes
|
|
271
|
+
// currentColor and follows $skinMenuTextColor; a consumer can override the var.
|
|
272
|
+
$logout-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6.5 2.5H3.2v11h3.3'/%3E%3Cpath d='M12.8 8H6'/%3E%3Cpath d='M9.5 5 12.8 8l-3.3 3'/%3E%3C/svg%3E")!default;
|
|
273
|
+
|
|
243
274
|
// A wrong-typed override is legal SassScript, so it compiles without a word and
|
|
244
275
|
// emits CSS the browser drops — `border-bottom: none solid #5ea3d3`,
|
|
245
276
|
// `padding: 10 12px`. The rule silently vanishes and ActiveAdmin's own value
|
|
@@ -337,11 +368,11 @@ $theme-icon-dark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/s
|
|
|
337
368
|
@error "$#{$name} must be a color or a CSS custom property (e.g. var(--aa-page-bg)), got `#{$value}`.";
|
|
338
369
|
}
|
|
339
370
|
}
|
|
340
|
-
//
|
|
341
|
-
//
|
|
342
|
-
//
|
|
343
|
-
//
|
|
344
|
-
// calc(0 - 1px)
|
|
371
|
+
// A cell's inner corner is 1px tighter than the outer one, so it does not
|
|
372
|
+
// show from under the table border. Subtracting px directly will not do: the
|
|
373
|
+
// radius is a project's to set, and 0.25rem fails the whole compile with
|
|
374
|
+
// "Incompatible units". calc() defers the subtraction to the browser, and a
|
|
375
|
+
// unitless 0 is handled separately because calc(0 - 1px) is invalid.
|
|
345
376
|
@function inner-radius($radius) {
|
|
346
377
|
@if unitless($radius) { @return 0; }
|
|
347
378
|
@return calc(#{$radius} - 1px);
|
|
@@ -352,10 +383,35 @@ $theme-icon-dark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/s
|
|
|
352
383
|
html {
|
|
353
384
|
background: var(--aa-page-bg);
|
|
354
385
|
}
|
|
386
|
+
|
|
387
|
+
// Pin a bar (#header, #title_bar) to the viewport's left edge at the visible
|
|
388
|
+
// viewport width while a wide index table scrolls the whole page sideways
|
|
389
|
+
// (#wrapper is display:table, min-width:100%). width = 100vw minus the vertical
|
|
390
|
+
// scrollbar — the JS-set --scrollbar-width var (0 when wigu/scrollbar_width is
|
|
391
|
+
// absent, and then max-width:100% keeps 100vw's scrollbar allowance from adding a
|
|
392
|
+
// stray horizontal scrollbar). It's a plain max-width, not min(…, 100%):
|
|
393
|
+
// sassc/libsass evaluates the Sass min() function and rejects calc() as a
|
|
394
|
+
// non-number. No `top`, so the bar still scrolls vertically.
|
|
395
|
+
@mixin viewport-pinned-bar {
|
|
396
|
+
position: sticky;
|
|
397
|
+
left: 0;
|
|
398
|
+
width: calc(100vw - var(--scrollbar-width, 0px));
|
|
399
|
+
max-width: 100%;
|
|
400
|
+
box-sizing: border-box;
|
|
401
|
+
}
|
|
402
|
+
|
|
355
403
|
body.active_admin {
|
|
356
404
|
background: var(--aa-page-bg);
|
|
357
405
|
}
|
|
358
406
|
#wrapper {
|
|
407
|
+
// ActiveAdmin lays #wrapper out as `display: table`, which sizes to its
|
|
408
|
+
// content: a wide index table therefore scrolls the WHOLE page horizontally
|
|
409
|
+
// (the master / pre-theme behaviour admins are used to). Only guarantee the
|
|
410
|
+
// layout fills the viewport when the content is narrow. The utility nav
|
|
411
|
+
// (clock / theme toggle / logout) is pinned `sticky` (see #utility_nav below)
|
|
412
|
+
// so it stays reachable while the page scrolls sideways.
|
|
413
|
+
min-width: 100%;
|
|
414
|
+
|
|
359
415
|
div.tabs {
|
|
360
416
|
> ul > li > a {
|
|
361
417
|
background-image: none;
|
|
@@ -418,6 +474,12 @@ body.active_admin {
|
|
|
418
474
|
border: none;
|
|
419
475
|
text-shadow: none;
|
|
420
476
|
background-image: none;
|
|
477
|
+
|
|
478
|
+
// A wide index table scrolls the WHOLE page sideways. Pin the header on
|
|
479
|
+
// screen at the viewport width so it doesn't stretch to the table's width
|
|
480
|
+
// (which spread the menu out under the utility nav and overlapped it); it
|
|
481
|
+
// still grows to fit a wrapped menu, ActiveAdmin's natural layout.
|
|
482
|
+
@include viewport-pinned-bar;
|
|
421
483
|
h1.site_title {
|
|
422
484
|
color: $skinMainSecondColor;
|
|
423
485
|
font-size: 16px;
|
|
@@ -448,10 +510,34 @@ body.active_admin {
|
|
|
448
510
|
// tabs: drop the pill padding, and on hover highlight by text colour only — no
|
|
449
511
|
// background block. The clock has no click action, so it gets no hover at all.
|
|
450
512
|
#utility_nav {
|
|
513
|
+
// Sits at the top-right of the header; the header itself is pinned on screen
|
|
514
|
+
// (sticky, see #header above) so the clock / theme toggle / logout stay
|
|
515
|
+
// reachable while a wide table scrolls the page sideways.
|
|
516
|
+
z-index: 2;
|
|
517
|
+
white-space: nowrap;
|
|
518
|
+
|
|
451
519
|
> li > a { padding: 0 5px; }
|
|
452
520
|
> li:hover > a, > li.current > a { background-color: transparent; }
|
|
453
521
|
> li#servertime:hover > a { color: #ffffff; }
|
|
454
522
|
|
|
523
|
+
// Server clock (server_clock.js), rendered as two compact lines like
|
|
524
|
+
// yeti-web: time + timezone (larger) over year/month/day (smaller). A
|
|
525
|
+
// right-aligned flex column sized to the nav band (~24px) so both lines
|
|
526
|
+
// fit the header height unchanged. Monospace + tabular figures keep the
|
|
527
|
+
// ticking time a constant width, so the adjacent logout doesn't jitter.
|
|
528
|
+
> li#servertime > span {
|
|
529
|
+
display: inline-flex;
|
|
530
|
+
flex-direction: column;
|
|
531
|
+
justify-content: center;
|
|
532
|
+
align-items: flex-end;
|
|
533
|
+
vertical-align: middle;
|
|
534
|
+
height: 24px;
|
|
535
|
+
font-family: 'SFMono-Regular', Menlo, Consolas, 'Liberation Mono', monospace;
|
|
536
|
+
font-variant-numeric: tabular-nums;
|
|
537
|
+
}
|
|
538
|
+
> li#servertime .clock-time { font-size: 12px; line-height: 1.1; }
|
|
539
|
+
> li#servertime .clock-date { font-size: 9px; line-height: 1.1; }
|
|
540
|
+
|
|
455
541
|
// The theme switch (app/assets/javascripts/wigu/theme_toggle.js). The
|
|
456
542
|
// script only writes data-mode; the glyph is drawn here, so a project can
|
|
457
543
|
// swap it for its own icon font without forking the script. Masked rather
|
|
@@ -488,6 +574,35 @@ body.active_admin {
|
|
|
488
574
|
-webkit-mask-image: $theme-icon-dark;
|
|
489
575
|
mask-image: $theme-icon-dark;
|
|
490
576
|
}
|
|
577
|
+
|
|
578
|
+
// Logout as an icon ($logout-icon), to match the toggle beside it.
|
|
579
|
+
// font-size:0 hides the "Logout" text visually; the accessible name is
|
|
580
|
+
// the aria-label the gem's Ruby puts on the anchor, because zero-sized
|
|
581
|
+
// text is pruned from the accessibility tree by some screen readers
|
|
582
|
+
// (the toggle gets its aria-label from theme_toggle.js the same way).
|
|
583
|
+
// The masked glyph follows the bar's text colour. The real logout
|
|
584
|
+
// link/method from add_logout_button_to_menu is untouched.
|
|
585
|
+
// Scoped to a.wigu-logout — the class the gem's Ruby puts on the item
|
|
586
|
+
// it adds — so a consumer-rendered logout keeps its own label instead
|
|
587
|
+
// of collapsing to an unlabeled glyph.
|
|
588
|
+
> li#logout:has(> a.wigu-logout) { display: inline-flex; align-items: center; vertical-align: middle; }
|
|
589
|
+
> li#logout > a.wigu-logout {
|
|
590
|
+
display: flex;
|
|
591
|
+
align-items: center;
|
|
592
|
+
font-size: 0;
|
|
593
|
+
opacity: 0.75;
|
|
594
|
+
|
|
595
|
+
&:before {
|
|
596
|
+
content: "";
|
|
597
|
+
display: block;
|
|
598
|
+
width: 16px;
|
|
599
|
+
height: 16px;
|
|
600
|
+
background-color: currentColor;
|
|
601
|
+
-webkit-mask: #{$logout-icon} center / contain no-repeat;
|
|
602
|
+
mask: #{$logout-icon} center / contain no-repeat;
|
|
603
|
+
}
|
|
604
|
+
&:hover, &:focus { opacity: 1; }
|
|
605
|
+
}
|
|
491
606
|
}
|
|
492
607
|
ul.tabs {
|
|
493
608
|
li.has_nested {
|
|
@@ -557,26 +672,87 @@ body.active_admin {
|
|
|
557
672
|
background-color: $skinTitleBarColor;
|
|
558
673
|
border: none;
|
|
559
674
|
border-bottom: $skinTitleBarBorderWidth solid $skinTitleBarBorderColor;
|
|
675
|
+
// Pin the whole bar to the viewport like #header, so the title AND the action
|
|
676
|
+
// buttons stay visible while a wide index table scrolls the page sideways.
|
|
677
|
+
@include viewport-pinned-bar;
|
|
678
|
+
// Lay the title (left) and action items (right) on one compact row. Without
|
|
679
|
+
// this, resetting #titlebar_right to static (below) stacks it under the
|
|
680
|
+
// title and the bar grows tall. min-height, NOT height: with a fixed height
|
|
681
|
+
// the bar cannot contain its content — action items that wrap on a narrow
|
|
682
|
+
// window would overflow it and paint over the page — while min-height still
|
|
683
|
+
// makes breadcrumb (detail) pages match plain index pages. Drop the base
|
|
684
|
+
// clearfix — in a flex container it becomes a stray third item that
|
|
685
|
+
// space-between strands right.
|
|
686
|
+
display: flex;
|
|
687
|
+
align-items: center;
|
|
688
|
+
justify-content: space-between;
|
|
689
|
+
min-height: $skinTitleBarHeight;
|
|
690
|
+
&::after { display: none; }
|
|
560
691
|
#titlebar_left {
|
|
692
|
+
display: flex;
|
|
693
|
+
align-items: center;
|
|
694
|
+
gap: 6px;
|
|
695
|
+
height: auto;
|
|
696
|
+
// Let the title shrink below its min-content width: flex items refuse to
|
|
697
|
+
// otherwise, and a long nowrap record title would push the action items
|
|
698
|
+
// out of the pinned bar — unreachable past the viewport on wide pages.
|
|
699
|
+
min-width: 0;
|
|
561
700
|
span.breadcrumb {
|
|
562
701
|
font-size: 12px;
|
|
563
702
|
text-shadow: none;
|
|
564
|
-
margin-bottom:
|
|
703
|
+
margin-bottom: 0;
|
|
565
704
|
a, span {
|
|
566
|
-
color: lighten( $skinMainFirstColor, 30% )!important;
|
|
705
|
+
color: lighten( $skinMainFirstColor, 30% )!important;
|
|
567
706
|
}
|
|
568
707
|
}
|
|
708
|
+
// Own a sensible title size so consumer apps don't each shrink AA's large
|
|
709
|
+
// default (which towered over the breadcrumb). margin:0 + the flex parent
|
|
710
|
+
// centre it on the breadcrumb's line; nowrap + ellipsis keep a long
|
|
711
|
+
// record title (show pages) on one line without pushing the action
|
|
712
|
+
// items out of the bar — min-width: 0 lets it actually shrink.
|
|
569
713
|
h2 {
|
|
570
714
|
color: #ffffff;
|
|
571
715
|
text-shadow: none;
|
|
716
|
+
font-size: 16px;
|
|
717
|
+
margin: 0;
|
|
718
|
+
min-width: 0;
|
|
719
|
+
// Screen only: AA registers the stylesheet with media "all", and paper
|
|
720
|
+
// has no horizontal scroll — a nowrap/ellipsis title would print
|
|
721
|
+
// truncated at the page edge where it used to wrap.
|
|
722
|
+
@media screen {
|
|
723
|
+
white-space: nowrap;
|
|
724
|
+
overflow: hidden;
|
|
725
|
+
text-overflow: ellipsis;
|
|
726
|
+
}
|
|
572
727
|
}
|
|
573
728
|
}
|
|
574
729
|
#titlebar_right {
|
|
730
|
+
// Horizontal pinning is handled by #title_bar (sticky + viewport width),
|
|
731
|
+
// so the action items just sit at the right of the bar. Reset any
|
|
732
|
+
// consumer `position: absolute/sticky` (each app used to pin the buttons
|
|
733
|
+
// itself via local stylesheet overrides).
|
|
734
|
+
position: static;
|
|
735
|
+
// Shrink to the action-items height (some apps/base leave it ~50px, taller
|
|
736
|
+
// than the 37px bar, so centering pushed it over the top edge).
|
|
737
|
+
height: auto;
|
|
738
|
+
// Space multiple action items apart (e.g. a Menu dropdown next to a New
|
|
739
|
+
// button); the base leaves them flush on this side.
|
|
740
|
+
.action_items > .action_item:not(:last-child):not(:empty) { margin-right: 10px; }
|
|
741
|
+
// The form selectors cover button_to action items: Rails renders them as
|
|
742
|
+
// form > input[type=submit] (or button), which the anchor selectors
|
|
743
|
+
// miss — consumer apps were re-hardcoding the 6px/10px padding to
|
|
744
|
+
// compensate, desyncing from the $skin* knobs on every change.
|
|
575
745
|
// `> a` and `> .dropdown_menu > a`: an action item may hold a dropdown, and
|
|
576
746
|
// a descendant selector here paints its menu entries with the button fill
|
|
577
747
|
// too — with !important, so the entry rules below cannot undo it.
|
|
748
|
+
// A button_to action item renders as a block <form>; inline-block
|
|
749
|
+
// keeps it on the bar's single row (consumers used to float it, which
|
|
750
|
+
// collapsed the flex bar's height instead).
|
|
751
|
+
.action_item > form { display: inline-block; }
|
|
578
752
|
.action_item > a,
|
|
579
|
-
.action_item > .dropdown_menu > a
|
|
753
|
+
.action_item > .dropdown_menu > a,
|
|
754
|
+
.action_item > form > input[type="submit"],
|
|
755
|
+
.action_item > form > button {
|
|
580
756
|
background-image: none;
|
|
581
757
|
border: none;
|
|
582
758
|
box-shadow: none;
|
|
@@ -592,7 +768,28 @@ body.active_admin {
|
|
|
592
768
|
}
|
|
593
769
|
}
|
|
594
770
|
div.dropdown_menu {
|
|
771
|
+
// Containing block for the panel below, so `right: 0` means "the
|
|
772
|
+
// trigger's right edge". AA leaves this element unpositioned, which
|
|
773
|
+
// makes the panel resolve against #title_bar (sticky) and park at the
|
|
774
|
+
// bar's far right no matter which action item was clicked. inline-block
|
|
775
|
+
// over AA's `display: inline`: an inline box's containing block spans
|
|
776
|
+
// its text fragments, so the markup's whitespace around the button
|
|
777
|
+
// pushed the panel a few px past the button's edge.
|
|
778
|
+
position: relative;
|
|
779
|
+
display: inline-block;
|
|
595
780
|
div.dropdown_menu_list_wrapper {
|
|
781
|
+
// Always right-align title-bar dropdowns under their own button,
|
|
782
|
+
// overriding AA's inline positioning. AA 3.x's _position() sets
|
|
783
|
+
// inline `left` OR `right` per open depending on a window-geometry
|
|
784
|
+
// branch and never clears the other, and the wrapper persists across
|
|
785
|
+
// opens — after a resize between opens both offsets accumulate and
|
|
786
|
+
// the width:auto wrapper stretches from the stale left coordinate to
|
|
787
|
+
// the right edge. Its `right` branch is wrong here anyway: it offsets
|
|
788
|
+
// from the window, not from the bar. Consumer apps used to carry
|
|
789
|
+
// exactly this pair as a local hotfix; the theme owns the bar now, so
|
|
790
|
+
// it owns the guard.
|
|
791
|
+
left: auto !important;
|
|
792
|
+
right: 0 !important;
|
|
596
793
|
background-color: var(--aa-elevated);
|
|
597
794
|
border: 1px solid var(--aa-border);
|
|
598
795
|
background-image: none;
|
|
@@ -603,6 +800,12 @@ body.active_admin {
|
|
|
603
800
|
// that is invisible whenever the panel fill is close to the page —
|
|
604
801
|
// which is exactly what a light surface is. Outline it like the panel.
|
|
605
802
|
div.dropdown_menu_nipple {
|
|
803
|
+
// The panel is pinned right (above) while AA still offsets the
|
|
804
|
+
// arrow from the panel's LEFT edge by the button's centre, which
|
|
805
|
+
// lands it on empty bar. Pin it right too, centred on the button's
|
|
806
|
+
// own caret (AA draws that 6px wide at right: 12px).
|
|
807
|
+
left: auto !important;
|
|
808
|
+
right: 9px !important;
|
|
606
809
|
border-color: var(--aa-border) transparent;
|
|
607
810
|
&:before, &:after { border-color: var(--aa-elevated) transparent; }
|
|
608
811
|
}
|
|
@@ -630,6 +833,12 @@ body.active_admin {
|
|
|
630
833
|
}
|
|
631
834
|
}
|
|
632
835
|
.flashes {
|
|
836
|
+
// Pin like #header/#title_bar: this is the one full-width bar between the
|
|
837
|
+
// two pinned ones, and on a wide page scrolled right its left-aligned text
|
|
838
|
+
// would leave the viewport, leaving an unreadable colored stripe. AA puts
|
|
839
|
+
// all padding/background on the inner .flash, so the always-rendered empty
|
|
840
|
+
// wrapper stays zero-height and inert on flash-less pages.
|
|
841
|
+
@include viewport-pinned-bar;
|
|
633
842
|
.flash {
|
|
634
843
|
color: #ffffff;
|
|
635
844
|
background-image: none;
|
|
@@ -905,27 +1114,27 @@ body.active_admin {
|
|
|
905
1114
|
// link keeps its full width so the whole cell stays clickable, and the
|
|
906
1115
|
// marker takes currentColor — the stock sprite is a fixed grey PNG that
|
|
907
1116
|
// cannot follow the text into dark mode.
|
|
908
|
-
//
|
|
909
|
-
//
|
|
910
|
-
//
|
|
911
|
-
|
|
912
|
-
th.sortable > a[href*="order="] {
|
|
1117
|
+
// The sprite goes from every anchor in a sortable heading, because
|
|
1118
|
+
// ActiveAdmin sets it on every one — an application link in there would
|
|
1119
|
+
// otherwise keep the low-res PNG and the 13px indent it needs.
|
|
1120
|
+
th.sortable a {
|
|
913
1121
|
padding-left: 0;
|
|
914
1122
|
background-image: none;
|
|
1123
|
+
}
|
|
1124
|
+
// The marker, though, only on ActiveAdmin's own heading link, which always
|
|
1125
|
+
// carries the order parameter: an application's link is its own business.
|
|
1126
|
+
th.sortable > a[href*="order="] {
|
|
915
1127
|
|
|
916
1128
|
&:after {
|
|
917
1129
|
content: "";
|
|
918
1130
|
display: inline-block;
|
|
1131
|
+
width: 9px;
|
|
1132
|
+
height: 12px;
|
|
919
1133
|
margin-left: 6px;
|
|
920
1134
|
vertical-align: middle;
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
// heights, because `vertical-align: middle` centres the box and the
|
|
925
|
-
// visible half then sits off-centre within it.
|
|
926
|
-
border: 4px solid transparent;
|
|
927
|
-
border-bottom-width: 0;
|
|
928
|
-
border-top-color: currentColor;
|
|
1135
|
+
background-color: currentColor;
|
|
1136
|
+
-webkit-mask: #{$sort-icon-none} center / contain no-repeat;
|
|
1137
|
+
mask: #{$sort-icon-none} center / contain no-repeat;
|
|
929
1138
|
// 0.6, not lower: the marker is the only thing separating a sortable
|
|
930
1139
|
// heading from a plain one, so WCAG 1.4.11 asks 3:1 of it. Against the
|
|
931
1140
|
// header fill it gives 3.40 light and 4.22 dark; at 0.4 it was 2.13
|
|
@@ -934,13 +1143,15 @@ body.active_admin {
|
|
|
934
1143
|
}
|
|
935
1144
|
}
|
|
936
1145
|
th.sorted-asc > a[href*="order="]:after {
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
1146
|
+
-webkit-mask-image: $sort-icon-asc;
|
|
1147
|
+
mask-image: $sort-icon-asc;
|
|
1148
|
+
opacity: 1;
|
|
1149
|
+
}
|
|
1150
|
+
th.sorted-desc > a[href*="order="]:after {
|
|
1151
|
+
-webkit-mask-image: $sort-icon-desc;
|
|
1152
|
+
mask-image: $sort-icon-desc;
|
|
941
1153
|
opacity: 1;
|
|
942
1154
|
}
|
|
943
|
-
th.sorted-desc > a[href*="order="]:after { opacity: 1; }
|
|
944
1155
|
// Right edge = a single 1px line on the last-column cells (header th, body
|
|
945
1156
|
// td, footer cells) coloured like the table border, since the table itself
|
|
946
1157
|
// no longer draws a right border.
|
|
@@ -1205,6 +1416,38 @@ table.index_table thead th a {
|
|
|
1205
1416
|
color: var(--aa-table-header-text) !important;
|
|
1206
1417
|
}
|
|
1207
1418
|
|
|
1419
|
+
// Sticky table headers: keep the column labels visible while a long index table
|
|
1420
|
+
// scrolls vertically. The header/title bar pin only horizontally (no `top`), so
|
|
1421
|
+
// they scroll away on vertical scroll and this thead pins to the viewport top —
|
|
1422
|
+
// no overlap. Scoped to .paginated_collection so it only hits real AA index
|
|
1423
|
+
// listings, not custom report/dashboard tables.
|
|
1424
|
+
//
|
|
1425
|
+
// Opting out: AA 3.x hardcodes the index table's class attribute and ignores
|
|
1426
|
+
// `index class:` options, so .skip-sticky-headers is reachable only on tables
|
|
1427
|
+
// whose markup you render yourself. For real AA listings, opt out app-wide
|
|
1428
|
+
// with one CSS line in your own stylesheet:
|
|
1429
|
+
// .paginated_collection table.index_table thead tr th { position: static; }
|
|
1430
|
+
// Opt a hand-built table IN with .with-sticky-headers.
|
|
1431
|
+
// tr:first-child only: with a multi-row thead (group header over column
|
|
1432
|
+
// header) every row would stick at the same offset and paint over each other —
|
|
1433
|
+
// per-row offsets need measurements CSS alone can't express. The first row
|
|
1434
|
+
// pins; any further header rows scroll away normally.
|
|
1435
|
+
.paginated_collection table.index_table:not(.skip-sticky-headers) thead tr:first-child th,
|
|
1436
|
+
table.with-sticky-headers thead tr:first-child th {
|
|
1437
|
+
position: sticky;
|
|
1438
|
+
top: -1px;
|
|
1439
|
+
z-index: 98;
|
|
1440
|
+
}
|
|
1441
|
+
// Square the corner cells of sticky theads: their inner-radius top corners are
|
|
1442
|
+
// transparent, so once the header detaches from the table's rounded border the
|
|
1443
|
+
// rows scrolling beneath flicker through the ~3px notches. At rest the square
|
|
1444
|
+
// background overpaints the border's rounding by the same ~3px — the lesser,
|
|
1445
|
+
// static artifact (CSS cannot tell "stuck" from "at rest").
|
|
1446
|
+
.paginated_collection table.index_table:not(.skip-sticky-headers) thead tr:first-child th:first-child,
|
|
1447
|
+
table.with-sticky-headers thead tr:first-child th:first-child { border-top-left-radius: 0; }
|
|
1448
|
+
.paginated_collection table.index_table:not(.skip-sticky-headers) thead tr:first-child th:last-child,
|
|
1449
|
+
table.with-sticky-headers thead tr:first-child th:last-child { border-top-right-radius: 0; }
|
|
1450
|
+
|
|
1208
1451
|
// Form section header: a <legend> interrupts the fieldset's top border, so the
|
|
1209
1452
|
// header bar has no border around it (unlike a panel header). Float the legend
|
|
1210
1453
|
// so it flows as a normal block and the fieldset border wraps around it.
|
|
@@ -1349,7 +1592,47 @@ form fieldset > ol > li fieldset ol li {
|
|
|
1349
1592
|
border-color: var(--aa-border);
|
|
1350
1593
|
}
|
|
1351
1594
|
.dropdown_menu .dropdown_menu_list_wrapper .dropdown_menu_list li {
|
|
1352
|
-
|
|
1595
|
+
// Was repainted to --aa-border, but a hairline under every row makes the
|
|
1596
|
+
// flyout read as a table of cells rather than a menu. Drop it — the hover
|
|
1597
|
+
// highlight is enough separation. (Same depth as the base rule, later wins.)
|
|
1598
|
+
border-bottom: none;
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
// Dropdown-button caret. ActiveAdmin draws it with two stacked triangles on the
|
|
1602
|
+
// button: :before is a #FFF "shadow", :after the #777 arrow — both hard-coded.
|
|
1603
|
+
// On the themed blue title-bar action button and on the dark elevated
|
|
1604
|
+
// table-tools buttons the #777 arrow is ~invisible. Recolor it to the button's
|
|
1605
|
+
// own text colour and hide the light shadow into the fill.
|
|
1606
|
+
#titlebar_right .dropdown_menu .dropdown_menu_button {
|
|
1607
|
+
&:before { border-top-color: var(--aa-button); }
|
|
1608
|
+
&:after { border-top-color: var(--aa-button-text); }
|
|
1609
|
+
}
|
|
1610
|
+
.table_tools .dropdown_menu .dropdown_menu_button,
|
|
1611
|
+
.batch_actions_selector .dropdown_menu_button {
|
|
1612
|
+
&:before { border-top-color: var(--aa-elevated); }
|
|
1613
|
+
&:after { border-top-color: var(--aa-text); }
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
// Disabled form controls. The theme recolors inputs/selects via --aa-*, but a
|
|
1617
|
+
// disabled one looked identical to an enabled one (especially in dark). Mute
|
|
1618
|
+
// the fill, text and cursor so "disabled" reads in both modes. select2 sets its
|
|
1619
|
+
// control bg with !important, so the disabled override needs it too.
|
|
1620
|
+
#active_admin_content {
|
|
1621
|
+
input:disabled, textarea:disabled, select:disabled {
|
|
1622
|
+
background-color: var(--aa-surface-2) !important;
|
|
1623
|
+
color: var(--aa-text-muted) !important;
|
|
1624
|
+
opacity: 0.6;
|
|
1625
|
+
cursor: not-allowed !important;
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
// Both container classes (--default --disabled) so this out-specifies the
|
|
1629
|
+
// enabled control rule's `--default` fill (which is !important) regardless of
|
|
1630
|
+
// source order.
|
|
1631
|
+
.select2-container--default.select2-container--disabled .select2-selection {
|
|
1632
|
+
background-color: var(--aa-surface-2) !important;
|
|
1633
|
+
opacity: 0.6;
|
|
1634
|
+
cursor: not-allowed !important;
|
|
1635
|
+
.select2-selection__rendered { color: var(--aa-text-muted) !important; }
|
|
1353
1636
|
}
|
|
1354
1637
|
|
|
1355
1638
|
.ui-dialog {
|
|
@@ -1359,6 +1642,11 @@ form fieldset > ol > li fieldset ol li {
|
|
|
1359
1642
|
background-color: var(--aa-surface);
|
|
1360
1643
|
color: var(--aa-text);
|
|
1361
1644
|
border-bottom: 1px solid var(--aa-border);
|
|
1645
|
+
// jQuery-UI's default `minHeight: 150` option is applied inline to the content
|
|
1646
|
+
// box (min-height:~54px), so a one-line confirm leaves a big empty area
|
|
1647
|
+
// between the message and the buttons. Let the content size to its text
|
|
1648
|
+
// (the inline min-height needs !important to beat).
|
|
1649
|
+
.ui-dialog-content { min-height: 0 !important; }
|
|
1362
1650
|
.ui-dialog-titlebar {
|
|
1363
1651
|
background-image: none;
|
|
1364
1652
|
box-shadow: none;
|
|
@@ -1454,6 +1742,28 @@ form.filter_form .filter_form_field.filter_date_range .seperator {
|
|
|
1454
1742
|
width: 10px;
|
|
1455
1743
|
}
|
|
1456
1744
|
|
|
1745
|
+
// Date-only range filters (jQuery-UI datepicker, input.datepicker) get no width
|
|
1746
|
+
// from the base, so the two inputs fall back to their size="12" intrinsic width
|
|
1747
|
+
// and line up side by side only by luck; the label's float:right "Set range"
|
|
1748
|
+
// link then leaks into the input band on a longer label and bumps the "To"
|
|
1749
|
+
// input onto a second line. Lay the field out with flexbox: the label takes a
|
|
1750
|
+
// full row, the two inputs share the next, immune to the float.
|
|
1751
|
+
form.filter_form .filter_form_field.filter_date_range {
|
|
1752
|
+
display: flex;
|
|
1753
|
+
flex-wrap: wrap;
|
|
1754
|
+
|
|
1755
|
+
> label { flex: 0 0 100%; }
|
|
1756
|
+
|
|
1757
|
+
input.datepicker {
|
|
1758
|
+
box-sizing: border-box;
|
|
1759
|
+
flex: 1 1 0;
|
|
1760
|
+
min-width: 0;
|
|
1761
|
+
margin: 0;
|
|
1762
|
+
|
|
1763
|
+
& + input.datepicker { margin-left: 6px; }
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1457
1767
|
//filter select box border radius
|
|
1458
1768
|
.filter_form_field select {
|
|
1459
1769
|
border-radius: 3px;
|
|
@@ -1538,8 +1848,10 @@ input[type='radio'] {
|
|
|
1538
1848
|
// the seven :not()s are worth seven class-level points, and that beat every
|
|
1539
1849
|
// component rule declared later — pagination links and the Clear Filters
|
|
1540
1850
|
// button came out --aa-link instead of --aa-text.
|
|
1541
|
-
a:where(:not(.button):not(.action_item):not(.table_tools_button):not(.dropdown_menu_button):not(.ui-tabs-anchor):not(.delete_link):not([data-method="delete"])) { color: var(--aa-link); }
|
|
1542
|
-
|
|
1851
|
+
a:where(:not(.button):not(.action_item):not(.table_tools_button):not(.dropdown_menu_button):not(.ui-tabs-anchor):not(.delete_link):not(.delete-link):not([data-method="delete"])) { color: var(--aa-link); }
|
|
1852
|
+
// `.delete-link` (hyphen) as well as AA's own `.delete_link`: some apps name
|
|
1853
|
+
// their soft-delete links with the hyphen.
|
|
1854
|
+
a[data-method="delete"], a.delete_link, a.delete-link { color: var(--aa-delete-link); }
|
|
1543
1855
|
|
|
1544
1856
|
// Pagination — non-current page chips use a light-grey bg in the theme
|
|
1545
1857
|
.pagination span > a { background-color: var(--aa-surface-2); color: var(--aa-text); }
|
|
@@ -1549,7 +1861,10 @@ input[type='radio'] {
|
|
|
1549
1861
|
// cannot be out-specified by anything sane here, which is why this needs
|
|
1550
1862
|
// !important, like the accent fill one line over in the base pagination
|
|
1551
1863
|
// block. Without it the digit renders at 1.00:1 on its own background.
|
|
1552
|
-
|
|
1864
|
+
// The hover fill is the accent ($skinMainSecondColor); $skinMenuPillTextColor
|
|
1865
|
+
// is a light blue that sits on it at ~1.16:1 (invisible). White reads on the
|
|
1866
|
+
// accent (matches the base pagination block's own hover colour one file over).
|
|
1867
|
+
.pagination span > a:hover { color: #fff !important; }
|
|
1553
1868
|
|
|
1554
1869
|
// Batch-actions / table-tools dropdown menu items are white by default
|
|
1555
1870
|
.table_tools .dropdown_menu_list li a {
|
|
@@ -1621,12 +1936,25 @@ input[type='radio'] {
|
|
|
1621
1936
|
table.index_table tbody tr:nth-child(even) > td,
|
|
1622
1937
|
table.index_table tbody tr.even > td { background: var(--aa-surface-2); }
|
|
1623
1938
|
table.index_table tbody tr:hover > td { background: var(--aa-surface-hover); }
|
|
1624
|
-
//
|
|
1625
|
-
// `tr.selected td`, so without this a ticked row
|
|
1626
|
-
//
|
|
1627
|
-
//
|
|
1939
|
+
// Selected cells: the zebra and hover rules above outrank ActiveAdmin's own
|
|
1940
|
+
// `tr.selected td` / `td.selected`, so without this a ticked row (batch
|
|
1941
|
+
// actions) or a click-highlighted row + column (crisscross) looks unselected.
|
|
1942
|
+
// The `tr >` in the td.selected selector is load-bearing: the even-stripe
|
|
1943
|
+
// rule is `...tbody tr:nth-child(even) > td` (specificity 0,0,2,4); a plain
|
|
1944
|
+
// `tbody td.selected` is only (0,0,2,3) and loses on even rows, breaking the
|
|
1945
|
+
// cross every other row. Matching the `tr >` ties the specificity, so source
|
|
1946
|
+
// order wins. The :hover variants keep the selection visible under the pointer.
|
|
1628
1947
|
table.index_table tbody tr.selected > td,
|
|
1629
|
-
table.index_table tbody tr.selected:hover > td
|
|
1948
|
+
table.index_table tbody tr.selected:hover > td,
|
|
1949
|
+
table.index_table tbody tr > td.selected,
|
|
1950
|
+
table.index_table tbody tr:hover > td.selected { background: var(--aa-selected); }
|
|
1951
|
+
// The clicked cell sits at the centre of the cross; an accent outline marks
|
|
1952
|
+
// it apart from the row/column tint without a competing fill (outset inward
|
|
1953
|
+
// so it adds no layout shift).
|
|
1954
|
+
table.index_table tbody tr > td.selected-cell {
|
|
1955
|
+
outline: 2px solid var(--aa-accent);
|
|
1956
|
+
outline-offset: -2px;
|
|
1957
|
+
}
|
|
1630
1958
|
// Plain content tables (e.g. the CDR show "Attempts" table) are striped by the
|
|
1631
1959
|
// base CSS with light fills; map the odd/even rows onto the dark surfaces too.
|
|
1632
1960
|
table tbody tr.odd > td, table tbody tr.odd > th { background-color: var(--aa-surface); }
|
|
@@ -1643,11 +1971,23 @@ input[type='radio'] {
|
|
|
1643
1971
|
color: var(--aa-text);
|
|
1644
1972
|
}
|
|
1645
1973
|
|
|
1974
|
+
// Give the content column its own block-formatting context so #index_footer's
|
|
1975
|
+
// `clear: both` (below) only clears the pagination floats INSIDE the table
|
|
1976
|
+
// area — not the floated #sidebar. Without this, a tall filter sidebar pushes
|
|
1977
|
+
// the pagination far below a short table (it clears the sidebar's float too).
|
|
1978
|
+
#main_content { display: flow-root; }
|
|
1979
|
+
|
|
1646
1980
|
// Index footer (per-page selector, pagination, "displaying…" info, download
|
|
1647
1981
|
// links): lay them out in one left-packed, vertically-centred row. The gem
|
|
1648
1982
|
// floats them, so they sat top-aligned and, having different heights, looked
|
|
1649
1983
|
// misaligned. A slightly larger font than the gem default (0.85em) too.
|
|
1650
1984
|
#index_footer {
|
|
1985
|
+
// ActiveAdmin floats .pagination_top and .paginated_collection_contents
|
|
1986
|
+
// left; the footer has no clear, so it rode up beside them and rendered
|
|
1987
|
+
// ABOVE the table (per-page + page numbers + "Displaying…" duplicated on
|
|
1988
|
+
// top, nothing below). Clear the floats so it sits under the table — one
|
|
1989
|
+
// pagination on top, one on the bottom, like master.
|
|
1990
|
+
clear: both;
|
|
1651
1991
|
text-align: left;
|
|
1652
1992
|
font-size: 0.95em;
|
|
1653
1993
|
.pagination_per_page,
|
|
@@ -1700,6 +2040,83 @@ input[type='radio'] {
|
|
|
1700
2040
|
table.ui-datepicker-calendar tbody td span { color: var(--aa-text-muted); }
|
|
1701
2041
|
.ui-state-hover, .ui-state-active { background: var(--aa-surface-hover); }
|
|
1702
2042
|
}
|
|
2043
|
+
|
|
2044
|
+
// select2 (used by most ActiveAdmin apps). It ships its own light chrome and
|
|
2045
|
+
// appends the dropdown to <body>, so it is styled here at the mixin level
|
|
2046
|
+
// like the datepicker. Drive the control, the dropdown panel, the results
|
|
2047
|
+
// list and the search field from the --aa-* tokens so it follows both modes;
|
|
2048
|
+
// without this the dropdown stays a white panel with white/near-invisible
|
|
2049
|
+
// text in dark mode. !important is required because select2's own stylesheet
|
|
2050
|
+
// sets these to white with equal specificity and loads after this in the
|
|
2051
|
+
// bundle — same reason the datetime picker overrides use it.
|
|
2052
|
+
.select2-container--default {
|
|
2053
|
+
.select2-selection--single,
|
|
2054
|
+
.select2-selection--multiple {
|
|
2055
|
+
background-color: var(--aa-input-bg) !important;
|
|
2056
|
+
border-color: var(--aa-input-border) !important;
|
|
2057
|
+
color: var(--aa-text);
|
|
2058
|
+
}
|
|
2059
|
+
.select2-selection__rendered { color: var(--aa-text) !important; }
|
|
2060
|
+
.select2-selection__placeholder { color: var(--aa-text-muted) !important; }
|
|
2061
|
+
// Clear "×": keep it a small, muted inline glyph that brightens on hover.
|
|
2062
|
+
// select2 4.1 renders it as a <button> that takes a large square hover fill
|
|
2063
|
+
// (the "big blue square"); neutralize that and the 4.0 span the same way so
|
|
2064
|
+
// the affordance is just the colour change, correctly aligned.
|
|
2065
|
+
.select2-selection__clear {
|
|
2066
|
+
color: var(--aa-text-muted) !important;
|
|
2067
|
+
background: transparent !important;
|
|
2068
|
+
border: none !important;
|
|
2069
|
+
box-shadow: none !important;
|
|
2070
|
+
padding: 0 4px !important;
|
|
2071
|
+
&:hover, &:focus { color: var(--aa-text) !important; background: transparent !important; }
|
|
2072
|
+
}
|
|
2073
|
+
.select2-selection--multiple .select2-selection__choice {
|
|
2074
|
+
background-color: var(--aa-surface-2) !important;
|
|
2075
|
+
border-color: var(--aa-border) !important;
|
|
2076
|
+
color: var(--aa-text) !important;
|
|
2077
|
+
}
|
|
2078
|
+
.select2-search__field { color: var(--aa-text) !important; }
|
|
2079
|
+
}
|
|
2080
|
+
.select2-dropdown {
|
|
2081
|
+
background-color: var(--aa-surface) !important;
|
|
2082
|
+
border-color: var(--aa-border) !important;
|
|
2083
|
+
color: var(--aa-text);
|
|
2084
|
+
}
|
|
2085
|
+
.select2-results__option { color: var(--aa-text) !important; }
|
|
2086
|
+
.select2-results__option--highlighted[aria-selected] {
|
|
2087
|
+
background-color: var(--aa-surface-hover) !important;
|
|
2088
|
+
color: var(--aa-text) !important;
|
|
2089
|
+
}
|
|
2090
|
+
.select2-results__option[aria-selected="true"] {
|
|
2091
|
+
background-color: var(--aa-selected) !important;
|
|
2092
|
+
color: var(--aa-text) !important;
|
|
2093
|
+
}
|
|
2094
|
+
|
|
2095
|
+
// tom-select (used by e.g. yeti). Same situation as select2: its own light
|
|
2096
|
+
// chrome, dropdown rendered in place; recolor from the --aa-* tokens.
|
|
2097
|
+
.ts-wrapper {
|
|
2098
|
+
.ts-control {
|
|
2099
|
+
background: var(--aa-input-bg) !important;
|
|
2100
|
+
border-color: var(--aa-input-border) !important;
|
|
2101
|
+
color: var(--aa-text);
|
|
2102
|
+
input, input::placeholder { color: var(--aa-text) !important; }
|
|
2103
|
+
.item {
|
|
2104
|
+
background: var(--aa-surface-2) !important;
|
|
2105
|
+
border-color: var(--aa-border) !important;
|
|
2106
|
+
color: var(--aa-text) !important;
|
|
2107
|
+
}
|
|
2108
|
+
}
|
|
2109
|
+
}
|
|
2110
|
+
.ts-dropdown {
|
|
2111
|
+
background: var(--aa-surface) !important;
|
|
2112
|
+
border-color: var(--aa-border) !important;
|
|
2113
|
+
color: var(--aa-text);
|
|
2114
|
+
.optgroup-header { background: var(--aa-surface-2) !important; color: var(--aa-text-muted) !important; }
|
|
2115
|
+
.option { color: var(--aa-text) !important; }
|
|
2116
|
+
.option.active,
|
|
2117
|
+
.active { background: var(--aa-surface-hover) !important; color: var(--aa-text) !important; }
|
|
2118
|
+
.option[aria-selected="true"] { background: var(--aa-selected) !important; color: var(--aa-text) !important; }
|
|
2119
|
+
}
|
|
1703
2120
|
}
|
|
1704
2121
|
|
|
1705
2122
|
// DARK-ONLY content overrides — genuinely dark-specific values with no light
|
|
@@ -1718,3 +2135,58 @@ input[type='radio'] {
|
|
|
1718
2135
|
html:not([data-theme="light"]) { @include aa-dark-content; }
|
|
1719
2136
|
}
|
|
1720
2137
|
html[data-theme="dark"] { @include aa-dark-content; }
|
|
2138
|
+
|
|
2139
|
+
// Trix / ActionText editor. Trix ships with ActionText (a Rails built-in), so
|
|
2140
|
+
// its chrome is themed here for every consumer; the app still imports Trix's
|
|
2141
|
+
// own base CSS (trix/dist/trix). All rules key off the --aa-* tokens, so they
|
|
2142
|
+
// follow the active palette in both light and dark, and are inert when no
|
|
2143
|
+
// editor is on the page.
|
|
2144
|
+
trix-toolbar {
|
|
2145
|
+
.trix-button-group { border-color: var(--aa-border); }
|
|
2146
|
+
.trix-button {
|
|
2147
|
+
background: var(--aa-surface);
|
|
2148
|
+
color: var(--aa-text);
|
|
2149
|
+
border-bottom-color: var(--aa-border);
|
|
2150
|
+
&:not(:first-child) { border-left-color: var(--aa-border); }
|
|
2151
|
+
&:not(:disabled):hover { background: var(--aa-surface-hover); }
|
|
2152
|
+
&.trix-active { background: var(--aa-selected); }
|
|
2153
|
+
}
|
|
2154
|
+
// Trix dims idle icons to opacity 0.6 and disabled ones to 0.125 — both read
|
|
2155
|
+
// as faint in either palette, the 0.125 so faint the block-format buttons
|
|
2156
|
+
// (disabled until the editor is focused) look broken. Lift idle to 0.8 and
|
|
2157
|
+
// disabled to 0.4: still clearly dimmer than idle, but legible. Trix keeps the
|
|
2158
|
+
// active icon at 1 via a higher-specificity rule.
|
|
2159
|
+
.trix-button--icon::before { opacity: 0.8; }
|
|
2160
|
+
.trix-button--icon:disabled::before { opacity: 0.4; }
|
|
2161
|
+
}
|
|
2162
|
+
|
|
2163
|
+
trix-editor {
|
|
2164
|
+
background: var(--aa-input-bg);
|
|
2165
|
+
border-color: var(--aa-input-border);
|
|
2166
|
+
color: var(--aa-text);
|
|
2167
|
+
&:empty:not(:focus)::before { color: var(--aa-text-muted); } // placeholder
|
|
2168
|
+
}
|
|
2169
|
+
|
|
2170
|
+
.trix-content {
|
|
2171
|
+
pre { background: var(--aa-surface-2); }
|
|
2172
|
+
blockquote { border-left: 0.3em solid var(--aa-border); }
|
|
2173
|
+
}
|
|
2174
|
+
|
|
2175
|
+
.trix-dialog {
|
|
2176
|
+
background: var(--aa-surface);
|
|
2177
|
+
color: var(--aa-text);
|
|
2178
|
+
box-shadow: 0 2px 8px var(--aa-shadow);
|
|
2179
|
+
input[type="text"], input[type="url"] {
|
|
2180
|
+
background: var(--aa-input-bg);
|
|
2181
|
+
border-color: var(--aa-input-border);
|
|
2182
|
+
color: var(--aa-text);
|
|
2183
|
+
}
|
|
2184
|
+
.trix-button { background: var(--aa-accent); color: #fff; }
|
|
2185
|
+
}
|
|
2186
|
+
|
|
2187
|
+
// Trix bakes its toolbar icons into the base CSS as black SVG background images
|
|
2188
|
+
// on ::before; invert them in dark mode so they read on the dark toolbar (the
|
|
2189
|
+
// idle/disabled opacity lift above applies in both modes).
|
|
2190
|
+
@include aa-dark {
|
|
2191
|
+
trix-toolbar .trix-button--icon::before { filter: invert(1); }
|
|
2192
|
+
}
|