Basic adding of pages works
This commit is contained in:
parent
27b7e3afec
commit
e3ddcefb30
|
@ -18,17 +18,16 @@
|
||||||
"block": {
|
"block": {
|
||||||
"type": "json"
|
"type": "json"
|
||||||
},
|
},
|
||||||
"public": {
|
"slug": {
|
||||||
"type": "boolean",
|
|
||||||
"default": true,
|
|
||||||
"required": false
|
|
||||||
},
|
|
||||||
"path": {
|
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"required": true,
|
"required": false,
|
||||||
"regex": "^(\\/|(\\/[A-z0-9\\-]+)+)$",
|
"regex": "[A-z0-9\\-]*",
|
||||||
"unique": true,
|
"unique": false
|
||||||
"default": "/"
|
},
|
||||||
|
"parent": {
|
||||||
|
"type": "relation",
|
||||||
|
"relation": "oneToOne",
|
||||||
|
"target": "api::page.page"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
.sb-block-ordering {
|
.sb-block-ordering {
|
||||||
|
font-family: 'Montserrat';
|
||||||
display: flex;
|
display: flex;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
.sb-block-picker {
|
.sb-block-picker {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
|
||||||
&__add-button {
|
&__add-button {
|
||||||
padding: 24px 32px;
|
padding: 24px 32px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
.sb-block-placeholder {
|
.sb-block-placeholder {
|
||||||
flex-basis: 100%;
|
font-family: 'Montserrat';
|
||||||
flex-shrink: 2;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
flex-basis: 1rem;
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
|
|
||||||
&__add {
|
&__add {
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
.sb-block-toolbar {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
.sb-button {
|
.sb-button {
|
||||||
|
font-family: 'Montserrat';
|
||||||
border: 0;
|
border: 0;
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
background-color: var(--grey-0);
|
background-color: var(--grey-0);
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.sb-context-menu {
|
.sb-context-menu {
|
||||||
|
font-family: 'Montserrat';
|
||||||
display: none;
|
display: none;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
background: var(--grey-0);
|
background: var(--grey-0);
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
|
$sb-style-root: '@schlechtenburg/style';
|
||||||
|
@import '@schlechtenburg/style/scss/montserrat.scss';
|
||||||
|
|
||||||
.sb-main {
|
.sb-main {
|
||||||
position: relative;
|
position: relative;
|
||||||
color: var(--fg);
|
color: var(--fg);
|
||||||
background-color: var(--bg);
|
background-color: var(--bg);
|
||||||
|
padding: 0;
|
||||||
|
transition: padding 0.2s ease;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
--grey-0: white;
|
--grey-0: white;
|
||||||
--grey-1-t: rgba(0, 0, 0, 0.05);
|
--grey-1-t: rgba(0, 0, 0, 0.05);
|
||||||
|
@ -25,6 +31,7 @@
|
||||||
--z-toolbar: 2000;
|
--z-toolbar: 2000;
|
||||||
--z-context-menu: 3000;
|
--z-context-menu: 3000;
|
||||||
--z-tree-block-select: 4000;
|
--z-tree-block-select: 4000;
|
||||||
|
--z-main-menu: 5000;
|
||||||
--z-modal: 10000;
|
--z-modal: 10000;
|
||||||
|
|
||||||
*,
|
*,
|
||||||
|
@ -32,4 +39,32 @@
|
||||||
*::after {
|
*::after {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&_edit {
|
||||||
|
padding: 0rem 3rem 3rem 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--menu {
|
||||||
|
opacity: 1;
|
||||||
|
margin-bottom: 3rem;
|
||||||
|
transform: none;
|
||||||
|
|
||||||
|
&-enter-active,
|
||||||
|
&-leave-active {
|
||||||
|
transition-property: opacity, margin-bottom, transform;
|
||||||
|
transition-duration: 0.1s;
|
||||||
|
transition-timing-function: ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-enter-active {
|
||||||
|
transition-delay: 0s 0s 0.1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-enter-from,
|
||||||
|
&-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
transform: translateY(-100%);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@ import {
|
||||||
shallowReactive,
|
shallowReactive,
|
||||||
ref,
|
ref,
|
||||||
watch,
|
watch,
|
||||||
|
computed,
|
||||||
|
Transition,
|
||||||
PropType,
|
PropType,
|
||||||
Ref,
|
Ref,
|
||||||
} from 'vue';
|
} from 'vue';
|
||||||
|
@ -26,7 +28,6 @@ import { SymEditorDimensions, useResizeObserver } from '../use-resize-observer';
|
||||||
import { SymActiveBlock } from '../use-activation';
|
import { SymActiveBlock } from '../use-activation';
|
||||||
|
|
||||||
import { SbMainMenu } from './MainMenu';
|
import { SbMainMenu } from './MainMenu';
|
||||||
import { SbBlockToolbar } from './BlockToolbar';
|
|
||||||
import { SbBlock } from './Block';
|
import { SbBlock } from './Block';
|
||||||
|
|
||||||
export interface ISbMainProps {
|
export interface ISbMainProps {
|
||||||
|
@ -79,6 +80,11 @@ export const SbMain = defineComponent({
|
||||||
mode.value = newMode;
|
mode.value = newMode;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const classes = computed(() => ({
|
||||||
|
'sb-main': true,
|
||||||
|
[`sb-main_${mode.value}`]: true,
|
||||||
|
}));
|
||||||
|
|
||||||
const activeBlock = ref(null);
|
const activeBlock = ref(null);
|
||||||
provide(SymActiveBlock, activeBlock);
|
provide(SymActiveBlock, activeBlock);
|
||||||
|
|
||||||
|
@ -98,18 +104,22 @@ export const SbMain = defineComponent({
|
||||||
|
|
||||||
return () => (
|
return () => (
|
||||||
<div
|
<div
|
||||||
class="sb-main"
|
class={classes.value}
|
||||||
ref={el}
|
ref={el}
|
||||||
>
|
>
|
||||||
{
|
<Transition
|
||||||
mode.value === SbMode.Edit
|
name="sb-main--menu"
|
||||||
? <>
|
mode="out-in"
|
||||||
<SbMainMenu block={props.block} />
|
>
|
||||||
<SbBlockToolbar />
|
{mode.value === SbMode.Edit
|
||||||
</>
|
? <SbMainMenu
|
||||||
: null
|
block={props.block}
|
||||||
}
|
class="sb-main--menu"
|
||||||
|
/>
|
||||||
|
: null}
|
||||||
|
</Transition>
|
||||||
<SbBlock
|
<SbBlock
|
||||||
|
class="sb-main--block"
|
||||||
block={props.block}
|
block={props.block}
|
||||||
eventUpdate={props.eventUpdate}
|
eventUpdate={props.eventUpdate}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
.sb-main-menu {
|
.sb-main-menu {
|
||||||
|
font-family: 'Montserrat';
|
||||||
display: flex;
|
display: flex;
|
||||||
padding-bottom: 4rem;
|
|
||||||
background-color: var(--grey-0);
|
background-color: var(--grey-0);
|
||||||
|
position: sticky;
|
||||||
|
z-index: var(--z-main-menu);
|
||||||
|
top: 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ import {
|
||||||
PropType,
|
PropType,
|
||||||
} from 'vue';
|
} from 'vue';
|
||||||
import { IBlockData } from '../types';
|
import { IBlockData } from '../types';
|
||||||
|
import { SbBlockToolbar } from './BlockToolbar';
|
||||||
import { SbTreeBlockSelect } from './TreeBlockSelect';
|
import { SbTreeBlockSelect } from './TreeBlockSelect';
|
||||||
|
|
||||||
import './MainMenu.scss';
|
import './MainMenu.scss';
|
||||||
|
@ -21,6 +22,7 @@ export const SbMainMenu = defineComponent({
|
||||||
return () => (
|
return () => (
|
||||||
<div class="sb-main-menu">
|
<div class="sb-main-menu">
|
||||||
<SbTreeBlockSelect />
|
<SbTreeBlockSelect />
|
||||||
|
<SbBlockToolbar />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
.sb-missing-block {
|
.sb-missing-block {
|
||||||
|
font-family: 'Montserrat';
|
||||||
flex-basis: 100%;
|
flex-basis: 100%;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
.sb-modal {
|
.sb-modal {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
|
||||||
&__overlay {
|
&__overlay {
|
||||||
background-color: var(--grey-3-t);
|
background-color: var(--grey-3-t);
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
.sb-select {
|
.sb-select {
|
||||||
|
font-family: 'Montserrat';
|
||||||
background-color: var(--grey-0);
|
background-color: var(--grey-0);
|
||||||
border: 1px solid var(--grey-2);
|
border: 1px solid var(--grey-2);
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
.sb-toolbar {
|
.sb-toolbar {
|
||||||
|
font-family: 'Montserrat';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: auto;
|
width: auto;
|
||||||
height: auto;
|
height: auto;
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
.sb-tree-block-select {
|
.sb-tree-block-select {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
|
||||||
&__list {
|
&__list {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
color: var(--fg);
|
color: var(--fg);
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
"url": "git@git.b12f.io:b12f/schlechtenburg.git"
|
"url": "git@git.b12f.io:b12f/schlechtenburg.git"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@schlechtenburg/style": "^0.0.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"uuid": "^8.3.2"
|
"uuid": "^8.3.2"
|
||||||
},
|
},
|
||||||
|
|
|
@ -9,8 +9,39 @@ body {
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
|
|
||||||
--nav-width: 60px;
|
--ex-nav-width: 60px;
|
||||||
--nav-expanded-width: 320px;
|
--ex-nav-expanded-width: 320px;
|
||||||
|
|
||||||
|
--interact: #3f9cff;
|
||||||
|
--interact-lite: #3f9cff;
|
||||||
|
|
||||||
|
--grey-0: white;
|
||||||
|
--grey-1-t: rgba(0, 0, 0, 0.05);
|
||||||
|
--grey-1: rgb(242, 242, 242);
|
||||||
|
--grey-2-t: rgba(0, 0, 0, 0.1);
|
||||||
|
--grey-2: rgb(230, 230, 230);
|
||||||
|
--grey-3-t: rgba(0, 0, 0, 0.2);
|
||||||
|
--grey-3: rgb(205, 205, 205);
|
||||||
|
--grey-4-t: rgba(0, 0, 0, 0.4);
|
||||||
|
--grey-4: rgb(155, 155, 155);
|
||||||
|
--grey-5-t: rgba(0, 0, 0, 0.7);
|
||||||
|
--grey-5: rgb(75, 75, 75);
|
||||||
|
--black: rgba(0, 0, 0, 0.9);
|
||||||
|
|
||||||
|
--bg: var(--grey-1);
|
||||||
|
--fg: var(--black);
|
||||||
|
|
||||||
|
--interact: #3f9cff;
|
||||||
|
--interact-lite: #3f9cff;
|
||||||
|
|
||||||
|
--z-toolbar: 2000;
|
||||||
|
--z-context-menu: 3000;
|
||||||
|
--z-tree-block-select: 4000;
|
||||||
|
--z-modal: 10000;
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
&--admin-nav {
|
&--admin-nav {
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
|
@ -22,15 +53,19 @@ body {
|
||||||
|
|
||||||
&--page {
|
&--page {
|
||||||
flex-basis: 100%;
|
flex-basis: 100%;
|
||||||
|
|
||||||
|
&:not(:first-child) {
|
||||||
|
margin-left: var(--ex-nav-width);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 1000px) {
|
@media screen and (min-width: 1000px) {
|
||||||
--nav-width: var(--nav-expanded-width);
|
--ex-nav-width: var(--ex-nav-expanded-width);
|
||||||
|
|
||||||
&--admin-nav {
|
&--admin-nav {
|
||||||
position: unset;
|
position: unset;
|
||||||
width: unset;
|
width: unset;
|
||||||
flex-basis: var(--nav-width);
|
flex-basis: var(--ex-nav-width);
|
||||||
flex-grow: 0;
|
flex-grow: 0;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,50 +12,23 @@ export default defineComponent({
|
||||||
|
|
||||||
const loggedIn = computed(() => !!me.value?.id);
|
const loggedIn = computed(() => !!me.value?.id);
|
||||||
|
|
||||||
const { page, setPage } = usePage();
|
const { currentPage } = useCurrentPage();
|
||||||
const block = page.value?.attributes?.block;
|
const block = computed(() => currentPage.value?.attributes?.block);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
mode,
|
mode,
|
||||||
draft,
|
draft,
|
||||||
updateDraft,
|
updateDraft,
|
||||||
revision,
|
|
||||||
} = useEditor();
|
} = useEditor();
|
||||||
|
|
||||||
watch(revision, async () => {
|
watchEffect(() => {
|
||||||
const { data, error } = await useAsyncGql(
|
updateDraft(block.value!);
|
||||||
'updatePage',
|
|
||||||
{
|
|
||||||
id: page.value?.id || '',
|
|
||||||
data: {
|
|
||||||
block: draft.value!
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if (error.value) {
|
|
||||||
console.error('Error updating page!');
|
|
||||||
console.error('error:', error.value);
|
|
||||||
console.error('data:', data.value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setPage(data.value?.updatePage?.data?.attributes?.block);
|
|
||||||
updateDraft(data.value?.updatePage?.data?.attributes?.block);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(mode, async (newMode) => {
|
|
||||||
if (newMode === SbMode.View) {
|
|
||||||
updateDraft(block!);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
updateDraft(block!);
|
|
||||||
|
|
||||||
|
|
||||||
if (!block) {
|
if (!block) {
|
||||||
console.error('No block!');
|
console.error('No block!');
|
||||||
console.error('page', page.value);
|
console.error('page', currentPage.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => (
|
return () => (
|
||||||
|
@ -74,7 +47,7 @@ export default defineComponent({
|
||||||
SbImage,
|
SbImage,
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
: <div class="ex-page ex-page_corrupt">Corrupt page: {page.value?.attributes?.path} ({page.value?.id})</div>}
|
: <div class="ex-page ex-page_corrupt">Corrupt page: {currentPage.value?.attributes?.slug} ({currentPage.value?.id})</div>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
3
packages/example-site/components/PageBreadcrumb.scss
Normal file
3
packages/example-site/components/PageBreadcrumb.scss
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
.ex-page-breadcrumb {
|
||||||
|
display: flex;
|
||||||
|
}
|
27
packages/example-site/components/PageBreadcrumb.tsx
Normal file
27
packages/example-site/components/PageBreadcrumb.tsx
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import { ComputedRef, defineComponent } from 'vue';
|
||||||
|
import { NuxtLink } from '#components';
|
||||||
|
import { IPage } from '~~/composables/pages';
|
||||||
|
|
||||||
|
import './PageBreadcrumb.scss';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
async setup() {
|
||||||
|
const { currentPage } = useCurrentPage();
|
||||||
|
const { pages } = usePages();
|
||||||
|
|
||||||
|
const parents:ComputedRef<IPage[]> = computed(() => currentPage.value ? getPageParents(currentPage.value, pages.value, [currentPage.value]) : []);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
return (<div class="ex-page-breadcrumb">
|
||||||
|
{...parents.value.map((parent) => (
|
||||||
|
<div class="ex-page-breadcrumb--crumb">
|
||||||
|
/
|
||||||
|
<NuxtLink to={getPagePath(parent, pages.value)}>
|
||||||
|
{parent?.attributes?.slug}
|
||||||
|
</NuxtLink>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
7
packages/example-site/components/PageToolbar.scss
Normal file
7
packages/example-site/components/PageToolbar.scss
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
.ex-page-toolbar {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
border-bottom: 1px solid var(--grey-2);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
|
@ -1,9 +1,18 @@
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { SbButton, SbMode } from '@schlechtenburg/core';
|
import { SbButton, SbMode } from '@schlechtenburg/core';
|
||||||
|
import PageBreadcrumb from '~~/components/PageBreadcrumb';
|
||||||
|
|
||||||
|
import './PageToolbar.scss';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
async setup() {
|
async setup() {
|
||||||
const { page } = usePage();
|
const {
|
||||||
|
currentPage,
|
||||||
|
currentPageId,
|
||||||
|
setCurrentPageId,
|
||||||
|
} = useCurrentPage();
|
||||||
|
|
||||||
|
const { pages, insertPage } = usePages();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
mode,
|
mode,
|
||||||
|
@ -12,12 +21,38 @@ export default defineComponent({
|
||||||
save,
|
save,
|
||||||
} = useEditor();
|
} = useEditor();
|
||||||
|
|
||||||
|
const addChildPage = () => {
|
||||||
|
insertPage({
|
||||||
|
id: 'draft',
|
||||||
|
attributes: {
|
||||||
|
title: 'New page',
|
||||||
|
block: getNewPageBlock(),
|
||||||
|
slug: 'new-page',
|
||||||
|
parent: {
|
||||||
|
data: {
|
||||||
|
id: currentPage.value?.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
setCurrentPageId('draft');
|
||||||
|
edit(currentPage.value?.attributes?.block!);
|
||||||
|
};
|
||||||
|
|
||||||
return () => (
|
return () => (
|
||||||
<div class="ex-page-toolbar">
|
<div class="ex-page-toolbar">
|
||||||
|
<PageBreadcrumb />
|
||||||
|
{currentPageId.value !== 'draft'
|
||||||
|
? <SbButton
|
||||||
|
type="button"
|
||||||
|
onClick={() => addChildPage()}
|
||||||
|
>Add child page</SbButton>
|
||||||
|
: null}
|
||||||
{ mode.value === SbMode.View
|
{ mode.value === SbMode.View
|
||||||
? <SbButton
|
? <SbButton
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => edit(page.value?.attributes?.block!)}
|
onClick={() => edit(currentPage.value?.attributes?.block!)}
|
||||||
>Edit</SbButton>
|
>Edit</SbButton>
|
||||||
: <>
|
: <>
|
||||||
<SbButton
|
<SbButton
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
.ex-main-menu {
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,12 +1,83 @@
|
||||||
.ex-admin-nav {
|
.ex-admin-nav {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
width: var(--nav-width);
|
width: var(--ex-nav-width);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
transition: width 0.2s ease;
|
||||||
|
|
||||||
&_expanded {
|
&_expanded {
|
||||||
width: 80vw;
|
width: 300px;
|
||||||
max-width: 300px;
|
max-width: 80vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--menu {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
flex-grow: 1;
|
||||||
|
border-right: 1px solid var(--grey-2);
|
||||||
|
|
||||||
|
&-spacer {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--menu-item {
|
||||||
|
&-action {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: var(--ex-nav-width);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
overflow: hidden;
|
||||||
|
color: var(--fg);
|
||||||
|
background-color: var(--bg);
|
||||||
|
font-weight: bold;
|
||||||
|
border: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 12px;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--bg);
|
||||||
|
background-color: var(--interact);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-title {
|
||||||
|
opacity: 0.001;
|
||||||
|
height: auto;
|
||||||
|
width: calc(100% - 60px);
|
||||||
|
overflow: hidden;
|
||||||
|
margin: 0px;
|
||||||
|
margin-left: 16px;
|
||||||
|
transition: opacity 0.1s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-icon {
|
||||||
|
position: absolute;
|
||||||
|
left: calc((var(--ex-nav-width) / 2) - 8px);
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&_expanded &--menu-item {
|
||||||
|
&-title {
|
||||||
|
//width: calc(100% - (32px + 24px));
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-icon {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 1000px) {
|
@media screen and (min-width: 1000px) {
|
||||||
|
&--toggle {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { NuxtLink } from '~~/.nuxt/components';
|
import { NuxtLink } from '#components';
|
||||||
|
|
||||||
import './Nav.scss';
|
import './Nav.scss';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
setup() {
|
setup() {
|
||||||
|
const { setMe } = useMe();
|
||||||
|
|
||||||
const expanded = useState(() => false);
|
const expanded = useState(() => false);
|
||||||
const toggle = () => {
|
const toggle = () => {
|
||||||
expanded.value != expanded.value;
|
expanded.value = !expanded.value;
|
||||||
};
|
};
|
||||||
|
|
||||||
const classes = computed(() => ({
|
const classes = computed(() => ({
|
||||||
|
@ -15,18 +17,54 @@ export default defineComponent({
|
||||||
'ex-admin-nav_expanded': expanded.value,
|
'ex-admin-nav_expanded': expanded.value,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const logout = () => {
|
||||||
|
setMe(null);
|
||||||
|
useGqlToken({
|
||||||
|
token: null,
|
||||||
|
config: { type: 'Bearer' },
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return () => (
|
return () => (
|
||||||
<nav
|
<nav class={classes.value}>
|
||||||
class={classes.value}
|
|
||||||
>
|
|
||||||
<button
|
<button
|
||||||
class="ex-admin-nav--toggle"
|
class="ex-admin-nav--toggle"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => toggle()}
|
onClick={() => toggle()}
|
||||||
>Toggle</button>
|
aria-label="Toggle"
|
||||||
|
>
|
||||||
|
<font-awesome-icon
|
||||||
|
icon={`fa-solid fa-arrow-${expanded.value ? 'left' : 'right'}`}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
<ul class="ex-admin-nav--menu">
|
<ul class="ex-admin-nav--menu">
|
||||||
<li class="ex-admin-nav--menu-item">
|
<li class="ex-admin-nav--menu-item">
|
||||||
<NuxtLink to="/">Logout</NuxtLink>
|
<NuxtLink
|
||||||
|
class="ex-admin-nav--menu-item-action"
|
||||||
|
to="/"
|
||||||
|
>
|
||||||
|
<font-awesome-icon
|
||||||
|
class="ex-admin-nav--menu-item-icon"
|
||||||
|
icon="fa-solid fa-home"
|
||||||
|
/>
|
||||||
|
<span class="ex-admin-nav--menu-item-title">Website</span>
|
||||||
|
</NuxtLink>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="ex-admin-nav--menu-spacer"></li>
|
||||||
|
|
||||||
|
<li class="ex-admin-nav--menu-item">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="ex-admin-nav--menu-item-action"
|
||||||
|
onClick={() => logout()}
|
||||||
|
>
|
||||||
|
<font-awesome-icon
|
||||||
|
class="ex-admin-nav--menu-item-icon"
|
||||||
|
icon="fa-solid fa-right-from-bracket"
|
||||||
|
/>
|
||||||
|
<span class="ex-admin-nav--menu-item-title">Logout</span>
|
||||||
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
|
@ -1,8 +1,20 @@
|
||||||
import { IBlockData, SbMode } from "@schlechtenburg/core";
|
import { IBlockData, SbMode } from "@schlechtenburg/core";
|
||||||
|
import { IPage } from "./pages";
|
||||||
|
|
||||||
export const useEditor = () => {
|
export const useEditor = () => {
|
||||||
|
const {
|
||||||
|
currentPage,
|
||||||
|
currentPageId,
|
||||||
|
setCurrentPageId,
|
||||||
|
} = useCurrentPage();
|
||||||
|
|
||||||
|
const {
|
||||||
|
removePage,
|
||||||
|
updatePage,
|
||||||
|
pages,
|
||||||
|
} = usePages();
|
||||||
|
|
||||||
const mode = useState<SbMode>('mode', () => SbMode.View);
|
const mode = useState<SbMode>('mode', () => SbMode.View);
|
||||||
const revision = useState<number>('revision', () => 0);
|
|
||||||
const draft = useState<IBlockData<any>|null>('draft', () => null);
|
const draft = useState<IBlockData<any>|null>('draft', () => null);
|
||||||
|
|
||||||
const setMode = (newMode: SbMode) => {
|
const setMode = (newMode: SbMode) => {
|
||||||
|
@ -16,13 +28,64 @@ export const useEditor = () => {
|
||||||
const edit = (block: IBlockData<any>) => {
|
const edit = (block: IBlockData<any>) => {
|
||||||
draft.value = block;
|
draft.value = block;
|
||||||
mode.value = SbMode.Edit;
|
mode.value = SbMode.Edit;
|
||||||
|
updateDraft(currentPage.value?.attributes?.block!);
|
||||||
};
|
};
|
||||||
const save = () => {
|
|
||||||
revision.value = revision.value + 1;
|
const save = async () => {
|
||||||
mode.value = SbMode.View;
|
if (currentPageId.value === 'draft') {
|
||||||
|
const { data, error } = await useAsyncGql(
|
||||||
|
'createPage',
|
||||||
|
{ data: {
|
||||||
|
title: currentPage.value?.attributes?.title,
|
||||||
|
slug: currentPage.value?.attributes?.slug,
|
||||||
|
block: currentPage.value?.attributes?.block,
|
||||||
|
parent: currentPage.value?.attributes?.parent?.data?.id,
|
||||||
|
publishedAt: (new Date()).toISOString(),
|
||||||
|
}}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (error.value) {
|
||||||
|
console.error('Error creating page!');
|
||||||
|
console.error('error:', error.value);
|
||||||
|
console.error('data:', data.value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setMode(SbMode.View);
|
||||||
|
updatePage(data.value?.createPage?.data?.attributes?.block);
|
||||||
|
updateDraft(data.value?.createPage?.data?.attributes?.block);
|
||||||
|
navigateTo(getPagePath(data.value?.createPage?.data! as IPage, pages.value));
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
const { data, error } = await useAsyncGql(
|
||||||
|
'updatePage',
|
||||||
|
{
|
||||||
|
id: currentPage.value?.id || '',
|
||||||
|
data: {
|
||||||
|
block: draft.value!
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (error.value) {
|
||||||
|
console.error('Error updating page!');
|
||||||
|
console.error('error:', error.value);
|
||||||
|
console.error('data:', data.value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setMode(SbMode.View);
|
||||||
|
updatePage(data.value?.updatePage?.data?.attributes?.block);
|
||||||
|
updateDraft(data.value?.updatePage?.data?.attributes?.block);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
mode.value = SbMode.View;
|
setMode(SbMode.View);
|
||||||
|
if (currentPageId.value === 'draft') {
|
||||||
|
setCurrentPageId(currentPage.value?.attributes?.parent?.data?.id || null);
|
||||||
|
removePage('draft');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -32,7 +95,6 @@ export const useEditor = () => {
|
||||||
edit,
|
edit,
|
||||||
cancel,
|
cancel,
|
||||||
save,
|
save,
|
||||||
revision,
|
|
||||||
|
|
||||||
draft,
|
draft,
|
||||||
updateDraft,
|
updateDraft,
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
import { IBlockData } from "@schlechtenburg/core";
|
|
||||||
|
|
||||||
export interface IRole {
|
export interface IRole {
|
||||||
id?: string|null;
|
id?: string|null;
|
||||||
attributes?: {
|
attributes?: {
|
||||||
|
@ -31,25 +29,3 @@ export const useMe = () => {
|
||||||
setMe,
|
setMe,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface IPage {
|
|
||||||
id?: string|null;
|
|
||||||
attributes?: {
|
|
||||||
title?: string;
|
|
||||||
block?: IBlockData<any>|null;
|
|
||||||
path?: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const usePage = () => {
|
|
||||||
const page = useState<IPage|null>('page', () => null);
|
|
||||||
|
|
||||||
const setPage = (newPage: IPage|null) => {
|
|
||||||
page.value = newPage;
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
page,
|
|
||||||
setPage,
|
|
||||||
};
|
|
||||||
};
|
|
104
packages/example-site/composables/pages.ts
Normal file
104
packages/example-site/composables/pages.ts
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
import { IBlockData } from "@schlechtenburg/core";
|
||||||
|
|
||||||
|
export interface IPage {
|
||||||
|
id?: string|null;
|
||||||
|
attributes?: {
|
||||||
|
title?: string;
|
||||||
|
block?: IBlockData<any>|null;
|
||||||
|
slug?: string;
|
||||||
|
parent?: {
|
||||||
|
data?: {
|
||||||
|
id?: string|null;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const usePages = () => {
|
||||||
|
const pages = useState<IPage[]|[]>('pages', () => []);
|
||||||
|
|
||||||
|
const getPage = (id:string) => pages.value.find(p => p.id === id);
|
||||||
|
|
||||||
|
const setPages = (newPages: IPage[] = []) => {
|
||||||
|
pages.value = newPages;
|
||||||
|
};
|
||||||
|
|
||||||
|
const updatePage = (page: Partial<IPage>) => {
|
||||||
|
const existing = pages.value.find(p => p.id === page.id);
|
||||||
|
if (!existing) {
|
||||||
|
console.warn('Could not update page because it was not found in the store', page);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setPages([
|
||||||
|
...pages.value.filter(p => p.id !== page.id),
|
||||||
|
{
|
||||||
|
id: existing.id,
|
||||||
|
attributes: {
|
||||||
|
...existing.attributes,
|
||||||
|
...page.attributes,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const removePage = (id: string) => {
|
||||||
|
setPages(pages.value.filter(p => p.id !== id));
|
||||||
|
};
|
||||||
|
|
||||||
|
const insertPage = (page: IPage) => {
|
||||||
|
setPages([
|
||||||
|
...pages.value,
|
||||||
|
page,
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchPages = async () => {
|
||||||
|
const { data, error } = await useAsyncGql('pages');
|
||||||
|
setPages(data.value?.pages?.data as IPage[]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
pages,
|
||||||
|
setPages,
|
||||||
|
getPage,
|
||||||
|
|
||||||
|
fetchPages,
|
||||||
|
|
||||||
|
insertPage,
|
||||||
|
updatePage,
|
||||||
|
removePage,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useCurrentPage = () => {
|
||||||
|
const { pages, insertPage } = usePages();
|
||||||
|
|
||||||
|
const currentPageId = useState<string|null>('currentPageId', () => null);
|
||||||
|
|
||||||
|
const setCurrentPage = (newPage: IPage|null) => {
|
||||||
|
if (!newPage || !newPage.id) {
|
||||||
|
currentPageId.value = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pages.value.find(p => p.id === newPage.id)) {
|
||||||
|
insertPage(newPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPageId.value = newPage.id;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setCurrentPageId = (newPageId: string|null) => {
|
||||||
|
currentPageId.value = newPageId;
|
||||||
|
};
|
||||||
|
|
||||||
|
const currentPage = computed(() => pages.value.find(p => p.id === currentPageId.value));
|
||||||
|
|
||||||
|
return {
|
||||||
|
currentPage,
|
||||||
|
setCurrentPage,
|
||||||
|
currentPageId,
|
||||||
|
setCurrentPageId,
|
||||||
|
};
|
||||||
|
};
|
|
@ -1,14 +1,29 @@
|
||||||
import { IPage } from "~~/composables/states";
|
import { IPage } from "~~/composables/pages";
|
||||||
|
|
||||||
export default defineNuxtRouteMiddleware(async (to, from) => {
|
export default defineNuxtRouteMiddleware(async (to) => {
|
||||||
const { setPage } = usePage();
|
const { setCurrentPage } = useCurrentPage();
|
||||||
|
const { fetchPages } = usePages();
|
||||||
|
|
||||||
const { data, error } = await useAsyncGql({
|
|
||||||
|
const pathParts = to.path.split('/').filter(p => p !== '');
|
||||||
|
pathParts.unshift('');
|
||||||
|
|
||||||
|
const filters = pathParts.reduce((total, part) => {
|
||||||
|
return {
|
||||||
|
id: { ne: null },
|
||||||
|
slug: { eq: part === '' ? null : part },
|
||||||
|
|
||||||
|
parent: total,
|
||||||
|
};
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
const [{ data, error }] = await Promise.all([
|
||||||
|
useAsyncGql({
|
||||||
operation: 'pages',
|
operation: 'pages',
|
||||||
variables: {
|
variables: { filters },
|
||||||
filters: { path: { eq: to.path }},
|
}),
|
||||||
},
|
fetchPages(),
|
||||||
});
|
]);
|
||||||
|
|
||||||
if (error.value) {
|
if (error.value) {
|
||||||
console.error('Error getting pages!');
|
console.error('Error getting pages!');
|
||||||
|
@ -17,10 +32,9 @@ export default defineNuxtRouteMiddleware(async (to, from) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const newPage = (data.value?.pages?.data[0] as IPage) || null;
|
const newPage = (data.value?.pages?.data[0] as IPage) || null;
|
||||||
|
if (!newPage) {
|
||||||
if (newPage?.attributes && !newPage?.attributes?.block) {
|
setResponseStatus(404)
|
||||||
newPage.attributes.block = getNewPageBlock();
|
return;
|
||||||
}
|
}
|
||||||
|
setCurrentPage(newPage);
|
||||||
setPage(newPage);
|
|
||||||
});
|
});
|
||||||
|
|
26
packages/example-site/package-lock.json
generated
26
packages/example-site/package-lock.json
generated
|
@ -812,6 +812,32 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
|
"@fortawesome/fontawesome-common-types": {
|
||||||
|
"version": "6.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.2.1.tgz",
|
||||||
|
"integrity": "sha512-Sz07mnQrTekFWLz5BMjOzHl/+NooTdW8F8kDQxjWwbpOJcnoSg4vUDng8d/WR1wOxM0O+CY9Zw0nR054riNYtQ=="
|
||||||
|
},
|
||||||
|
"@fortawesome/fontawesome-svg-core": {
|
||||||
|
"version": "6.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.2.1.tgz",
|
||||||
|
"integrity": "sha512-HELwwbCz6C1XEcjzyT1Jugmz2NNklMrSPjZOWMlc+ZsHIVk+XOvOXLGGQtFBwSyqfJDNgRq4xBCwWOaZ/d9DEA==",
|
||||||
|
"requires": {
|
||||||
|
"@fortawesome/fontawesome-common-types": "6.2.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@fortawesome/free-solid-svg-icons": {
|
||||||
|
"version": "6.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.2.1.tgz",
|
||||||
|
"integrity": "sha512-oKuqrP5jbfEPJWTij4sM+/RvgX+RMFwx3QZCZcK9PrBDgxC35zuc7AOFsyMjMd/PIFPeB2JxyqDr5zs/DZFPPw==",
|
||||||
|
"requires": {
|
||||||
|
"@fortawesome/fontawesome-common-types": "6.2.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@fortawesome/vue-fontawesome": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/vue-fontawesome/-/vue-fontawesome-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-xHVtVY8ASUeEvgcA/7vULUesENhD+pi/EirRHdMBqooHlXBqK+yrV6d8tUye1m5UKQKVgYAHMhUBfOnoiwvc8Q=="
|
||||||
|
},
|
||||||
"@graphql-codegen/cli": {
|
"@graphql-codegen/cli": {
|
||||||
"version": "2.16.1",
|
"version": "2.16.1",
|
||||||
"resolved": "https://registry.npmjs.org/@graphql-codegen/cli/-/cli-2.16.1.tgz",
|
"resolved": "https://registry.npmjs.org/@graphql-codegen/cli/-/cli-2.16.1.tgz",
|
||||||
|
|
|
@ -13,12 +13,16 @@
|
||||||
"nuxt": "3.0.0"
|
"nuxt": "3.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-svg-core": "^6.2.1",
|
||||||
|
"@fortawesome/free-solid-svg-icons": "^6.2.1",
|
||||||
|
"@fortawesome/vue-fontawesome": "^3.0.2",
|
||||||
"@graphql-codegen/cli": "^2.16.1",
|
"@graphql-codegen/cli": "^2.16.1",
|
||||||
"@schlechtenburg/core": "^0.0.0",
|
"@schlechtenburg/core": "^0.0.0",
|
||||||
"@schlechtenburg/heading": "^0.0.0",
|
"@schlechtenburg/heading": "^0.0.0",
|
||||||
"@schlechtenburg/image": "^0.0.0",
|
"@schlechtenburg/image": "^0.0.0",
|
||||||
"@schlechtenburg/layout": "^0.0.0",
|
"@schlechtenburg/layout": "^0.0.0",
|
||||||
"@schlechtenburg/paragraph": "^0.0.0",
|
"@schlechtenburg/paragraph": "^0.0.0",
|
||||||
|
"@schlechtenburg/style": "^0.0.0",
|
||||||
"event-target-polyfill": "^0.0.3",
|
"event-target-polyfill": "^0.0.3",
|
||||||
"nuxt-graphql-client": "^0.2.23"
|
"nuxt-graphql-client": "^0.2.23"
|
||||||
}
|
}
|
||||||
|
|
19
packages/example-site/plugins/fontawesome.ts
Normal file
19
packages/example-site/plugins/fontawesome.ts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import { library } from '@fortawesome/fontawesome-svg-core';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
|
||||||
|
import {
|
||||||
|
faRightFromBracket,
|
||||||
|
faHome,
|
||||||
|
faArrowRight,
|
||||||
|
faArrowLeft,
|
||||||
|
} from '@fortawesome/free-solid-svg-icons';
|
||||||
|
|
||||||
|
/* add icons to the library */
|
||||||
|
library.add(faRightFromBracket);
|
||||||
|
library.add(faArrowRight);
|
||||||
|
library.add(faArrowLeft);
|
||||||
|
library.add(faHome);
|
||||||
|
|
||||||
|
|
||||||
|
export default defineNuxtPlugin((nuxtApp) => {
|
||||||
|
nuxtApp.vueApp.component('font-awesome-icon', FontAwesomeIcon);
|
||||||
|
})
|
|
@ -4,10 +4,13 @@ mutation createPage($data: PageInput!) {
|
||||||
id
|
id
|
||||||
attributes {
|
attributes {
|
||||||
title
|
title
|
||||||
path
|
slug
|
||||||
block
|
block
|
||||||
public
|
parent {
|
||||||
publishedAt
|
data {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,13 @@ query page($id: ID) {
|
||||||
id
|
id
|
||||||
attributes {
|
attributes {
|
||||||
title
|
title
|
||||||
path
|
slug
|
||||||
block
|
block
|
||||||
public
|
parent {
|
||||||
publishedAt
|
data {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,13 @@ query pages($filters: PageFiltersInput) {
|
||||||
id
|
id
|
||||||
attributes {
|
attributes {
|
||||||
title
|
title
|
||||||
path
|
slug
|
||||||
block
|
block
|
||||||
public
|
parent {
|
||||||
publishedAt
|
data {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,16 @@
|
||||||
mutation updatePage($id: ID!, $data: PageInput!) {
|
mutation updatePage($id: ID!, $data: PageInput!) {
|
||||||
updatePage(id: $id, data: $data) {
|
updatePage(id: $id, data: $data) {
|
||||||
data {
|
data {
|
||||||
|
id
|
||||||
attributes {
|
attributes {
|
||||||
|
title
|
||||||
|
slug
|
||||||
block
|
block
|
||||||
|
parent {
|
||||||
|
data {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { generateBlockId, IBlockData } from "@schlechtenburg/core";
|
import { generateBlockId, IBlockData } from "@schlechtenburg/core";
|
||||||
import { getDefaultData as getDefaultLayoutData, ILayoutData, name as layoutName } from "@schlechtenburg/layout";
|
import { getDefaultData as getDefaultLayoutData, ILayoutData, name as layoutName } from "@schlechtenburg/layout";
|
||||||
import { getDefaultData as getDefaultHeadingData, name as headingName } from "@schlechtenburg/heading";
|
import { getDefaultData as getDefaultHeadingData, name as headingName } from "@schlechtenburg/heading";
|
||||||
|
import { IPage } from "~~/composables/pages";
|
||||||
|
|
||||||
export const getNewPageBlock: () => IBlockData<ILayoutData> = () => ({
|
export const getNewPageBlock: () => IBlockData<ILayoutData> = () => ({
|
||||||
id: generateBlockId(),
|
id: generateBlockId(),
|
||||||
|
@ -15,3 +16,28 @@ export const getNewPageBlock: () => IBlockData<ILayoutData> = () => ({
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const getPageParents = (page: IPage, pages: IPage[], parents: IPage[]):IPage[] => {
|
||||||
|
const parent = pages.find(p => p.id === page.attributes?.parent?.data?.id);
|
||||||
|
if (!parent) {
|
||||||
|
return parents;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getPageParents(
|
||||||
|
parent,
|
||||||
|
pages,
|
||||||
|
[
|
||||||
|
parent,
|
||||||
|
...parents,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getPagePath = (page: IPage, pages: IPage[]) => {
|
||||||
|
const ancestors = [
|
||||||
|
...getPageParents(page, pages, []),
|
||||||
|
page,
|
||||||
|
];
|
||||||
|
|
||||||
|
return ancestors.reduce((path, page) => page.attributes?.slug ? `${path}/${page.attributes?.slug}` : path, '');
|
||||||
|
}
|
||||||
|
|
|
@ -104,7 +104,7 @@ export default defineComponent({
|
||||||
<img
|
<img
|
||||||
src={localData.src}
|
src={localData.src}
|
||||||
alt={localData.alt}
|
alt={localData.alt}
|
||||||
class="sb-image__content"
|
class="sb-image--content"
|
||||||
/>
|
/>
|
||||||
<SbBlock
|
<SbBlock
|
||||||
block={localData.description}
|
block={localData.description}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
.sb-image {
|
.sb-image {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
||||||
&__content {
|
&--content {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,11 +9,7 @@
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__item {
|
> *:not(.sb-block-placeholder) {
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
> * {
|
|
||||||
flex-basis: auto;
|
flex-basis: auto;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
flex-shrink: 1;
|
flex-shrink: 1;
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
0
packages/style/lib/index.ts
Normal file
0
packages/style/lib/index.ts
Normal file
29
packages/style/package.json
Normal file
29
packages/style/package.json
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"name": "@schlechtenburg/style",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "Styles for schlechtenburg",
|
||||||
|
"author": "Benjamin Bädorf <hello@benjaminbaedorf.eu>",
|
||||||
|
"homepage": "",
|
||||||
|
"main": "lib/index.ts",
|
||||||
|
"license": "GPL-3.0-or-later",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"directories": {
|
||||||
|
"lib": "lib",
|
||||||
|
"test": "__tests__"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"lib",
|
||||||
|
"fonts",
|
||||||
|
"images",
|
||||||
|
"scss"
|
||||||
|
],
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git@git.pub.solar:b12f/schlechtenburg.git"
|
||||||
|
}
|
||||||
|
}
|
360
packages/style/scss/montserrat.scss
Normal file
360
packages/style/scss/montserrat.scss
Normal file
|
@ -0,0 +1,360 @@
|
||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 100;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUQjIg1_i6t8kCHKm459WxRxC7m0dR9pBOi.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 100;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUQjIg1_i6t8kCHKm459WxRzS7m0dR9pBOi.woff2) format('woff2');
|
||||||
|
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 100;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUQjIg1_i6t8kCHKm459WxRxi7m0dR9pBOi.woff2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 100;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUQjIg1_i6t8kCHKm459WxRxy7m0dR9pBOi.woff2) format('woff2');
|
||||||
|
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 100;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUQjIg1_i6t8kCHKm459WxRyS7m0dR9pA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUQjIg1_i6t8kCHKm459WxRxC7m0dR9pBOi.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUQjIg1_i6t8kCHKm459WxRzS7m0dR9pBOi.woff2) format('woff2');
|
||||||
|
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUQjIg1_i6t8kCHKm459WxRxi7m0dR9pBOi.woff2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUQjIg1_i6t8kCHKm459WxRxy7m0dR9pBOi.woff2) format('woff2');
|
||||||
|
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUQjIg1_i6t8kCHKm459WxRyS7m0dR9pA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUQjIg1_i6t8kCHKm459WxRxC7m0dR9pBOi.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUQjIg1_i6t8kCHKm459WxRzS7m0dR9pBOi.woff2) format('woff2');
|
||||||
|
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUQjIg1_i6t8kCHKm459WxRxi7m0dR9pBOi.woff2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUQjIg1_i6t8kCHKm459WxRxy7m0dR9pBOi.woff2) format('woff2');
|
||||||
|
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUQjIg1_i6t8kCHKm459WxRyS7m0dR9pA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 100;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUSjIg1_i6t8kCHKm459WRhyyTh89ZNpQ.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 100;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUSjIg1_i6t8kCHKm459W1hyyTh89ZNpQ.woff2) format('woff2');
|
||||||
|
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 100;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUSjIg1_i6t8kCHKm459WZhyyTh89ZNpQ.woff2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 100;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUSjIg1_i6t8kCHKm459WdhyyTh89ZNpQ.woff2) format('woff2');
|
||||||
|
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 100;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUSjIg1_i6t8kCHKm459WlhyyTh89Y.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUSjIg1_i6t8kCHKm459WRhyyTh89ZNpQ.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUSjIg1_i6t8kCHKm459W1hyyTh89ZNpQ.woff2) format('woff2');
|
||||||
|
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUSjIg1_i6t8kCHKm459WZhyyTh89ZNpQ.woff2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUSjIg1_i6t8kCHKm459WdhyyTh89ZNpQ.woff2) format('woff2');
|
||||||
|
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUSjIg1_i6t8kCHKm459WlhyyTh89Y.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUSjIg1_i6t8kCHKm459WRhyyTh89ZNpQ.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUSjIg1_i6t8kCHKm459W1hyyTh89ZNpQ.woff2) format('woff2');
|
||||||
|
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUSjIg1_i6t8kCHKm459WZhyyTh89ZNpQ.woff2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUSjIg1_i6t8kCHKm459WdhyyTh89ZNpQ.woff2) format('woff2');
|
||||||
|
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUSjIg1_i6t8kCHKm459WlhyyTh89Y.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUSjIg1_i6t8kCHKm459WRhyyTh89ZNpQ.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUSjIg1_i6t8kCHKm459W1hyyTh89ZNpQ.woff2) format('woff2');
|
||||||
|
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUSjIg1_i6t8kCHKm459WZhyyTh89ZNpQ.woff2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUSjIg1_i6t8kCHKm459WdhyyTh89ZNpQ.woff2) format('woff2');
|
||||||
|
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUSjIg1_i6t8kCHKm459WlhyyTh89Y.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 900;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUSjIg1_i6t8kCHKm459WRhyyTh89ZNpQ.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 900;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUSjIg1_i6t8kCHKm459W1hyyTh89ZNpQ.woff2) format('woff2');
|
||||||
|
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 900;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUSjIg1_i6t8kCHKm459WZhyyTh89ZNpQ.woff2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 900;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUSjIg1_i6t8kCHKm459WdhyyTh89ZNpQ.woff2) format('woff2');
|
||||||
|
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 900;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(#{$sb-style-root}/fonts/montserrat/v25/JTUSjIg1_i6t8kCHKm459WlhyyTh89Y.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
Loading…
Reference in a new issue