Skip to content

Commit c4107a4

Browse files
matdavetheboxer
andauthored
theme-settings (#514)
* Init for theme settings * Re-render element on theme setting change * - full page theme editor - add breadcrumbs * adding sub-menu styles for theme-settings * add breadcrumbs for MODX 2 * fix broken dialog boxes in elfinder * Saving & rendering * add theme settings model for 2.x * Saving & Rendering in 2.x * Save to context settings for non-global theme settings * working on twig output for theme settings Signed-off-by: matdave <[email protected]> * more tweaks to theme-settings Signed-off-by: matdave <[email protected]> * adjusting look of fred and adding some basic documentation for theme settings Signed-off-by: matdave <[email protected]> * add global flag to the documentation. Signed-off-by: matdave <[email protected]> * add global flag to the documentation. Signed-off-by: matdave <[email protected]> * Remove comments --------- Signed-off-by: matdave <[email protected]> Co-authored-by: Jan Peca <[email protected]>
1 parent 234b888 commit c4107a4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+2189
-125
lines changed

Writerside/topics/themer/cmp/cmp_themes.md

+48-3
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,54 @@ When you create a Theme, Fred will automatically create a directory named for th
2727

2828
### Default Element
2929

30-
The default element setting allows you to chose a default Fred Element and target area for placing the content on existing documents. The setting is formatted as `ID|target` where ID is the identification number of the Fred Element and the target is the HTML object within containing a `data-fred-name` attribute. This is useful for converting a standard resource to Fred, as it will place the existing content in the default element.
31-
32-
If you aren't finding the identification number of the Fred Element, right-click on the top of the element grid and make sure the ID column is selected.
30+
The default element setting allows you to choose a default Fred Element and target area for placing the content on existing documents. The setting is formatted as `UUID|target` where UUID is the universally unique identification number of the Fred Element and the target is the HTML object within containing a `data-fred-name` attribute. This is useful for converting a standard resource to Fred, as it will place the existing content in the default element.
31+
32+
If you aren't finding the UUID of the Fred Element, open an element and look for a display field labeled "UUID".
33+
34+
### Theme Settings
35+
36+
Themes can have settings that are used to configure the theme. These settings are stored in the "Settings" section of the Theme. The settings are stored as a JSON object and can be accessed in the theme's twig templates using the `theme_setting` object. For example, if you have a setting named `logo`, you can access it in a template like this:
37+
38+
```twig
39+
<img src="{{ theme_setting.logo }}" />
40+
```
41+
42+
Theme settings are saved in the system settings and can be accessed outside of fred using the theme's Setting Prefix. For example, if the theme's setting prefix is `my_theme`, you can access the setting `logo` in a chunk like this:
43+
44+
```html
45+
<img src="[[++fred.theme.my_theme.setting.logo]]" alt="[[++site_name]]" />
46+
```
47+
48+
Theme settings can use any of the [setting types](settings.md#available-settings-types) described in the option groups documentation.
49+
50+
#### Format
51+
52+
The theme settings are formatted as a JSON array. Here is an example of a theme setting:
53+
54+
```json
55+
[
56+
{
57+
"group": "Look and Feel",
58+
"settings": [
59+
{
60+
"name": "site_color",
61+
"type": "colorswatch",
62+
"options": [
63+
"lightcoral",
64+
"red",
65+
"black"
66+
]
67+
},
68+
{
69+
"name": "site_logo",
70+
"type": "image"
71+
}
72+
]
73+
}
74+
]
75+
```
76+
77+
One additional option that is specific to Theme Settings is that each setting can have a `"global": false` flag. This flag will cause the setting to save to the context it is used in, rather than the system settings. This is useful for multi-context sites where you want to have different settings for different contexts.
3378

3479
### Elements
3580

Writerside/topics/themer/elements/attributes.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ The value of this attribute has to be unique in each Element, but you can have m
2828
<p data-fred-name="description">Default value</p>
2929

3030
<!-- Editable image -->
31-
<img src="http://via.placeholder.com/450x150" data-fred-name="header-image">
31+
<img src="http://placehold.co/450x150" data-fred-name="header-image">
3232
```
3333

3434
## data-fred-editable
@@ -48,7 +48,7 @@ Defines other HTML attributes (comma separated) to save with the content of the
4848
### Example {id="example_3"}
4949

5050
```html
51-
<img src="http://via.placeholder.com/450x150" alt="Default Alt" data-fred-name="header-image" data-fred-attrs="alt,title">
51+
<img src="http://placehold.co/450x150" alt="Default Alt" data-fred-name="header-image" data-fred-attrs="alt,title">
5252
```
5353

5454
## data-fred-render
@@ -124,7 +124,7 @@ Identical to `data-fred-media-source` but only for images.
124124
### Example {id="example_8"}
125125

126126
```html
127-
<img src="http://via.placeholder.com/450x150" data-fred-name="header-image" data-fred-image-media-source="Blogs,Images">
127+
<img src="http://placehold.co/450x150" data-fred-name="header-image" data-fred-image-media-source="Blogs,Images">
128128
```
129129

130130
## data-fred-block-class

Writerside/topics/themer/elements/markup.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Template Variables can be accessed in the element markup object with the prefix
2323
<!-- Simple Element -->
2424
<div class="panel">
2525
<p data-fred-name="header_text">Default Value</p>
26-
<img src="http://via.placeholder.com/450x150" data-fred-name="header_image">
26+
<img src="http://placehold.co/450x150" data-fred-name="header_image">
2727
</div>
2828

2929
<!-- Enhanced Element -->

Writerside/topics/themer/themes.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Basic Tutorial Tutorial
1+
# Basic Tutorial
22

33
Once you have created a design you are happy with, it is straightforward to build a Theme to share. To start creating a theme, follow the steps below:
44

_build/assets/js/Actions/blueprints.js

-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ export const createBlueprint = (name, description, category, rank, isPublic, dat
3939
};
4040

4141
export const createBlueprintCategory = (name, rank, isPublic, templates) => {
42-
console.log({name, rank, isPublic, templates});
4342
return fetch(`${fredConfig.config.assetsUrl}endpoints/ajax.php?modx=${fredConfig.config.modxVersion}&action=blueprints-create-category`, {
4443
method: "post",
4544
headers: {

_build/assets/js/Components/Sidebar/PageSettings.js

+147
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@ export default class PageSettings extends SidebarPlugin {
1919
this.setTVWithEmitter = this.setTVWithEmitter.bind(this);
2020
this.setMultiTVWithEmitter = this.setMultiTVWithEmitter.bind(this);
2121
this.addTVChangeListener = this.addTVChangeListener.bind(this);
22+
this.setThemeSettingWithEmitter = this.setThemeSettingWithEmitter.bind(this);
23+
this.setMultiThemeSettingWithEmitter = this.setMultiThemeSettingWithEmitter.bind(this);
2224

2325
this.pageSettings = fredConfig.pageSettings;
26+
this.themeSettings = fredConfig.themeSettings;
2427
this.content = this.render();
2528
}
2629

@@ -33,6 +36,8 @@ export default class PageSettings extends SidebarPlugin {
3336

3437
settingsForm.appendChild(this.getGeneralFields());
3538

39+
settingsForm.appendChild(this.getThemeSettingFields());
40+
3641
if (fredConfig.permission.fred_settings_advanced) {
3742
settingsForm.appendChild(this.getAdvancedFields());
3843
}
@@ -157,6 +162,122 @@ export default class PageSettings extends SidebarPlugin {
157162
return advancedList;
158163
}
159164

165+
getThemeSettingFields() {
166+
const advancedList = dl();
167+
168+
const advancedTab = dt('fred.fe.page_settings.theme_settings', ['fred--accordion-cog'], e => {
169+
const activeTabs = advancedList.parentElement.querySelectorAll('dt.active');
170+
171+
const isActive = advancedTab.classList.contains('active');
172+
173+
for (let tab of activeTabs) {
174+
tab.classList.remove('active');
175+
}
176+
177+
if (!isActive) {
178+
advancedTab.classList.add('active');
179+
e.stopPropagation();
180+
emitter.emit('fred-sidebar-dt-active', advancedTab, advancedContent);
181+
}
182+
183+
});
184+
185+
const advancedContent = dd();
186+
const advancedHeader = h3('fred.fe.page_settings.theme_settings');
187+
const fields = fieldSet(['fred--page_settings_form_theme_settings']);
188+
189+
this.themeSettings.forEach(setting => {
190+
if (setting.group && setting.settings) {
191+
const groupEl = this.renderThemeSettingsGroup(setting);
192+
if (groupEl !== false) {
193+
fields.appendChild(groupEl);
194+
}
195+
} else {
196+
const settingEl = this.renderThemeSetting(setting);
197+
if (settingEl !== false) {
198+
fields.appendChild(settingEl);
199+
}
200+
}
201+
});
202+
203+
advancedContent.appendChild(advancedHeader);
204+
advancedContent.appendChild(fields);
205+
advancedList.appendChild(advancedTab);
206+
advancedList.appendChild(advancedContent);
207+
208+
return advancedList;
209+
}
210+
211+
renderThemeSettingsGroup(group) {
212+
const content = dl();
213+
214+
const settingGroup = dt(group.group, [], (e, el) => {
215+
const activeTabs = content.parentElement.querySelectorAll('dt.active');
216+
217+
const isActive = el.classList.contains('active');
218+
219+
for (let tab of activeTabs) {
220+
tab.classList.remove('active');
221+
}
222+
223+
if (!isActive) {
224+
el.classList.add('active');
225+
e.stopPropagation();
226+
}
227+
});
228+
const settingGroupContent = dd();
229+
230+
group.settings.forEach(setting => {
231+
const settingEl = this.renderThemeSetting(setting);
232+
if (settingEl !== false) {
233+
settingGroupContent.appendChild(settingEl);
234+
}
235+
});
236+
237+
content.appendChild(settingGroup);
238+
content.appendChild(settingGroupContent);
239+
240+
return content;
241+
}
242+
243+
renderThemeSetting(setting) {
244+
const defaultValue = setting.value;
245+
246+
switch (setting.type) {
247+
case 'select':
248+
return ui.select(setting, defaultValue, this.setThemeSettingWithEmitter);
249+
case 'toggle':
250+
return ui.toggle(setting, defaultValue, this.setThemeSettingWithEmitter);
251+
case 'colorswatch':
252+
return ui.colorSwatch(setting, defaultValue, this.setThemeSettingWithEmitter);
253+
case 'colorpicker':
254+
return ui.colorPicker(setting, defaultValue, this.setThemeSettingWithEmitter);
255+
case 'slider':
256+
return ui.slider(setting, defaultValue, this.setThemeSettingWithEmitter);
257+
case 'page':
258+
return ui.page(setting, defaultValue, this.setThemeSettingWithEmitter);
259+
case 'chunk':
260+
return ui.chunk(setting, defaultValue, this.setThemeSettingWithEmitter);
261+
case 'tagger':
262+
return ui.tagger(setting, defaultValue, this.setThemeSettingWithEmitter);
263+
case 'image':
264+
return ui.image(setting, defaultValue, this.setThemeSettingWithEmitter);
265+
case 'file': {
266+
return ui.file(setting, defaultValue, this.setThemeSettingWithEmitter);
267+
}
268+
case 'folder': {
269+
return ui.folder(setting, defaultValue, this.setThemeSettingWithEmitter);
270+
}
271+
case 'togglegroup':
272+
case 'checkbox':
273+
return ui.toggleGroup(setting, defaultValue, this.setMultiThemeSettingWithEmitter);
274+
case 'textarea':
275+
return ui.area(setting, defaultValue, this.setThemeSettingWithEmitter);
276+
default:
277+
return ui.text(setting, defaultValue, this.setThemeSettingWithEmitter);
278+
}
279+
}
280+
160281
getTaggerFields() {
161282
const taggerList = dl();
162283

@@ -299,6 +420,11 @@ export default class PageSettings extends SidebarPlugin {
299420
}
300421
}
301422

423+
setThemeSetting(name, value) {
424+
fredConfig.setThemeSettingValue(name, value);
425+
emitter.emit('fred-content-changed');
426+
}
427+
302428
getSetting(name, namespace = null) {
303429
if (namespace) {
304430
if (!this.pageSettings[namespace]) this.pageSettings[namespace] = {};
@@ -309,6 +435,27 @@ export default class PageSettings extends SidebarPlugin {
309435
}
310436
}
311437

438+
setThemeSettingWithEmitter(name, value, input) {
439+
this.setThemeSetting(name, value);
440+
441+
emitter.emit('fred-theme-setting-change', name, value, valueParser(value), input);
442+
}
443+
444+
setMultiThemeSettingWithEmitter(name, value, input) {
445+
let oValue = this.themeSettings[name];
446+
oValue = (oValue) ? oValue.split('||') : [];
447+
let nValue = [value];
448+
oValue.forEach((ov) => {
449+
if(value !== ov){
450+
nValue.push(ov);
451+
}
452+
});
453+
nValue = this.trim(nValue.join('||'), '|');
454+
this.setThemeSetting(name, nValue);
455+
456+
emitter.emit('fred-theme-setting-change', name, value, valueParser(value), input);
457+
}
458+
312459
setSettingWithEmitter(name, value, input) {
313460
this.setSetting(name, value);
314461

0 commit comments

Comments
 (0)