panda_cms 0.5.10 → 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +3 -1
- data/Rakefile +0 -1
- data/app/assets/builds/panda_cms.css +2432 -1
- data/app/assets/config/panda_cms_manifest.js +3 -0
- data/app/assets/stylesheets/panda_cms/application.tailwind.css +3 -27
- data/app/builders/panda_cms/form_builder.rb +1 -1
- data/app/components/panda_cms/admin/button_component.rb +6 -3
- data/app/components/panda_cms/admin/flash_message_component.rb +1 -1
- data/app/components/panda_cms/admin/tag_component.rb +1 -1
- data/app/components/panda_cms/code_component.rb +62 -0
- data/app/components/panda_cms/menu_component.html.erb +3 -0
- data/app/components/panda_cms/menu_component.rb +8 -1
- data/app/components/panda_cms/page_menu_component.html.erb +12 -8
- data/app/components/panda_cms/page_menu_component.rb +24 -13
- data/app/components/panda_cms/rich_text_component.html.erb +6 -38
- data/app/components/panda_cms/rich_text_component.rb +32 -7
- data/app/components/panda_cms/text_component.rb +25 -22
- data/app/controllers/panda_cms/admin/block_contents_controller.rb +1 -1
- data/app/controllers/panda_cms/admin/dashboard_controller.rb +14 -6
- data/app/controllers/panda_cms/admin/menus_controller.rb +1 -54
- data/app/controllers/panda_cms/admin/pages_controller.rb +2 -1
- data/app/controllers/panda_cms/admin/sessions_controller.rb +13 -6
- data/app/controllers/panda_cms/application_controller.rb +1 -1
- data/app/controllers/panda_cms/pages_controller.rb +1 -1
- data/app/controllers/panda_cms/posts_controller.rb +1 -1
- data/app/helpers/panda_cms/application_helper.rb +2 -2
- 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 +4 -0
- data/app/javascript/panda_cms/controllers/dashboard_controller.js +7 -0
- data/app/javascript/panda_cms/controllers/editor_controller.js +247 -0
- data/app/javascript/panda_cms/controllers/index.js +45 -0
- data/app/javascript/panda_cms/controllers/slug_controller.js +48 -0
- data/app/javascript/panda_cms/editor/plain_text_editor.js +102 -0
- data/app/javascript/panda_cms/editor/resource_loader.js +69 -0
- data/app/javascript/panda_cms/editor/rich_text_editor.js +89 -0
- data/app/javascript/panda_cms/tailwindcss-stimulus-components.js +4 -0
- data/app/lib/panda_cms/demo_site_generator.rb +1 -3
- data/app/lib/panda_cms/editor_js/blocks/alert.rb +32 -0
- data/app/lib/panda_cms/editor_js/blocks/base.rb +28 -0
- data/app/lib/panda_cms/editor_js/blocks/header.rb +13 -0
- data/app/lib/panda_cms/editor_js/blocks/image.rb +34 -0
- data/app/lib/panda_cms/editor_js/blocks/list.rb +30 -0
- data/app/lib/panda_cms/editor_js/blocks/paragraph.rb +13 -0
- data/app/lib/panda_cms/editor_js/blocks/quote.rb +27 -0
- data/app/lib/panda_cms/editor_js/blocks/table.rb +48 -0
- data/app/lib/panda_cms/editor_js/renderer.rb +120 -0
- data/app/lib/panda_cms/slug.rb +1 -1
- data/app/models/panda_cms/block.rb +2 -2
- data/app/models/panda_cms/block_content.rb +12 -2
- data/app/models/panda_cms/page.rb +9 -3
- data/app/models/panda_cms/post.rb +1 -1
- data/app/models/panda_cms/template.rb +4 -2
- data/app/models/panda_cms/user.rb +9 -1
- data/app/views/panda_cms/admin/dashboard/show.html.erb +11 -9
- data/app/views/panda_cms/admin/forms/new.html.erb +6 -7
- data/app/views/panda_cms/admin/menus/index.html.erb +0 -2
- data/app/views/panda_cms/admin/pages/edit.html.erb +22 -19
- data/app/views/panda_cms/admin/pages/new.html.erb +6 -7
- data/app/views/panda_cms/admin/posts/_form.html.erb +4 -4
- data/app/views/panda_cms/admin/sessions/new.html.erb +1 -2
- data/app/views/panda_cms/admin/shared/_sidebar.html.erb +12 -16
- data/app/views/panda_cms/shared/_header.html.erb +13 -14
- data/app/views/panda_cms/shared/_importmap.html.erb +32 -0
- data/config/importmap.rb +13 -10
- data/config/initializers/panda_cms.rb +57 -55
- data/config/routes.rb +9 -9
- data/config/tailwind.config.js +1 -0
- data/db/migrate/20240205223709_create_panda_cms_pages.rb +6 -4
- data/db/migrate/20240315125411_add_status_to_panda_cms_pages.rb +9 -0
- data/db/migrate/20241031205109_add_cached_content_to_panda_cms_block_contents.rb +5 -0
- data/db/seeds.rb +1 -0
- data/lib/generators/panda_cms/install_generator.rb +3 -0
- data/lib/panda_cms/engine.rb +42 -29
- data/lib/panda_cms/version.rb +1 -1
- data/lib/panda_cms.rb +58 -10
- data/lib/tasks/panda_cms.rake +41 -57
- data/public/panda-cms-assets/rich_text_editor.css +568 -0
- metadata +228 -304
- data/app/javascript/base.js +0 -37
- data/app/javascript/controllers/menu_controller.js +0 -19
- data/app/javascript/controllers/text_controller.js +0 -78
- data/app/javascript/controllers/text_field_update_controller.js +0 -51
- data/app/javascript/vendor/stimulus-components-rails-nested-form.js +0 -2
- data/app/javascript/vendor/tailwindcss-stimulus-components.js +0 -2
- data/app/views/panda_cms/admin/menus/_form.html.erb +0 -21
- data/app/views/panda_cms/admin/menus/_menu_item_fields.html.erb +0 -7
- data/app/views/panda_cms/admin/menus/edit.html.erb +0 -58
- data/app/views/panda_cms/admin/menus/new.html.erb +0 -5
- data/db/migrate/20240804110225_add_status_to_panda_cms_pages.rb +0 -7
- data/public/panda-cms-assets/javascripts/base.js +0 -37
- data/public/panda-cms-assets/javascripts/controllers/menu_controller.js +0 -19
- data/public/panda-cms-assets/javascripts/controllers/text_field_update_controller.js +0 -23
- data/public/panda-cms-assets/javascripts/embed/editable.js +0 -358
- data/public/panda-cms-assets/javascripts/embed/rich_text.css +0 -1294
- data/public/panda-cms-assets/javascripts/vendor/stimulus-components-rails-nested-form.js +0 -2
- data/public/panda-cms-assets/javascripts/vendor/stimulus-loading.js +0 -113
- data/public/panda-cms-assets/javascripts/vendor/tailwindcss-stimulus-components.js +0 -2
data/app/javascript/base.js
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
import { Application as PandaCmsApplication } from "@hotwired/stimulus";
|
2
|
-
|
3
|
-
const panda_cms = PandaCmsApplication.start();
|
4
|
-
|
5
|
-
// Configure Stimulus development experience
|
6
|
-
panda_cms.debug = location.hostname === "localhost";
|
7
|
-
window.pandaStimulus = panda_cms;
|
8
|
-
|
9
|
-
export { panda_cms };
|
10
|
-
|
11
|
-
// Eager load all controllers defined in the import map under controllers/**/*_controller
|
12
|
-
import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading";
|
13
|
-
eagerLoadControllersFrom("panda_cms/controllers", panda_cms);
|
14
|
-
|
15
|
-
import {
|
16
|
-
Alert,
|
17
|
-
Autosave,
|
18
|
-
ColorPreview,
|
19
|
-
Dropdown,
|
20
|
-
Modal,
|
21
|
-
Tabs,
|
22
|
-
Popover,
|
23
|
-
Toggle,
|
24
|
-
Slideover,
|
25
|
-
} from "panda_cms/vendor/tailwindcss-stimulus-components";
|
26
|
-
panda_cms.register("alert", Alert);
|
27
|
-
panda_cms.register("autosave", Autosave);
|
28
|
-
panda_cms.register("color-preview", ColorPreview);
|
29
|
-
panda_cms.register("dropdown", Dropdown);
|
30
|
-
panda_cms.register("modal", Modal);
|
31
|
-
panda_cms.register("popover", Popover);
|
32
|
-
panda_cms.register("slideover", Slideover);
|
33
|
-
panda_cms.register("tabs", Tabs);
|
34
|
-
panda_cms.register("toggle", Toggle);
|
35
|
-
|
36
|
-
import RailsNestedForm from "panda_cms/vendor/stimulus-components-rails-nested-form";
|
37
|
-
panda_cms.register("nested-form", RailsNestedForm);
|
@@ -1,19 +0,0 @@
|
|
1
|
-
import { Controller as PandaCmsController } from "@hotwired/stimulus"
|
2
|
-
|
3
|
-
export default class extends PandaCmsController {
|
4
|
-
static targets = ["pandaCmsMenu"]
|
5
|
-
static values = {
|
6
|
-
open: { type: Boolean, default: false }
|
7
|
-
}
|
8
|
-
|
9
|
-
toggle(event) {
|
10
|
-
this.openValue = !this.openValue
|
11
|
-
this.animate()
|
12
|
-
}
|
13
|
-
|
14
|
-
animate() {
|
15
|
-
this.toggleableTargets.forEach(target => {
|
16
|
-
transition(target, this.openValue)
|
17
|
-
})
|
18
|
-
}
|
19
|
-
}
|
@@ -1,78 +0,0 @@
|
|
1
|
-
import { Controller as PandaCmsController } from "@hotwired/stimulus";
|
2
|
-
|
3
|
-
export default class extends PandaCmsController {
|
4
|
-
static targets = ["source"];
|
5
|
-
static values = { page: String, blockcontent: String };
|
6
|
-
static classes = ["initial", "success", "error"];
|
7
|
-
|
8
|
-
connect() {
|
9
|
-
this.sourceTarget.classList.add(...this.initialClasses);
|
10
|
-
}
|
11
|
-
|
12
|
-
save() {
|
13
|
-
this.cleanedContent = this.clean(this.sourceTarget.innerHTML);
|
14
|
-
|
15
|
-
fetch(
|
16
|
-
`/admin/pages/${this.pageValue}/block_contents/${this.blockcontentValue}`,
|
17
|
-
{
|
18
|
-
method: "PATCH",
|
19
|
-
headers: {
|
20
|
-
"Content-Type": "application/json",
|
21
|
-
"X-CSRF-Token": document
|
22
|
-
.querySelector('meta[name="csrf-token"]')
|
23
|
-
.getAttribute("content"),
|
24
|
-
},
|
25
|
-
body: JSON.stringify({ content: this.cleanedContent }),
|
26
|
-
}
|
27
|
-
)
|
28
|
-
.then((response) => response.json())
|
29
|
-
.then((data) => {
|
30
|
-
this.setSuccessClasses();
|
31
|
-
})
|
32
|
-
.catch((error) => {
|
33
|
-
alert("Error:", error);
|
34
|
-
console.log(error);
|
35
|
-
this.element.classList.remove(
|
36
|
-
...this.initialClasses,
|
37
|
-
...this.successClasses
|
38
|
-
);
|
39
|
-
this.element.classList.add(...this.errorClasses);
|
40
|
-
});
|
41
|
-
}
|
42
|
-
|
43
|
-
setInitialClasses() {
|
44
|
-
this.element.classList.remove(...this.successClasses, ...this.errorClasses);
|
45
|
-
this.element.classList.add(...this.initialClasses);
|
46
|
-
}
|
47
|
-
|
48
|
-
setSuccessClasses() {
|
49
|
-
this.element.classList.remove(...this.initialClasses, ...this.errorClasses);
|
50
|
-
this.element.classList.add(...this.successClasses);
|
51
|
-
this.resetInitialClassesTimer();
|
52
|
-
}
|
53
|
-
|
54
|
-
setErrorClasses() {
|
55
|
-
this.element.classList.remove(
|
56
|
-
...this.initialClasses,
|
57
|
-
...this.successClasses
|
58
|
-
);
|
59
|
-
this.element.classList.add(...this.errorClasses);
|
60
|
-
this.resetInitialClassesTimer();
|
61
|
-
}
|
62
|
-
|
63
|
-
resetInitialClassesTimer() {
|
64
|
-
setTimeout(
|
65
|
-
function () {
|
66
|
-
this.setInitialClasses();
|
67
|
-
}.bind(this),
|
68
|
-
1000
|
69
|
-
);
|
70
|
-
}
|
71
|
-
|
72
|
-
clean(content) {
|
73
|
-
// Replace horrible bullet points
|
74
|
-
content = content.replace(/• /g, "* ");
|
75
|
-
// TODO: More formatting
|
76
|
-
return content;
|
77
|
-
}
|
78
|
-
}
|
@@ -1,51 +0,0 @@
|
|
1
|
-
import { Controller as PandaCmsController } from "@hotwired/stimulus";
|
2
|
-
export default class extends PandaCmsController {
|
3
|
-
static targets = [
|
4
|
-
"existing_root",
|
5
|
-
"input_select",
|
6
|
-
"input_text",
|
7
|
-
"output_text",
|
8
|
-
];
|
9
|
-
|
10
|
-
connect() {}
|
11
|
-
|
12
|
-
generatePath() {
|
13
|
-
this.output_textTarget.value =
|
14
|
-
"/" + this.createSlug(this.input_textTarget.value);
|
15
|
-
}
|
16
|
-
|
17
|
-
setPrePath() {
|
18
|
-
this.parent_slugs =
|
19
|
-
this.input_selectTarget.options[
|
20
|
-
this.input_selectTarget.selectedIndex
|
21
|
-
].text.match(/.*\((.*)\)$/)[1];
|
22
|
-
this.output_textTarget.previousSibling.innerHTML = (
|
23
|
-
this.existing_rootTarget.value + this.parent_slugs
|
24
|
-
).replace(/\/$/, "");
|
25
|
-
}
|
26
|
-
|
27
|
-
// TODO: Invoke a library or helper which can be shared with the backend
|
28
|
-
// and check for uniqueness at the same time
|
29
|
-
createSlug(input) {
|
30
|
-
var str = input
|
31
|
-
.toLowerCase()
|
32
|
-
.trim()
|
33
|
-
.replace(/[^\w\s-]/g, "-")
|
34
|
-
.replace(/&/g, "and")
|
35
|
-
.replace(/[\s_-]+/g, "-")
|
36
|
-
.trim();
|
37
|
-
|
38
|
-
return this.trimStartEnd(str, "-");
|
39
|
-
}
|
40
|
-
|
41
|
-
trimStartEnd(str, ch) {
|
42
|
-
var start = 0,
|
43
|
-
end = str.length;
|
44
|
-
|
45
|
-
while (start < end && str[start] === ch) ++start;
|
46
|
-
|
47
|
-
while (end > start && str[end - 1] === ch) --end;
|
48
|
-
|
49
|
-
return start > 0 || end < str.length ? str.substring(start, end) : str;
|
50
|
-
}
|
51
|
-
}
|
@@ -1,2 +0,0 @@
|
|
1
|
-
import{Controller as e}from"@hotwired/stimulus";const t=class _RailsNestedForm extends e{add(e){e.preventDefault();const t=this.templateTarget.innerHTML.replace(/NEW_RECORD/g,(new Date).getTime().toString());this.targetTarget.insertAdjacentHTML("beforebegin",t);const r=new CustomEvent("rails-nested-form:add",{bubbles:!0});this.element.dispatchEvent(r)}remove(e){e.preventDefault();const t=e.target.closest(this.wrapperSelectorValue);if(t.dataset.newRecord==="true")t.remove();else{t.style.display="none";const e=t.querySelector("input[name*='_destroy']");e.value="1"}const r=new CustomEvent("rails-nested-form:remove",{bubbles:!0});this.element.dispatchEvent(r)}};t.targets=["target","template"],t.values={wrapperSelector:{type:String,default:".nested-form-wrapper"}};let r=t;export{r as default};
|
2
|
-
|
@@ -1,2 +0,0 @@
|
|
1
|
-
import{Controller as e}from"@hotwired/stimulus";var t=Object.defineProperty;var V=(e,a,i)=>a in e?t(e,a,{enumerable:!0,configurable:!0,writable:!0,value:i}):e[a]=i;var s=(e,t,a)=>(V(e,typeof t!="symbol"?t+"":t,a),a);async function r(e,t,a={}){t?T(e,a):b(e,a)}async function T(e,t={}){let a=e.dataset.transitionEnter||t.enter||"enter",i=e.dataset.transitionEnterFrom||t.enterFrom||"enter-from",n=e.dataset.transitionEnterTo||t.enterTo||"enter-to",o=e.dataset.toggleClass||t.toggleClass||"hidden";e.classList.add(...a.split(" ")),e.classList.add(...i.split(" ")),e.classList.remove(...n.split(" ")),e.classList.remove(...o.split(" ")),await v(),e.classList.remove(...i.split(" ")),e.classList.add(...n.split(" "));try{await x(e)}finally{e.classList.remove(...a.split(" "))}}async function b(e,t={}){let a=e.dataset.transitionLeave||t.leave||"leave",i=e.dataset.transitionLeaveFrom||t.leaveFrom||"leave-from",n=e.dataset.transitionLeaveTo||t.leaveTo||"leave-to",o=e.dataset.toggleClass||t.toggle||"hidden";e.classList.add(...a.split(" ")),e.classList.add(...i.split(" ")),e.classList.remove(...n.split(" ")),await v(),e.classList.remove(...i.split(" ")),e.classList.add(...n.split(" "));try{await x(e)}finally{e.classList.remove(...a.split(" ")),e.classList.add(...o.split(" "))}}function v(){return new Promise((e=>{requestAnimationFrame((()=>{requestAnimationFrame(e)}))}))}function x(e){return Promise.all(e.getAnimations().map((e=>e.finished)))}var a=class extends e{connect(){setTimeout((()=>{T(this.element)}),this.showDelayValue),this.hasDismissAfterValue&&setTimeout((()=>{this.close()}),this.dismissAfterValue)}close(){b(this.element).then((()=>{this.element.remove()}))}};s(a,"values",{dismissAfter:Number,showDelay:{type:Number,default:0}});var i=class extends e{connect(){this.timeout=null}save(){clearTimeout(this.timeout),this.timeout=setTimeout((()=>{this.statusTarget.textContent=this.submittingTextValue,this.formTarget.requestSubmit()}),this.submitDurationValue)}success(){this.setStatus(this.successTextValue)}error(){this.setStatus(this.errorTextValue)}setStatus(e){this.statusTarget.textContent=e,this.timeout=setTimeout((()=>{this.statusTarget.textContent=""}),this.statusDurationValue)}};s(i,"targets",["form","status"]),s(i,"values",{submitDuration:{type:Number,default:1e3},statusDuration:{type:Number,default:2e3},submittingText:{type:String,default:"Saving..."},successText:{type:String,default:"Saved!"},errorText:{type:String,default:"Unable to save."}});var n=class extends e{update(){this.preview=this.colorTarget.value}set preview(e){this.previewTarget.style[this.styleValue]=e;let t=this._getContrastYIQ(e);this.styleValue==="color"?this.previewTarget.style.backgroundColor=t:this.previewTarget.style.color=t}_getContrastYIQ(e){e=e.replace("#","");let t=128,a=parseInt(e.substr(0,2),16),i=parseInt(e.substr(2,2),16),n=parseInt(e.substr(4,2),16);return(a*299+i*587+n*114)/1e3>=t?"#000":"#fff"}};s(n,"targets",["preview","color"]),s(n,"values",{style:{type:String,default:"backgroundColor"}});var o=class extends e{connect(){document.addEventListener("turbo:before-cache",this.beforeCache.bind(this))}disconnect(){document.removeEventListener("turbo:before-cache",this.beforeCache.bind(this))}openValueChanged(){r(this.menuTarget,this.openValue,this.transitionOptions),this.openValue===!0&&this.hasMenuItemTarget&&this.menuItemTargets[0].focus()}show(){this.openValue=!0}close(){this.openValue=!1}hide(e){this.closeOnClickOutsideValue&&e.target.nodeType&&this.element.contains(e.target)===!1&&this.openValue&&(this.openValue=!1),this.closeOnEscapeValue&&e.key==="Escape"&&this.openValue&&(this.openValue=!1)}toggle(){this.openValue=!this.openValue}nextItem(e){e.preventDefault(),this.menuItemTargets[this.nextIndex].focus()}previousItem(e){e.preventDefault(),this.menuItemTargets[this.previousIndex].focus()}get currentItemIndex(){return this.menuItemTargets.indexOf(document.activeElement)}get nextIndex(){return Math.min(this.currentItemIndex+1,this.menuItemTargets.length-1)}get previousIndex(){return Math.max(this.currentItemIndex-1,0)}get transitionOptions(){return{enter:this.hasEnterClass?this.enterClass:"transition ease-out duration-100",enterFrom:this.hasEnterFromClass?this.enterFromClass:"transform opacity-0 scale-95",enterTo:this.hasEnterToClass?this.enterToClass:"transform opacity-100 scale-100",leave:this.hasLeaveClass?this.leaveClass:"transition ease-in duration-75",leaveFrom:this.hasLeaveFromClass?this.leaveFromClass:"transform opacity-100 scale-100",leaveTo:this.hasLeaveToClass?this.leaveToClass:"transform opacity-0 scale-95",toggleClass:this.hasToggleClass?this.toggleClass:"hidden"}}beforeCache(){this.openValue=!1,this.menuTarget.classList.add("hidden")}};s(o,"targets",["menu","button","menuItem"]),s(o,"values",{open:{type:Boolean,default:!1},closeOnEscape:{type:Boolean,default:!0},closeOnClickOutside:{type:Boolean,default:!0}}),s(o,"classes",["enter","enterFrom","enterTo","leave","leaveFrom","leaveTo","toggle"]);var l=class extends e{connect(){this.openValue&&this.open(),document.addEventListener("turbo:before-cache",this.beforeCache.bind(this))}disconnect(){document.removeEventListener("turbo:before-cache",this.beforeCache.bind(this))}open(){this.dialogTarget.showModal()}close(){this.dialogTarget.setAttribute("closing",""),Promise.all(this.dialogTarget.getAnimations().map((e=>e.finished))).then((()=>{this.dialogTarget.removeAttribute("closing"),this.dialogTarget.close()}))}backdropClose(e){e.target.nodeName=="DIALOG"&&this.close()}show(){this.dialogTarget.show()}hide(){this.close()}beforeCache(){this.close()}};s(l,"targets",["dialog"]),s(l,"values",{open:Boolean});var h=class extends e{openValueChanged(){r(this.contentTarget,this.openValue),this.shouldAutoDismiss&&this.scheduleDismissal()}show(e){this.shouldAutoDismiss&&this.scheduleDismissal(),this.openValue=!0}hide(){this.openValue=!1}toggle(){this.openValue=!this.openValue}get shouldAutoDismiss(){return this.openValue&&this.hasDismissAfterValue}scheduleDismissal(){this.hasDismissAfterValue&&(this.cancelDismissal(),this.timeoutId=setTimeout((()=>{this.hide(),this.timeoutId=void 0}),this.dismissAfterValue))}cancelDismissal(){typeof this.timeoutId=="number"&&(clearTimeout(this.timeoutId),this.timeoutId=void 0)}};s(h,"targets",["content"]),s(h,"values",{dismissAfter:Number,open:{type:Boolean,default:!1}});var u=class extends e{connect(){this.openValue&&this.open(),document.addEventListener("turbo:before-cache",this.beforeCache.bind(this))}disconnect(){document.removeEventListener("turbo:before-cache",this.beforeCache.bind(this))}open(){this.dialogTarget.showModal()}close(){this.dialogTarget.setAttribute("closing",""),Promise.all(this.dialogTarget.getAnimations().map((e=>e.finished))).then((()=>{this.dialogTarget.removeAttribute("closing"),this.dialogTarget.close()}))}backdropClose(e){e.target.nodeName=="DIALOG"&&this.close()}show(){this.open()}hide(){this.close()}beforeCache(){this.close()}};s(u,"targets",["dialog"]),s(u,"values",{open:Boolean});var c=class extends e{initialize(){this.anchor&&(this.indexValue=this.tabTargets.findIndex((e=>e.id===this.anchor)))}connect(){this.showTab()}change(e){e.currentTarget.tagName==="SELECT"?this.indexValue=e.currentTarget.selectedIndex:e.currentTarget.dataset.index?this.indexValue=e.currentTarget.dataset.index:e.currentTarget.dataset.id?this.indexValue=this.tabTargets.findIndex((t=>t.id==e.currentTarget.dataset.id)):this.indexValue=this.tabTargets.indexOf(e.currentTarget)}nextTab(){this.indexValue=Math.min(this.indexValue+1,this.tabsCount-1)}previousTab(){this.indexValue=Math.max(this.indexValue-1,0)}firstTab(){this.indexValue=0}lastTab(){this.indexValue=this.tabsCount-1}indexValueChanged(){if(this.showTab(),this.dispatch("tab-change",{target:this.tabTargets[this.indexValue],detail:{activeIndex:this.indexValue}}),this.updateAnchorValue){let e=this.tabTargets[this.indexValue].id;if(this.scrollToAnchorValue)location.hash=e;else{let t=window.location.href.split("#")[0]+"#"+e;history.replaceState({},document.title,t)}}}showTab(){this.panelTargets.forEach(((e,t)=>{let a=this.tabTargets[t];t===this.indexValue?(e.classList.remove("hidden"),a.ariaSelected="true",a.dataset.active=!0,this.hasInactiveTabClass&&a?.classList?.remove(...this.inactiveTabClasses),this.hasActiveTabClass&&a?.classList?.add(...this.activeTabClasses)):(e.classList.add("hidden"),a.ariaSelected=null,delete a.dataset.active,this.hasActiveTabClass&&a?.classList?.remove(...this.activeTabClasses),this.hasInactiveTabClass&&a?.classList?.add(...this.inactiveTabClasses))})),this.hasSelectTarget&&(this.selectTarget.selectedIndex=this.indexValue),this.scrollActiveTabIntoViewValue&&this.scrollToActiveTab()}scrollToActiveTab(){let e=this.element.querySelector("[aria-selected]");e&&e.scrollIntoView({inline:"center"})}get tabsCount(){return this.tabTargets.length}get anchor(){return document.URL.split("#").length>1?document.URL.split("#")[1]:null}};s(c,"classes",["activeTab","inactiveTab"]),s(c,"targets",["tab","panel","select"]),s(c,"values",{index:0,updateAnchor:Boolean,scrollToAnchor:Boolean,scrollActiveTabIntoView:Boolean});var d=class extends e{toggle(e){this.openValue=!this.openValue,this.animate()}toggleInput(e){this.openValue=e.target.checked,this.animate()}hide(){this.openValue=!1,this.animate()}show(){this.openValue=!0,this.animate()}animate(){this.toggleableTargets.forEach((e=>{r(e,this.openValue)}))}};s(d,"targets",["toggleable"]),s(d,"values",{open:{type:Boolean,default:!1}});export{a as Alert,i as Autosave,n as ColorPreview,o as Dropdown,l as Modal,h as Popover,u as Slideover,c as Tabs,d as Toggle};
|
2
|
-
|
@@ -1,21 +0,0 @@
|
|
1
|
-
<%= panda_cms_form_with model: menu, url: admin_menus_path, method: :post do |form| %>
|
2
|
-
<%= form.text_field :name %>
|
3
|
-
|
4
|
-
<div data-controller="nested-form" nested_form_wrapper_selector_value=".nested-form-wrapper">
|
5
|
-
<template data-nested-form-target="template">
|
6
|
-
<%= form.fields_for :menu_items, PandaCms::MenuItem.new, child_index: 'NEW_RECORD' do |item| %>
|
7
|
-
<%= render "menu_item_fields", form: item %>
|
8
|
-
<% end %>
|
9
|
-
</template>
|
10
|
-
|
11
|
-
<%= form.fields_for :menu_items do |item| %>
|
12
|
-
<%= render "menu_item_fields", form: item %>
|
13
|
-
<% end %>
|
14
|
-
|
15
|
-
<div data-nested-form-target="target"></div>
|
16
|
-
|
17
|
-
<%= render PandaCms::Admin::ButtonComponent.new(text: "Add Menu Item", action: :add, data: {action: "nested-form#add"}, size: :small) %>
|
18
|
-
</div>
|
19
|
-
|
20
|
-
<%= form.submit "Create" %>
|
21
|
-
<% end %>
|
@@ -1,7 +0,0 @@
|
|
1
|
-
<div class="p-4 mt-2 mb-4 rounded-md border nested-form-wrapper border-grey-900" data-new-record="<%= form.object.new_record? %>">
|
2
|
-
<%= form.text_field :text %>
|
3
|
-
<%= form.text_field :external_url %>
|
4
|
-
<%= form.collection_select :panda_cms_page_id, PandaCms::Page.all, :id, :title, include_blank: true %>
|
5
|
-
<%= render PandaCms::Admin::ButtonComponent.new(text: "Remove Menu Item", action: :delete, data: {action: "nested-form#remove"}, size: :small) %>
|
6
|
-
<%= form.hidden_field :_destroy %>
|
7
|
-
</div>
|
@@ -1,58 +0,0 @@
|
|
1
|
-
<%= render PandaCms::Admin::ContainerComponent.new do |component| %>
|
2
|
-
<% component.with_heading(text: "Edit Menu", level: 1) %>
|
3
|
-
|
4
|
-
<%= panda_cms_form_with model: @menu, url: admin_menu_path, method: :put do |form| %>
|
5
|
-
<%= form.text_field :name %>
|
6
|
-
|
7
|
-
<% if @menu.kind == "static" %>
|
8
|
-
<div data-controller="nested-form" data-nested-form-wrapper-selector-value=".nested-form-wrapper">
|
9
|
-
<template data-nested-form-target="template">
|
10
|
-
<%= form.fields_for :menu_items, PandaCms::MenuItem.new, child_index: "NEW_RECORD" do |item| %>
|
11
|
-
<%= render "menu_item_fields", form: item %>
|
12
|
-
<% end %>
|
13
|
-
</template>
|
14
|
-
|
15
|
-
<% if @menu.menu_items.count > 0 %>
|
16
|
-
<%= form.fields_for :menu_items, @menu.menu_items.sort_by(&:lft) do |item| %>
|
17
|
-
<%= render "menu_item_fields", form: item %>
|
18
|
-
<% end %>
|
19
|
-
<% end %>
|
20
|
-
|
21
|
-
<div data-nested-form-target="target"></div>
|
22
|
-
|
23
|
-
<%= render PandaCms::Admin::ButtonComponent.new(text: "Add Menu Item", action: :add, data: {action: "nested-form#add"}, size: :small) %>
|
24
|
-
</div>
|
25
|
-
<% else %>
|
26
|
-
<table class="-mx-3 min-w-full divide-y divide-gray-300">
|
27
|
-
<thead>
|
28
|
-
<tr>
|
29
|
-
<th scope="col" class="py-3.5 px-3 text-sm font-semibold text-left text-gray-900">Text</th>
|
30
|
-
<th scope="col" class="py-3.5 px-3 text-sm font-semibold text-left text-gray-900">Page</th>
|
31
|
-
<th scope="col" class="py-3.5 px-3 text-sm font-semibold text-left text-gray-900">External Link</th>
|
32
|
-
</tr>
|
33
|
-
</thead>
|
34
|
-
<tbody class="bg-white divide-y divide-gray-200">
|
35
|
-
<% @menu.menu_items.root.self_and_descendants.each do |menu_item| %>
|
36
|
-
<tr>
|
37
|
-
<td class="py-5 pr-3 pl-3 text-sm whitespace-nowrap">
|
38
|
-
<div class="flex items-center">
|
39
|
-
<div class="<%= table_indent(menu_item) %>">
|
40
|
-
<div class="font-medium text-gray-900"><%= menu_item.text %></div>
|
41
|
-
</div>
|
42
|
-
</div>
|
43
|
-
</td>
|
44
|
-
<td class="py-5 px-3 text-sm text-gray-500 whitespace-nowrap">
|
45
|
-
<div class="text-gray-900"><%= menu_item.page.title %></div>
|
46
|
-
</td>
|
47
|
-
<td class="py-5 px-3 text-sm text-gray-500 whitespace-nowrap">
|
48
|
-
<div class="text-gray-900"><%= menu_item.external_url %></div>
|
49
|
-
</td>
|
50
|
-
</tr>
|
51
|
-
<% end %>
|
52
|
-
</tbody>
|
53
|
-
</table>
|
54
|
-
<% end %>
|
55
|
-
|
56
|
-
<%= form.button %>
|
57
|
-
<% end %>
|
58
|
-
<% end %>
|
@@ -1,7 +0,0 @@
|
|
1
|
-
class AddStatusToPandaCmsPages < ActiveRecord::Migration[7.1]
|
2
|
-
def change
|
3
|
-
create_enum :panda_cms_page_status, ["active", "draft", "hidden", "archived"]
|
4
|
-
add_column :panda_cms_pages, :status, :panda_cms_page_status, default: "active", null: false
|
5
|
-
add_index :panda_cms_pages, :status
|
6
|
-
end
|
7
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
import { Application as PandaCmsApplication } from "@hotwired/stimulus";
|
2
|
-
|
3
|
-
const panda_cms = PandaCmsApplication.start();
|
4
|
-
|
5
|
-
// Configure Stimulus development experience
|
6
|
-
panda_cms.debug = location.hostname === "localhost";
|
7
|
-
window.pandaStimulus = panda_cms;
|
8
|
-
|
9
|
-
export { panda_cms };
|
10
|
-
|
11
|
-
// Eager load all controllers defined in the import map under controllers/**/*_controller
|
12
|
-
import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading";
|
13
|
-
eagerLoadControllersFrom("panda_cms/controllers", panda_cms);
|
14
|
-
|
15
|
-
import {
|
16
|
-
Alert,
|
17
|
-
Autosave,
|
18
|
-
ColorPreview,
|
19
|
-
Dropdown,
|
20
|
-
Modal,
|
21
|
-
Tabs,
|
22
|
-
Popover,
|
23
|
-
Toggle,
|
24
|
-
Slideover,
|
25
|
-
} from "panda_cms/vendor/tailwindcss-stimulus-components";
|
26
|
-
panda_cms.register("alert", Alert);
|
27
|
-
panda_cms.register("autosave", Autosave);
|
28
|
-
panda_cms.register("color-preview", ColorPreview);
|
29
|
-
panda_cms.register("dropdown", Dropdown);
|
30
|
-
panda_cms.register("modal", Modal);
|
31
|
-
panda_cms.register("popover", Popover);
|
32
|
-
panda_cms.register("slideover", Slideover);
|
33
|
-
panda_cms.register("tabs", Tabs);
|
34
|
-
panda_cms.register("toggle", Toggle);
|
35
|
-
|
36
|
-
import RailsNestedForm from "panda_cms/vendor/stimulus-components-rails-nested-form";
|
37
|
-
panda_cms.register("nested-form", RailsNestedForm);
|
@@ -1,19 +0,0 @@
|
|
1
|
-
import { Controller as PandaCmsController } from "@hotwired/stimulus"
|
2
|
-
|
3
|
-
export default class extends PandaCmsController {
|
4
|
-
static targets = ["pandaCmsMenu"]
|
5
|
-
static values = {
|
6
|
-
open: { type: Boolean, default: false }
|
7
|
-
}
|
8
|
-
|
9
|
-
toggle(event) {
|
10
|
-
this.openValue = !this.openValue
|
11
|
-
this.animate()
|
12
|
-
}
|
13
|
-
|
14
|
-
animate() {
|
15
|
-
this.toggleableTargets.forEach(target => {
|
16
|
-
transition(target, this.openValue)
|
17
|
-
})
|
18
|
-
}
|
19
|
-
}
|
@@ -1,23 +0,0 @@
|
|
1
|
-
import { Controller as PandaCmsController } from "@hotwired/stimulus"
|
2
|
-
export default class extends PandaCmsController {
|
3
|
-
static targets = [ "existing_root", "input_select", "input_text", "output_text" ]
|
4
|
-
|
5
|
-
connect() {
|
6
|
-
}
|
7
|
-
|
8
|
-
generatePath() {
|
9
|
-
this.output_textTarget.value = "/" + this.createSlug(this.input_textTarget.value);
|
10
|
-
}
|
11
|
-
|
12
|
-
setPrePath() {
|
13
|
-
this.parent_slugs = this.input_selectTarget.options[this.input_selectTarget.selectedIndex].text.match(/.*\((.*)\)$/)[1];
|
14
|
-
this.output_textTarget.previousSibling.innerHTML = (this.existing_rootTarget.value + this.parent_slugs).replace(/\/$/, '');;
|
15
|
-
}
|
16
|
-
|
17
|
-
createSlug(input) {
|
18
|
-
return input.toLowerCase().trim()
|
19
|
-
.replace(/[^\w\s-]/g, "-")
|
20
|
-
.replace(/&/, "and")
|
21
|
-
.replace(/[\s_-]+/g, "-");
|
22
|
-
}
|
23
|
-
}
|