maglevcms 1.8.0 → 2.0.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 +4 -4
- data/.yarn/install-state.gz +0 -0
- data/README.md +4 -4
- data/Rakefile +2 -1
- data/app/components/maglev/block_component.rb +1 -1
- data/app/components/maglev/content/base.rb +1 -1
- data/app/components/maglev/content/link.rb +4 -0
- data/app/components/maglev/section_component.rb +2 -2
- data/app/controllers/concerns/maglev/fetchers_concern.rb +3 -1
- data/app/controllers/concerns/maglev/resource_id_concern.rb +10 -0
- data/app/controllers/concerns/maglev/standalone_sections_concern.rb +6 -0
- data/app/controllers/concerns/maglev/{ui_locale_concern.rb → user_interface_locale_concern.rb} +1 -1
- data/app/controllers/maglev/api/collection_items_controller.rb +7 -0
- data/app/controllers/maglev/api/page_clones_controller.rb +1 -2
- data/app/controllers/maglev/api_controller.rb +1 -1
- data/app/controllers/maglev/application_controller.rb +1 -5
- data/app/controllers/maglev/assets/active_storage_proxy_controller.rb +17 -0
- data/app/controllers/maglev/assets/proxy_controller.rb +21 -0
- data/app/controllers/maglev/editor_controller.rb +1 -1
- data/app/controllers/maglev/page_preview_controller.rb +3 -3
- data/app/frontend/admin/controllers/screenshot_controller.js +29 -1
- data/app/frontend/editor/assets/remixicons/clipboard-line.svg +1 -0
- data/app/frontend/editor/assets/remixicons/ri-draggable.svg +1 -0
- data/app/frontend/editor/assets/remixicons/ri-folders-line.svg +1 -0
- data/app/frontend/editor/assets/remixicons/ri-more-fill.svg +1 -0
- data/app/frontend/editor/assets/remixicons/ri-shadow-line.svg +1 -0
- data/app/frontend/editor/components/errors/forbidden.vue +24 -0
- data/app/frontend/editor/components/errors/stale-record.vue +2 -2
- data/app/frontend/editor/components/header-nav/device-toggler.vue +6 -3
- data/app/frontend/editor/components/header-nav/index.vue +13 -42
- data/app/frontend/editor/components/header-nav/locale-toggler/index.vue +1 -1
- data/app/frontend/editor/components/header-nav/page-info.vue +41 -0
- data/app/frontend/editor/components/header-nav/preview-button.vue +6 -1
- data/app/frontend/editor/components/header-nav/separator.vue +1 -1
- data/app/frontend/editor/components/image-library/index.vue +26 -29
- data/app/frontend/editor/components/kit/collection-item-input.vue +9 -0
- data/app/frontend/editor/components/kit/copy-paste-button.vue +26 -0
- data/app/frontend/editor/components/kit/dropdown.vue +5 -0
- data/app/frontend/editor/components/kit/icon-button.vue +24 -0
- data/app/frontend/editor/components/kit/icon.vue +2 -3
- data/app/frontend/editor/components/kit/index.js +4 -2
- data/app/frontend/editor/components/kit/link-input.vue +1 -1
- data/app/frontend/editor/components/kit/modal.vue +1 -1
- data/app/frontend/editor/components/kit/page-icon.vue +1 -1
- data/app/frontend/editor/components/kit/rich-text-input/link-buttons.vue +1 -1
- data/app/frontend/editor/components/kit/select-input.vue +4 -2
- data/app/frontend/editor/components/link-picker/actions.vue +1 -1
- data/app/frontend/editor/components/link-picker/index.vue +1 -1
- data/app/frontend/editor/components/link-picker/page.vue +2 -0
- data/app/frontend/editor/components/page/form/main.vue +1 -1
- data/app/frontend/editor/components/page/list/actions-button.vue +159 -0
- data/app/frontend/editor/components/page/list/index.vue +15 -24
- data/app/frontend/editor/components/page/list/list-item.vue +10 -61
- data/app/frontend/editor/components/section-highlighter/index.vue +47 -46
- data/app/frontend/editor/components/section-list/add-button.vue +39 -0
- data/app/frontend/editor/components/section-list/index.vue +30 -15
- data/app/frontend/editor/components/section-list/list-item.vue +23 -8
- data/app/frontend/editor/components/section-pane/block-list/index.vue +1 -0
- data/app/frontend/editor/components/section-pane/block-list/list-item.vue +9 -6
- data/app/frontend/editor/components/section-pane/block-tree/new-nested-block-button.vue +2 -2
- data/app/frontend/editor/components/section-pane/block-tree/tree-node.vue +2 -2
- data/app/frontend/editor/components/sidebar-nav/index.vue +102 -0
- data/app/frontend/editor/components/sidebar-nav/link.vue +60 -0
- data/app/frontend/editor/components/theme-section-list/category.vue +47 -0
- data/app/frontend/editor/components/theme-section-list/index.vue +7 -31
- data/app/frontend/editor/components/theme-section-list/list-item.vue +10 -3
- data/app/frontend/editor/design/components/modal.scss +1 -1
- data/app/frontend/editor/design/components/tooltip.scss +6 -0
- data/app/frontend/editor/design/transitions.scss +1 -1
- data/app/frontend/editor/layouts/app.vue +14 -2
- data/app/frontend/editor/layouts/default.vue +2 -2
- data/app/frontend/editor/layouts/slide-pane.vue +1 -1
- data/app/frontend/editor/locales/editor.ar.json +265 -0
- data/app/frontend/editor/locales/editor.en.json +23 -15
- data/app/frontend/editor/locales/editor.es.json +18 -10
- data/app/frontend/editor/locales/editor.fr.json +28 -13
- data/app/frontend/editor/locales/editor.pt-BR.json +18 -10
- data/app/frontend/editor/locales/index.js +3 -0
- data/app/frontend/editor/mixins/error-modal.js +7 -2
- data/app/frontend/editor/mixins/preview-transformation.js +0 -1
- data/app/frontend/editor/plugins/i18n.js +2 -17
- data/app/frontend/editor/services/__tests__/section.spec.js +6 -0
- data/app/frontend/editor/services/collection-item.js +8 -0
- data/app/frontend/editor/services/live-preview.js +11 -1
- data/app/frontend/editor/services/page.js +1 -1
- data/app/frontend/editor/services/section.js +30 -0
- data/app/frontend/editor/services/site.js +4 -4
- data/app/frontend/editor/services/theme.js +1 -0
- data/app/frontend/editor/spec/__mocks__/page.js +3 -1
- data/app/frontend/editor/spec/__mocks__/services.js +1 -0
- data/app/frontend/editor/store/__tests__/getters.spec.js +56 -1
- data/app/frontend/editor/store/actions/index.js +1 -0
- data/app/frontend/editor/store/actions/site.js +8 -4
- data/app/frontend/editor/store/getters.js +11 -0
- data/app/frontend/editor/views/page-preview.vue +2 -1
- data/app/frontend/images/favicon.svg +11 -0
- data/app/frontend/images/logo.svg +14 -0
- data/app/frontend/live-preview-client/iframe-decorator.js +20 -17
- data/app/frontend/live-preview-client/message.js +1 -0
- data/app/frontend/live-preview-client/rails.js +12 -2
- data/app/helpers/maglev/application_helper.rb +7 -2
- data/app/helpers/maglev/editor_helper.rb +12 -5
- data/app/models/concerns/maglev/sections_concern.rb +4 -0
- data/app/models/maglev/asset.rb +13 -14
- data/app/models/maglev/page/path_concern.rb +23 -8
- data/app/models/maglev/page.rb +17 -18
- data/app/models/maglev/page_path.rb +18 -18
- data/app/models/maglev/section/setting.rb +1 -1
- data/app/models/maglev/section.rb +18 -9
- data/app/models/maglev/setting_types/link.rb +1 -1
- data/app/models/maglev/site.rb +13 -24
- data/app/services/maglev/app_container.rb +2 -2
- data/app/services/maglev/extract_locale.rb +3 -2
- data/app/services/maglev/fetch_page.rb +2 -0
- data/app/services/maglev/fetch_theme_layout.rb +2 -0
- data/app/services/maglev/get_page_fullpath.rb +1 -2
- data/app/services/maglev/remove_section_type.rb +50 -0
- data/app/services/maglev/rename_section_type.rb +57 -0
- data/app/services/maglev/search_pages.rb +2 -1
- data/app/views/layouts/maglev/admin/application.html.erb +1 -1
- data/app/views/maglev/admin/sections/previews/show.html.erb +16 -1
- data/app/views/maglev/api/collection_items/show.json.jbuilder +7 -0
- data/app/views/maglev/api/page_clones/create.json.jbuilder +3 -0
- data/app/views/maglev/editor/show.html.erb +6 -5
- data/config/locales/activerecord.ar.yml +13 -0
- data/config/locales/activerecord.en.yml +8 -2
- data/config/locales/activerecord.es.yml +4 -0
- data/config/locales/activerecord.fr.yml +6 -2
- data/config/locales/activerecord.pt-BR.yml +13 -0
- data/config/routes.rb +3 -4
- data/db/migrate/20200831101942_create_maglev_section_content.rb +10 -2
- data/db/migrate/20210819092740_switch_to_localized_page_fields.rb +13 -3
- data/db/migrate/20211008064437_add_locales_to_sites.rb +7 -1
- data/db/migrate/20211013210954_translate_section_content.rb +16 -2
- data/db/migrate/20211203224112_add_open_graph_tags_to_pages.rb +9 -3
- data/db/migrate/20220612092235_add_style_to_sites.rb +5 -1
- data/lib/commands/maglev/change_site_locales_command.rb +61 -0
- data/lib/commands/maglev/create_site_command.rb +28 -0
- data/lib/commands/maglev/sections/remove_command.rb +48 -0
- data/lib/commands/maglev/sections/rename_command.rb +49 -0
- data/lib/generators/maglev/templates/install/config/initializers/maglev.rb +4 -1
- data/lib/generators/maglev/templates/theme/app/views/theme/layout.html.erb.tt +8 -2
- data/lib/maglev/errors.rb +1 -0
- data/lib/maglev/preview_constraint.rb +5 -1
- data/lib/maglev/theme_filesystem_loader.rb +7 -0
- data/lib/maglev/version.rb +1 -1
- data/lib/maglev.rb +13 -3
- data/lib/tasks/maglev/icons.rake +123 -0
- data/lib/tasks/maglev/vite.rake +62 -0
- data/lib/tasks/maglev_tasks.rake +9 -107
- data/tailwind.config.js +1 -0
- metadata +48 -33
- data/app/controllers/maglev/assets_controller.rb +0 -10
- data/app/frontend/editor/components/kit/list-item-button.vue +0 -16
- data/app/frontend/editor/components/sidebar-nav.vue +0 -125
- data/app/frontend/editor/plugins/maglev_dummy.js +0 -2
- data/app/frontend/images/favicon.png +0 -0
- data/app/frontend/images/logo.png +0 -0
@@ -2,7 +2,7 @@
|
|
2
2
|
"headerNav": {
|
3
3
|
"pages": "Pages :",
|
4
4
|
"pageSettings": "Paramètres page",
|
5
|
-
"previewSite": "Prévisualiser
|
5
|
+
"previewSite": "Prévisualiser",
|
6
6
|
"previewToggler": {
|
7
7
|
"button": "Voir site",
|
8
8
|
"draftLink": "Version brouillon",
|
@@ -22,7 +22,7 @@
|
|
22
22
|
}
|
23
23
|
},
|
24
24
|
"sidebarNav": {
|
25
|
-
"
|
25
|
+
"listPagesTooltip": "Gérer les pages de votre site",
|
26
26
|
"managePageSectionsTooltip": "Gérer les sections de la page",
|
27
27
|
"editStyleTooltip": "Modifier le style du site",
|
28
28
|
"openImageLibraryTooltip": "Ouvrir la galerie d'images",
|
@@ -43,14 +43,16 @@
|
|
43
43
|
"title": "Liste des pages",
|
44
44
|
"subTitle": "Gérer les pages de votre site",
|
45
45
|
"newButton": "Nouvelle page",
|
46
|
-
"searchPlaceholder": "Tapez
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
46
|
+
"searchPlaceholder": "Tapez votre recherche ici..."
|
47
|
+
},
|
48
|
+
"actions": {
|
49
|
+
"edit": "Modifier les paramètres",
|
50
|
+
"clone": "Dupliquer",
|
51
|
+
"hide": "Masquer",
|
52
|
+
"show": "Afficher",
|
53
|
+
"delete": "Supprimer",
|
54
|
+
"copyUrlToClipboard": "Copier l'URL",
|
55
|
+
"copyUrlToClipboardSuccess": "Copié !"
|
54
56
|
},
|
55
57
|
"new": {
|
56
58
|
"title": "Créer une nouvelle page",
|
@@ -97,7 +99,8 @@
|
|
97
99
|
},
|
98
100
|
"listPane": {
|
99
101
|
"title": "Organiser les sections",
|
100
|
-
"empty": "Vous n'avez aucune section."
|
102
|
+
"empty": "Vous n'avez aucune section.",
|
103
|
+
"addButton": "Ajouter une nouvelle section"
|
101
104
|
}
|
102
105
|
},
|
103
106
|
"sectionPane": {
|
@@ -113,6 +116,7 @@
|
|
113
116
|
"sectionBlockPane": {
|
114
117
|
"tabs": {
|
115
118
|
"settings": "Contenu",
|
119
|
+
"blocks": "Blocs",
|
116
120
|
"advanced": "Paramètres"
|
117
121
|
}
|
118
122
|
},
|
@@ -121,7 +125,13 @@
|
|
121
125
|
},
|
122
126
|
"style": {
|
123
127
|
"edit": {
|
124
|
-
"title": "Styler site"
|
128
|
+
"title": "Styler votre site",
|
129
|
+
"submitButton": {
|
130
|
+
"default": "Mettre à jour le style",
|
131
|
+
"inProgress": "Mise à jour...",
|
132
|
+
"success": "Style mis à jour !",
|
133
|
+
"fail": "Échec !"
|
134
|
+
}
|
125
135
|
}
|
126
136
|
},
|
127
137
|
"imageInput": {
|
@@ -228,7 +238,12 @@
|
|
228
238
|
"staleRecord": {
|
229
239
|
"title": "Nous sommes désolés 🙇",
|
230
240
|
"message": "Nous n'avons pu sauvegarder vos modifications car de plus récentes viennent d'être effectuées par une autre personne.",
|
231
|
-
"button": "
|
241
|
+
"button": "Veuillez recharger votre page"
|
242
|
+
},
|
243
|
+
"forbidden": {
|
244
|
+
"title": "Nous sommes désolés 🙇",
|
245
|
+
"message": "Vous n'êtes pas autorisé à effectuer cette action. Veuillez contacter votre administrateur.",
|
246
|
+
"button": "Fermer"
|
232
247
|
}
|
233
248
|
},
|
234
249
|
"support": {
|
@@ -22,7 +22,7 @@
|
|
22
22
|
}
|
23
23
|
},
|
24
24
|
"sidebarNav": {
|
25
|
-
"
|
25
|
+
"listPagesTooltip": "Gerenciar as páginas do seu site",
|
26
26
|
"managePageSectionsTooltip": "Reordenar / excluir as seções da página",
|
27
27
|
"editStyleTooltip": "Alterar o estilo do seu site",
|
28
28
|
"openImageLibraryTooltip": "Abrir a galeria de imagens",
|
@@ -43,14 +43,16 @@
|
|
43
43
|
"title": "Lista de páginas",
|
44
44
|
"subTitle": "Gerenciar as páginas do seu site",
|
45
45
|
"newButton": "Nova página",
|
46
|
-
"searchPlaceholder": "Digite sua pesquisa aqui..."
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
46
|
+
"searchPlaceholder": "Digite sua pesquisa aqui..."
|
47
|
+
},
|
48
|
+
"actions": {
|
49
|
+
"edit": "Editar configurações",
|
50
|
+
"clone": "Clonar",
|
51
|
+
"hide": "Ocultar",
|
52
|
+
"show": "Mostrar",
|
53
|
+
"delete": "Excluir",
|
54
|
+
"copyUrlToClipboard": "Copiar URL",
|
55
|
+
"copyUrlToClipboardSuccess": "Copiado!"
|
54
56
|
},
|
55
57
|
"new": {
|
56
58
|
"title": "Criar uma nova página",
|
@@ -97,7 +99,8 @@
|
|
97
99
|
},
|
98
100
|
"listPane": {
|
99
101
|
"title": "Organizar seções",
|
100
|
-
"empty": "Não há seções."
|
102
|
+
"empty": "Não há seções.",
|
103
|
+
"addButton": "Adicionar uma nova seção"
|
101
104
|
}
|
102
105
|
},
|
103
106
|
"sectionPane": {
|
@@ -236,6 +239,11 @@
|
|
236
239
|
"title": "Pedimos desculpas 🙇",
|
237
240
|
"message": "Não conseguimos salvar suas alterações porque outra pessoa atualizou o conteúdo no intervalo de tempo.",
|
238
241
|
"button": "Por favor, recarregue a página"
|
242
|
+
},
|
243
|
+
"forbidden": {
|
244
|
+
"title": "Pedimos desculpas 🙇",
|
245
|
+
"message": "Você não tem permissão para realizar esta ação. Consulte seu administrador.",
|
246
|
+
"button": "Fechar"
|
239
247
|
}
|
240
248
|
},
|
241
249
|
"support": {
|
@@ -2,9 +2,11 @@ import EditorEN from './editor.en.json'
|
|
2
2
|
import EditorES from './editor.es.json'
|
3
3
|
import EditorFR from './editor.fr.json'
|
4
4
|
import EditorPTBR from './editor.pt-BR.json'
|
5
|
+
import EditorAR from './editor.ar.json'
|
5
6
|
import { deepMerge } from '@/misc/utils'
|
6
7
|
|
7
8
|
const overriddenEN = window.customTranslations?.en ?? {}
|
9
|
+
const overriddenAR = window.customTranslations?.ar ?? {}
|
8
10
|
const overriddenES = window.customTranslations?.es ?? {}
|
9
11
|
const overriddenFR = window.customTranslations?.fr ?? {}
|
10
12
|
const overriddenPTBR =
|
@@ -17,4 +19,5 @@ export default {
|
|
17
19
|
es: deepMerge(EditorES, overriddenES),
|
18
20
|
fr: deepMerge(EditorFR, overriddenFR),
|
19
21
|
'pt-BR': deepMerge(EditorPTBR, overriddenPTBR),
|
22
|
+
ar: deepMerge(EditorAR, overriddenAR),
|
20
23
|
}
|
@@ -1,4 +1,5 @@
|
|
1
|
-
import
|
1
|
+
import StaleRecordModal from '@/components/errors/stale-record.vue'
|
2
|
+
import ForbiddenModal from '@/components/errors/forbidden.vue'
|
2
3
|
|
3
4
|
export default {
|
4
5
|
methods: {
|
@@ -7,9 +8,13 @@ export default {
|
|
7
8
|
|
8
9
|
switch (errorType) {
|
9
10
|
case 'staleRecord':
|
10
|
-
ModalComponent =
|
11
|
+
ModalComponent = StaleRecordModal
|
12
|
+
break
|
13
|
+
case 'forbidden':
|
14
|
+
ModalComponent = ForbiddenModal
|
11
15
|
break
|
12
16
|
default:
|
17
|
+
console.warn("Unknown errorType:", errorType)
|
13
18
|
return // unknown error type
|
14
19
|
}
|
15
20
|
|
@@ -9,7 +9,6 @@ export default {
|
|
9
9
|
previewPaneMaxWidth() {
|
10
10
|
const sectionPaneWidth =
|
11
11
|
document.querySelector('.slide-pane')?.offsetWidth || 0
|
12
|
-
console.log('previewPaneMaxWidth', this.windowWidth, sectionPaneWidth)
|
13
12
|
return this.windowWidth - sectionPaneWidth
|
14
13
|
},
|
15
14
|
previewScaleRatio() {
|
@@ -4,24 +4,9 @@ import messages from '@/locales'
|
|
4
4
|
|
5
5
|
Vue.use(VueI18n)
|
6
6
|
|
7
|
-
const AVAILABLE_LOCALES = ['en', 'fr']
|
8
|
-
var locale = 'en'
|
9
|
-
|
10
|
-
if (document.documentElement.lang) {
|
11
|
-
// fetch the local from the HTML tag
|
12
|
-
locale = document.documentElement.lang
|
13
|
-
} else {
|
14
|
-
// try to fetch the browser locale
|
15
|
-
const language = navigator.languages[0]
|
16
|
-
if (language) {
|
17
|
-
locale = language.split('-')[0]
|
18
|
-
if (AVAILABLE_LOCALES.indexOf(locale) === -1) locale = null
|
19
|
-
}
|
20
|
-
}
|
21
|
-
|
22
7
|
const i18n = new VueI18n({
|
23
|
-
locale,
|
24
|
-
fallbackLocale:
|
8
|
+
locale: window.uiLocale,
|
9
|
+
fallbackLocale: 'en',
|
25
10
|
messages,
|
26
11
|
})
|
27
12
|
|
@@ -30,4 +30,10 @@ describe('SectionService', () => {
|
|
30
30
|
])
|
31
31
|
})
|
32
32
|
})
|
33
|
+
describe('#getSectionLabel', () => {
|
34
|
+
it('returns the label of the section', () => {
|
35
|
+
const label = service.getSectionLabel(simpleContentSection, theme.sections[0])
|
36
|
+
expect(label).toEqual('preTitle')
|
37
|
+
})
|
38
|
+
})
|
33
39
|
})
|
@@ -9,4 +9,12 @@ export default (api) => ({
|
|
9
9
|
.get(`/collections/${collectionId}`, options)
|
10
10
|
.then(({ data }) => data)
|
11
11
|
},
|
12
|
+
findOne: (collectionId, id) => {
|
13
|
+
console.log(
|
14
|
+
`[CollectionItem] Fetching the item ${id} of ${collectionId}`,
|
15
|
+
)
|
16
|
+
return api
|
17
|
+
.get(`/collections/${collectionId}/${id}`)
|
18
|
+
.then(({ data }) => data)
|
19
|
+
},
|
12
20
|
})
|
@@ -26,6 +26,12 @@ export const removeSection = (sectionId) => {
|
|
26
26
|
postMessage('section:remove', { sectionId })
|
27
27
|
}
|
28
28
|
|
29
|
+
export const pingSection = (sectionId) => {
|
30
|
+
if (!sectionId) return
|
31
|
+
postMessage('section:ping', { sectionId })
|
32
|
+
}
|
33
|
+
|
34
|
+
|
29
35
|
// === Block related actions ===
|
30
36
|
export const addBlock = (content, section, sectionBlock) => {
|
31
37
|
postMessage('block:add', { content, section, sectionBlock })
|
@@ -43,6 +49,10 @@ export const removeBlock = (content, section, sectionBlockId) => {
|
|
43
49
|
postMessage('block:remove', { content, section, sectionBlockId })
|
44
50
|
}
|
45
51
|
|
52
|
+
export const simulateFakeScroll = () => {
|
53
|
+
notifyScrolling(null)
|
54
|
+
}
|
55
|
+
|
46
56
|
// === Other actions ===
|
47
57
|
|
48
58
|
export const updateStyle = (content, style) => {
|
@@ -113,7 +123,7 @@ const openSettingPane = (name, params) => {
|
|
113
123
|
})
|
114
124
|
}
|
115
125
|
|
116
|
-
const notifyScrolling = (boundingRect) => {
|
126
|
+
export const notifyScrolling = (boundingRect) => {
|
117
127
|
const event = new CustomEvent('maglev:preview:scroll', {
|
118
128
|
detail: { boundingRect },
|
119
129
|
})
|
@@ -146,6 +146,36 @@ const buildDefaultBlocks = (definition) => {
|
|
146
146
|
return blocks
|
147
147
|
}
|
148
148
|
|
149
|
+
export const getSectionLabel = (section, definition) => {
|
150
|
+
let label = null
|
151
|
+
|
152
|
+
definition.settings.some((setting) => {
|
153
|
+
const value = section.settings.find(
|
154
|
+
(contentSetting) => contentSetting.id === setting.id,
|
155
|
+
)?.value
|
156
|
+
|
157
|
+
if (value === undefined) return false
|
158
|
+
|
159
|
+
switch (setting.type) {
|
160
|
+
case 'text':
|
161
|
+
const doc = new DOMParser().parseFromString(value.replace(/<br\/?>/g, ' '), 'text/html')
|
162
|
+
label = doc.body.textContent
|
163
|
+
break
|
164
|
+
case 'link':
|
165
|
+
if (!isBlank(value?.text)) label = value.text
|
166
|
+
break
|
167
|
+
case 'collection_item':
|
168
|
+
if (!isBlank(value?.label)) label = value.label
|
169
|
+
break
|
170
|
+
default:
|
171
|
+
break
|
172
|
+
}
|
173
|
+
|
174
|
+
return !!label
|
175
|
+
})
|
176
|
+
return label
|
177
|
+
}
|
178
|
+
|
149
179
|
export const getBlockLabel = (block, definition, index) => {
|
150
180
|
let label, image
|
151
181
|
definition.settings.forEach((setting) => {
|
@@ -12,10 +12,10 @@ export default (api) => ({
|
|
12
12
|
return response.headers['lock-version']
|
13
13
|
})
|
14
14
|
},
|
15
|
-
publish() {
|
16
|
-
return api.post(`/publication
|
15
|
+
publish({ pageId }) {
|
16
|
+
return api.post(`/publication`, { page_id: pageId }).then(({ data }) => data)
|
17
17
|
},
|
18
|
-
getLastPublication() {
|
19
|
-
return api.get(
|
18
|
+
getLastPublication({ pageId }) {
|
19
|
+
return api.get('/publication', { params: { page_id: pageId }}).then(({ data }) => data)
|
20
20
|
},
|
21
21
|
})
|
@@ -204,6 +204,7 @@ export const page = {
|
|
204
204
|
ogDescription: null,
|
205
205
|
ogImageUrl: null,
|
206
206
|
previewUrl: '/maglev/preview',
|
207
|
+
liveUrl: '/',
|
207
208
|
sectionNames: [
|
208
209
|
{ id: 'GrYZW-VP', name: 'Navbar 01' },
|
209
210
|
{ id: '8hKSujtd', name: 'Content #1' },
|
@@ -418,13 +419,14 @@ export const normalizedPage = {
|
|
418
419
|
ogDescription: null,
|
419
420
|
ogImageUrl: null,
|
420
421
|
previewUrl: '/maglev/preview',
|
422
|
+
liveUrl: '/',
|
421
423
|
sectionNames: [
|
422
424
|
{ id: 'GrYZW-VP', name: 'Navbar 01' },
|
423
425
|
{ id: '8hKSujtd', name: 'Content #1' },
|
424
426
|
{ id: 'xM6f-kyh', name: 'List #1' },
|
425
427
|
],
|
426
428
|
lockVersion: 1,
|
427
|
-
translated: true,
|
429
|
+
translated: true,
|
428
430
|
},
|
429
431
|
},
|
430
432
|
},
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import Vuex from 'vuex'
|
2
|
-
import { vi } from 'vitest'
|
2
|
+
import { describe, vi } from 'vitest'
|
3
3
|
import { createLocalVue } from '@vue/test-utils'
|
4
4
|
import defaultState from '@/store/default-state'
|
5
5
|
import buildGetters from '@/store/getters'
|
@@ -29,6 +29,58 @@ describe('Getters', () => {
|
|
29
29
|
store.commit('SET_SITE', site)
|
30
30
|
})
|
31
31
|
|
32
|
+
describe('#currentPagePath', () => {
|
33
|
+
let freshNormalizedPage = null
|
34
|
+
beforeEach(() => {
|
35
|
+
freshNormalizedPage = structuredClone(normalizedPage)
|
36
|
+
mockedServices.page.normalize = vi.fn(() => freshNormalizedPage)
|
37
|
+
})
|
38
|
+
describe('Given this is the home page', () => {
|
39
|
+
it('returns the path of the page', () => {
|
40
|
+
store.commit('SET_PAGE', page)
|
41
|
+
expect(store.getters.currentPagePath).toStrictEqual('/index')
|
42
|
+
})
|
43
|
+
})
|
44
|
+
describe('Given this is a random page', () => {
|
45
|
+
it('returns the path of the page', () => {
|
46
|
+
freshNormalizedPage.entities.page['1'].path = '/bonjour'
|
47
|
+
freshNormalizedPage.entities.page['1'].liveUrl = '/fr/bonjour'
|
48
|
+
store.commit('SET_PAGE', page)
|
49
|
+
expect(store.getters.currentPagePath).toStrictEqual('/fr/bonjour')
|
50
|
+
})
|
51
|
+
})
|
52
|
+
describe('Given the liveUrl contains the domain name', () => {
|
53
|
+
it('returns the path of the page', () => {
|
54
|
+
freshNormalizedPage.entities.page['1'].liveUrl = 'https://example.com:8080/fr'
|
55
|
+
freshNormalizedPage.entities.page['1'].path = 'index'
|
56
|
+
store.commit('SET_PAGE', page)
|
57
|
+
expect(store.getters.currentPagePath).toStrictEqual('/fr/index')
|
58
|
+
})
|
59
|
+
})
|
60
|
+
})
|
61
|
+
|
62
|
+
describe('#currentPageUrl', () => {
|
63
|
+
let freshNormalizedPage = null
|
64
|
+
beforeEach(() => {
|
65
|
+
freshNormalizedPage = structuredClone(normalizedPage)
|
66
|
+
mockedServices.page.normalize = vi.fn(() => freshNormalizedPage)
|
67
|
+
})
|
68
|
+
describe('Given the page live URL is not prefixed with the base URL', () => {
|
69
|
+
it('returns the url of the page', () => {
|
70
|
+
freshNormalizedPage.entities.page['1'].liveUrl = '/hello-world'
|
71
|
+
store.commit('SET_PAGE', page)
|
72
|
+
expect(store.getters.currentPageUrl).toStrictEqual('http://localhost:3000/hello-world')
|
73
|
+
})
|
74
|
+
})
|
75
|
+
describe('Given the page live URL is prefixed with the base URL', () => {
|
76
|
+
it('returns the url of the page', () => {
|
77
|
+
freshNormalizedPage.entities.page['1'].liveUrl = 'https://example.com:8080/fr'
|
78
|
+
store.commit('SET_PAGE', page)
|
79
|
+
expect(store.getters.currentPageUrl).toStrictEqual('https://example.com:8080/fr')
|
80
|
+
})
|
81
|
+
})
|
82
|
+
})
|
83
|
+
|
32
84
|
describe('#content', () => {
|
33
85
|
it('returns the content of the sections for the page', () => {
|
34
86
|
mockedServices.page.denormalize = vi.fn(() => page)
|
@@ -83,18 +135,21 @@ describe('Getters', () => {
|
|
83
135
|
id: 'GrYZW-VP',
|
84
136
|
type: 'navbar_01',
|
85
137
|
name: 'Navbar 01',
|
138
|
+
label: undefined,
|
86
139
|
viewportFixedPosition: false,
|
87
140
|
},
|
88
141
|
{
|
89
142
|
id: '8hKSujtd',
|
90
143
|
type: 'content_01',
|
91
144
|
name: 'Content #1',
|
145
|
+
label: undefined,
|
92
146
|
viewportFixedPosition: false,
|
93
147
|
},
|
94
148
|
{
|
95
149
|
id: 'xM6f-kyh',
|
96
150
|
type: 'list_01',
|
97
151
|
name: 'List #1',
|
152
|
+
label: undefined,
|
98
153
|
viewportFixedPosition: false,
|
99
154
|
},
|
100
155
|
])
|
@@ -7,15 +7,19 @@ export default (services) => ({
|
|
7
7
|
commit('SET_STYLE', style)
|
8
8
|
})
|
9
9
|
},
|
10
|
-
loadPublishButtonState({ commit }) {
|
10
|
+
loadPublishButtonState({ state, commit }) {
|
11
11
|
services.site
|
12
|
-
.getLastPublication()
|
12
|
+
.getLastPublication({ pageId: state.page.id })
|
13
13
|
.then((data) => commit('SET_PUBLISH_BUTTON_STATE', data))
|
14
14
|
},
|
15
|
-
async publishSite({ commit }) {
|
15
|
+
async publishSite({ state, commit }) {
|
16
16
|
services.site
|
17
|
-
.publish()
|
17
|
+
.publish({ pageId: state.page.id })
|
18
18
|
.then((data) => commit('SET_PUBLISH_BUTTON_STATE', data))
|
19
|
+
.catch(({ response: { status } }) => {
|
20
|
+
console.log('[Maglev] could not publish the page', status)
|
21
|
+
if (status === 403) commit('OPEN_ERROR_MODAL', 'forbidden')
|
22
|
+
})
|
19
23
|
},
|
20
24
|
pollLastPublication({ dispatch }) {
|
21
25
|
dispatch('loadPublishButtonState')
|
@@ -1,4 +1,14 @@
|
|
1
|
+
import { isBlank } from '@/misc/utils'
|
2
|
+
|
1
3
|
export default (services) => ({
|
4
|
+
currentPagePath: ({ page }) => {
|
5
|
+
const nakedPath = page.liveUrl.startsWith('http') ? new URL(page.liveUrl).pathname : page.liveUrl
|
6
|
+
return page.path === 'index' ? `${nakedPath}/index`.replace('//', '/') : nakedPath
|
7
|
+
},
|
8
|
+
currentPageUrl: ({ page }) => {
|
9
|
+
if (page.liveUrl.startsWith('http')) return page.liveUrl
|
10
|
+
return new URL(page.liveUrl, location.origin).toString()
|
11
|
+
},
|
2
12
|
sectionList: (
|
3
13
|
{ page, sections, sectionBlocks },
|
4
14
|
{ sectionDefinition: getSectiondefinition },
|
@@ -14,6 +24,7 @@ export default (services) => ({
|
|
14
24
|
id: sectionContent.id,
|
15
25
|
type: sectionContent['type'],
|
16
26
|
name: sectionDefinition.name,
|
27
|
+
label: services.section.getSectionLabel(sectionContent, sectionDefinition),
|
17
28
|
viewportFixedPosition: !!sectionDefinition.viewportFixedPosition,
|
18
29
|
}
|
19
30
|
})
|
@@ -19,6 +19,7 @@
|
|
19
19
|
v-if="currentPage"
|
20
20
|
>
|
21
21
|
<div
|
22
|
+
id="iframe-wrapper"
|
22
23
|
class="transition-all duration-100 ease-in-out"
|
23
24
|
:class="{ [deviceClass]: true, hidden: isPageEmpty }"
|
24
25
|
:style="{ opacity: previewReady ? 1 : 0 }"
|
@@ -64,7 +65,7 @@
|
|
64
65
|
>
|
65
66
|
<template v-slot:icon>
|
66
67
|
<uikit-icon
|
67
|
-
name="
|
68
|
+
name="ri-stack-line"
|
68
69
|
size="1.5rem"
|
69
70
|
class="mx-1 text-black"
|
70
71
|
/>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<ns0:svg height="314px" version="1.1" viewBox="0 0 464 314" width="464px" xmlns:ns0="http://www.w3.org/2000/svg">
|
3
|
+
<ns0:defs>
|
4
|
+
|
5
|
+
</ns0:defs>
|
6
|
+
<ns0:g fill="none" fill-rule="evenodd" id="Page-1" stroke="none" stroke-width="1">
|
7
|
+
<ns0:g fill="#000000" id="maglev-3">
|
8
|
+
<ns0:path d="M454.3,164.08 L419.43,88.31 C394.87,34.93 341.49,0.74 282.74,0.74 L103.98,0.74 C92.95,0.74 84.01,9.68 84.01,20.71 C84.01,31.74 92.95,40.68 103.98,40.68 L229.29,40.68 C229.29,40.68 219.11,64.98 219.11,64.98 C212.3,81.22 196.41,91.79 178.8,91.79 L20.74,91.79 C9.71,91.79 0.77,100.73 0.77,111.76 C0.77,122.79 9.71,131.73 20.74,131.73 L191.14,131.73 C191.14,131.73 180.96,156.04 180.96,156.04 C174.15,172.28 158.26,182.85 140.65,182.85 L52.82,182.85 C41.79,182.85 32.85,191.79 32.85,202.82 C32.85,213.85 41.79,222.79 52.82,222.79 L414.89,222.79 C418.73,222.79 421.53,226.58 420.25,230.19 C417.74,237.29 413.97,244.05 408.92,250.15 C396.11,265.63 376.56,273.93 356.46,273.93 L126,273.93 C114.97,273.93 106.03,282.87 106.03,293.9 C106.03,304.93 114.97,313.87 126,313.87 L355.88,313.87 C390.23,313.87 423.3,298.4 443.55,270.65 C466.4,239.34 470.31,198.94 454.28,164.09 L454.3,164.08 Z" id="Path"/>
|
9
|
+
</ns0:g>
|
10
|
+
</ns0:g>
|
11
|
+
</ns0:svg>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<svg width="464px" height="314px" viewBox="0 0 464 314" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
3
|
+
<defs>
|
4
|
+
<linearGradient x1="0.00215870369%" y1="49.9984032%" x2="100.004107%" y2="49.9984032%" id="linearGradient-1">
|
5
|
+
<stop stop-color="#0061FF" offset="0%"></stop>
|
6
|
+
<stop stop-color="#EC1FDA" offset="100%"></stop>
|
7
|
+
</linearGradient>
|
8
|
+
</defs>
|
9
|
+
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
10
|
+
<g id="maglev-3" fill="url(#linearGradient-1)">
|
11
|
+
<path d="M454.3,164.08 L419.43,88.31 C394.87,34.93 341.49,0.74 282.74,0.74 L103.98,0.74 C92.95,0.74 84.01,9.68 84.01,20.71 C84.01,31.74 92.95,40.68 103.98,40.68 L229.29,40.68 C229.29,40.68 219.11,64.98 219.11,64.98 C212.3,81.22 196.41,91.79 178.8,91.79 L20.74,91.79 C9.71,91.79 0.77,100.73 0.77,111.76 C0.77,122.79 9.71,131.73 20.74,131.73 L191.14,131.73 C191.14,131.73 180.96,156.04 180.96,156.04 C174.15,172.28 158.26,182.85 140.65,182.85 L52.82,182.85 C41.79,182.85 32.85,191.79 32.85,202.82 C32.85,213.85 41.79,222.79 52.82,222.79 L414.89,222.79 C418.73,222.79 421.53,226.58 420.25,230.19 C417.74,237.29 413.97,244.05 408.92,250.15 C396.11,265.63 376.56,273.93 356.46,273.93 L126,273.93 C114.97,273.93 106.03,282.87 106.03,293.9 C106.03,304.93 114.97,313.87 126,313.87 L355.88,313.87 C390.23,313.87 423.3,298.4 443.55,270.65 C466.4,239.34 470.31,198.94 454.28,164.09 L454.3,164.08 Z" id="Path"></path>
|
12
|
+
</g>
|
13
|
+
</g>
|
14
|
+
</svg>
|
@@ -53,6 +53,19 @@ export const start = (config) => {
|
|
53
53
|
|
54
54
|
// click on links
|
55
55
|
disableLinks(previewDocument)
|
56
|
+
|
57
|
+
// Only works on Google Chrome
|
58
|
+
selectHoveredSectionAtStartup(previewDocument, config.stickySectionIds)
|
59
|
+
}
|
60
|
+
|
61
|
+
const selectHoveredSectionAtStartup = (previewDocument, stickySectionIds) => {
|
62
|
+
setTimeout(() => {
|
63
|
+
const section = previewDocument.querySelector('[data-maglev-section-id]:hover')
|
64
|
+
|
65
|
+
if (section) {
|
66
|
+
onSectionHovered(previewDocument, section, stickySectionIds, true)
|
67
|
+
}
|
68
|
+
}, 200)
|
56
69
|
}
|
57
70
|
|
58
71
|
const listen = (previewDocument, eventType, handler) => {
|
@@ -96,28 +109,18 @@ const listen = (previewDocument, eventType, handler) => {
|
|
96
109
|
}
|
97
110
|
|
98
111
|
const listenScrolling = (previewDocument) => {
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
addEventListener(previewDocument, 'mousemove', (e) => {
|
103
|
-
mouseX = e.clientX
|
104
|
-
mouseY = e.clientY
|
105
|
-
})
|
106
|
-
|
107
|
-
const debouncedScrollNotifier = debounce(() => {
|
108
|
-
const el = previewDocument
|
109
|
-
.elementFromPoint(mouseX, mouseY)
|
110
|
-
?.closest('[data-maglev-section-id]')
|
111
|
-
|
112
|
+
const scrollNotifier = () => {
|
113
|
+
const el = previewDocument.querySelector('[data-maglev-section-id]:hover')
|
112
114
|
if (el) postMessage('scroll', { boundingRect: el.getBoundingClientRect() })
|
113
|
-
}
|
115
|
+
}
|
114
116
|
|
115
|
-
addEventListener(previewDocument, 'scroll',
|
117
|
+
addEventListener(previewDocument, 'scroll', scrollNotifier)
|
116
118
|
}
|
117
119
|
|
118
|
-
const onSectionHovered = (previewDocument, el, stickySectionIds) => {
|
120
|
+
const onSectionHovered = (previewDocument, el, stickySectionIds, force = false) => {
|
119
121
|
const sectionId = el.dataset.maglevSectionId
|
120
|
-
|
122
|
+
|
123
|
+
if (hoveredSectionId !== sectionId || force) {
|
121
124
|
postMessage('section:hover', {
|
122
125
|
sectionId,
|
123
126
|
sectionRect: el.getBoundingClientRect(),
|