plutonium 0.65.0 → 0.67.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/.claude/skills/plutonium/SKILL.md +43 -43
- data/.claude/skills/plutonium-app/SKILL.md +101 -59
- data/.claude/skills/plutonium-async-interactions/SKILL.md +19 -19
- data/.claude/skills/plutonium-auth/SKILL.md +119 -53
- data/.claude/skills/plutonium-behavior/SKILL.md +110 -78
- data/.claude/skills/plutonium-dashboard/SKILL.md +11 -4
- data/.claude/skills/plutonium-kanban/SKILL.md +81 -49
- data/.claude/skills/plutonium-resource/SKILL.md +158 -141
- data/.claude/skills/plutonium-tenancy/SKILL.md +104 -55
- data/.claude/skills/plutonium-testing/SKILL.md +130 -33
- data/.claude/skills/plutonium-ui/SKILL.md +161 -98
- data/.claude/skills/plutonium-wizard/SKILL.md +93 -82
- data/CHANGELOG.md +43 -0
- data/README.md +9 -9
- data/SECURITY.md +1 -1
- data/app/assets/plutonium.css +1 -1
- data/app/assets/plutonium.js +56 -3
- data/app/assets/plutonium.js.map +4 -4
- data/app/assets/plutonium.min.js +32 -32
- data/app/assets/plutonium.min.js.map +4 -4
- data/config/brakeman.ignore +1 -1
- data/config/locales/en/js.yml +4 -0
- data/config/locales/en/ui.yml +16 -0
- data/docs/.vitepress/sync-skills.mjs +6 -3
- data/docs/blog/introducing-plutonium-dashboards.md +4 -5
- data/docs/blog/introducing-plutonium-i18n.md +4 -5
- data/docs/getting-started/installation.md +5 -5
- data/docs/getting-started/tutorial/02-first-resource.md +3 -3
- data/docs/getting-started/tutorial/03-authentication.md +7 -7
- data/docs/getting-started/tutorial/04-authorization.md +21 -4
- data/docs/getting-started/tutorial/05-custom-actions.md +2 -2
- data/docs/getting-started/tutorial/06-nested-resources.md +5 -2
- data/docs/getting-started/tutorial/07-author-portal.md +2 -2
- data/docs/getting-started/tutorial/08-customizing-ui.md +45 -30
- data/docs/getting-started/tutorial/index.md +1 -1
- data/docs/guides/adding-resources.md +10 -7
- data/docs/guides/authentication.md +25 -25
- data/docs/guides/authorization.md +24 -24
- data/docs/guides/creating-packages.md +17 -17
- data/docs/guides/custom-actions.md +32 -32
- data/docs/guides/customizing-ui.md +29 -26
- data/docs/guides/dashboards.md +1 -1
- data/docs/guides/index.md +3 -3
- data/docs/guides/kanban.md +55 -55
- data/docs/guides/multi-tenancy.md +35 -22
- data/docs/guides/nested-resources.md +21 -21
- data/docs/guides/performance.md +3 -3
- data/docs/guides/search-filtering.md +13 -13
- data/docs/guides/testing.md +16 -12
- data/docs/guides/theming.md +32 -17
- data/docs/guides/troubleshooting.md +2 -2
- data/docs/guides/user-invites.md +17 -17
- data/docs/guides/user-profile.md +51 -24
- data/docs/guides/wizards.md +55 -55
- data/docs/reference/app/generators.md +22 -22
- data/docs/reference/app/index.md +15 -18
- data/docs/reference/app/packages.md +8 -8
- data/docs/reference/app/portals.md +75 -29
- data/docs/reference/auth/accounts.md +15 -15
- data/docs/reference/auth/index.md +12 -12
- data/docs/reference/auth/profile.md +67 -29
- data/docs/reference/behavior/async-interactions.md +24 -24
- data/docs/reference/behavior/controllers.md +28 -28
- data/docs/reference/behavior/index.md +5 -5
- data/docs/reference/behavior/interactions.md +44 -44
- data/docs/reference/behavior/policies.md +48 -28
- data/docs/reference/configuration.md +6 -6
- data/docs/reference/dashboard/dsl.md +2 -2
- data/docs/reference/dashboard/index.md +1 -1
- data/docs/reference/generators/lite.md +7 -7
- data/docs/reference/i18n.md +23 -0
- data/docs/reference/index.md +1 -1
- data/docs/reference/kanban/authorization.md +9 -9
- data/docs/reference/kanban/dsl.md +32 -32
- data/docs/reference/kanban/index.md +1 -1
- data/docs/reference/kanban/positioning.md +17 -15
- data/docs/reference/resource/actions.md +51 -51
- data/docs/reference/resource/definition.md +85 -80
- data/docs/reference/resource/export.md +6 -6
- data/docs/reference/resource/index.md +16 -16
- data/docs/reference/resource/model.md +24 -24
- data/docs/reference/resource/positioning.md +78 -76
- data/docs/reference/resource/query.md +24 -14
- data/docs/reference/tenancy/entity-scoping.md +65 -35
- data/docs/reference/tenancy/index.md +11 -11
- data/docs/reference/tenancy/invites.md +20 -20
- data/docs/reference/tenancy/nested-resources.md +13 -13
- data/docs/reference/testing/index.md +116 -22
- data/docs/reference/ui/assets.md +57 -25
- data/docs/reference/ui/components.md +20 -20
- data/docs/reference/ui/displays.md +32 -15
- data/docs/reference/ui/forms.md +89 -39
- data/docs/reference/ui/index.md +17 -15
- data/docs/reference/ui/layouts.md +21 -21
- data/docs/reference/ui/pages.md +22 -22
- data/docs/reference/ui/tables.md +7 -7
- data/docs/reference/wizard/anchoring-resume.md +33 -32
- data/docs/reference/wizard/dsl.md +44 -44
- data/docs/reference/wizard/index.md +6 -6
- data/docs/reference/wizard/one-time.md +18 -18
- data/docs/reference/wizard/registration-launch.md +32 -32
- data/docs/reference/wizard/storage-config.md +23 -23
- data/gemfiles/rails_7.gemfile +1 -0
- data/gemfiles/rails_7.gemfile.lock +13 -3
- data/gemfiles/rails_8.0.gemfile +1 -0
- data/gemfiles/rails_8.0.gemfile.lock +10 -1
- data/gemfiles/rails_8.1.gemfile +1 -0
- data/gemfiles/rails_8.1.gemfile.lock +10 -1
- data/lib/generators/pu/profile/conn_generator.rb +6 -0
- data/lib/plutonium/auth/rodauth.rb +7 -0
- data/lib/plutonium/core/controller.rb +0 -2
- data/lib/plutonium/helpers/content_helper.rb +0 -3
- data/lib/plutonium/query/filter.rb +2 -1
- data/lib/plutonium/query/filters/tags.rb +36 -0
- data/lib/plutonium/resource/record/associated_with.rb +23 -2
- data/lib/plutonium/ui/component/resolves_tags.rb +13 -0
- data/lib/plutonium/ui/display/base.rb +50 -2
- data/lib/plutonium/ui/display/components/badge.rb +1 -1
- data/lib/plutonium/ui/display/components/binary.rb +20 -0
- data/lib/plutonium/ui/display/components/boolean.rb +1 -1
- data/lib/plutonium/ui/display/components/code.rb +23 -0
- data/lib/plutonium/ui/display/components/color.rb +14 -6
- data/lib/plutonium/ui/display/components/duration.rb +31 -0
- data/lib/plutonium/ui/display/components/file_size.rb +22 -0
- data/lib/plutonium/ui/display/components/key_value.rb +37 -0
- data/lib/plutonium/ui/display/components/list.rb +33 -0
- data/lib/plutonium/ui/display/components/number.rb +32 -0
- data/lib/plutonium/ui/display/components/progress.rb +36 -0
- data/lib/plutonium/ui/display/components/rating.rb +36 -0
- data/lib/plutonium/ui/display/components/relative_time.rb +25 -0
- data/lib/plutonium/ui/display/components/rich_text.rb +23 -0
- data/lib/plutonium/ui/display/components/tags.rb +18 -0
- data/lib/plutonium/ui/display/options/inferred_types.rb +13 -0
- data/lib/plutonium/ui/display/theme.rb +24 -2
- data/lib/plutonium/ui/form/base.rb +30 -1
- data/lib/plutonium/ui/form/components/binary.rb +40 -0
- data/lib/plutonium/ui/form/components/key_value_store.rb +22 -71
- data/lib/plutonium/ui/form/components/list.rb +46 -0
- data/lib/plutonium/ui/form/components/rating.rb +51 -0
- data/lib/plutonium/ui/form/components/rich_text.rb +20 -0
- data/lib/plutonium/ui/form/components/tags.rb +45 -0
- data/lib/plutonium/ui/form/components/tags_filter.rb +40 -0
- data/lib/plutonium/ui/form/components/uppy.rb +1 -1
- data/lib/plutonium/ui/form/concerns/typeahead_attributes.rb +7 -1
- data/lib/plutonium/ui/form/options/inferred_types.rb +16 -15
- data/lib/plutonium/ui/form/theme.rb +20 -4
- data/lib/plutonium/ui/grid/card.rb +13 -1
- data/lib/plutonium/ui/layout/base.rb +10 -1
- data/lib/plutonium/ui/options/rich_text_field.rb +18 -0
- data/lib/plutonium/ui/options/secret_field.rb +32 -0
- data/lib/plutonium/ui/options/tags_field.rb +23 -0
- data/lib/plutonium/ui/table/components/toolbar.rb +2 -2
- data/lib/plutonium/ui/table/components/view_switcher.rb +4 -2
- data/lib/plutonium/ui/table/display_theme.rb +30 -2
- data/lib/plutonium/version.rb +1 -1
- data/package.json +1 -1
- data/src/css/components.css +53 -10
- data/src/css/flatpickr.css +91 -0
- data/src/js/controllers/easymde_controller.js +1 -0
- data/src/js/controllers/register_controllers.js +2 -0
- data/src/js/controllers/slim_select_controller.js +32 -3
- data/src/js/controllers/timeago_controller.js +40 -0
- metadata +25 -2
data/lib/plutonium/version.rb
CHANGED
data/package.json
CHANGED
data/src/css/components.css
CHANGED
|
@@ -971,7 +971,7 @@ html.pu-rail-pinned .icon-rail-pin-expand {
|
|
|
971
971
|
@apply flex items-center p-4 mb-4 rounded-lg;
|
|
972
972
|
}
|
|
973
973
|
.dark .pu-alert {
|
|
974
|
-
@apply bg-
|
|
974
|
+
@apply bg-gray-800;
|
|
975
975
|
}
|
|
976
976
|
|
|
977
977
|
.pu-alert-message {
|
|
@@ -982,7 +982,7 @@ html.pu-rail-pinned .icon-rail-pin-expand {
|
|
|
982
982
|
@apply ms-auto -mx-1.5 -my-1.5 rounded-lg focus:ring-2 p-1.5 inline-flex items-center justify-center h-8 w-8;
|
|
983
983
|
}
|
|
984
984
|
.dark .pu-alert-close {
|
|
985
|
-
@apply bg-
|
|
985
|
+
@apply bg-gray-800 hover:bg-gray-700;
|
|
986
986
|
}
|
|
987
987
|
|
|
988
988
|
/* --- Variants: success / warning / danger / info ---
|
|
@@ -995,11 +995,11 @@ html.pu-rail-pinned .icon-rail-pin-expand {
|
|
|
995
995
|
.pu-toast-success .pu-toast-icon { @apply text-success-500 bg-success-100; }
|
|
996
996
|
.dark .pu-toast-success .pu-toast-icon { @apply bg-success-800 text-success-200; }
|
|
997
997
|
.pu-toast-success .pu-toast-close { @apply bg-success-50 text-success-400 hover:bg-success-200 focus:ring-success-400; }
|
|
998
|
-
.dark .pu-toast-success .pu-toast-close { @apply text-success-400; }
|
|
998
|
+
.dark .pu-toast-success .pu-toast-close { @apply bg-gray-800 text-success-400 hover:bg-gray-700; }
|
|
999
999
|
.pu-alert-success { @apply bg-success-50 text-success-800; }
|
|
1000
1000
|
.dark .pu-alert-success { @apply text-success-400; }
|
|
1001
1001
|
.pu-alert-success .pu-alert-close { @apply bg-success-50 text-success-500 hover:bg-success-200 focus:ring-success-400; }
|
|
1002
|
-
.dark .pu-alert-success .pu-alert-close { @apply text-success-400; }
|
|
1002
|
+
.dark .pu-alert-success .pu-alert-close { @apply bg-gray-800 text-success-400 hover:bg-gray-700; }
|
|
1003
1003
|
|
|
1004
1004
|
/* warning */
|
|
1005
1005
|
.pu-toast-warning { @apply bg-warning-50; }
|
|
@@ -1007,11 +1007,11 @@ html.pu-rail-pinned .icon-rail-pin-expand {
|
|
|
1007
1007
|
.pu-toast-warning .pu-toast-icon { @apply text-warning-500 bg-warning-100; }
|
|
1008
1008
|
.dark .pu-toast-warning .pu-toast-icon { @apply bg-warning-800 text-warning-200; }
|
|
1009
1009
|
.pu-toast-warning .pu-toast-close { @apply bg-warning-50 text-warning-400 hover:bg-warning-200 focus:ring-warning-400; }
|
|
1010
|
-
.dark .pu-toast-warning .pu-toast-close { @apply text-warning-400; }
|
|
1010
|
+
.dark .pu-toast-warning .pu-toast-close { @apply bg-gray-800 text-warning-400 hover:bg-gray-700; }
|
|
1011
1011
|
.pu-alert-warning { @apply bg-warning-50 text-warning-800; }
|
|
1012
1012
|
.dark .pu-alert-warning { @apply text-warning-400; }
|
|
1013
1013
|
.pu-alert-warning .pu-alert-close { @apply bg-warning-50 text-warning-500 hover:bg-warning-200 focus:ring-warning-400; }
|
|
1014
|
-
.dark .pu-alert-warning .pu-alert-close { @apply text-warning-400; }
|
|
1014
|
+
.dark .pu-alert-warning .pu-alert-close { @apply bg-gray-800 text-warning-400 hover:bg-gray-700; }
|
|
1015
1015
|
|
|
1016
1016
|
/* danger */
|
|
1017
1017
|
.pu-toast-danger { @apply bg-danger-50; }
|
|
@@ -1019,11 +1019,11 @@ html.pu-rail-pinned .icon-rail-pin-expand {
|
|
|
1019
1019
|
.pu-toast-danger .pu-toast-icon { @apply text-danger-500 bg-danger-100; }
|
|
1020
1020
|
.dark .pu-toast-danger .pu-toast-icon { @apply bg-danger-800 text-danger-200; }
|
|
1021
1021
|
.pu-toast-danger .pu-toast-close { @apply bg-danger-50 text-danger-400 hover:bg-danger-200 focus:ring-danger-400; }
|
|
1022
|
-
.dark .pu-toast-danger .pu-toast-close { @apply text-danger-400; }
|
|
1022
|
+
.dark .pu-toast-danger .pu-toast-close { @apply bg-gray-800 text-danger-400 hover:bg-gray-700; }
|
|
1023
1023
|
.pu-alert-danger { @apply bg-danger-50 text-danger-800; }
|
|
1024
1024
|
.dark .pu-alert-danger { @apply text-danger-400; }
|
|
1025
1025
|
.pu-alert-danger .pu-alert-close { @apply bg-danger-50 text-danger-500 hover:bg-danger-200 focus:ring-danger-400; }
|
|
1026
|
-
.dark .pu-alert-danger .pu-alert-close { @apply text-danger-400; }
|
|
1026
|
+
.dark .pu-alert-danger .pu-alert-close { @apply bg-gray-800 text-danger-400 hover:bg-gray-700; }
|
|
1027
1027
|
|
|
1028
1028
|
/* info (default / :notice) */
|
|
1029
1029
|
.pu-toast-info { @apply bg-info-50; }
|
|
@@ -1031,11 +1031,11 @@ html.pu-rail-pinned .icon-rail-pin-expand {
|
|
|
1031
1031
|
.pu-toast-info .pu-toast-icon { @apply text-info-500 bg-info-100; }
|
|
1032
1032
|
.dark .pu-toast-info .pu-toast-icon { @apply bg-info-800 text-info-200; }
|
|
1033
1033
|
.pu-toast-info .pu-toast-close { @apply bg-info-50 text-info-400 hover:bg-info-200 focus:ring-info-400; }
|
|
1034
|
-
.dark .pu-toast-info .pu-toast-close { @apply text-info-400; }
|
|
1034
|
+
.dark .pu-toast-info .pu-toast-close { @apply bg-gray-800 text-info-400 hover:bg-gray-700; }
|
|
1035
1035
|
.pu-alert-info { @apply bg-info-50 text-info-800; }
|
|
1036
1036
|
.dark .pu-alert-info { @apply text-info-400; }
|
|
1037
1037
|
.pu-alert-info .pu-alert-close { @apply bg-info-50 text-info-500 hover:bg-info-200 focus:ring-info-400; }
|
|
1038
|
-
.dark .pu-alert-info .pu-alert-close { @apply text-info-400; }
|
|
1038
|
+
.dark .pu-alert-info .pu-alert-close { @apply bg-gray-800 text-info-400 hover:bg-gray-700; }
|
|
1039
1039
|
|
|
1040
1040
|
/* ===========================================================================
|
|
1041
1041
|
Wizard — horizontal "steps" stepper (numbered nodes on a connector track)
|
|
@@ -1247,3 +1247,46 @@ html.pu-rail-pinned .icon-rail-pin-expand {
|
|
|
1247
1247
|
opacity: 0.6;
|
|
1248
1248
|
}
|
|
1249
1249
|
}
|
|
1250
|
+
|
|
1251
|
+
/* Star rating input (Form::Components::Rating). Radios run max..1 in a
|
|
1252
|
+
row-reversed box, so `~ label` reaches the stars below the checked or
|
|
1253
|
+
hovered one. */
|
|
1254
|
+
.pu-rating {
|
|
1255
|
+
@apply inline-flex flex-row-reverse justify-end gap-0.5 border-0 p-0 m-0;
|
|
1256
|
+
}
|
|
1257
|
+
.pu-rating label {
|
|
1258
|
+
@apply cursor-pointer text-[var(--pu-border)] transition-colors;
|
|
1259
|
+
}
|
|
1260
|
+
.pu-rating label svg {
|
|
1261
|
+
@apply w-6 h-6;
|
|
1262
|
+
}
|
|
1263
|
+
.pu-rating input:checked ~ label,
|
|
1264
|
+
.pu-rating label:hover,
|
|
1265
|
+
.pu-rating label:hover ~ label {
|
|
1266
|
+
@apply text-warning-500;
|
|
1267
|
+
}
|
|
1268
|
+
.pu-rating input:checked ~ label svg,
|
|
1269
|
+
.pu-rating label:hover svg,
|
|
1270
|
+
.pu-rating label:hover ~ label svg {
|
|
1271
|
+
fill: currentColor;
|
|
1272
|
+
}
|
|
1273
|
+
/* "Clear" comes last in the DOM; order: -1 puts it after the stars
|
|
1274
|
+
(row-reverse lays out from the right). `input ~` matches the star-fill
|
|
1275
|
+
rules' specificity, and coming later lets this win. */
|
|
1276
|
+
.pu-rating input ~ label.pu-rating-clear {
|
|
1277
|
+
@apply order-[-1] ml-2 self-center text-sm text-[var(--pu-text-muted)] hover:text-[var(--pu-text)] hover:underline;
|
|
1278
|
+
}
|
|
1279
|
+
.pu-rating input:focus-visible + label {
|
|
1280
|
+
@apply rounded-sm outline-2 outline-offset-2 outline-primary-500;
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
/* Tailwind's preflight strips list markers. Restore them inside the rich
|
|
1284
|
+
text editors (Trix, Lexxy) so lists look like lists while editing. */
|
|
1285
|
+
trix-editor ul,
|
|
1286
|
+
.lexxy-content ul {
|
|
1287
|
+
@apply list-disc ps-6;
|
|
1288
|
+
}
|
|
1289
|
+
trix-editor ol,
|
|
1290
|
+
.lexxy-content ol {
|
|
1291
|
+
@apply list-decimal ps-6;
|
|
1292
|
+
}
|
data/src/css/flatpickr.css
CHANGED
|
@@ -795,3 +795,94 @@ span.flatpickr-weekday {
|
|
|
795
795
|
[data-controller="remote-modal"] > .flatpickr-calendar {
|
|
796
796
|
left: auto !important;
|
|
797
797
|
}
|
|
798
|
+
|
|
799
|
+
/* Dark mode: map flatpickr's hardcoded light palette onto the design tokens. */
|
|
800
|
+
.dark .flatpickr-calendar {
|
|
801
|
+
background: var(--pu-surface);
|
|
802
|
+
box-shadow: 0 0 0 1px var(--pu-border), 0 3px 13px rgba(0, 0, 0, 0.4);
|
|
803
|
+
}
|
|
804
|
+
.dark .flatpickr-calendar.arrowTop:after {
|
|
805
|
+
border-bottom-color: var(--pu-surface);
|
|
806
|
+
}
|
|
807
|
+
.dark .flatpickr-calendar.arrowBottom:after {
|
|
808
|
+
border-top-color: var(--pu-surface);
|
|
809
|
+
}
|
|
810
|
+
.dark .flatpickr-calendar.arrowTop:before {
|
|
811
|
+
border-bottom-color: var(--pu-border);
|
|
812
|
+
}
|
|
813
|
+
.dark .flatpickr-calendar.arrowBottom:before {
|
|
814
|
+
border-top-color: var(--pu-border);
|
|
815
|
+
}
|
|
816
|
+
.dark .flatpickr-calendar.hasTime .flatpickr-time {
|
|
817
|
+
border-top-color: var(--pu-border);
|
|
818
|
+
}
|
|
819
|
+
.dark .flatpickr-months .flatpickr-month,
|
|
820
|
+
.dark .flatpickr-months .flatpickr-prev-month,
|
|
821
|
+
.dark .flatpickr-months .flatpickr-next-month,
|
|
822
|
+
.dark .flatpickr-current-month input.cur-year,
|
|
823
|
+
.dark .flatpickr-current-month .flatpickr-monthDropdown-months {
|
|
824
|
+
color: var(--pu-text);
|
|
825
|
+
fill: var(--pu-text);
|
|
826
|
+
}
|
|
827
|
+
.dark .flatpickr-months .flatpickr-prev-month:hover svg,
|
|
828
|
+
.dark .flatpickr-months .flatpickr-next-month:hover svg {
|
|
829
|
+
fill: var(--pu-text-muted);
|
|
830
|
+
}
|
|
831
|
+
.dark .flatpickr-current-month .flatpickr-monthDropdown-months,
|
|
832
|
+
.dark .flatpickr-current-month .flatpickr-monthDropdown-months .flatpickr-monthDropdown-month {
|
|
833
|
+
background: var(--pu-surface);
|
|
834
|
+
}
|
|
835
|
+
.dark .flatpickr-current-month .numInputWrapper span.arrowUp:after {
|
|
836
|
+
border-bottom-color: var(--pu-text);
|
|
837
|
+
}
|
|
838
|
+
.dark .flatpickr-current-month .numInputWrapper span.arrowDown:after {
|
|
839
|
+
border-top-color: var(--pu-text);
|
|
840
|
+
}
|
|
841
|
+
.dark span.flatpickr-weekday {
|
|
842
|
+
color: var(--pu-text-muted);
|
|
843
|
+
}
|
|
844
|
+
.dark .flatpickr-day {
|
|
845
|
+
color: var(--pu-text);
|
|
846
|
+
}
|
|
847
|
+
.dark .flatpickr-day:hover,
|
|
848
|
+
.dark .flatpickr-day:focus,
|
|
849
|
+
.dark .flatpickr-day.prevMonthDay:hover,
|
|
850
|
+
.dark .flatpickr-day.nextMonthDay:hover,
|
|
851
|
+
.dark .flatpickr-day.inRange {
|
|
852
|
+
background: var(--pu-surface-alt);
|
|
853
|
+
border-color: var(--pu-surface-alt);
|
|
854
|
+
}
|
|
855
|
+
.dark .flatpickr-day.inRange {
|
|
856
|
+
box-shadow: -5px 0 0 var(--pu-surface-alt), 5px 0 0 var(--pu-surface-alt);
|
|
857
|
+
}
|
|
858
|
+
.dark .flatpickr-day.today {
|
|
859
|
+
border-color: var(--pu-text-muted);
|
|
860
|
+
}
|
|
861
|
+
.dark .flatpickr-day.prevMonthDay,
|
|
862
|
+
.dark .flatpickr-day.nextMonthDay,
|
|
863
|
+
.dark .flatpickr-day.flatpickr-disabled,
|
|
864
|
+
.dark .flatpickr-day.flatpickr-disabled:hover {
|
|
865
|
+
color: var(--pu-text-muted);
|
|
866
|
+
opacity: 0.5;
|
|
867
|
+
}
|
|
868
|
+
.dark .flatpickr-weekwrapper .flatpickr-weeks,
|
|
869
|
+
.dark .dayContainer + .dayContainer {
|
|
870
|
+
box-shadow: none;
|
|
871
|
+
}
|
|
872
|
+
.dark .flatpickr-time input,
|
|
873
|
+
.dark .flatpickr-time .flatpickr-am-pm,
|
|
874
|
+
.dark .flatpickr-time .flatpickr-time-separator {
|
|
875
|
+
color: var(--pu-text);
|
|
876
|
+
}
|
|
877
|
+
.dark .flatpickr-time .numInputWrapper span.arrowUp:after {
|
|
878
|
+
border-bottom-color: var(--pu-text);
|
|
879
|
+
}
|
|
880
|
+
.dark .flatpickr-time .numInputWrapper span.arrowDown:after {
|
|
881
|
+
border-top-color: var(--pu-text);
|
|
882
|
+
}
|
|
883
|
+
.dark .flatpickr-time input:hover,
|
|
884
|
+
.dark .flatpickr-time .flatpickr-am-pm:hover,
|
|
885
|
+
.dark .flatpickr-time input:focus,
|
|
886
|
+
.dark .flatpickr-time .flatpickr-am-pm:focus {
|
|
887
|
+
background: var(--pu-surface-alt);
|
|
888
|
+
}
|
|
@@ -43,6 +43,7 @@ import BreadcrumbsController from "./breadcrumbs_controller.js"
|
|
|
43
43
|
import RunProgressController from "./run_progress_controller.js"
|
|
44
44
|
import ChartController from "./chart_controller.js"
|
|
45
45
|
import FrameRefreshController from "./frame_refresh_controller.js"
|
|
46
|
+
import TimeagoController from "./timeago_controller.js"
|
|
46
47
|
|
|
47
48
|
export default function (application) {
|
|
48
49
|
// Register controllers here
|
|
@@ -90,4 +91,5 @@ export default function (application) {
|
|
|
90
91
|
application.register("run-progress", RunProgressController)
|
|
91
92
|
application.register("chart", ChartController)
|
|
92
93
|
application.register("frame-refresh", FrameRefreshController)
|
|
94
|
+
application.register("timeago", TimeagoController)
|
|
93
95
|
}
|
|
@@ -9,10 +9,15 @@ import { t } from "../i18n.js";
|
|
|
9
9
|
// When present, SlimSelect's built-in client-side
|
|
10
10
|
// filter is replaced by a debounced fetch through
|
|
11
11
|
// this URL.
|
|
12
|
+
// addable — typed text can be added as a new option (chip
|
|
13
|
+
// inputs, see Form::Components::List).
|
|
14
|
+
// max-selected — caps how many options a multi-select keeps.
|
|
12
15
|
export default class extends Controller {
|
|
13
16
|
static values = {
|
|
14
17
|
typeaheadUrl: String,
|
|
15
|
-
typeaheadDebounceMs: { type: Number, default: 200 }
|
|
18
|
+
typeaheadDebounceMs: { type: Number, default: 200 },
|
|
19
|
+
addable: Boolean,
|
|
20
|
+
maxSelected: Number
|
|
16
21
|
}
|
|
17
22
|
|
|
18
23
|
connect() {
|
|
@@ -39,11 +44,19 @@ export default class extends Controller {
|
|
|
39
44
|
// define placeholderText, searchText, searchPlaceholder and searchingText.
|
|
40
45
|
const strings = t("plutonium.js.libraries.slim_select");
|
|
41
46
|
if (strings && typeof strings === "object") {
|
|
42
|
-
const { placeholderText, searchText, searchPlaceholder, searchingText } = strings;
|
|
43
|
-
Object.assign(settings, { placeholderText, searchText, searchPlaceholder, searchingText });
|
|
47
|
+
const { placeholderText, searchText, searchPlaceholder, searchingText, addableText } = strings;
|
|
48
|
+
Object.assign(settings, { placeholderText, searchText, searchPlaceholder, searchingText, addableText });
|
|
44
49
|
Object.keys(settings).forEach((k) => settings[k] === undefined && delete settings[k]);
|
|
45
50
|
}
|
|
46
51
|
|
|
52
|
+
if (this.hasMaxSelectedValue) settings.maxSelected = this.maxSelectedValue;
|
|
53
|
+
|
|
54
|
+
if (this.addableValue) {
|
|
55
|
+
// A plain "Select Value" / "Search" hides that new values can be typed in.
|
|
56
|
+
settings.placeholderText = t("plutonium.js.slim_select.add_placeholder");
|
|
57
|
+
settings.searchPlaceholder = t("plutonium.js.slim_select.add_search_placeholder");
|
|
58
|
+
}
|
|
59
|
+
|
|
47
60
|
this.modal = this.element.closest('[data-controller="remote-modal"]');
|
|
48
61
|
|
|
49
62
|
if (this.modal) {
|
|
@@ -67,6 +80,20 @@ export default class extends Controller {
|
|
|
67
80
|
|
|
68
81
|
const events = {};
|
|
69
82
|
|
|
83
|
+
if (this.modal) {
|
|
84
|
+
// A modal <dialog> gets `overflow: auto` from the UA stylesheet, so a
|
|
85
|
+
// dropdown that runs past the dialog's edge (a select near the bottom
|
|
86
|
+
// of a short modal) is clipped. The dialog never scrolls itself (its
|
|
87
|
+
// body owns the scroll regions), so let it overflow while open.
|
|
88
|
+
events.afterOpen = () => { this.modal.style.overflow = "visible"; };
|
|
89
|
+
events.afterClose = () => { this.modal.style.overflow = ""; };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (this.addableValue) {
|
|
93
|
+
// Returning false rejects blank input instead of adding an empty chip.
|
|
94
|
+
events.addable = (value) => value.trim() || false;
|
|
95
|
+
}
|
|
96
|
+
|
|
70
97
|
if (this.hasTypeaheadUrlValue && this.typeaheadUrlValue) {
|
|
71
98
|
// Replace SlimSelect's client-side filter with a server fetch.
|
|
72
99
|
// Returns the SlimSelect data array shape: {value, text}.
|
|
@@ -193,6 +220,8 @@ export default class extends Controller {
|
|
|
193
220
|
this.boundModalReposition = null;
|
|
194
221
|
}
|
|
195
222
|
|
|
223
|
+
if (this.modal) this.modal.style.overflow = "";
|
|
224
|
+
|
|
196
225
|
if (this.slimSelect) {
|
|
197
226
|
this.slimSelect.destroy();
|
|
198
227
|
this.slimSelect = null;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
|
2
|
+
|
|
3
|
+
// Renders a <time> as relative text ("3 days ago", "in 5 minutes") in the
|
|
4
|
+
// page's locale and keeps it current. The server-rendered absolute date stays
|
|
5
|
+
// in the element's title, so hovering still shows the exact time.
|
|
6
|
+
const UNITS = [
|
|
7
|
+
["year", 60 * 60 * 24 * 365],
|
|
8
|
+
["month", 60 * 60 * 24 * 30],
|
|
9
|
+
["week", 60 * 60 * 24 * 7],
|
|
10
|
+
["day", 60 * 60 * 24],
|
|
11
|
+
["hour", 60 * 60],
|
|
12
|
+
["minute", 60],
|
|
13
|
+
["second", 1],
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
export default class extends Controller {
|
|
17
|
+
static values = {
|
|
18
|
+
datetime: String,
|
|
19
|
+
refreshInterval: { type: Number, default: 60000 },
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
connect() {
|
|
23
|
+
this.formatter = new Intl.RelativeTimeFormat(document.documentElement.lang || undefined, { numeric: "auto" })
|
|
24
|
+
this.render()
|
|
25
|
+
this.timer = setInterval(() => this.render(), this.refreshIntervalValue)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
disconnect() {
|
|
29
|
+
clearInterval(this.timer)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
render() {
|
|
33
|
+
const date = new Date(this.datetimeValue)
|
|
34
|
+
if (isNaN(date)) return
|
|
35
|
+
|
|
36
|
+
const seconds = Math.round((date - Date.now()) / 1000)
|
|
37
|
+
const [unit, size] = UNITS.find(([, size]) => Math.abs(seconds) >= size) || UNITS[UNITS.length - 1]
|
|
38
|
+
this.element.textContent = this.formatter.format(Math.round(seconds / size), unit)
|
|
39
|
+
}
|
|
40
|
+
}
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: plutonium
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.67.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Stefan Froelich
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-10-
|
|
10
|
+
date: 2026-10-09 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: zeitwerk
|
|
@@ -1234,6 +1234,7 @@ files:
|
|
|
1234
1234
|
- lib/plutonium/query/filters/date.rb
|
|
1235
1235
|
- lib/plutonium/query/filters/date_range.rb
|
|
1236
1236
|
- lib/plutonium/query/filters/select.rb
|
|
1237
|
+
- lib/plutonium/query/filters/tags.rb
|
|
1237
1238
|
- lib/plutonium/query/filters/text.rb
|
|
1238
1239
|
- lib/plutonium/query/model_scope.rb
|
|
1239
1240
|
- lib/plutonium/railtie.rb
|
|
@@ -1311,13 +1312,25 @@ files:
|
|
|
1311
1312
|
- lib/plutonium/ui/display/components/association.rb
|
|
1312
1313
|
- lib/plutonium/ui/display/components/attachment.rb
|
|
1313
1314
|
- lib/plutonium/ui/display/components/badge.rb
|
|
1315
|
+
- lib/plutonium/ui/display/components/binary.rb
|
|
1314
1316
|
- lib/plutonium/ui/display/components/boolean.rb
|
|
1317
|
+
- lib/plutonium/ui/display/components/code.rb
|
|
1315
1318
|
- lib/plutonium/ui/display/components/color.rb
|
|
1316
1319
|
- lib/plutonium/ui/display/components/currency.rb
|
|
1320
|
+
- lib/plutonium/ui/display/components/duration.rb
|
|
1321
|
+
- lib/plutonium/ui/display/components/file_size.rb
|
|
1317
1322
|
- lib/plutonium/ui/display/components/formatted_value.rb
|
|
1323
|
+
- lib/plutonium/ui/display/components/key_value.rb
|
|
1324
|
+
- lib/plutonium/ui/display/components/list.rb
|
|
1318
1325
|
- lib/plutonium/ui/display/components/markdown.rb
|
|
1326
|
+
- lib/plutonium/ui/display/components/number.rb
|
|
1319
1327
|
- lib/plutonium/ui/display/components/phlexi_render.rb
|
|
1328
|
+
- lib/plutonium/ui/display/components/progress.rb
|
|
1329
|
+
- lib/plutonium/ui/display/components/rating.rb
|
|
1330
|
+
- lib/plutonium/ui/display/components/relative_time.rb
|
|
1331
|
+
- lib/plutonium/ui/display/components/rich_text.rb
|
|
1320
1332
|
- lib/plutonium/ui/display/components/section.rb
|
|
1333
|
+
- lib/plutonium/ui/display/components/tags.rb
|
|
1321
1334
|
- lib/plutonium/ui/display/options/inferred_types.rb
|
|
1322
1335
|
- lib/plutonium/ui/display/resource.rb
|
|
1323
1336
|
- lib/plutonium/ui/display/theme.rb
|
|
@@ -1326,6 +1339,7 @@ files:
|
|
|
1326
1339
|
- lib/plutonium/ui/empty_card.rb
|
|
1327
1340
|
- lib/plutonium/ui/export_button.rb
|
|
1328
1341
|
- lib/plutonium/ui/form/base.rb
|
|
1342
|
+
- lib/plutonium/ui/form/components/binary.rb
|
|
1329
1343
|
- lib/plutonium/ui/form/components/currency.rb
|
|
1330
1344
|
- lib/plutonium/ui/form/components/easymde.rb
|
|
1331
1345
|
- lib/plutonium/ui/form/components/flatpickr.rb
|
|
@@ -1333,12 +1347,17 @@ files:
|
|
|
1333
1347
|
- lib/plutonium/ui/form/components/intl_tel_input.rb
|
|
1334
1348
|
- lib/plutonium/ui/form/components/json.rb
|
|
1335
1349
|
- lib/plutonium/ui/form/components/key_value_store.rb
|
|
1350
|
+
- lib/plutonium/ui/form/components/list.rb
|
|
1336
1351
|
- lib/plutonium/ui/form/components/password.rb
|
|
1352
|
+
- lib/plutonium/ui/form/components/rating.rb
|
|
1337
1353
|
- lib/plutonium/ui/form/components/resource_select.rb
|
|
1354
|
+
- lib/plutonium/ui/form/components/rich_text.rb
|
|
1338
1355
|
- lib/plutonium/ui/form/components/section.rb
|
|
1339
1356
|
- lib/plutonium/ui/form/components/secure_association.rb
|
|
1340
1357
|
- lib/plutonium/ui/form/components/secure_polymorphic_association.rb
|
|
1341
1358
|
- lib/plutonium/ui/form/components/sticky_footer.rb
|
|
1359
|
+
- lib/plutonium/ui/form/components/tags.rb
|
|
1360
|
+
- lib/plutonium/ui/form/components/tags_filter.rb
|
|
1342
1361
|
- lib/plutonium/ui/form/components/toggle.rb
|
|
1343
1362
|
- lib/plutonium/ui/form/components/uppy.rb
|
|
1344
1363
|
- lib/plutonium/ui/form/concerns/renders_nested_resource_fields.rb
|
|
@@ -1376,6 +1395,9 @@ files:
|
|
|
1376
1395
|
- lib/plutonium/ui/nav_grid_menu.rb
|
|
1377
1396
|
- lib/plutonium/ui/nav_user.rb
|
|
1378
1397
|
- lib/plutonium/ui/options/has_cents_field.rb
|
|
1398
|
+
- lib/plutonium/ui/options/rich_text_field.rb
|
|
1399
|
+
- lib/plutonium/ui/options/secret_field.rb
|
|
1400
|
+
- lib/plutonium/ui/options/tags_field.rb
|
|
1379
1401
|
- lib/plutonium/ui/page/base.rb
|
|
1380
1402
|
- lib/plutonium/ui/page/dashboard.rb
|
|
1381
1403
|
- lib/plutonium/ui/page/edit.rb
|
|
@@ -1511,6 +1533,7 @@ files:
|
|
|
1511
1533
|
- src/js/controllers/table_column_menu_controller.js
|
|
1512
1534
|
- src/js/controllers/table_header_controller.js
|
|
1513
1535
|
- src/js/controllers/textarea_autogrow_controller.js
|
|
1536
|
+
- src/js/controllers/timeago_controller.js
|
|
1514
1537
|
- src/js/controllers/view_switcher_controller.js
|
|
1515
1538
|
- src/js/controllers/wizard_controller.js
|
|
1516
1539
|
- src/js/core.js
|