maglevcms 1.8.0 → 2.0.0.beta1
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 +1 -1
- 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/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 +17 -15
- data/app/frontend/live-preview-client/rails.js +1 -1
- 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
@@ -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
|
})
|
@@ -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,18 @@ 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)
|
67
|
+
}, 200)
|
56
68
|
}
|
57
69
|
|
58
70
|
const listen = (previewDocument, eventType, handler) => {
|
@@ -96,27 +108,17 @@ const listen = (previewDocument, eventType, handler) => {
|
|
96
108
|
}
|
97
109
|
|
98
110
|
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
|
-
|
111
|
+
const scrollNotifier = () => {
|
112
|
+
const el = previewDocument.querySelector('[data-maglev-section-id]:hover')
|
112
113
|
if (el) postMessage('scroll', { boundingRect: el.getBoundingClientRect() })
|
113
|
-
}
|
114
|
+
}
|
114
115
|
|
115
|
-
addEventListener(previewDocument, 'scroll',
|
116
|
+
addEventListener(previewDocument, 'scroll', scrollNotifier)
|
116
117
|
}
|
117
118
|
|
118
119
|
const onSectionHovered = (previewDocument, el, stickySectionIds) => {
|
119
120
|
const sectionId = el.dataset.maglevSectionId
|
121
|
+
|
120
122
|
if (hoveredSectionId !== sectionId) {
|
121
123
|
postMessage('section:hover', {
|
122
124
|
sectionId,
|
@@ -17,8 +17,13 @@ module Maglev
|
|
17
17
|
|
18
18
|
entries = maglev_asset_manifest.resolve_entries(*%w[live-preview-rails-client], type: :javascript)
|
19
19
|
|
20
|
-
javascript_include_tag(
|
21
|
-
|
20
|
+
javascript_include_tag(
|
21
|
+
*entries.fetch(:scripts).flatten.uniq,
|
22
|
+
crossorigin: 'anonymous',
|
23
|
+
type: 'module',
|
24
|
+
defer: true,
|
25
|
+
nonce: true
|
26
|
+
)
|
22
27
|
end
|
23
28
|
|
24
29
|
def maglev_asset_manifest
|
@@ -20,7 +20,14 @@ module Maglev
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def editor_window_title
|
23
|
-
maglev_config.title
|
23
|
+
case maglev_config.title
|
24
|
+
when nil
|
25
|
+
'Maglev - EDITOR'
|
26
|
+
when String
|
27
|
+
maglev_config.title
|
28
|
+
when Proc
|
29
|
+
instance_exec(maglev_site, &maglev_config.title)
|
30
|
+
end
|
24
31
|
end
|
25
32
|
|
26
33
|
def editor_primary_hex_color
|
@@ -45,9 +52,9 @@ module Maglev
|
|
45
52
|
def editor_logo_url
|
46
53
|
case maglev_config.logo
|
47
54
|
when nil
|
48
|
-
editor_asset_path(nil, 'logo.
|
55
|
+
editor_asset_path(nil, 'logo.svg')
|
49
56
|
when String
|
50
|
-
editor_asset_path(maglev_config.logo, 'logo.
|
57
|
+
editor_asset_path(maglev_config.logo, 'logo.svg')
|
51
58
|
when Proc
|
52
59
|
instance_exec(maglev_site, &maglev_config.logo)
|
53
60
|
end
|
@@ -56,9 +63,9 @@ module Maglev
|
|
56
63
|
def editor_favicon_url
|
57
64
|
case maglev_config.favicon
|
58
65
|
when nil
|
59
|
-
editor_asset_path(nil, 'favicon.
|
66
|
+
editor_asset_path(nil, 'favicon.svg')
|
60
67
|
when String
|
61
|
-
editor_asset_path(maglev_config.favicon, 'favicon.
|
68
|
+
editor_asset_path(maglev_config.favicon, 'favicon.svg')
|
62
69
|
when Proc
|
63
70
|
instance_exec(maglev_site, &maglev_config.favicon)
|
64
71
|
end
|
data/app/models/maglev/asset.rb
CHANGED
@@ -1,5 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# == Schema Information
|
4
|
+
#
|
5
|
+
# Table name: maglev_assets
|
6
|
+
#
|
7
|
+
# id :bigint not null, primary key
|
8
|
+
# byte_size :integer
|
9
|
+
# content_type :string
|
10
|
+
# filename :string
|
11
|
+
# height :integer
|
12
|
+
# width :integer
|
13
|
+
# created_at :datetime not null
|
14
|
+
# updated_at :datetime not null
|
15
|
+
#
|
3
16
|
module Maglev
|
4
17
|
class Asset < ApplicationRecord
|
5
18
|
include ::Maglev.uploader
|
@@ -26,17 +39,3 @@ module Maglev
|
|
26
39
|
end
|
27
40
|
end
|
28
41
|
end
|
29
|
-
|
30
|
-
# == Schema Information
|
31
|
-
#
|
32
|
-
# Table name: maglev_assets
|
33
|
-
#
|
34
|
-
# id :bigint not null, primary key
|
35
|
-
# byte_size :integer
|
36
|
-
# content_type :string
|
37
|
-
# filename :string
|
38
|
-
# height :integer
|
39
|
-
# width :integer
|
40
|
-
# created_at :datetime not null
|
41
|
-
# updated_at :datetime not null
|
42
|
-
#
|