iron-cms 0.1.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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +174 -0
- data/Rakefile +8 -0
- data/app/assets/builds/iron.css +2 -0
- data/app/assets/config/iron_manifest.js +1 -0
- data/app/assets/images/iron/icons/sprite.svg +9425 -0
- data/app/assets/tailwind/iron/actiontext.css +550 -0
- data/app/assets/tailwind/iron/application.css +66 -0
- data/app/assets/tailwind/iron/components/button.css +74 -0
- data/app/assets/tailwind/iron/components/dropdown.css +42 -0
- data/app/assets/tailwind/iron/components/fieldset.css +18 -0
- data/app/assets/tailwind/iron/components/form.css +14 -0
- data/app/assets/tailwind/iron/components/icon-picker.css +9 -0
- data/app/assets/tailwind/iron/components/input.css +44 -0
- data/app/assets/tailwind/iron/components/page.css +7 -0
- data/app/assets/tailwind/iron/components/select.css +36 -0
- data/app/assets/tailwind/iron/components/sidebar.css +21 -0
- data/app/assets/tailwind/iron/components/textarea.css +27 -0
- data/app/controllers/concerns/iron/authentication.rb +66 -0
- data/app/controllers/concerns/iron/authorization.rb +11 -0
- data/app/controllers/concerns/iron/locale_aware.rb +20 -0
- data/app/controllers/concerns/iron/web_page.rb +18 -0
- data/app/controllers/iron/application_controller.rb +7 -0
- data/app/controllers/iron/block_definitions/field_definitions_controller.rb +8 -0
- data/app/controllers/iron/block_definitions_controller.rb +52 -0
- data/app/controllers/iron/blocks_controller.rb +12 -0
- data/app/controllers/iron/content_types/field_definitions_controller.rb +8 -0
- data/app/controllers/iron/content_types_controller.rb +52 -0
- data/app/controllers/iron/entries_controller.rb +103 -0
- data/app/controllers/iron/field_definitions_controller.rb +55 -0
- data/app/controllers/iron/first_runs_controller.rb +29 -0
- data/app/controllers/iron/home_controller.rb +6 -0
- data/app/controllers/iron/icons_controller.rb +10 -0
- data/app/controllers/iron/locales_controller.rb +52 -0
- data/app/controllers/iron/passwords_controller.rb +36 -0
- data/app/controllers/iron/references_controller.rb +11 -0
- data/app/controllers/iron/schemas_controller.rb +32 -0
- data/app/controllers/iron/sessions_controller.rb +32 -0
- data/app/controllers/iron/settings_controller.rb +23 -0
- data/app/controllers/iron/users_controller.rb +66 -0
- data/app/helpers/iron/application_helper.rb +25 -0
- data/app/helpers/iron/avatar_helper.rb +35 -0
- data/app/helpers/iron/block_helper.rb +4 -0
- data/app/helpers/iron/buttons_helper.rb +14 -0
- data/app/helpers/iron/components/badge_helper.rb +70 -0
- data/app/helpers/iron/components/dropdown_helper.rb +161 -0
- data/app/helpers/iron/content_types_helper.rb +11 -0
- data/app/helpers/iron/entries_helper.rb +13 -0
- data/app/helpers/iron/field_definitions_helper.rb +5 -0
- data/app/helpers/iron/form_builder.rb +43 -0
- data/app/helpers/iron/icons_helper.rb +30 -0
- data/app/helpers/iron/image_helper.rb +50 -0
- data/app/javascript/iron/application.js +6 -0
- data/app/javascript/iron/controllers/application.js +9 -0
- data/app/javascript/iron/controllers/element_controller.js +11 -0
- data/app/javascript/iron/controllers/file_upload_controller.js +18 -0
- data/app/javascript/iron/controllers/form_controller.js +7 -0
- data/app/javascript/iron/controllers/handle_controller.js +27 -0
- data/app/javascript/iron/controllers/icon_picker_controller.js +48 -0
- data/app/javascript/iron/controllers/index.js +4 -0
- data/app/javascript/iron/controllers/sortable_list_controller.js +125 -0
- data/app/javascript/iron/controllers/toggle_controller.js +14 -0
- data/app/javascript/iron/controllers/trix_controller.js +19 -0
- data/app/javascript/iron/lib/lexorank.js +51 -0
- data/app/jobs/iron/application_job.rb +4 -0
- data/app/jobs/iron/generate_entry_routes_job.rb +15 -0
- data/app/mailers/iron/application_mailer.rb +6 -0
- data/app/mailers/passwords_mailer.rb +6 -0
- data/app/models/concerns/iron/csv_serializable.rb +28 -0
- data/app/models/iron/account/joinable.rb +16 -0
- data/app/models/iron/account.rb +13 -0
- data/app/models/iron/application_record.rb +5 -0
- data/app/models/iron/block_definition/portable.rb +20 -0
- data/app/models/iron/block_definition.rb +10 -0
- data/app/models/iron/content_type/field_queryable.rb +101 -0
- data/app/models/iron/content_type/portable.rb +30 -0
- data/app/models/iron/content_type/titlable.rb +13 -0
- data/app/models/iron/content_type/web_publishable.rb +47 -0
- data/app/models/iron/content_type.rb +39 -0
- data/app/models/iron/content_types/collection.rb +6 -0
- data/app/models/iron/content_types/single.rb +9 -0
- data/app/models/iron/current.rb +12 -0
- data/app/models/iron/entry/deep_validation.rb +32 -0
- data/app/models/iron/entry/presentable.rb +40 -0
- data/app/models/iron/entry/schemable.rb +16 -0
- data/app/models/iron/entry/titlable.rb +35 -0
- data/app/models/iron/entry/web_publishable.rb +85 -0
- data/app/models/iron/entry.rb +16 -0
- data/app/models/iron/field/belongs_to_entry.rb +29 -0
- data/app/models/iron/field.rb +20 -0
- data/app/models/iron/field_definition/portable.rb +36 -0
- data/app/models/iron/field_definition.rb +42 -0
- data/app/models/iron/field_definitions/block.rb +23 -0
- data/app/models/iron/field_definitions/block_list.rb +8 -0
- data/app/models/iron/field_definitions/boolean.rb +7 -0
- data/app/models/iron/field_definitions/date.rb +7 -0
- data/app/models/iron/field_definitions/file.rb +67 -0
- data/app/models/iron/field_definitions/number.rb +7 -0
- data/app/models/iron/field_definitions/reference.rb +8 -0
- data/app/models/iron/field_definitions/reference_list.rb +8 -0
- data/app/models/iron/field_definitions/rich_text_area.rb +4 -0
- data/app/models/iron/field_definitions/text_area.rb +7 -0
- data/app/models/iron/field_definitions/text_field.rb +25 -0
- data/app/models/iron/fields/block.rb +40 -0
- data/app/models/iron/fields/block_list.rb +16 -0
- data/app/models/iron/fields/boolean.rb +7 -0
- data/app/models/iron/fields/date.rb +7 -0
- data/app/models/iron/fields/file.rb +29 -0
- data/app/models/iron/fields/number.rb +7 -0
- data/app/models/iron/fields/reference.rb +14 -0
- data/app/models/iron/fields/reference_list.rb +17 -0
- data/app/models/iron/fields/rich_text_area.rb +9 -0
- data/app/models/iron/fields/text_area.rb +7 -0
- data/app/models/iron/fields/text_field.rb +19 -0
- data/app/models/iron/first_run.rb +13 -0
- data/app/models/iron/icon_catalog.rb +45 -0
- data/app/models/iron/locale.rb +30 -0
- data/app/models/iron/reference.rb +8 -0
- data/app/models/iron/schema_archive.rb +71 -0
- data/app/models/iron/schema_exporter.rb +15 -0
- data/app/models/iron/schema_importer.rb +278 -0
- data/app/models/iron/session.rb +5 -0
- data/app/models/iron/user/role.rb +21 -0
- data/app/models/iron/user.rb +37 -0
- data/app/views/active_storage/blobs/_blob.html.erb +14 -0
- data/app/views/iron/block_definitions/_block_definition.html.erb +21 -0
- data/app/views/iron/block_definitions/_form.html.erb +46 -0
- data/app/views/iron/block_definitions/edit.html.erb +8 -0
- data/app/views/iron/block_definitions/index.html.erb +18 -0
- data/app/views/iron/block_definitions/new.html.erb +8 -0
- data/app/views/iron/block_definitions/show.html.erb +34 -0
- data/app/views/iron/blocks/new.turbo_stream.erb +6 -0
- data/app/views/iron/content_types/_content_type.html.erb +21 -0
- data/app/views/iron/content_types/_form.html.erb +137 -0
- data/app/views/iron/content_types/edit.html.erb +8 -0
- data/app/views/iron/content_types/index.html.erb +28 -0
- data/app/views/iron/content_types/new.html.erb +8 -0
- data/app/views/iron/content_types/show.html.erb +49 -0
- data/app/views/iron/entries/_entry.html.erb +17 -0
- data/app/views/iron/entries/_entry_option.html.erb +19 -0
- data/app/views/iron/entries/_form.html.erb +63 -0
- data/app/views/iron/entries/edit.html.erb +52 -0
- data/app/views/iron/entries/entry.html.erb +21 -0
- data/app/views/iron/entries/fields/_block.html.erb +92 -0
- data/app/views/iron/entries/fields/_block_list.html.erb +45 -0
- data/app/views/iron/entries/fields/_boolean.html.erb +13 -0
- data/app/views/iron/entries/fields/_date.html.erb +11 -0
- data/app/views/iron/entries/fields/_file.html.erb +60 -0
- data/app/views/iron/entries/fields/_number.html.erb +11 -0
- data/app/views/iron/entries/fields/_reference.html.erb +12 -0
- data/app/views/iron/entries/fields/_reference_item.html.erb +28 -0
- data/app/views/iron/entries/fields/_reference_list.html.erb +44 -0
- data/app/views/iron/entries/fields/_rich_text_area.html.erb +13 -0
- data/app/views/iron/entries/fields/_text_area.html.erb +11 -0
- data/app/views/iron/entries/fields/_text_field.html.erb +28 -0
- data/app/views/iron/entries/index.html.erb +21 -0
- data/app/views/iron/entries/new.html.erb +8 -0
- data/app/views/iron/entries/search.html.erb +33 -0
- data/app/views/iron/field_definitions/_field_definition.html.erb +37 -0
- data/app/views/iron/field_definitions/block/_form.html.erb +16 -0
- data/app/views/iron/field_definitions/block_list/_form.html.erb +13 -0
- data/app/views/iron/field_definitions/boolean/_form.html.erb +2 -0
- data/app/views/iron/field_definitions/date/_form.html.erb +2 -0
- data/app/views/iron/field_definitions/edit.html.erb +16 -0
- data/app/views/iron/field_definitions/file/_form.html.erb +40 -0
- data/app/views/iron/field_definitions/index.html.erb +14 -0
- data/app/views/iron/field_definitions/layouts/_form.html.erb +47 -0
- data/app/views/iron/field_definitions/new.html.erb +22 -0
- data/app/views/iron/field_definitions/number/_form.html.erb +2 -0
- data/app/views/iron/field_definitions/reference/_form.html.erb +13 -0
- data/app/views/iron/field_definitions/reference_list/_form.html.erb +13 -0
- data/app/views/iron/field_definitions/rich_text_area/_form.html.erb +2 -0
- data/app/views/iron/field_definitions/text_area/_form.html.erb +2 -0
- data/app/views/iron/field_definitions/text_field/_form.html.erb +17 -0
- data/app/views/iron/first_runs/show.html.erb +44 -0
- data/app/views/iron/home/show.html.erb +2 -0
- data/app/views/iron/icons/index.html.erb +21 -0
- data/app/views/iron/locales/_form.html.erb +24 -0
- data/app/views/iron/locales/_locale.html.erb +15 -0
- data/app/views/iron/locales/edit.html.erb +8 -0
- data/app/views/iron/locales/index.html.erb +12 -0
- data/app/views/iron/locales/new.html.erb +8 -0
- data/app/views/iron/passwords/edit.html.erb +7 -0
- data/app/views/iron/passwords/new.html.erb +26 -0
- data/app/views/iron/passwords_mailer/reset.html.erb +4 -0
- data/app/views/iron/passwords_mailer/reset.text.erb +2 -0
- data/app/views/iron/published_pages/show.html.erb +10 -0
- data/app/views/iron/references/new.turbo_stream.erb +6 -0
- data/app/views/iron/schemas/new.html.erb +57 -0
- data/app/views/iron/sessions/new.html.erb +36 -0
- data/app/views/iron/settings/show.html.erb +38 -0
- data/app/views/iron/shared/_icon_picker.html.erb +60 -0
- data/app/views/iron/users/_form.html.erb +21 -0
- data/app/views/iron/users/_user.html.erb +27 -0
- data/app/views/iron/users/edit.html.erb +12 -0
- data/app/views/iron/users/index.html.erb +21 -0
- data/app/views/iron/users/new.html.erb +29 -0
- data/app/views/iron/users/show.html.erb +21 -0
- data/app/views/layouts/action_text/contents/_content.html.erb +3 -0
- data/app/views/layouts/iron/_sidebar.html.erb +83 -0
- data/app/views/layouts/iron/_sidebar_item.html.erb +14 -0
- data/app/views/layouts/iron/_toast.html.erb +29 -0
- data/app/views/layouts/iron/application.html.erb +46 -0
- data/app/views/layouts/iron/authentication.html.erb +41 -0
- data/config/importmap.rb +9 -0
- data/config/routes.rb +40 -0
- data/db/migrate/20250422131656_initial_iron_schema.rb +105 -0
- data/db/migrate/20250427100754_create_iron_accounts.rb +10 -0
- data/db/migrate/20250427104020_add_role_to_iron_users.rb +5 -0
- data/db/migrate/20250428094923_add_default_iron_locale_to_iron_account.rb +5 -0
- data/db/migrate/20250504144731_create_join_table_content_types_field_definitions.rb +25 -0
- data/db/migrate/20250505090716_add_title_field_definition_to_iron_content_types.rb +5 -0
- data/db/migrate/20250512210352_create_iron_references.rb +11 -0
- data/db/migrate/20250524220355_add_referenced_entry_id_to_iron_fields.rb +5 -0
- data/db/migrate/20250529211703_add_metadata_to_iron_field_definitions.rb +5 -0
- data/db/migrate/20250529211704_add_value_boolean_to_iron_fields.rb +5 -0
- data/db/migrate/20250531172837_add_type_to_iron_content_types.rb +5 -0
- data/db/migrate/20250601080146_add_icon_to_iron_content_types.rb +5 -0
- data/db/migrate/20250609091605_add_web_publishing_to_iron_content_types.rb +7 -0
- data/db/migrate/20250609091813_add_route_to_iron_entries.rb +6 -0
- data/lib/generators/iron/pages/pages_generator.rb +34 -0
- data/lib/generators/iron/pages/templates/pages_controller.rb +14 -0
- data/lib/generators/iron/pages/templates/show.html.erb +9 -0
- data/lib/generators/iron/template/template_generator.rb +35 -0
- data/lib/generators/iron/template/templates/content_type.html.erb +5 -0
- data/lib/iron/cva.rb +69 -0
- data/lib/iron/engine.rb +42 -0
- data/lib/iron/image_analyzer.rb +26 -0
- data/lib/iron/lexorank/exceptions.rb +4 -0
- data/lib/iron/lexorank/rankable.rb +185 -0
- data/lib/iron/lexorank/rebalance_rank_job.rb +10 -0
- data/lib/iron/lexorank/utils.rb +77 -0
- data/lib/iron/lexorank.rb +7 -0
- data/lib/iron/routing.rb +66 -0
- data/lib/iron/sdk.rb +19 -0
- data/lib/iron/version.rb +3 -0
- data/lib/iron.rb +8 -0
- data/lib/puma/plugin/iron_tailwindcss.rb +78 -0
- metadata +458 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
@utility dropdown {
|
2
|
+
/* Anchor position */
|
3
|
+
/* position: absolute; */
|
4
|
+
position-area: top span-right;
|
5
|
+
position-anchor: var(--popover-anchor);
|
6
|
+
/* position-try-options: flip-block, flip-inline, flip-block flip-inline; */
|
7
|
+
@apply m-0 p-0 min-w-64;
|
8
|
+
/* Base styles */
|
9
|
+
@apply isolate w-max rounded-xl p-1;
|
10
|
+
/* Invisible border that is only visible in `forced-colors` mode for accessibility purposes */
|
11
|
+
@apply outline outline-1 outline-transparent focus:outline-hidden;
|
12
|
+
/* Handle scrolling when menu won't fit in viewport */
|
13
|
+
@apply overflow-y-auto;
|
14
|
+
/* Popover background */
|
15
|
+
@apply bg-white/75 backdrop-blur-xl dark:bg-stone-800/75;
|
16
|
+
/* Shadows */
|
17
|
+
@apply shadow-lg ring-1 ring-stone-950/10 dark:ring-inset dark:ring-white/10;
|
18
|
+
}
|
19
|
+
|
20
|
+
@utility dropdown-item {
|
21
|
+
/* Base styles */
|
22
|
+
@apply cursor-default rounded-lg px-3.5 py-2.5 focus:outline-hidden sm:px-3 sm:py-1.5;
|
23
|
+
/* Text styles */
|
24
|
+
@apply text-left text-base/6 text-stone-950 sm:text-sm/6 dark:text-white forced-colors:text-[CanvasText];
|
25
|
+
/* Focus */
|
26
|
+
@apply focus:bg-blue-500 hover:bg-blue-500 focus:text-white;
|
27
|
+
/* Disabled state */
|
28
|
+
@apply disabled:opacity-50;
|
29
|
+
/* Forced colors mode */
|
30
|
+
@apply forced-color-adjust-none forced-colors:focus:bg-[Highlight] forced-colors:focus:text-[HighlightText] forced-colors:focus:*:data-[slot=icon]:text-[HighlightText];
|
31
|
+
/* Children positioning */
|
32
|
+
@apply flex items-center;
|
33
|
+
/* Icons */
|
34
|
+
@apply *:data-[slot=icon]:col-start-1 *:data-[slot=icon]:row-start-1 *:data-[slot=icon]:-ml-0.5 *:data-[slot=icon]:mr-2.5 *:data-[slot=icon]:size-5 sm:*:data-[slot=icon]:mr-2 sm:*:data-[slot=icon]:size-4;
|
35
|
+
@apply *:data-[slot=icon]:text-stone-500 focus:*:data-[slot=icon]:text-white hover:*:data-[slot=icon]:text-white dark:*:data-[slot=icon]:text-stone-400 dark:focus:*:data-[slot=icon]:text-white;
|
36
|
+
/* Avatar */
|
37
|
+
@apply *:data-[slot=avatar]:-ml-1 *:data-[slot=avatar]:mr-2.5 *:data-[slot=avatar]:size-6 sm:*:data-[slot=avatar]:mr-2 sm:*:data-[slot=avatar]:size-5;
|
38
|
+
}
|
39
|
+
|
40
|
+
@utility dropdown-divider {
|
41
|
+
@apply col-span-full mx-3.5 my-1 h-px border-0 bg-stone-950/5 sm:mx-3 dark:bg-white/10 forced-colors:bg-[CanvasText];
|
42
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
@utility field-group {
|
2
|
+
@apply space-y-4;
|
3
|
+
}
|
4
|
+
|
5
|
+
@utility field {
|
6
|
+
@apply [&>label+[data-slot=control]]:mt-2;
|
7
|
+
@apply [&>label+[data-slot=description]]:mt-1;
|
8
|
+
@apply [&>[data-slot=description]+[data-slot=control]]:mt-2;
|
9
|
+
@apply [&>[data-slot=control]+[data-slot=description]]:mt-2;
|
10
|
+
@apply [&>[data-slot=control]+[data-slot=error]]:mt-2;
|
11
|
+
@apply [&>label]:font-medium;
|
12
|
+
& label {
|
13
|
+
@apply select-none text-base/6 text-stone-950 disabled:opacity-50 sm:text-sm/6 dark:text-white;
|
14
|
+
}
|
15
|
+
& [data-slot='description'] {
|
16
|
+
@apply text-base/6 text-stone-500 data-disabled:opacity-50 sm:text-sm/6 dark:text-stone-400;
|
17
|
+
}
|
18
|
+
}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
@layer base {
|
2
|
+
form {
|
3
|
+
textarea {
|
4
|
+
@apply textarea;
|
5
|
+
}
|
6
|
+
|
7
|
+
input:not([type="checkbox"]):not([type="radio"]):not([type="submit"]):not([type="button"]) {
|
8
|
+
@apply input;
|
9
|
+
}
|
10
|
+
input[type="submit"], input[type="button"], button {
|
11
|
+
@apply btn;
|
12
|
+
}
|
13
|
+
}
|
14
|
+
}
|
@@ -0,0 +1,44 @@
|
|
1
|
+
@utility input {
|
2
|
+
@apply relative block w-full appearance-none rounded-lg;
|
3
|
+
@apply px-3 py-2 sm:px-2.5 sm:py-1.5;
|
4
|
+
@apply text-base/6 sm:text-sm/6;
|
5
|
+
@apply text-stone-100 placeholder:text-stone-500;
|
6
|
+
|
7
|
+
/* Border and background */
|
8
|
+
@apply border border-stone-950/10;
|
9
|
+
@apply dark:border-white/10;
|
10
|
+
@apply bg-transparent dark:bg-white/5;
|
11
|
+
|
12
|
+
/* Focus state */
|
13
|
+
@apply focus:outline focus:outline-2 focus:outline-stone-500;
|
14
|
+
|
15
|
+
/* States */
|
16
|
+
@apply disabled:opacity-50 disabled:bg-stone-700 disabled:border-stone-600;
|
17
|
+
|
18
|
+
/* Error state */
|
19
|
+
&.is-invalid {
|
20
|
+
@apply border-red-500 hover:border-red-500;
|
21
|
+
}
|
22
|
+
|
23
|
+
/* Date and time input specific styling */
|
24
|
+
&[type="date"],
|
25
|
+
&[type="datetime-local"],
|
26
|
+
&[type="month"],
|
27
|
+
&[type="time"],
|
28
|
+
&[type="week"] {
|
29
|
+
@apply [color-scheme:dark];
|
30
|
+
@apply [&::-webkit-calendar-picker-indicator]:invert-[.8];
|
31
|
+
@apply [&::-webkit-datetime-edit-fields-wrapper]:p-0;
|
32
|
+
@apply [&::-webkit-date-and-time-value]:min-h-[1.5em];
|
33
|
+
@apply [&::-webkit-datetime-edit]:inline-flex;
|
34
|
+
@apply [&::-webkit-datetime-edit]:p-0;
|
35
|
+
@apply [&::-webkit-datetime-edit-year-field]:p-0;
|
36
|
+
@apply [&::-webkit-datetime-edit-month-field]:p-0;
|
37
|
+
@apply [&::-webkit-datetime-edit-day-field]:p-0;
|
38
|
+
@apply [&::-webkit-datetime-edit-hour-field]:p-0;
|
39
|
+
@apply [&::-webkit-datetime-edit-minute-field]:p-0;
|
40
|
+
@apply [&::-webkit-datetime-edit-second-field]:p-0;
|
41
|
+
@apply [&::-webkit-datetime-edit-millisecond-field]:p-0;
|
42
|
+
@apply [&::-webkit-datetime-edit-meridiem-field]:p-0;
|
43
|
+
}
|
44
|
+
}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
@utility select {
|
2
|
+
@apply block w-full rounded-lg appearance-none;
|
3
|
+
@apply py-[calc(--spacing(2.5)-1px)] sm:py-[calc(--spacing(1.5)-1px)];
|
4
|
+
@apply pl-[calc(--spacing(3.5)-1px)] pr-[calc(--spacing(4.5)-1px)]
|
5
|
+
sm:pl-[calc(--spacing(3)-1px)] sm:pr-[calc(--spacing(4)-1px)];
|
6
|
+
@apply text-base/6 sm:text-sm/6 text-stone-950 placeholder:text-stone-500
|
7
|
+
dark:text-white;
|
8
|
+
@apply border border-stone-950/10 hover:border-stone-950/20
|
9
|
+
dark:border-white/10 dark:hover:border-white/20;
|
10
|
+
@apply bg-white dark:bg-stone-800;
|
11
|
+
@apply focus:outline-none focus:ring-2 focus:ring-inset focus:ring-blue-500;
|
12
|
+
@apply disabled:opacity-50 disabled:border-stone-950/20
|
13
|
+
dark:disabled:border-white/15 dark:disabled:bg-white/[2.5%];
|
14
|
+
|
15
|
+
/* Multi-select needs equal padding both sides */
|
16
|
+
&[multiple] { @apply px-[calc(--spacing(3.5)-1px)]
|
17
|
+
sm:px-[calc(--spacing(3)-1px)]; }
|
18
|
+
|
19
|
+
/* Validation error, toggled with attribute */
|
20
|
+
&[data-ui~="invalid"] {
|
21
|
+
@apply border-red-500 hover:border-red-500
|
22
|
+
dark:border-red-500 dark:hover:border-red-500;
|
23
|
+
}
|
24
|
+
|
25
|
+
@supports (appearance: base-select) {
|
26
|
+
appearance: base-select;
|
27
|
+
|
28
|
+
&::picker-icon {
|
29
|
+
@apply text-stone-500 dark:text-stone-400 transition duration-200;
|
30
|
+
}
|
31
|
+
&:open::picker-icon {
|
32
|
+
@apply rotate-180;
|
33
|
+
}
|
34
|
+
}
|
35
|
+
}
|
36
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
@utility sidebar-item {
|
2
|
+
/* Base */
|
3
|
+
@apply flex w-full items-center gap-3 rounded-lg px-2 py-2.5 text-left text-base/6 font-medium text-stone-950 sm:py-2 sm:text-sm/5;
|
4
|
+
/* Leading icon/icon-only */
|
5
|
+
@apply *:data-[slot=icon]:size-6 *:data-[slot=icon]:shrink-0 sm:*:data-[slot=icon]:size-5;
|
6
|
+
/* Trailing icon (down chevron or similar) */
|
7
|
+
@apply *:last:data-[slot=icon]:ml-auto *:last:data-[slot=icon]:size-5 sm:*:last:data-[slot=icon]:size-4;
|
8
|
+
/* Avatar */
|
9
|
+
@apply *:data-[slot=avatar]:-m-0.5 *:data-[slot=avatar]:size-7 *:data-[slot=avatar]:[--ring-opacity:10%] sm:*:data-[slot=avatar]:size-6;
|
10
|
+
/* Hover */
|
11
|
+
@apply hover:bg-stone-950/5;
|
12
|
+
/* Active */
|
13
|
+
@apply active:bg-stone-950/5 active:*:data-[slot=icon]:fill-stone-950;
|
14
|
+
/* Current */
|
15
|
+
@apply data-current:*:data-[slot=icon]:bg-transparent;
|
16
|
+
/* Dark mode */
|
17
|
+
@apply dark:text-white dark:*:data-[slot=icon]:text-stone-400;
|
18
|
+
@apply dark:hover:bg-white/5 dark:hover:*:data-[slot=icon]:text-white;
|
19
|
+
@apply dark:active:bg-white/5 dark:active:*:data-[slot=icon]:text-white;
|
20
|
+
@apply dark:data-current:*:data-[slot=icon]:text-white;
|
21
|
+
}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
@utility textarea {
|
2
|
+
/* Basic layout */
|
3
|
+
@apply relative block w-full appearance-none rounded-lg;
|
4
|
+
@apply px-[calc(--spacing(3.5)-1px)] py-[calc(--spacing(2.5)-1px)];
|
5
|
+
@apply sm:px-[calc(--spacing(3)-1px)] sm:py-[calc(--spacing(1.5)-1px)];
|
6
|
+
|
7
|
+
/* Typography */
|
8
|
+
@apply text-base/6 text-stone-950 placeholder:text-stone-500 sm:text-sm/6;
|
9
|
+
@apply dark:text-white;
|
10
|
+
|
11
|
+
/* Border and background */
|
12
|
+
@apply border border-stone-950/10;
|
13
|
+
@apply dark:border-white/10;
|
14
|
+
@apply bg-transparent dark:bg-white/5;
|
15
|
+
|
16
|
+
/* Focus state */
|
17
|
+
@apply focus:outline focus:outline-2 focus:outline-stone-500;
|
18
|
+
|
19
|
+
/* Invalid state - using data attribute selector */
|
20
|
+
&[data-ui~="invalid"] {
|
21
|
+
@apply border-red-500 hover:border-red-500 dark:border-red-500 dark:hover:border-red-500;
|
22
|
+
}
|
23
|
+
|
24
|
+
/* Disabled state */
|
25
|
+
@apply disabled:border-stone-950/20 disabled:opacity-50;
|
26
|
+
@apply dark:disabled:border-white/15 dark:disabled:hover:border-white/15 dark:disabled:bg-white/[2.5%];
|
27
|
+
}
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Iron
|
2
|
+
module Authentication
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
before_action :require_authentication
|
7
|
+
helper_method :authenticated?
|
8
|
+
end
|
9
|
+
|
10
|
+
class_methods do
|
11
|
+
def require_unauthenticated_access(**options)
|
12
|
+
allow_unauthenticated_access **options
|
13
|
+
before_action :redirect_signed_in_user_to_root, **options
|
14
|
+
end
|
15
|
+
|
16
|
+
def allow_unauthenticated_access(**options)
|
17
|
+
skip_before_action :require_authentication, **options
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
def authenticated?
|
23
|
+
resume_session
|
24
|
+
end
|
25
|
+
|
26
|
+
def redirect_signed_in_user_to_root
|
27
|
+
redirect_to root_url if authenticated?
|
28
|
+
end
|
29
|
+
|
30
|
+
def require_authentication
|
31
|
+
resume_session || request_authentication
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
def resume_session
|
36
|
+
Current.session ||= find_session_by_cookie
|
37
|
+
end
|
38
|
+
|
39
|
+
def find_session_by_cookie
|
40
|
+
Session.find_by(id: cookies.signed[:session_id])
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
def request_authentication
|
45
|
+
session[:return_to_after_authenticating] = request.url
|
46
|
+
redirect_to sign_in_url
|
47
|
+
end
|
48
|
+
|
49
|
+
def after_authentication_url
|
50
|
+
session.delete(:return_to_after_authenticating) || root_url
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
def start_new_session_for(user)
|
55
|
+
user.sessions.create!(user_agent: request.user_agent, ip_address: request.remote_ip).tap do |session|
|
56
|
+
Current.session = session
|
57
|
+
cookies.signed.permanent[:session_id] = { value: session.id, httponly: true, same_site: :lax }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def terminate_session
|
62
|
+
Current.session.destroy
|
63
|
+
cookies.delete(:session_id)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Iron
|
2
|
+
module LocaleAware
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
before_action :set_current_locale
|
7
|
+
helper_method :current_locale if respond_to?(:helper_method)
|
8
|
+
end
|
9
|
+
|
10
|
+
def current_locale
|
11
|
+
Iron::Current.locale
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def set_current_locale
|
17
|
+
Iron::Current.locale = Iron::Locale.detect(request) || Iron::Locale.default
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Iron
|
2
|
+
module WebPage
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
before_action :set_content_type, only: %i[ show ]
|
7
|
+
before_action :set_entry, only: %i[ show ]
|
8
|
+
end
|
9
|
+
|
10
|
+
def set_content_type
|
11
|
+
@content_type = Iron::ContentType.web_published.find_by_handle!(params[:content_type])
|
12
|
+
end
|
13
|
+
|
14
|
+
def set_entry
|
15
|
+
@entry = @content_type.entries.find_by!(route: params[:route])
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Iron
|
2
|
+
class BlockDefinitionsController < ApplicationController
|
3
|
+
before_action :set_block_definition, only: %i[ show edit update destroy ]
|
4
|
+
before_action :ensure_can_administer
|
5
|
+
|
6
|
+
def index
|
7
|
+
@block_definitions = BlockDefinition.all
|
8
|
+
end
|
9
|
+
|
10
|
+
def show
|
11
|
+
end
|
12
|
+
|
13
|
+
def new
|
14
|
+
@block_definition = BlockDefinition.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def edit
|
18
|
+
end
|
19
|
+
|
20
|
+
def create
|
21
|
+
@block_definition = BlockDefinition.new(block_definition_params)
|
22
|
+
|
23
|
+
if @block_definition.save
|
24
|
+
redirect_to @block_definition, notice: "Block definition was successfully created."
|
25
|
+
else
|
26
|
+
render :new, status: :unprocessable_entity
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def update
|
31
|
+
if @block_definition.update(block_definition_params)
|
32
|
+
redirect_to @block_definition, notice: "Block definition was successfully updated.", status: :see_other
|
33
|
+
else
|
34
|
+
render :edit, status: :unprocessable_entity
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def destroy
|
39
|
+
@block_definition.destroy!
|
40
|
+
redirect_to block_definitions_path, notice: "Block definition was successfully destroyed.", status: :see_other
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
def set_block_definition
|
45
|
+
@block_definition = BlockDefinition.find(params.expect(:id))
|
46
|
+
end
|
47
|
+
|
48
|
+
def block_definition_params
|
49
|
+
params.expect(block_definition: [ :name, :handle, :description ])
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Iron
|
2
|
+
class BlocksController < ApplicationController
|
3
|
+
def new
|
4
|
+
@block_list = Fields::BlockList.build(
|
5
|
+
locale: Locale.find(params[:locale_id]),
|
6
|
+
definition: FieldDefinition.find(params[:block_list_field_definition_id]),
|
7
|
+
)
|
8
|
+
@block = @block_list.blocks.build_for(BlockDefinition.find(params[:block_definition_id]))
|
9
|
+
@form_field_name = params[:form_field_name]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Iron
|
2
|
+
class ContentTypesController < ApplicationController
|
3
|
+
before_action :set_content_type, only: %i[ show edit update destroy ]
|
4
|
+
before_action :ensure_can_administer
|
5
|
+
|
6
|
+
def index
|
7
|
+
@content_types = ContentType.all
|
8
|
+
end
|
9
|
+
|
10
|
+
def show
|
11
|
+
end
|
12
|
+
|
13
|
+
def new
|
14
|
+
@content_type = ContentType.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def edit
|
18
|
+
end
|
19
|
+
|
20
|
+
def create
|
21
|
+
@content_type = ContentType.new(content_type_params)
|
22
|
+
|
23
|
+
if @content_type.save
|
24
|
+
redirect_to @content_type, notice: "Content type was successfully created."
|
25
|
+
else
|
26
|
+
render :new, status: :unprocessable_entity
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def update
|
31
|
+
if @content_type.update(content_type_params)
|
32
|
+
redirect_to @content_type, notice: "Content type was successfully updated.", status: :see_other
|
33
|
+
else
|
34
|
+
render :edit, status: :unprocessable_entity
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def destroy
|
39
|
+
@content_type.destroy!
|
40
|
+
redirect_to content_types_path, notice: "Content type was successfully destroyed.", status: :see_other
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
def set_content_type
|
45
|
+
@content_type = ContentType.find(params.expect(:id))
|
46
|
+
end
|
47
|
+
|
48
|
+
def content_type_params
|
49
|
+
params.expect(content_type: [ :name, :handle, :description, :type, :title_field_definition_id, :icon, :web_publishing_enabled, :web_page_title_field_definition_id, :base_path ])
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module Iron
|
2
|
+
class EntriesController < ApplicationController
|
3
|
+
before_action :set_locale
|
4
|
+
before_action :set_entry, only: %i[ edit update destroy ]
|
5
|
+
before_action :set_content_type, only: %i[ index new create ]
|
6
|
+
before_action :set_content_type_from_params, only: %i[ entry ]
|
7
|
+
|
8
|
+
def index
|
9
|
+
if @content_type.single?
|
10
|
+
redirect_to entry_content_type_path(@content_type)
|
11
|
+
else
|
12
|
+
@entries = @content_type.entries
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def entry
|
17
|
+
@entry = @content_type.entry
|
18
|
+
end
|
19
|
+
|
20
|
+
def search
|
21
|
+
@definition = FieldDefinitions::ReferenceList.find(params[:reference_list_field_definition_id])
|
22
|
+
@entries = Entry.with_content_type(@definition.supported_content_types.pluck(:id))
|
23
|
+
@entries = @entries.search_by_title(params[:q]) if params[:q].present?
|
24
|
+
|
25
|
+
@reference_list_field_definition_id = params[:reference_list_field_definition_id]
|
26
|
+
@form_field_name = params[:form_field_name]
|
27
|
+
@reference_list_dom_id = params[:reference_list_dom_id]
|
28
|
+
render layout: false
|
29
|
+
end
|
30
|
+
|
31
|
+
def new
|
32
|
+
@entry = @content_type.entries.build
|
33
|
+
end
|
34
|
+
|
35
|
+
def edit
|
36
|
+
end
|
37
|
+
|
38
|
+
def create
|
39
|
+
@entry = @content_type.entries.build(entry_params)
|
40
|
+
|
41
|
+
if @entry.save
|
42
|
+
if @entry.content_type.single?
|
43
|
+
redirect_to entry_content_type_url(@entry.content_type), notice: "#{@entry.content_type.name} was successfully created."
|
44
|
+
else
|
45
|
+
redirect_to edit_entry_url(@entry), notice: "#{@entry.content_type.name} was successfully created."
|
46
|
+
end
|
47
|
+
else
|
48
|
+
if @entry.errors.any?
|
49
|
+
flash.now[:alert] = "Could not save changes due to validation errors"
|
50
|
+
else
|
51
|
+
flash.now[:alert] = "#{@entry.content_type.name} could not be created"
|
52
|
+
end
|
53
|
+
render :new, status: :unprocessable_entity
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def update
|
58
|
+
if @entry.update(entry_params)
|
59
|
+
if @entry.content_type.single?
|
60
|
+
redirect_to entry_content_type_url(@entry.content_type, locale: @locale.code), notice: "#{@entry.content_type.name} was successfully updated."
|
61
|
+
else
|
62
|
+
redirect_to edit_entry_url(@entry, locale: @locale.code), notice: "#{@entry.content_type.name} was successfully updated."
|
63
|
+
end
|
64
|
+
else
|
65
|
+
if @entry.errors.any?
|
66
|
+
flash.now[:alert] = "Could not save changes due to validation errors"
|
67
|
+
else
|
68
|
+
flash.now[:alert] = "#{@entry.content_type.name} could not be updated"
|
69
|
+
end
|
70
|
+
render :edit, status: :unprocessable_entity
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def destroy
|
75
|
+
@entry.destroy!
|
76
|
+
redirect_to content_type_entries_path(@entry.content_type), notice: "Entry was successfully destroyed.", status: :see_other
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def set_locale
|
82
|
+
@locale = Locale.find_by(code: params[:locale]) if params[:locale].present?
|
83
|
+
@locale ||= Locale.first
|
84
|
+
end
|
85
|
+
|
86
|
+
def set_entry
|
87
|
+
@entry = Entry.find(params.expect(:id))
|
88
|
+
end
|
89
|
+
|
90
|
+
def set_content_type
|
91
|
+
@content_type = ContentType.find(params[:content_type_id])
|
92
|
+
end
|
93
|
+
|
94
|
+
def set_content_type_from_params
|
95
|
+
@content_type = ContentType.find(params[:id])
|
96
|
+
end
|
97
|
+
|
98
|
+
def entry_params
|
99
|
+
params.require(:entry).permit!
|
100
|
+
# params.expect(entry: [ :content_type_id ])
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Iron
|
2
|
+
class FieldDefinitionsController < ApplicationController
|
3
|
+
before_action :set_schemable, only: %i[ new create ]
|
4
|
+
before_action :set_field_definition, only: %i[ edit update destroy ]
|
5
|
+
before_action :ensure_can_administer
|
6
|
+
|
7
|
+
def index
|
8
|
+
@field_definitions = FieldDefinition.all
|
9
|
+
end
|
10
|
+
|
11
|
+
def new
|
12
|
+
@field_definition = @schemable.field_definitions.build(type: selected_field_definition_type)
|
13
|
+
end
|
14
|
+
|
15
|
+
def edit
|
16
|
+
end
|
17
|
+
|
18
|
+
def create
|
19
|
+
@field_definition = @schemable.field_definitions.build(field_definition_params)
|
20
|
+
|
21
|
+
if @field_definition.save
|
22
|
+
redirect_to @schemable, notice: "Field definition was successfully created."
|
23
|
+
else
|
24
|
+
render :new, status: :unprocessable_entity
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def update
|
29
|
+
if @field_definition.update(field_definition_params)
|
30
|
+
redirect_to @field_definition.schemable, notice: "Field definition was successfully updated.", status: :see_other
|
31
|
+
else
|
32
|
+
render :edit, status: :unprocessable_entity
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def destroy
|
37
|
+
@field_definition.destroy!
|
38
|
+
redirect_to @field_definition.schemable, notice: "Field definition was successfully destroyed.", status: :see_other
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
def set_field_definition
|
43
|
+
@field_definition = FieldDefinition.find(params.expect(:id))
|
44
|
+
end
|
45
|
+
|
46
|
+
def field_definition_params
|
47
|
+
params.expect(field_definition: [ :type, :name, :handle, :rank, :allowed_values_text, :required, :file_scope, selected_presets: [], supported_block_definition_ids: [], supported_content_type_ids: [] ])
|
48
|
+
end
|
49
|
+
|
50
|
+
def selected_field_definition_type
|
51
|
+
type = FieldDefinition::TYPES.include?(params[:type]) ? params[:type] : FieldDefinition::TYPES.first
|
52
|
+
FieldDefinition.classify_type(type)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|