@silexlabs/silex 3.4.0 → 3.5.1-1
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.
- package/.silex.js +0 -3
- package/dist/client/client/config.d.ts +8 -0
- package/dist/client/client/grapesjs/cms/DataSource.d.ts +43 -0
- package/dist/client/client/grapesjs/cms/blocks.d.ts +2 -0
- package/dist/client/client/grapesjs/cms/buttons.d.ts +2 -0
- package/dist/client/client/grapesjs/cms/collection-pages.d.ts +4 -0
- package/dist/client/client/grapesjs/cms/config.d.ts +9 -0
- package/dist/client/client/grapesjs/cms/filters.d.ts +3 -0
- package/dist/client/client/grapesjs/cms/index.d.ts +44 -0
- package/dist/client/client/grapesjs/cms/liquid.d.ts +59 -0
- package/dist/client/client/grapesjs/cms/page-settings.d.ts +6 -0
- package/dist/client/client/grapesjs/cms/publication.d.ts +60 -0
- package/dist/client/client/grapesjs/cms/site-settings.d.ts +3 -0
- package/dist/client/client/grapesjs/cms/states.d.ts +8 -0
- package/dist/client/client/grapesjs/cms/traits.d.ts +8 -0
- package/dist/client/client/grapesjs/settings.d.ts +12 -3
- package/dist/client/client/grapesjs/view-buttons.d.ts +2 -1
- package/dist/client/client/utils.d.ts +1 -0
- package/dist/client/constants.d.ts +2 -1
- package/dist/client/css/admin.css +88 -14
- package/dist/client/index.html +2 -2
- package/dist/client/js/main.js +1968 -264
- package/dist/client/types.d.ts +3 -1
- package/dist/plugins/client/plugins/client/template.js +1 -1
- package/dist/plugins/client/plugins/client/template.js.map +1 -1
- package/dist/plugins/client/types.d.ts +3 -1
- package/dist/plugins/client/types.js +11 -8
- package/dist/plugins/client/types.js.map +1 -1
- package/dist/plugins/server/constants.d.ts +2 -1
- package/dist/plugins/server/constants.js +3 -2
- package/dist/plugins/server/constants.js.map +1 -1
- package/dist/plugins/server/plugins/server/FtpConnector.js +15 -20
- package/dist/plugins/server/plugins/server/FtpConnector.js.map +1 -1
- package/dist/plugins/server/plugins/server/GitlabConnector.js +34 -7
- package/dist/plugins/server/plugins/server/GitlabConnector.js.map +1 -1
- package/dist/plugins/server/server/connectors/FsStorage.js +16 -20
- package/dist/plugins/server/server/connectors/FsStorage.js.map +1 -1
- package/dist/plugins/server/server/utils/websiteDataSerialization.d.ts +4 -0
- package/dist/plugins/server/server/utils/websiteDataSerialization.js +21 -12
- package/dist/plugins/server/server/utils/websiteDataSerialization.js.map +1 -1
- package/dist/plugins/server/types.d.ts +3 -1
- package/dist/plugins/server/types.js +12 -9
- package/dist/plugins/server/types.js.map +1 -1
- package/dist/server/constants.js +3 -2
- package/dist/server/server/connectors/FsStorage.js +14 -18
- package/dist/server/server/utils/websiteDataSerialization.js +16 -11
- package/dist/server/types.js +6 -2
- package/package.json +15 -10
- package/src/css/_variables.scss +2 -1
- package/src/css/grapesjs-plugins.scss +31 -0
- package/src/css/grapesjs.scss +15 -0
- package/src/css/page-panel.scss +1 -1
- package/src/css/silex.scss +64 -5
- package/src/ts/client/config.ts +23 -0
- package/src/ts/client/grapesjs/breadcrumbs.ts +3 -2
- package/src/ts/client/grapesjs/cms/DataSource.ts +333 -0
- package/src/ts/client/grapesjs/cms/blocks.ts +124 -0
- package/src/ts/client/grapesjs/cms/buttons.ts +137 -0
- package/src/ts/client/grapesjs/cms/collection-pages.ts +205 -0
- package/src/ts/client/grapesjs/cms/config.ts +47 -0
- package/src/ts/client/grapesjs/cms/filters.ts +53 -0
- package/src/ts/client/grapesjs/cms/index.ts +130 -0
- package/src/ts/client/grapesjs/cms/liquid.mock.ts +181 -0
- package/src/ts/client/grapesjs/cms/liquid.test.ts +239 -0
- package/src/ts/client/grapesjs/cms/liquid.ts +325 -0
- package/src/ts/client/grapesjs/cms/page-settings.ts +285 -0
- package/src/ts/client/grapesjs/cms/publication.test.ts +300 -0
- package/src/ts/client/grapesjs/cms/publication.ts +708 -0
- package/src/ts/client/grapesjs/cms/site-settings.ts +79 -0
- package/src/ts/client/grapesjs/cms/states.ts +125 -0
- package/src/ts/client/grapesjs/cms/traits.ts +95 -0
- package/src/ts/client/grapesjs/flex.ts +59 -39
- package/src/ts/client/grapesjs/img.ts +1 -1
- package/src/ts/client/grapesjs/index.ts +77 -4
- package/src/ts/client/grapesjs/internal-links.ts +4 -2
- package/src/ts/client/grapesjs/page-panel.ts +8 -7
- package/src/ts/client/grapesjs/sectors.ts +18 -10
- package/src/ts/client/grapesjs/settings.ts +252 -101
- package/src/ts/client/grapesjs/storage.ts +6 -1
- package/src/ts/client/grapesjs/view-buttons.ts +39 -3
- package/src/ts/client/utils.ts +15 -2
- package/src/ts/constants.ts +2 -1
- package/src/ts/plugins/client/template.ts +1 -1
- package/src/ts/plugins/server/FtpConnector.test.ts +1 -0
- package/src/ts/plugins/server/FtpConnector.ts +20 -23
- package/src/ts/plugins/server/GitlabConnector.ts +40 -10
- package/src/ts/server/connectors/FsStorage.test.ts +3 -2
- package/src/ts/server/connectors/FsStorage.ts +21 -23
- package/src/ts/server/utils/websiteDataSerialization.test.ts +45 -13
- package/src/ts/server/utils/websiteDataSerialization.ts +23 -14
- package/src/ts/types.ts +6 -2
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { Editor } from 'grapesjs'
|
|
2
|
+
import { ClientConfig } from '../../config'
|
|
3
|
+
import { COMMAND_REFRESH, COMMAND_PREVIEW_ACTIVATE, COMMAND_PREVIEW_DEACTIVATE, DATA_SOURCE_CHANGED, DATA_SOURCE_DATA_LOAD_CANCEL, DATA_SOURCE_DATA_LOAD_END, DATA_SOURCE_DATA_LOAD_START, DATA_SOURCE_ERROR, COMMAND_PREVIEW_TOGGLE, PREVIEW_DEACTIVATED, PREVIEW_ACTIVATED } from '@silexlabs/grapesjs-data-source'
|
|
4
|
+
|
|
5
|
+
document.querySelector('head')?.insertAdjacentHTML('beforeend', `
|
|
6
|
+
<style>
|
|
7
|
+
.data-source-refresh {
|
|
8
|
+
&.fa-refresh:before {
|
|
9
|
+
content: "\\f021";
|
|
10
|
+
font-weight: 900;
|
|
11
|
+
}
|
|
12
|
+
&.fa-refresh:hover {
|
|
13
|
+
transform: rotate(180deg);
|
|
14
|
+
transition: transform 0.5s;
|
|
15
|
+
}
|
|
16
|
+
&.fa-spinner:before {
|
|
17
|
+
content: "\\f110";
|
|
18
|
+
font-weight: 900;
|
|
19
|
+
}
|
|
20
|
+
&.fa-spinner {
|
|
21
|
+
animation: fa-spin 2s infinite linear;
|
|
22
|
+
}
|
|
23
|
+
&.fa-exclamation-triangle:before {
|
|
24
|
+
content: "\\f071";
|
|
25
|
+
font-weight: 900;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
.data-source-preview-toggle {
|
|
29
|
+
&.fa-table:before {
|
|
30
|
+
content: "\\f0ce";
|
|
31
|
+
font-weight: 900;
|
|
32
|
+
}
|
|
33
|
+
&.gjs-pn-active {
|
|
34
|
+
background-color: rgba(0, 0, 0, 0.15);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
.gjs-pn-btn.data-source-separator {
|
|
38
|
+
min-width: 1px;
|
|
39
|
+
height: 24px;
|
|
40
|
+
min-height: auto;
|
|
41
|
+
background-color: rgba(255, 255, 255, 0.2);
|
|
42
|
+
margin: 0 15px 0 10px;
|
|
43
|
+
padding: 0;
|
|
44
|
+
pointer-events: none;
|
|
45
|
+
cursor: default;
|
|
46
|
+
}
|
|
47
|
+
</style>
|
|
48
|
+
`)
|
|
49
|
+
|
|
50
|
+
const REFRESH_BUTTON_BASE_CLASS = 'fa fa-fw data-source-refresh'
|
|
51
|
+
|
|
52
|
+
export default function(editor: Editor/*, opts: EleventyPluginOptions*/): void {
|
|
53
|
+
// Get the panel to add buttons at specific positions
|
|
54
|
+
const panel = editor.Panels.getPanel('options')
|
|
55
|
+
const panelButtons = panel.get('buttons')
|
|
56
|
+
|
|
57
|
+
// Add data source buttons at the beginning of the options panel
|
|
58
|
+
panelButtons.add([{
|
|
59
|
+
id: 'refresh-data-sources',
|
|
60
|
+
className: `${REFRESH_BUTTON_BASE_CLASS} fa-refresh`,
|
|
61
|
+
command: () => {
|
|
62
|
+
// Refresh all data sources
|
|
63
|
+
editor.runCommand(COMMAND_REFRESH)
|
|
64
|
+
},
|
|
65
|
+
togglable: false,
|
|
66
|
+
attributes: { title: 'Refresh data sources (reload dynamic content) - Ctrl+Alt+R' },
|
|
67
|
+
}, {
|
|
68
|
+
id: 'toggle-data-source-preview',
|
|
69
|
+
className: 'fa fa-fw data-source-preview-toggle fa-table',
|
|
70
|
+
command: {
|
|
71
|
+
run: () => editor.runCommand(COMMAND_PREVIEW_ACTIVATE),
|
|
72
|
+
stop: () => editor.runCommand(COMMAND_PREVIEW_DEACTIVATE),
|
|
73
|
+
},
|
|
74
|
+
togglable: true,
|
|
75
|
+
active: true,
|
|
76
|
+
attributes: { title: 'Enable data source preview (Ctrl+Alt+V)' },
|
|
77
|
+
}, {
|
|
78
|
+
// Visual separator after data source buttons
|
|
79
|
+
id: 'data-source-separator',
|
|
80
|
+
className: 'data-source-separator',
|
|
81
|
+
command: () => {}, // No action on click
|
|
82
|
+
togglable: false,
|
|
83
|
+
attributes: { title: '' },
|
|
84
|
+
}], { at: 0 })
|
|
85
|
+
|
|
86
|
+
// Listen for preview activation/deactivation events to update the button icon and tooltip
|
|
87
|
+
editor.on(PREVIEW_ACTIVATED, () => {
|
|
88
|
+
const button = editor.Panels.getButton('options', 'toggle-data-source-preview')
|
|
89
|
+
if (button) {
|
|
90
|
+
button.set('active', true)
|
|
91
|
+
button.set('attributes', { title: 'Disable data source preview (Ctrl+Alt+V)' })
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
editor.on(PREVIEW_DEACTIVATED, () => {
|
|
95
|
+
const button = editor.Panels.getButton('options', 'toggle-data-source-preview')
|
|
96
|
+
if (button) {
|
|
97
|
+
button.set('active', false)
|
|
98
|
+
button.set('attributes', { title: 'Enable data source preview (Ctrl+Alt+V)' })
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
// Listen for preview activation/deactivation events to update the button tooltip and style
|
|
103
|
+
// The button now handles its own state, so these listeners are not needed.
|
|
104
|
+
editor.on(DATA_SOURCE_DATA_LOAD_START, () => {
|
|
105
|
+
const button = editor.Panels.getButton('options', 'refresh-data-sources')
|
|
106
|
+
if (button) {
|
|
107
|
+
button.set('className', `${REFRESH_BUTTON_BASE_CLASS} fa-spinner`)
|
|
108
|
+
button.set('title', 'Refreshing data sources (loading dynamic content)...')
|
|
109
|
+
}
|
|
110
|
+
})
|
|
111
|
+
editor.on(`
|
|
112
|
+
${ DATA_SOURCE_DATA_LOAD_END }
|
|
113
|
+
${ DATA_SOURCE_DATA_LOAD_CANCEL }
|
|
114
|
+
`, () => {
|
|
115
|
+
const button = editor.Panels.getButton('options', 'refresh-data-sources')
|
|
116
|
+
if (button) {
|
|
117
|
+
button.set('className', `${REFRESH_BUTTON_BASE_CLASS} fa-refresh`)
|
|
118
|
+
button.set('title', 'Refresh data sources (reload dynamic content) - Ctrl+Alt+R')
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
editor.on(DATA_SOURCE_ERROR, (error: Error) => {
|
|
122
|
+
console.error('Data source error', error)
|
|
123
|
+
const button = editor.Panels.getButton('options', 'refresh-data-sources')
|
|
124
|
+
if (button) {
|
|
125
|
+
button.set('className', `${REFRESH_BUTTON_BASE_CLASS} fa-exclamation-triangle`)
|
|
126
|
+
button.set('title', 'Error refreshing data sources, check the notifications')
|
|
127
|
+
}
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
// Add keyboard shortcuts
|
|
131
|
+
editor.Keymaps.add('data-source:refresh', 'ctrl+alt+r', COMMAND_REFRESH, {
|
|
132
|
+
prevent: true,
|
|
133
|
+
})
|
|
134
|
+
editor.Keymaps.add('data-source:preview-toggle', 'ctrl+alt+v', COMMAND_PREVIEW_TOGGLE, {
|
|
135
|
+
prevent: true,
|
|
136
|
+
})
|
|
137
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { ClientConfig } from '../../config'
|
|
2
|
+
import { CMS_SETTINGS_SECTION_ID, EleventyPluginOptions, Silex11tyPluginWebsiteSettings } from './index'
|
|
3
|
+
import { Editor } from 'grapesjs'
|
|
4
|
+
import { html, render } from 'lit-html'
|
|
5
|
+
import { COMMAND_PREVIEW_REFRESH, COMMAND_REFRESH, DATA_SOURCE_DATA_LOAD_END, getState, getValue, toExpression, setPreviewIndex, Property } from '@silexlabs/grapesjs-data-source'
|
|
6
|
+
import { TemplateResult } from 'lit-html'
|
|
7
|
+
import { ClientEvent } from '../../events'
|
|
8
|
+
import { cmdOpenSettings } from '../settings'
|
|
9
|
+
import { updatePaginationStates } from './states'
|
|
10
|
+
import { debounce } from '../../utils'
|
|
11
|
+
|
|
12
|
+
// Add CSS for collection pages
|
|
13
|
+
document.querySelector('head')?.insertAdjacentHTML('beforeend', `
|
|
14
|
+
<style>
|
|
15
|
+
.pages__empty {
|
|
16
|
+
padding: 16px;
|
|
17
|
+
text-align: center;
|
|
18
|
+
color: #888;
|
|
19
|
+
font-size: 12px;
|
|
20
|
+
font-style: italic;
|
|
21
|
+
}
|
|
22
|
+
.pages__page {
|
|
23
|
+
cursor: pointer;
|
|
24
|
+
}
|
|
25
|
+
.pages__page:hover {
|
|
26
|
+
background-color: rgba(255, 255, 255, 0.1);
|
|
27
|
+
}
|
|
28
|
+
</style>
|
|
29
|
+
`)
|
|
30
|
+
|
|
31
|
+
let currentPage = 0
|
|
32
|
+
export const EVENT_UPDATE_PAGE_LIST = 'update:collection:pages:list'
|
|
33
|
+
|
|
34
|
+
export default function (editor: Editor, opts: EleventyPluginOptions): void {
|
|
35
|
+
let done = false
|
|
36
|
+
editor.once(`
|
|
37
|
+
${ ClientEvent.STARTUP_END }
|
|
38
|
+
storage:end:load
|
|
39
|
+
`, (...args) => {
|
|
40
|
+
if (done) throw new Error('FIXME: this should never happen')
|
|
41
|
+
done = true
|
|
42
|
+
|
|
43
|
+
if (!opts.enable11ty) return // Do not add the settings if 11ty is disabled
|
|
44
|
+
|
|
45
|
+
const pagesContainer = editor.Panels.getPanel('project-bar-container')
|
|
46
|
+
?.view
|
|
47
|
+
?.el
|
|
48
|
+
?.querySelector('.page-panel-container')
|
|
49
|
+
|
|
50
|
+
const container = document.createElement('div')
|
|
51
|
+
pagesContainer?.appendChild(container)
|
|
52
|
+
|
|
53
|
+
// Listen for data changes and page selection
|
|
54
|
+
editor.on(`
|
|
55
|
+
${ DATA_SOURCE_DATA_LOAD_END }
|
|
56
|
+
storage:load:end
|
|
57
|
+
page
|
|
58
|
+
`, debounce<() => void>(() => {
|
|
59
|
+
currentPage = 0
|
|
60
|
+
renderCollectionPageList(editor, container)
|
|
61
|
+
}))
|
|
62
|
+
|
|
63
|
+
editor.on(`
|
|
64
|
+
${ EVENT_UPDATE_PAGE_LIST }
|
|
65
|
+
`, debounce<() => void>(() => {
|
|
66
|
+
renderCollectionPageList(editor, container)
|
|
67
|
+
editor.runCommand(COMMAND_PREVIEW_REFRESH)
|
|
68
|
+
}))
|
|
69
|
+
|
|
70
|
+
// Initial render
|
|
71
|
+
renderCollectionPageList(editor, container)
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function renderCollectionPageList(editor: Editor, container: HTMLElement) {
|
|
76
|
+
// Guard: Ensure Pages exist, there are pages, and a selected page has a main component
|
|
77
|
+
const pages = editor.Pages
|
|
78
|
+
if (
|
|
79
|
+
!pages ||
|
|
80
|
+
pages.getAll().length === 0 ||
|
|
81
|
+
!pages.getSelected()?.getMainComponent()
|
|
82
|
+
) {
|
|
83
|
+
return
|
|
84
|
+
}
|
|
85
|
+
render(getHtml(editor), container)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function getHtml(editor: Editor): TemplateResult {
|
|
89
|
+
const groups = getCollectionData(editor)
|
|
90
|
+
const result = html`
|
|
91
|
+
<header class="project-bar__panel-header">
|
|
92
|
+
<h3 class="project-bar__panel-header-title">Collection Pages</h3>
|
|
93
|
+
</header>
|
|
94
|
+
<div class="pages__wrapper">
|
|
95
|
+
<section class="pages">
|
|
96
|
+
<main class="pages__main">
|
|
97
|
+
<div class="pages__list">
|
|
98
|
+
${groups.length === 0
|
|
99
|
+
? html`<div class="pages__empty">
|
|
100
|
+
No collection items found.
|
|
101
|
+
<a
|
|
102
|
+
href="#"
|
|
103
|
+
@click=${(event: MouseEvent) => {
|
|
104
|
+
event.preventDefault()
|
|
105
|
+
editor.runCommand(cmdOpenSettings, {
|
|
106
|
+
page: editor.Pages.getSelected(),
|
|
107
|
+
sectionId: CMS_SETTINGS_SECTION_ID,
|
|
108
|
+
})
|
|
109
|
+
}}
|
|
110
|
+
>
|
|
111
|
+
Add pagination data in the page settings
|
|
112
|
+
</a>
|
|
113
|
+
</div>`
|
|
114
|
+
: groups.map((items, index) => {
|
|
115
|
+
// Temporary pagination to this particular page
|
|
116
|
+
updatePaginationStates(editor, index, true)
|
|
117
|
+
return html`
|
|
118
|
+
<div
|
|
119
|
+
class="pages__page ${index === currentPage ? 'pages__page-selected' : ''}"
|
|
120
|
+
data-item-index="${index}"
|
|
121
|
+
@click=${() => handleItemClick(editor, index)}
|
|
122
|
+
>
|
|
123
|
+
<div class="pages__page-name">
|
|
124
|
+
${getItemDisplayName(editor, index)}
|
|
125
|
+
</div>
|
|
126
|
+
${index === currentPage ? html`<i class="pages__icon pages__remove-btn"></i>` : ''}
|
|
127
|
+
</div>
|
|
128
|
+
`
|
|
129
|
+
})
|
|
130
|
+
}
|
|
131
|
+
</div>
|
|
132
|
+
</main>
|
|
133
|
+
</section>
|
|
134
|
+
</div>
|
|
135
|
+
`
|
|
136
|
+
if (groups.length > 0) {
|
|
137
|
+
// Reset to current page
|
|
138
|
+
updatePaginationStates(editor, currentPage, true)
|
|
139
|
+
}
|
|
140
|
+
return result
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function getCollectionData(editor: Editor): unknown[][] {
|
|
144
|
+
const page = editor.Pages.getSelected()
|
|
145
|
+
const body = page?.getMainComponent()
|
|
146
|
+
|
|
147
|
+
if (!body) return
|
|
148
|
+
|
|
149
|
+
const settings = page?.get('settings') as Silex11tyPluginWebsiteSettings | undefined
|
|
150
|
+
const pageData = toExpression(settings?.eleventyPageData) as (Property[] | null)
|
|
151
|
+
const pageSize = parseInt(settings?.eleventyPageSize || '1')
|
|
152
|
+
|
|
153
|
+
if (pageData && pageData.length > 0) {
|
|
154
|
+
const rawData = getValue(pageData, body as never, false)
|
|
155
|
+
|
|
156
|
+
if (Array.isArray(rawData) && rawData.length > 0) {
|
|
157
|
+
// Group rawData into chunks of size groupBy
|
|
158
|
+
const grouped: unknown[][] = []
|
|
159
|
+
for (let i = 0; i < rawData.length; i += pageSize) {
|
|
160
|
+
grouped.push(rawData.slice(i, i + pageSize))
|
|
161
|
+
}
|
|
162
|
+
return grouped
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return []
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function getItemDisplayName(editor: Editor, index: number): string {
|
|
170
|
+
try {
|
|
171
|
+
const page = editor.Pages.getSelected()
|
|
172
|
+
const settings = page?.get('settings') as Silex11tyPluginWebsiteSettings | undefined
|
|
173
|
+
|
|
174
|
+
const body = page?.getMainComponent()
|
|
175
|
+
if (!body) return
|
|
176
|
+
|
|
177
|
+
if (settings?.eleventySeoTitle || settings?.eleventyPermalink) {
|
|
178
|
+
// Parse the permalink expression
|
|
179
|
+
const nameExpression = toExpression(settings.eleventySeoTitle || settings.eleventyPermalink)
|
|
180
|
+
|
|
181
|
+
if (Array.isArray(nameExpression) && nameExpression.length > 0) {
|
|
182
|
+
const name = getValue(nameExpression, body, false)
|
|
183
|
+
if (typeof name === 'string') return name
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return `Page ${index}`
|
|
187
|
+
} catch (e) {
|
|
188
|
+
console.error('Error generating permalink for item:', e)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Final fallback to index-based name
|
|
192
|
+
return `Page ${index + 1}`
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function handleItemClick(editor: Editor, index: number) {
|
|
196
|
+
const page = editor.Pages.getSelected()
|
|
197
|
+
const body = page?.getMainComponent()
|
|
198
|
+
currentPage = index
|
|
199
|
+
|
|
200
|
+
if (!body) return
|
|
201
|
+
|
|
202
|
+
// Trigger the canvas refresh
|
|
203
|
+
editor.trigger(EVENT_UPDATE_PAGE_LIST)
|
|
204
|
+
// editor.Canvas.refresh()
|
|
205
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview DataSource configuration with defaults
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import DataSourcePlugin from '@silexlabs/grapesjs-data-source'
|
|
6
|
+
import { EleventyPluginOptions } from './index'
|
|
7
|
+
import { Editor, EditorConfig } from 'grapesjs'
|
|
8
|
+
|
|
9
|
+
const settingsEl = document.createElement('div')
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Default for the data source plugin to work without config
|
|
13
|
+
*/
|
|
14
|
+
export function getZeroConfig(editor: Editor): EleventyPluginOptions {
|
|
15
|
+
return {
|
|
16
|
+
view: {
|
|
17
|
+
el: () => editor.Panels.getPanel('views-container')?.view.el,
|
|
18
|
+
button: () => editor.Panels.getPanel('views')!.get('buttons')!.get('open-tm'),
|
|
19
|
+
settingsEl: () => settingsEl,
|
|
20
|
+
defaultFixed: true,
|
|
21
|
+
// Show all editors by default
|
|
22
|
+
disableStates: false,
|
|
23
|
+
disableAttributes: false,
|
|
24
|
+
disableProperties: false,
|
|
25
|
+
},
|
|
26
|
+
previewActive: true,
|
|
27
|
+
// Liquid filters - will be set by optionsToGrapesJsConfig
|
|
28
|
+
filters: [],
|
|
29
|
+
// Default data source
|
|
30
|
+
dataSources: [],
|
|
31
|
+
// Enable 11ty publication and filters
|
|
32
|
+
enable11ty: true,
|
|
33
|
+
// 11ty plugins
|
|
34
|
+
// fetchPlugin: { cache: 'no-cache' },
|
|
35
|
+
// i18nPlugin: true,
|
|
36
|
+
// Default publication paths
|
|
37
|
+
dir: {
|
|
38
|
+
input: '',
|
|
39
|
+
assets: 'assets',
|
|
40
|
+
css: 'css',
|
|
41
|
+
},
|
|
42
|
+
urls: {
|
|
43
|
+
assets: '/assets',
|
|
44
|
+
css: '/css',
|
|
45
|
+
},
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Field, Filter, Options } from '@silexlabs/grapesjs-data-source'
|
|
2
|
+
import { html } from 'lit-html'
|
|
3
|
+
import { Component } from 'grapesjs'
|
|
4
|
+
|
|
5
|
+
// Export filters for use in client.ts
|
|
6
|
+
export const eleventyFilters: Filter[] = [{
|
|
7
|
+
type: 'filter',
|
|
8
|
+
id: 'log',
|
|
9
|
+
label: 'log (11ty)',
|
|
10
|
+
validate: (field: Field | null) => !!field,
|
|
11
|
+
output: type => type,
|
|
12
|
+
apply: (str) => {
|
|
13
|
+
console.info(str)
|
|
14
|
+
return str
|
|
15
|
+
},
|
|
16
|
+
options: {},
|
|
17
|
+
}, {
|
|
18
|
+
type: 'filter',
|
|
19
|
+
id: 'slugify',
|
|
20
|
+
label: 'slugify (11ty)',
|
|
21
|
+
validate: (field: Field | null) => !!field && field.typeIds.map(t => t.toLowerCase()).includes('string') && field.kind === 'scalar',
|
|
22
|
+
output: type => type,
|
|
23
|
+
apply: (str) => {
|
|
24
|
+
return str?.toString().toLowerCase().replace(/\s+/g, '-')
|
|
25
|
+
},
|
|
26
|
+
options: {},
|
|
27
|
+
}]
|
|
28
|
+
|
|
29
|
+
export const i18nFilters: Filter[] = [{
|
|
30
|
+
type: 'filter',
|
|
31
|
+
id: 'locale_url',
|
|
32
|
+
label: 'locale_url (11ty)',
|
|
33
|
+
validate: (input: Field | null) => !!input?.typeIds.map(t => t.toLowerCase()).includes('string') && input?.kind === 'scalar',
|
|
34
|
+
apply: (input: unknown/*, options: Options*/) => input,
|
|
35
|
+
output: (input: Field | null/*, options: Options*/) => ({ ...(input || {} as Field), typeIds: ['String'] }),
|
|
36
|
+
options: {
|
|
37
|
+
locale: '',
|
|
38
|
+
},
|
|
39
|
+
quotedOptions: ['locale'],
|
|
40
|
+
optionsForm: (selected: Component, input: Field | null, options: Options) => html`
|
|
41
|
+
<label>Locale
|
|
42
|
+
<input type="text" name="locale" value="${options.locale}" />
|
|
43
|
+
</label>
|
|
44
|
+
`,
|
|
45
|
+
}, {
|
|
46
|
+
type: 'filter',
|
|
47
|
+
id: 'locale_links',
|
|
48
|
+
label: 'locale_links (11ty)',
|
|
49
|
+
validate: (input: Field | null) => !!input?.typeIds.map(t => t.toLowerCase()).includes('string') && input?.kind === 'scalar',
|
|
50
|
+
apply: (input: unknown/*, options: Options*/) => ([{ url: input, lang: 'en', label: 'English' }, { url: input, lang: 'fr', label: 'Français' }]),
|
|
51
|
+
output: (input: Field | null/*, options: Options*/) => ({ ...(input || {} as Field), typeIds: ['locale_link'], kind: 'list' }),
|
|
52
|
+
options: {},
|
|
53
|
+
}]
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import dataSourcePlugin, { DataSourceEditorOptions } from '@silexlabs/grapesjs-data-source'
|
|
2
|
+
import { ClientConfig } from '../../config'
|
|
3
|
+
import { getZeroConfig } from './config'
|
|
4
|
+
import publication from './publication'
|
|
5
|
+
import pageSettings from './page-settings'
|
|
6
|
+
import siteSettings from './site-settings'
|
|
7
|
+
import states from './states'
|
|
8
|
+
import DataSource from './DataSource'
|
|
9
|
+
import merge from 'deepmerge'
|
|
10
|
+
import { WebsiteSettings } from '../../../types'
|
|
11
|
+
import blocks from './blocks'
|
|
12
|
+
import buttons from './buttons'
|
|
13
|
+
import traits from './traits'
|
|
14
|
+
import collectionPages from './collection-pages'
|
|
15
|
+
import { Editor } from 'grapesjs'
|
|
16
|
+
import { eleventyFilters } from './filters'
|
|
17
|
+
|
|
18
|
+
export const CMS_SETTINGS_SECTION_ID = 'CMS_SETTINGS_SECTION_ID'
|
|
19
|
+
|
|
20
|
+
export interface EleventyPluginOptions extends DataSourceEditorOptions {
|
|
21
|
+
// Enable the publication to 11ty version > 2
|
|
22
|
+
// Default: true
|
|
23
|
+
esModule?: boolean,
|
|
24
|
+
// Enable the publication to 11ty
|
|
25
|
+
// If false, the publication will not publish to 11ty and do not display 11ty data
|
|
26
|
+
// Default: true
|
|
27
|
+
enable11ty?: boolean,
|
|
28
|
+
// Add cache buster to graphql queries
|
|
29
|
+
// Default: false
|
|
30
|
+
cacheBuster?: boolean,
|
|
31
|
+
// 11ty fetch plugin options
|
|
32
|
+
// https://www.11ty.dev/docs/plugins/fetch/
|
|
33
|
+
fetchPluginSettings?: object | false,
|
|
34
|
+
// Internationalization plugin enabled to add specific filters
|
|
35
|
+
// https://www.11ty.dev/docs/plugins/i18n/
|
|
36
|
+
i18nPlugin?: boolean,
|
|
37
|
+
// Publication paths based on 11ty file structure
|
|
38
|
+
dir?: {
|
|
39
|
+
// Directory for 11ty input files
|
|
40
|
+
// Silex will publish in /_silex/ in this directory
|
|
41
|
+
// E.g. content
|
|
42
|
+
// Default: ''
|
|
43
|
+
input?: string,
|
|
44
|
+
// Directory for the HTML pages relative to the input directory
|
|
45
|
+
// Silex will add HTML pages to this directory
|
|
46
|
+
// Default: ''
|
|
47
|
+
html?: string,
|
|
48
|
+
// Directory for the assets relative to the input directory
|
|
49
|
+
// Silex will add assets to this directory
|
|
50
|
+
// Default assets
|
|
51
|
+
assets?: string,
|
|
52
|
+
// Directory for the CSS files relative to the input directory
|
|
53
|
+
// Silex will add CSS files to this directory
|
|
54
|
+
// Default css
|
|
55
|
+
css?: string,
|
|
56
|
+
},
|
|
57
|
+
urls?: {
|
|
58
|
+
// URL where the CSS files will be accessible to the front end
|
|
59
|
+
// Default: css
|
|
60
|
+
css?: string,
|
|
61
|
+
// URL where the assets will be accessible to the front end
|
|
62
|
+
// Default: assets
|
|
63
|
+
assets?: string,
|
|
64
|
+
},
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface Silex11tyPluginWebsiteSettings extends WebsiteSettings {
|
|
68
|
+
eleventyPageData?: string,
|
|
69
|
+
eleventyPermalink?: string,
|
|
70
|
+
eleventyPageSize?: string,
|
|
71
|
+
eleventyPageReverse?: boolean,
|
|
72
|
+
silexLanguagesList?: string,
|
|
73
|
+
silexLanguagesDefault?: string,
|
|
74
|
+
eleventyNavigationKey?: string,
|
|
75
|
+
eleventyNavigationTitle?: string,
|
|
76
|
+
eleventyNavigationOrder?: string,
|
|
77
|
+
eleventyNavigationParent?: string,
|
|
78
|
+
eleventyNavigationUrl?: string,
|
|
79
|
+
// SEO
|
|
80
|
+
eleventySeoTitle?: string,
|
|
81
|
+
eleventySeoDescription?: string,
|
|
82
|
+
eleventyFavicon?: string,
|
|
83
|
+
// Social
|
|
84
|
+
eleventyOGImage?: string,
|
|
85
|
+
eleventyOGTitle?: string,
|
|
86
|
+
eleventyOGDescription?: string,
|
|
87
|
+
// Client side settings
|
|
88
|
+
eleventyI18n?: boolean,
|
|
89
|
+
eleventyFetch?: boolean,
|
|
90
|
+
eleventyImage?: boolean,
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export default function (editor: Editor, options: Partial<EleventyPluginOptions> = {}) {
|
|
94
|
+
const filters = [
|
|
95
|
+
...eleventyFilters,
|
|
96
|
+
'liquid',
|
|
97
|
+
]
|
|
98
|
+
|
|
99
|
+
// Options with default
|
|
100
|
+
const opts = merge(
|
|
101
|
+
getZeroConfig(editor) as EleventyPluginOptions,
|
|
102
|
+
options,
|
|
103
|
+
{ arrayMerge: (_, sourceArray) => sourceArray }, // Do not merge arrays by concatenation, just replace if present
|
|
104
|
+
) as EleventyPluginOptions
|
|
105
|
+
|
|
106
|
+
dataSourcePlugin(editor, {
|
|
107
|
+
...opts,
|
|
108
|
+
filters,
|
|
109
|
+
} as DataSourceEditorOptions)
|
|
110
|
+
|
|
111
|
+
DataSource(editor, opts)
|
|
112
|
+
pageSettings(editor, opts)
|
|
113
|
+
siteSettings(editor, opts)
|
|
114
|
+
collectionPages(editor, opts)
|
|
115
|
+
states(editor)
|
|
116
|
+
publication(editor, opts)
|
|
117
|
+
blocks(editor)
|
|
118
|
+
buttons(editor)
|
|
119
|
+
traits(editor)
|
|
120
|
+
|
|
121
|
+
// Add styles on the editor to override the default colors
|
|
122
|
+
document.head.insertAdjacentHTML('beforeend', `<style>
|
|
123
|
+
:root {
|
|
124
|
+
--ds-lowlight: #292929 !important;
|
|
125
|
+
--tertiary-color: #a291ff !important;
|
|
126
|
+
--ds-highlight: #a291ff !important;
|
|
127
|
+
}
|
|
128
|
+
</style>`)
|
|
129
|
+
return editor
|
|
130
|
+
}
|