panda-cms 0.7.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/README.md +73 -0
- data/Rakefile +7 -0
- data/app/assets/builds/panda.cms.css +2808 -0
- data/app/assets/config/panda_cms_manifest.js +4 -0
- data/app/assets/stylesheets/panda/cms/application.tailwind.css +162 -0
- data/app/assets/stylesheets/panda/cms/editor.css +120 -0
- data/app/builders/panda/cms/form_builder.rb +234 -0
- data/app/components/panda/cms/admin/button_component.rb +70 -0
- data/app/components/panda/cms/admin/container_component.html.erb +13 -0
- data/app/components/panda/cms/admin/container_component.rb +13 -0
- data/app/components/panda/cms/admin/flash_message_component.html.erb +31 -0
- data/app/components/panda/cms/admin/flash_message_component.rb +47 -0
- data/app/components/panda/cms/admin/heading_component.rb +45 -0
- data/app/components/panda/cms/admin/panel_component.html.erb +7 -0
- data/app/components/panda/cms/admin/panel_component.rb +13 -0
- data/app/components/panda/cms/admin/slideover_component.html.erb +9 -0
- data/app/components/panda/cms/admin/slideover_component.rb +15 -0
- data/app/components/panda/cms/admin/statistics_component.html.erb +4 -0
- data/app/components/panda/cms/admin/statistics_component.rb +17 -0
- data/app/components/panda/cms/admin/tab_bar_component.html.erb +35 -0
- data/app/components/panda/cms/admin/tab_bar_component.rb +15 -0
- data/app/components/panda/cms/admin/table_component.html.erb +29 -0
- data/app/components/panda/cms/admin/table_component.rb +46 -0
- data/app/components/panda/cms/admin/tag_component.rb +35 -0
- data/app/components/panda/cms/admin/user_activity_component.html.erb +5 -0
- data/app/components/panda/cms/admin/user_activity_component.rb +33 -0
- data/app/components/panda/cms/admin/user_display_component.html.erb +17 -0
- data/app/components/panda/cms/admin/user_display_component.rb +21 -0
- data/app/components/panda/cms/code_component.rb +64 -0
- data/app/components/panda/cms/grid_component.html.erb +6 -0
- data/app/components/panda/cms/grid_component.rb +15 -0
- data/app/components/panda/cms/menu_component.html.erb +6 -0
- data/app/components/panda/cms/menu_component.rb +58 -0
- data/app/components/panda/cms/page_menu_component.html.erb +21 -0
- data/app/components/panda/cms/page_menu_component.rb +38 -0
- data/app/components/panda/cms/rich_text_component.html.erb +6 -0
- data/app/components/panda/cms/rich_text_component.rb +84 -0
- data/app/components/panda/cms/text_component.rb +72 -0
- data/app/constraints/panda/cms/admin_constraint.rb +18 -0
- data/app/controllers/panda/cms/admin/block_contents_controller.rb +52 -0
- data/app/controllers/panda/cms/admin/dashboard_controller.rb +20 -0
- data/app/controllers/panda/cms/admin/files_controller.rb +21 -0
- data/app/controllers/panda/cms/admin/forms_controller.rb +53 -0
- data/app/controllers/panda/cms/admin/menus_controller.rb +30 -0
- data/app/controllers/panda/cms/admin/pages_controller.rb +91 -0
- data/app/controllers/panda/cms/admin/posts_controller.rb +146 -0
- data/app/controllers/panda/cms/admin/sessions_controller.rb +94 -0
- data/app/controllers/panda/cms/admin/settings/bulk_editor_controller.rb +37 -0
- data/app/controllers/panda/cms/admin/settings_controller.rb +20 -0
- data/app/controllers/panda/cms/application_controller.rb +57 -0
- data/app/controllers/panda/cms/errors_controller.rb +33 -0
- data/app/controllers/panda/cms/form_submissions_controller.rb +23 -0
- data/app/controllers/panda/cms/pages_controller.rb +72 -0
- data/app/controllers/panda/cms/posts_controller.rb +13 -0
- data/app/helpers/panda/cms/admin/files_helper.rb +6 -0
- data/app/helpers/panda/cms/admin/pages_helper.rb +6 -0
- data/app/helpers/panda/cms/admin/posts_helper.rb +48 -0
- data/app/helpers/panda/cms/application_helper.rb +120 -0
- data/app/helpers/panda/cms/pages_helper.rb +6 -0
- data/app/helpers/panda/cms/theme_helper.rb +18 -0
- data/app/javascript/panda/cms/@editorjs--editorjs.js +2577 -0
- data/app/javascript/panda/cms/@hotwired--stimulus.js +4 -0
- data/app/javascript/panda/cms/@hotwired--turbo.js +160 -0
- data/app/javascript/panda/cms/@rails--actioncable--src.js +4 -0
- data/app/javascript/panda/cms/application_panda_cms.js +39 -0
- data/app/javascript/panda/cms/controllers/dashboard_controller.js +7 -0
- data/app/javascript/panda/cms/controllers/editor_form_controller.js +77 -0
- data/app/javascript/panda/cms/controllers/editor_iframe_controller.js +320 -0
- data/app/javascript/panda/cms/controllers/index.js +48 -0
- data/app/javascript/panda/cms/controllers/slug_controller.js +87 -0
- data/app/javascript/panda/cms/editor/css_extractor.js +80 -0
- data/app/javascript/panda/cms/editor/editor_js_config.js +177 -0
- data/app/javascript/panda/cms/editor/editor_js_initializer.js +285 -0
- data/app/javascript/panda/cms/editor/plain_text_editor.js +110 -0
- data/app/javascript/panda/cms/editor/resource_loader.js +115 -0
- data/app/javascript/panda/cms/tailwindcss-stimulus-components.js +4 -0
- data/app/jobs/panda/cms/application_job.rb +6 -0
- data/app/jobs/panda/cms/record_visit_job.rb +31 -0
- data/app/mailers/panda/cms/application_mailer.rb +8 -0
- data/app/mailers/panda/cms/form_mailer.rb +21 -0
- data/app/models/action_text/rich_text_version.rb +6 -0
- data/app/models/panda/cms/application_record.rb +7 -0
- data/app/models/panda/cms/block.rb +34 -0
- data/app/models/panda/cms/block_content.rb +18 -0
- data/app/models/panda/cms/block_content_version.rb +8 -0
- data/app/models/panda/cms/breadcrumb.rb +12 -0
- data/app/models/panda/cms/current.rb +17 -0
- data/app/models/panda/cms/form.rb +9 -0
- data/app/models/panda/cms/form_submission.rb +7 -0
- data/app/models/panda/cms/menu.rb +52 -0
- data/app/models/panda/cms/menu_item.rb +58 -0
- data/app/models/panda/cms/page.rb +96 -0
- data/app/models/panda/cms/page_version.rb +8 -0
- data/app/models/panda/cms/post.rb +60 -0
- data/app/models/panda/cms/post_version.rb +8 -0
- data/app/models/panda/cms/redirect.rb +11 -0
- data/app/models/panda/cms/template.rb +124 -0
- data/app/models/panda/cms/template_version.rb +8 -0
- data/app/models/panda/cms/user.rb +31 -0
- data/app/models/panda/cms/version.rb +8 -0
- data/app/models/panda/cms/visit.rb +9 -0
- data/app/services/panda/cms/html_to_editor_js_converter.rb +200 -0
- data/app/views/active_storage/blobs/blobs/_blob.html.erb +14 -0
- data/app/views/layouts/action_text/contents/_content.html.erb +3 -0
- data/app/views/layouts/panda/cms/application.html.erb +41 -0
- data/app/views/layouts/panda/cms/public.html.erb +3 -0
- data/app/views/panda/cms/admin/dashboard/show.html.erb +12 -0
- data/app/views/panda/cms/admin/files/index.html.erb +124 -0
- data/app/views/panda/cms/admin/files/show.html.erb +2 -0
- data/app/views/panda/cms/admin/forms/edit.html.erb +0 -0
- data/app/views/panda/cms/admin/forms/index.html.erb +13 -0
- data/app/views/panda/cms/admin/forms/new.html.erb +15 -0
- data/app/views/panda/cms/admin/forms/show.html.erb +35 -0
- data/app/views/panda/cms/admin/menus/index.html.erb +8 -0
- data/app/views/panda/cms/admin/pages/edit.html.erb +36 -0
- data/app/views/panda/cms/admin/pages/index.html.erb +22 -0
- data/app/views/panda/cms/admin/pages/new.html.erb +15 -0
- data/app/views/panda/cms/admin/pages/show.html.erb +1 -0
- data/app/views/panda/cms/admin/posts/_form.html.erb +29 -0
- data/app/views/panda/cms/admin/posts/edit.html.erb +6 -0
- data/app/views/panda/cms/admin/posts/index.html.erb +18 -0
- data/app/views/panda/cms/admin/posts/new.html.erb +6 -0
- data/app/views/panda/cms/admin/sessions/new.html.erb +17 -0
- data/app/views/panda/cms/admin/settings/bulk_editor/new.html.erb +68 -0
- data/app/views/panda/cms/admin/settings/index.html.erb +21 -0
- data/app/views/panda/cms/admin/settings/insta.html +4 -0
- data/app/views/panda/cms/admin/shared/_breadcrumbs.html.erb +28 -0
- data/app/views/panda/cms/admin/shared/_flash.html.erb +5 -0
- data/app/views/panda/cms/admin/shared/_sidebar.html.erb +41 -0
- data/app/views/panda/cms/form_mailer/notification_email.html.erb +11 -0
- data/app/views/panda/cms/shared/_editor.html.erb +0 -0
- data/app/views/panda/cms/shared/_favicons.html.erb +9 -0
- data/app/views/panda/cms/shared/_footer.html.erb +2 -0
- data/app/views/panda/cms/shared/_header.html.erb +15 -0
- data/app/views/panda/cms/shared/_importmap.html.erb +33 -0
- data/config/importmap.rb +13 -0
- data/config/initializers/inflections.rb +3 -0
- data/config/initializers/panda/cms/form_errors.rb +38 -0
- data/config/initializers/panda/cms/healthcheck_log_silencer.rb +11 -0
- data/config/initializers/panda/cms/paper_trail.rb +7 -0
- data/config/initializers/panda/cms.rb +10 -0
- data/config/initializers/zeitwork.rb +3 -0
- data/config/locales/en.yml +49 -0
- data/config/puma/test.rb +9 -0
- data/config/routes.rb +48 -0
- data/config/tailwind.config.js +37 -0
- data/db/migrate/20240205223709_create_panda_cms_pages.rb +9 -0
- data/db/migrate/20240219213327_create_panda_cms_page_versions.rb +14 -0
- data/db/migrate/20240303002805_create_panda_cms_templates.rb +11 -0
- data/db/migrate/20240303003434_create_panda_cms_template_versions.rb +14 -0
- data/db/migrate/20240303022441_create_panda_cms_blocks.rb +13 -0
- data/db/migrate/20240303024256_create_panda_cms_block_contents.rb +10 -0
- data/db/migrate/20240303024746_create_panda_cms_block_content_versions.rb +14 -0
- data/db/migrate/20240303233238_add_panda_cms_menu_table.rb +10 -0
- data/db/migrate/20240303234724_add_panda_cms_menu_item_table.rb +12 -0
- data/db/migrate/20240304134343_add_parent_id_to_panda_cms_pages.rb +5 -0
- data/db/migrate/20240305000000_convert_html_content_to_editor_js.rb +82 -0
- data/db/migrate/20240315125411_add_status_to_panda_cms_pages.rb +9 -0
- data/db/migrate/20240315125421_add_nested_sets_to_panda_cms_pages.rb +16 -0
- data/db/migrate/20240316212822_add_kind_to_panda_cms_menus.rb +6 -0
- data/db/migrate/20240316221425_add_start_page_to_panda_cms_menus.rb +5 -0
- data/db/migrate/20240316230706_add_nested_to_panda_cms_menu_items.rb +24 -0
- data/db/migrate/20240317010532_create_panda_cms_users.rb +12 -0
- data/db/migrate/20240317161534_add_max_uses_to_panda_cms_template.rb +7 -0
- data/db/migrate/20240317163053_reset_counter_cache_on_panda_cms_template.rb +5 -0
- data/db/migrate/20240317214827_create_panda_cms_redirects.rb +14 -0
- data/db/migrate/20240317230622_create_panda_cms_visits.rb +13 -0
- data/db/migrate/20240324205703_create_active_storage_tables.active_storage.rb +58 -0
- data/db/migrate/20240408084718_default_panda_cms_users_admin_to_false.rb +5 -0
- data/db/migrate/20240701225422_add_service_name_to_active_storage_blobs.active_storage.rb +22 -0
- data/db/migrate/20240701225423_create_active_storage_variant_records.active_storage.rb +28 -0
- data/db/migrate/20240701225424_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb +8 -0
- data/db/migrate/20240804235210_create_panda_cms_forms.rb +11 -0
- data/db/migrate/20240805013612_create_panda_cms_form_submissions.rb +9 -0
- data/db/migrate/20240805121123_create_panda_cms_posts.rb +27 -0
- data/db/migrate/20240805123104_create_panda_cms_post_versions.rb +14 -0
- data/db/migrate/20240806112735_fix_panda_cms_visits_column_names.rb +13 -0
- data/db/migrate/20240806204412_add_completion_path_to_panda_cms_forms.rb +5 -0
- data/db/migrate/20240820081917_change_form_submissions_to_submission_count.rb +5 -0
- data/db/migrate/20240904200605_create_action_text_tables.action_text.rb +24 -0
- data/db/migrate/20240923234535_add_depth_to_panda_cms_menus.rb +11 -0
- data/db/migrate/20241031205109_add_cached_content_to_panda_cms_block_contents.rb +5 -0
- data/db/migrate/20241119214548_convert_post_content_to_editor_js.rb +35 -0
- data/db/migrate/20241119214549_remove_action_text_from_posts.rb +9 -0
- data/db/migrate/20241120000419_remove_post_tag_references.rb +19 -0
- data/db/migrate/20241120110943_add_editor_js_to_posts.rb +27 -0
- data/db/migrate/20241120113859_add_cached_content_to_panda_cms_posts.rb +5 -0
- data/db/migrate/20241123234140_remove_post_tag_id_from_posts.rb +5 -0
- data/db/migrate/migrate +1 -0
- data/db/seeds.rb +5 -0
- data/lib/generators/panda/cms/install_generator.rb +29 -0
- data/lib/panda/cms/bulk_editor.rb +171 -0
- data/lib/panda/cms/demo_site_generator.rb +67 -0
- data/lib/panda/cms/editor_js/blocks/alert.rb +34 -0
- data/lib/panda/cms/editor_js/blocks/base.rb +33 -0
- data/lib/panda/cms/editor_js/blocks/header.rb +15 -0
- data/lib/panda/cms/editor_js/blocks/image.rb +36 -0
- data/lib/panda/cms/editor_js/blocks/list.rb +32 -0
- data/lib/panda/cms/editor_js/blocks/paragraph.rb +15 -0
- data/lib/panda/cms/editor_js/blocks/quote.rb +41 -0
- data/lib/panda/cms/editor_js/blocks/table.rb +50 -0
- data/lib/panda/cms/editor_js/renderer.rb +124 -0
- data/lib/panda/cms/editor_js.rb +16 -0
- data/lib/panda/cms/editor_js_content.rb +21 -0
- data/lib/panda/cms/engine.rb +257 -0
- data/lib/panda/cms/exceptions_app.rb +26 -0
- data/lib/panda/cms/railtie.rb +11 -0
- data/lib/panda/cms/slug.rb +24 -0
- data/lib/panda/cms.rb +0 -0
- data/lib/panda-cms/version.rb +5 -0
- data/lib/panda-cms.rb +81 -0
- data/lib/tasks/panda_cms.rake +54 -0
- data/lib/templates/erb/scaffold/_form.html.erb.tt +43 -0
- data/lib/templates/erb/scaffold/edit.html.erb.tt +8 -0
- data/lib/templates/erb/scaffold/index.html.erb.tt +14 -0
- data/lib/templates/erb/scaffold/new.html.erb.tt +7 -0
- data/lib/templates/erb/scaffold/partial.html.erb.tt +22 -0
- data/lib/templates/erb/scaffold/show.html.erb.tt +15 -0
- data/public/panda-cms-assets/favicons/android-chrome-192x192.png +0 -0
- data/public/panda-cms-assets/favicons/android-chrome-512x512.png +0 -0
- data/public/panda-cms-assets/favicons/apple-touch-icon.png +0 -0
- data/public/panda-cms-assets/favicons/browserconfig.xml +9 -0
- data/public/panda-cms-assets/favicons/favicon-16x16.png +0 -0
- data/public/panda-cms-assets/favicons/favicon-32x32.png +0 -0
- data/public/panda-cms-assets/favicons/favicon.ico +0 -0
- data/public/panda-cms-assets/favicons/mstile-150x150.png +0 -0
- data/public/panda-cms-assets/favicons/safari-pinned-tab.svg +61 -0
- data/public/panda-cms-assets/favicons/site.webmanifest +14 -0
- data/public/panda-cms-assets/panda-logo-screenprint.png +0 -0
- data/public/panda-cms-assets/panda-nav.png +0 -0
- data/public/panda-cms-assets/rich_text_editor.css +568 -0
- metadata +654 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
@tailwind base;
|
|
2
|
+
@tailwind components;
|
|
3
|
+
@tailwind utilities;
|
|
4
|
+
|
|
5
|
+
@layer base {
|
|
6
|
+
html[data-theme="default"] {
|
|
7
|
+
--color-white: 249 249 249; /* #F9F9F9 */
|
|
8
|
+
--color-black: 26 22 29; /* #1A161D */
|
|
9
|
+
|
|
10
|
+
--color-light: 238 206 230; /* #EECEE6 */
|
|
11
|
+
--color-mid: 141 94 183; /* #8D5EB7 */
|
|
12
|
+
--color-dark: 33 29 73; /* #211D49 */
|
|
13
|
+
|
|
14
|
+
--color-highlight: 208 64 20; /* #D04014 */
|
|
15
|
+
|
|
16
|
+
--color-active: 0 135 85; /* #008755 */
|
|
17
|
+
--color-warning: 250 207 142; /* #FACF8E */
|
|
18
|
+
--color-inactive: 216 247 245; /* #d6e4f7 */
|
|
19
|
+
--color-error: 245 129 129; /* #F58181 */
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
html[data-theme="sky"] {
|
|
23
|
+
--color-white: 249 249 249; /* #F9F9F9 */
|
|
24
|
+
--color-black: 26 22 29; /* #1A161D */
|
|
25
|
+
--color-light: 204 238 242; /* #CCEEF2 */
|
|
26
|
+
--color-mid: 42 102 159; /* #2A669F */
|
|
27
|
+
--color-dark: 20 32 74; /* #14204A */
|
|
28
|
+
--color-highlight: 208 64 20; /* #D04014 */
|
|
29
|
+
|
|
30
|
+
--color-active: 166 211 129; /* #A6D381 */
|
|
31
|
+
--color-warning: 244 190 102; /* #F4BE66 */
|
|
32
|
+
--color-inactive: 216 247 245; /* #d6e4f7 */
|
|
33
|
+
--color-error: 208 64 20; /* #D04014 */
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
a.block-link:after {
|
|
37
|
+
position: absolute;
|
|
38
|
+
content: "";
|
|
39
|
+
inset: 0;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* Default editor styles */
|
|
44
|
+
@layer components {
|
|
45
|
+
.codex-editor__redactor .ce-block .ce-block__content {
|
|
46
|
+
@apply text-base font-normal font-sans text-dark leading-[1.6] space-y-[1.6rem];
|
|
47
|
+
|
|
48
|
+
h1.ce-header {
|
|
49
|
+
@apply text-3xl md:text-4xl font-semibold font-sans leading-[1.2];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
h2.ce-header {
|
|
53
|
+
@apply text-2xl font-medium font-sans leading-[1.3] mb-4 mt-8;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
h3.ce-header {
|
|
57
|
+
@apply text-xl font-normal font-sans leading-[1.3] mb-4 mt-6;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
p,
|
|
61
|
+
li {
|
|
62
|
+
@apply leading-[1.6] tracking-wide max-w-[85ch];
|
|
63
|
+
|
|
64
|
+
a {
|
|
65
|
+
@apply text-[#1A9597] underline underline-offset-2 hover:text-[#158486] focus:outline-2 focus:outline-offset-2 focus:outline-[#1A9597];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
strong,
|
|
69
|
+
b {
|
|
70
|
+
@apply font-semibold;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
p {
|
|
75
|
+
@apply mb-4;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.cdx-quote {
|
|
79
|
+
@apply bg-[#eef0f3] border-l-inactive border-l-8 p-6 mb-4;
|
|
80
|
+
|
|
81
|
+
.cdx-quote__caption {
|
|
82
|
+
@apply block ml-6 mt-2 text-sm text-dark;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.cdx-quote__text {
|
|
86
|
+
quotes: "\201C""\201D""\2018""\2019";
|
|
87
|
+
@apply pl-6;
|
|
88
|
+
|
|
89
|
+
&:before {
|
|
90
|
+
@apply -ml-8 mr-2 text-dark text-6xl leading-4 align-text-bottom font-serif;
|
|
91
|
+
content: open-quote;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
p {
|
|
95
|
+
@apply inline italic text-lg;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.cdx-list {
|
|
101
|
+
@apply mb-4 pl-6;
|
|
102
|
+
|
|
103
|
+
&--ordered {
|
|
104
|
+
@apply list-decimal;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
&--unordered {
|
|
108
|
+
@apply list-disc;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.cdx-list {
|
|
112
|
+
@apply mt-2 mb-0;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.cdx-list__item {
|
|
116
|
+
@apply mb-2 pl-2;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.cdx-nested-list {
|
|
121
|
+
@apply mb-4 pl-6;
|
|
122
|
+
|
|
123
|
+
&--ordered {
|
|
124
|
+
@apply list-decimal;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
&--unordered {
|
|
128
|
+
@apply list-disc;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.cdx-nested-list {
|
|
132
|
+
@apply mt-2 mb-0;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.cdx-nested-list__item {
|
|
136
|
+
@apply mb-2 pl-2;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.cdx-table {
|
|
141
|
+
@apply w-full border-collapse border-2 border-dark my-6;
|
|
142
|
+
|
|
143
|
+
&__head {
|
|
144
|
+
@apply font-semibold border-dark border-r-2 p-3 bg-light;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
&__row {
|
|
148
|
+
@apply border-dark border-b-2;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
&__cell {
|
|
152
|
+
@apply border-dark border-r-2 p-3;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.cdx-embed {
|
|
157
|
+
iframe {
|
|
158
|
+
@apply w-full border-none;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/* Base content styles, where .codex-editor applies them to the Panda editor too */
|
|
2
|
+
@layer components {
|
|
3
|
+
.codex-editor__redactor .ce-block .ce-block__content {
|
|
4
|
+
@apply text-base font-normal font-sans text-dark leading-[1.6] space-y-[1.6rem];
|
|
5
|
+
|
|
6
|
+
h1.ce-header {
|
|
7
|
+
@apply text-3xl md:text-4xl font-semibold font-sans text-[#104071] leading-[1.2] max-w-[85ch];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
h2.ce-header {
|
|
11
|
+
@apply text-2xl font-medium font-sans text-[#104071] leading-[1.3] mb-4 mt-8 max-w-[85ch];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
h3.ce-header {
|
|
15
|
+
@apply text-xl font-normal font-sans text-[#104071] leading-[1.3] mb-4 mt-6 max-w-[85ch];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
p,
|
|
19
|
+
li {
|
|
20
|
+
@apply leading-[1.6] tracking-wide max-w-[85ch];
|
|
21
|
+
|
|
22
|
+
a {
|
|
23
|
+
@apply text-[#1A9597] underline underline-offset-2 hover:text-[#158486] focus:outline-2 focus:outline-offset-2 focus:outline-[#1A9597];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
strong,
|
|
27
|
+
b {
|
|
28
|
+
@apply font-semibold;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
p {
|
|
33
|
+
@apply mb-4;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.cdx-quote {
|
|
37
|
+
@apply bg-[#eef0f3] border-l-inactive border-l-8 p-6 mb-4;
|
|
38
|
+
|
|
39
|
+
.cdx-quote__caption {
|
|
40
|
+
@apply block ml-6 mt-2 text-sm text-dark;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.cdx-quote__text {
|
|
44
|
+
quotes: "\201C" "\201D" "\2018" "\2019";
|
|
45
|
+
@apply pl-6;
|
|
46
|
+
|
|
47
|
+
&:before {
|
|
48
|
+
@apply -ml-8 mr-2 text-dark text-6xl leading-4 align-text-bottom font-serif;
|
|
49
|
+
content: open-quote;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
p {
|
|
53
|
+
@apply inline italic text-lg;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.cdx-list {
|
|
59
|
+
@apply mb-4 pl-6;
|
|
60
|
+
|
|
61
|
+
&--ordered {
|
|
62
|
+
@apply list-decimal;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
&--unordered {
|
|
66
|
+
@apply list-disc;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.cdx-list {
|
|
70
|
+
@apply mt-2 mb-0;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.cdx-list__item {
|
|
74
|
+
@apply mb-2 pl-2;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.cdx-nested-list {
|
|
79
|
+
@apply mb-4 pl-6;
|
|
80
|
+
|
|
81
|
+
&--ordered {
|
|
82
|
+
@apply list-decimal;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
&--unordered {
|
|
86
|
+
@apply list-disc;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.cdx-nested-list {
|
|
90
|
+
@apply mt-2 mb-0;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.cdx-nested-list__item {
|
|
94
|
+
@apply mb-2 pl-2;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.cdx-table {
|
|
99
|
+
@apply w-full border-collapse border-2 border-dark my-6;
|
|
100
|
+
|
|
101
|
+
&__head {
|
|
102
|
+
@apply font-semibold border-dark border-r-2 p-3 bg-light;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
&__row {
|
|
106
|
+
@apply border-dark border-b-2;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
&__cell {
|
|
110
|
+
@apply border-dark border-r-2 p-3;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.cdx-embed {
|
|
115
|
+
iframe {
|
|
116
|
+
@apply w-full border-none;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
require "ostruct"
|
|
2
|
+
|
|
3
|
+
module Panda
|
|
4
|
+
module CMS
|
|
5
|
+
class FormBuilder < ActionView::Helpers::FormBuilder
|
|
6
|
+
include ActionView::Helpers::TagHelper
|
|
7
|
+
include ActionView::Helpers::FormTagHelper
|
|
8
|
+
|
|
9
|
+
def label(attribute, text = nil, options = {}, &block)
|
|
10
|
+
super(attribute, text, options.reverse_merge(class: label_styles))
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def text_field(attribute, options = {})
|
|
14
|
+
if options.dig(:data, :prefix)
|
|
15
|
+
content_tag :div, class: container_styles do
|
|
16
|
+
label(attribute) + meta_text(options) +
|
|
17
|
+
content_tag(:div, class: "flex flex-grow") do
|
|
18
|
+
content_tag(:span, class: "inline-flex items-center px-3 text-base border border-r-none rounded-s-md whitespace-nowrap break-keep") { options.dig(:data, :prefix) } +
|
|
19
|
+
super(attribute, options.reverse_merge(class: input_styles_prefix + " input-prefix rounded-l-none border-l-none"))
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
else
|
|
23
|
+
content_tag :div, class: container_styles do
|
|
24
|
+
label(attribute) + meta_text(options) + super(attribute, options.reverse_merge(class: input_styles))
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def email_field(method, options = {})
|
|
30
|
+
content_tag :div, class: container_styles do
|
|
31
|
+
label(method) + meta_text(options) + super(method, options.reverse_merge(class: input_styles))
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def datetime_field(method, options = {})
|
|
36
|
+
content_tag :div, class: container_styles do
|
|
37
|
+
label(method) + meta_text(options) + super(method, options.reverse_merge(class: input_styles))
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def text_area(method, options = {})
|
|
42
|
+
content_tag :div, class: container_styles do
|
|
43
|
+
label(method) + meta_text(options) + super(method, options.reverse_merge(class: input_styles))
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def password_field(attribute, options = {})
|
|
48
|
+
content_tag :div, class: container_styles do
|
|
49
|
+
label(attribute) + meta_text(options) + super(attribute, options.reverse_merge(class: input_styles))
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def select(method, choices = nil, options = {}, html_options = {}, &block)
|
|
54
|
+
content_tag :div, class: container_styles do
|
|
55
|
+
label(method) + meta_text(options) + super(method, choices, options, html_options.reverse_merge(class: select_styles)) + select_svg
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def collection_select(method, collection, value_method, text_method, options = {}, html_options = {})
|
|
60
|
+
content_tag :div, class: container_styles do
|
|
61
|
+
label(method) + meta_text(options) + super(method, collection, value_method, text_method, options, html_options.reverse_merge(class: input_styles))
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def time_zone_select(method, priority_zones = nil, options = {}, html_options = {})
|
|
66
|
+
wrap_field(method, options) do
|
|
67
|
+
super(
|
|
68
|
+
method,
|
|
69
|
+
priority_zones,
|
|
70
|
+
options,
|
|
71
|
+
html_options.reverse_merge(class: select_styles)
|
|
72
|
+
)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def file_field(method, options = {})
|
|
77
|
+
content_tag :div, class: container_styles do
|
|
78
|
+
label(method) + meta_text(options) + super(method, options.reverse_merge(class: "file:rounded file:border-0 file:text-sm file:bg-white file:text-gray-500 hover:file:bg-gray-50 bg-white px-2.5 hover:bg-gray-50".concat(input_styles)))
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def button(value = nil, options = {}, &block)
|
|
83
|
+
value ||= submit_default_value
|
|
84
|
+
options = options.dup
|
|
85
|
+
|
|
86
|
+
# Handle formmethod specially
|
|
87
|
+
if options[:formmethod] == "delete"
|
|
88
|
+
options[:name] = "_method"
|
|
89
|
+
options[:value] = "delete"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
base_classes = [
|
|
93
|
+
"inline-flex items-center rounded-md",
|
|
94
|
+
"px-3 py-2",
|
|
95
|
+
"text-base font-semibold",
|
|
96
|
+
"shadow-sm"
|
|
97
|
+
]
|
|
98
|
+
|
|
99
|
+
# Only add fa-circle-check for non-block buttons
|
|
100
|
+
base_classes << "fa-circle-check" unless block_given?
|
|
101
|
+
|
|
102
|
+
options[:class] = [
|
|
103
|
+
*base_classes,
|
|
104
|
+
options[:class]
|
|
105
|
+
].compact.join(" ")
|
|
106
|
+
|
|
107
|
+
if block_given?
|
|
108
|
+
@template.button_tag(options, &block)
|
|
109
|
+
else
|
|
110
|
+
@template.button_tag(value, options)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def submit(value = nil, options = {})
|
|
115
|
+
value ||= submit_default_value
|
|
116
|
+
|
|
117
|
+
# Use the same style logic as ButtonComponent
|
|
118
|
+
action = object.persisted? ? :save : :create
|
|
119
|
+
button_classes = case action
|
|
120
|
+
when :save, :create
|
|
121
|
+
"text-white bg-active"
|
|
122
|
+
when :save_inactive
|
|
123
|
+
"text-white bg-inactive"
|
|
124
|
+
when :secondary
|
|
125
|
+
"text-dark border-2 border-mid bg-transparent hover:bg-light transition-all"
|
|
126
|
+
else
|
|
127
|
+
"text-dark border-2 border-mid bg-transparent hover:bg-light transition-all"
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Combine with common button classes
|
|
131
|
+
classes = "inline-flex items-center rounded-md font-medium shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 #{button_classes}"
|
|
132
|
+
|
|
133
|
+
options[:class] = options[:class] ? "#{options[:class]} #{classes}" : classes
|
|
134
|
+
|
|
135
|
+
super
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def check_box(method, options = {}, checked_value = "1", unchecked_value = "0")
|
|
139
|
+
content_tag :div, class: container_styles do
|
|
140
|
+
label(method) + meta_text(options) + super(method, options.reverse_merge(class: "border-gray-300 ml-2"), checked_value, unchecked_value)
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def date_field(method, options = {})
|
|
145
|
+
content_tag :div, class: container_styles do
|
|
146
|
+
label(method) + meta_text(options) + super(method, options.reverse_merge(class: input_styles))
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def rich_text_area(method, options = {})
|
|
151
|
+
content_tag :div, class: container_styles do
|
|
152
|
+
label(method) + meta_text(options) + super(method, options.reverse_merge(class: textarea_styles))
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def rich_text_field(method, options = {})
|
|
157
|
+
wrap_field(method, options) do
|
|
158
|
+
if defined?(ActionText)
|
|
159
|
+
# For test environment
|
|
160
|
+
if Rails.env.test?
|
|
161
|
+
# Just render a textarea for testing
|
|
162
|
+
text_area(method, options.reverse_merge(class: textarea_styles))
|
|
163
|
+
else
|
|
164
|
+
rich_text_area(method, options.reverse_merge(class: textarea_styles))
|
|
165
|
+
end
|
|
166
|
+
else
|
|
167
|
+
text_area(method, options.reverse_merge(class: textarea_styles))
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def meta_text(options)
|
|
173
|
+
return unless options[:meta]
|
|
174
|
+
@template.content_tag(:p, options[:meta], class: "block text-black/60 text-sm mb-2")
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
private
|
|
178
|
+
|
|
179
|
+
def label_styles
|
|
180
|
+
"font-light inline-block mb-1 text-base leading-6"
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def base_input_styles
|
|
184
|
+
"bg-white block w-full rounded-md border border-mid focus:border-mid p-2 text-dark outline-0 focus:outline-0 ring-0 focus:ring-0 focus:ring-mid ring-offset-0 focus:ring-offset-0 shadow-none focus:shadow-none border-mid"
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def input_styles
|
|
188
|
+
base_input_styles
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def input_styles_prefix
|
|
192
|
+
input_styles.concat(" prefix")
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def select_styles
|
|
196
|
+
"col-start-1 row-start-1 w-full appearance-none rounded-md bg-white py-1.5 pl-3 pr-8 text-dark text-base outline-0 outline-dark focus:outline focus:-outline-offset-2 focus:outline-dark"
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def select_svg
|
|
200
|
+
@template.content_tag(:svg, class: "pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-gray-400", aria_hidden: true) do
|
|
201
|
+
@template.content_tag(:path, d: "M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z")
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def button_styles
|
|
206
|
+
"inline-flex items-center rounded-md font-medium shadow-sm focus-visible:outline focus-visible:outline-0 focus-visible:outline-offset-none text-dark border-2 border-mid bg-transparent hover:bg-light transition-all gap-x-1.5 px-3 py-2 text-base gap-x-1.5 px-2.5 py-1.5 mt-2 "
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def container_styles
|
|
210
|
+
"panda-cms-field-container mb-4"
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def textarea_styles
|
|
214
|
+
input_styles.concat(" min-h-32")
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def submit_default_value
|
|
218
|
+
object.persisted? ? "Update #{object.class.name.demodulize}" : "Create #{object.class.name.demodulize}"
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def wrap_field(method, options = {}, &block)
|
|
222
|
+
@template.content_tag(:div, class: "panda-cms-field-container") do
|
|
223
|
+
label(method, class: "font-light inline-block mb-1 text-base leading-6") +
|
|
224
|
+
meta_text(options) +
|
|
225
|
+
@template.content_tag(:div, class: field_wrapper_styles, &block)
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def field_wrapper_styles
|
|
230
|
+
"mt-1"
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Panda
|
|
4
|
+
module CMS
|
|
5
|
+
module Admin
|
|
6
|
+
class ButtonComponent < ViewComponent::Base
|
|
7
|
+
attr_accessor :text, :action, :link, :icon, :size, :data
|
|
8
|
+
|
|
9
|
+
def initialize(text: "Button", action: nil, data: {}, link: "#", icon: nil, size: :regular, id: nil)
|
|
10
|
+
@text = text
|
|
11
|
+
@action = action
|
|
12
|
+
@data = data
|
|
13
|
+
@link = link
|
|
14
|
+
@icon = icon
|
|
15
|
+
@size = size
|
|
16
|
+
@id = id
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def call
|
|
20
|
+
@icon = set_icon_from_action(@action) if @action && @icon.nil?
|
|
21
|
+
icon = content_tag(:i, "", class: "mr-2 fa-regular fa-#{@icon}") if @icon
|
|
22
|
+
@text = "#{icon} #{@text.titleize}".html_safe
|
|
23
|
+
|
|
24
|
+
classes = "inline-flex items-center rounded-md font-medium shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 "
|
|
25
|
+
|
|
26
|
+
case @size
|
|
27
|
+
when :small, :sm
|
|
28
|
+
classes += "gap-x-1.5 px-2.5 py-1.5 text-sm "
|
|
29
|
+
when :medium, :regular, :md
|
|
30
|
+
classes += "gap-x-1.5 px-3 py-2 text-base "
|
|
31
|
+
when :large, :lg
|
|
32
|
+
classes += "gap-x-2 px-3.5 py-2.5 text-lg "
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
classes += case @action
|
|
36
|
+
when :save, :create
|
|
37
|
+
"text-white bg-active"
|
|
38
|
+
when :save_inactive
|
|
39
|
+
"text-white bg-inactive"
|
|
40
|
+
when :secondary
|
|
41
|
+
"text-dark border-2 border-dark bg-transparent hover:bg-light transition-all "
|
|
42
|
+
when :delete, :destroy, :danger
|
|
43
|
+
"text-error border border-error bg-red-100 hover:bg-red-200 hover:text-error focus-visible:outline-red-300 "
|
|
44
|
+
else
|
|
45
|
+
"text-dark border-2 border-dark bg-transparent hover:bg-light transition-all "
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
content_tag :a, href: @link, class: classes, data: @data, id: @id do
|
|
49
|
+
@text
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def set_icon_from_action(action)
|
|
56
|
+
case action
|
|
57
|
+
when :add, :new, :create
|
|
58
|
+
"plus"
|
|
59
|
+
when :save
|
|
60
|
+
"check"
|
|
61
|
+
when :edit, :update
|
|
62
|
+
"pencil"
|
|
63
|
+
when :delete, :destroy
|
|
64
|
+
"trash"
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<main class="overflow-auto flex-1 h-full min-h-full max-h-full">
|
|
2
|
+
<div class="overflow-auto px-2 pt-4 mx-auto sm:px-6 lg:px-6">
|
|
3
|
+
<%= heading %>
|
|
4
|
+
<%= tab_bar %>
|
|
5
|
+
<%# I mean, you can edit this CSS if you want, but I hope you want to lose 2 hours to iFrame joy? %>
|
|
6
|
+
<section class="flex-auto h-[calc(100vh-10rem)]">
|
|
7
|
+
<div class="flex-1 mt-4 w-full h-full">
|
|
8
|
+
<%= content %>
|
|
9
|
+
</div>
|
|
10
|
+
<%= slideover %>
|
|
11
|
+
</section>
|
|
12
|
+
</div>
|
|
13
|
+
</main>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Panda
|
|
4
|
+
module CMS
|
|
5
|
+
module Admin
|
|
6
|
+
class ContainerComponent < ViewComponent::Base
|
|
7
|
+
renders_one :heading, "Panda::CMS::Admin::HeadingComponent"
|
|
8
|
+
renders_one :tab_bar, "Panda::CMS::Admin::TabBarComponent"
|
|
9
|
+
renders_one :slideover, "Panda::CMS::Admin::SlideoverComponent"
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<div class="fixed top-2 right-2 z-50 p-2 space-y-4 w-full max-w-sm pointer-events-none sm:items-end"
|
|
2
|
+
data-controller="alert"
|
|
3
|
+
<% if @temporary %> data-alert-dismiss-after-value="3000"<% end %>
|
|
4
|
+
data-transition-enter="ease-in-out duration-500"
|
|
5
|
+
data-transition-enter-from="translate-x-full opacity-0"
|
|
6
|
+
data-transition-enter-to="translate-x-0 opacity-100"
|
|
7
|
+
data-transition-leave="ease-in-out duration-500"
|
|
8
|
+
data-transition-leave-from="translate-x-0 opacity-100"
|
|
9
|
+
data-transition-leave-to="translate-x-full opacity-0">
|
|
10
|
+
<div class="overflow-hidden w-full max-w-sm bg-white rounded-lg ring-1 ring-black ring-opacity-5 shadow-lg pointer-events-auto">
|
|
11
|
+
<div class="p-4">
|
|
12
|
+
<div class="flex items-start">
|
|
13
|
+
<div class="flex-shrink-0">
|
|
14
|
+
<i class="fa-regular text-xl <%= icon_css %> <%= text_colour_css %>"></i>
|
|
15
|
+
</div>
|
|
16
|
+
<div class="flex-1 pt-0.5 ml-3 w-0">
|
|
17
|
+
<p class="mb-1 text-sm font-medium flash-message-title <%= text_colour_css %>"><%= kind.to_s.titleize %></p>
|
|
18
|
+
<p class="mt-1 mb-0 text-sm text-gray-500 flash-message-text"><%= message %></p>
|
|
19
|
+
</div>
|
|
20
|
+
<div class="flex flex-shrink-0 ml-4">
|
|
21
|
+
<button data-action="alert#close" type="button" class="inline-flex text-gray-400 bg-white rounded-md transition duration-150 ease-in-out hover:text-gray-500 focus:ring-2 focus:ring-offset-2 focus:outline-none focus:ring-sky-500">
|
|
22
|
+
<span class="sr-only">Close</span>
|
|
23
|
+
<svg class="w-5 h-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
24
|
+
<path d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" />
|
|
25
|
+
</svg>
|
|
26
|
+
</button>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Panda
|
|
4
|
+
module CMS
|
|
5
|
+
module Admin
|
|
6
|
+
class FlashMessageComponent < ::ViewComponent::Base
|
|
7
|
+
attr_reader :kind, :message
|
|
8
|
+
|
|
9
|
+
def initialize(message:, kind:, temporary: true)
|
|
10
|
+
@kind = kind.to_sym
|
|
11
|
+
@message = message
|
|
12
|
+
@temporary = temporary
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def text_colour_css
|
|
16
|
+
case kind
|
|
17
|
+
when :success
|
|
18
|
+
"text-active"
|
|
19
|
+
when :alert, :error
|
|
20
|
+
"text-error"
|
|
21
|
+
when :warning
|
|
22
|
+
"text-warning"
|
|
23
|
+
when :info, :notice
|
|
24
|
+
"text-active"
|
|
25
|
+
else
|
|
26
|
+
"text-mid"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def icon_css
|
|
31
|
+
case kind
|
|
32
|
+
when :success
|
|
33
|
+
"fa-circle-check"
|
|
34
|
+
when :alert
|
|
35
|
+
"fa-circle-xmark"
|
|
36
|
+
when :warning
|
|
37
|
+
"fa-triangle-exclamation"
|
|
38
|
+
when :info, :notice
|
|
39
|
+
"fa-circle-info"
|
|
40
|
+
else
|
|
41
|
+
"fa-circle-info"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|