diff --git a/content/getting-started/10.accessibility.md b/content/getting-started/10.accessibility.md index 2116a9d6..134163bf 100644 --- a/content/getting-started/10.accessibility.md +++ b/content/getting-started/10.accessibility.md @@ -26,8 +26,6 @@ Read more: https://www.tiny.cloud/docs/tinymce/6/tinymce-and-screenreaders/ ### Things to keep in mind -- Visual Editor is only accessible on the Directus side — not your website. So we always need to click an edit button first, then the - overlays are accessible. - Manual Sorting is currently not supported/accessible. - Once focused, the code interface (Codemirror) cannot be exited using the tab key. - The Markdown interface also doesn’t allow you to exit the field. This is because it supports tabs inside the editor’s diff --git a/content/guides/02.content/8.visual-editor/3.customization.md b/content/guides/02.content/8.visual-editor/3.customization.md index c9d9883a..183c6512 100644 --- a/content/guides/02.content/8.visual-editor/3.customization.md +++ b/content/guides/02.content/8.visual-editor/3.customization.md @@ -39,6 +39,9 @@ The library ships with a number of built in CSS Selectors already applied to its .directus-visual-editing-edit-button { /* the edit button */ } +.directus-visual-editing-actions-flipped { + /* a modifier on the rect that flips the action buttons below it, applied automatically when the rect is near the top of the viewport */ +} ``` ## CSS Variables @@ -48,21 +51,33 @@ The library also ships with a number of predefined CSS variables. These can be o ```css :root { --directus-visual-editing--overlay--z-index: 999999999; - --directus-visual-editing--rect--border-spacing: 9px; + --directus-visual-editing--rect--border-spacing: 8px; --directus-visual-editing--rect--border-width: 2px; --directus-visual-editing--rect--border-color: #6644ff; --directus-visual-editing--rect--border-radius: 6px; --directus-visual-editing--rect-hover--opacity: 0.333; --directus-visual-editing--rect-highlight--opacity: 0.333; - --directus-visual-editing--edit-btn--width: 28px; - --directus-visual-editing--edit-btn--height: 28px; - --directus-visual-editing--edit-btn--radius: 50%; + --directus-visual-editing--actions--offset: 4px; + --directus-visual-editing--actions--focus-ring-color: #6644ff; + --directus-visual-editing--actions--focus-ring-width: 2px; + --directus-visual-editing--actions--focus-ring-offset: 2px; + --directus-visual-editing--edit-btn--width: 24px; + --directus-visual-editing--edit-btn--height: 24px; + --directus-visual-editing--edit-btn--radius: 6px; --directus-visual-editing--edit-btn--bg-color: #6644ff; + --directus-visual-editing--edit-btn-hover--bg-color: color-mix(in srgb, #6644ff, #2e3C43 25%); --directus-visual-editing--edit-btn--icon-bg-image: url('data:image/svg+xml,'); --directus-visual-editing--edit-btn--icon-bg-size: 66.6%; + --directus-visual-editing--ai-btn--bg-color: #6644ff; + --directus-visual-editing--ai-btn-hover--bg-color: color-mix(in srgb, #6644ff, #2e3C43 25%); } ``` +::callout{icon="material-symbols:info-outline"} +**Defaults inside the Directus Studio** +When the visual editor runs inside the Directus Studio iframe, defaults for several variables are sourced from the active Studio theme (primary color, border radius, button size, focus-ring width/offset) rather than the compiled-in fallbacks shown above. Your own `:root` or `customClass` overrides still take precedence. +:: + ## Custom Classes Finally, custom classes can be added to all or a subset of elements defined by the library’s [apply method](/guides/content/visual-editor/frontend-library#api) using the `customClass` property. This class will be applied to the `div.directus-visual-editing-overlay` element within the `div#directus-visual-editing` container. diff --git a/content/guides/09.extensions/3.app-extensions/5.modules.md b/content/guides/09.extensions/3.app-extensions/5.modules.md index 8675d273..d1400593 100644 --- a/content/guides/09.extensions/3.app-extensions/5.modules.md +++ b/content/guides/09.extensions/3.app-extensions/5.modules.md @@ -23,19 +23,19 @@ The `index.js` or `index.ts` file exports an object that is read by Directus. It ## Entrypoint Example ```js -import { defineInterface } from '@directus/extensions-sdk' -import ModuleComponent from './module.vue'; +import { defineInterface } from "@directus/extensions-sdk"; +import ModuleComponent from "./module.vue"; export default defineInterface({ - id: 'custom', - name: 'Custom', - icon: 'box', - routes: [ - { - path: '', - component: ModuleComponent, - }, - ], + id: "custom", + name: "Custom", + icon: "box", + routes: [ + { + path: "", + component: ModuleComponent, + }, + ], }); ``` @@ -62,7 +62,6 @@ The route object uses the same syntax as Vue Router, defining each route as an o | `path` | The route path without the leading slash. | | `component` | A Vue component to be rendered for this route. | - The `routes` array should contain a root route with an empty path, which will load at the module's base route (the value of the module's `id`). Dynamic portions of the path can be defined using the `:param` syntax. ### Route Component @@ -71,7 +70,7 @@ The module route component will be rendered in the Data Studio when the route is ```vue @@ -357,19 +335,19 @@ To start using the new component in `module.vue`, add it to the `export default` ```js export default { - components: { // [!code ++] - PageNavigation, // [!code ++] - }, // [!code ++] - props: { - } -} + components: { + // [!code ++] + PageNavigation, // [!code ++] + }, // [!code ++] + props: {}, +}; ``` -Now this can be used in the template. After the `breadcrumbs`, add the following code: +Now this can be used in the template. Inside the `private-view`, add the following code: ```vue ``` @@ -394,11 +372,16 @@ In the template, create the HTML structure after the navigation and some new var ```html
- +
-
- +
+ {{ card.label }}
@@ -424,10 +407,10 @@ Add a new function to change the page called `change_page`. Import the `vue-rout import: ```js -import { ref, watch } from 'vue'; -import { useApi } from '@directus/extensions-sdk'; -import { useRouter } from 'vue-router'; // [!code ++] -import PageNavigation from './components/navigation.vue'; +import { ref, watch } from "vue"; +import { useApi } from "@directus/extensions-sdk"; +import { useRouter } from "vue-router"; // [!code ++] +import PageNavigation from "./components/navigation.vue"; ``` Assign the router to a variable: @@ -446,38 +429,48 @@ Create the function before the return and add the three new variables and the ne items. This will allow them to be used in the template. ```js -function change_page(to){ +function change_page(to) { const next = router.resolve(`${to}`); router.push(next); } -return { page_title, page_banner, page_cards, page_body, breadcrumb, all_pages, change_page }; +return { + page_title, + page_banner, + page_cards, + page_body, + all_pages, + change_page, +}; ``` Inside the render_page function, start adding content to these new variables. Here is an example using static content. ```js -switch(page) { - case 'home': - page_title.value = 'Home'; - page_banner.value = '/assets/83BD365C-C3CE-4015-B2AD-63EDA9E52A69?width=2000&height=563&fit=cover'; +switch (page) { + case "home": + page_title.value = "Home"; + page_banner.value = + "/assets/83BD365C-C3CE-4015-B2AD-63EDA9E52A69?width=2000&height=563&fit=cover"; page_cards.value = all_pages.value; - page_body.value = '

Lorem ipsum dolor sit amet

'; + page_body.value = "

Lorem ipsum dolor sit amet

"; break; - case 'hello-world': - page_title.value = 'Hello World'; - page_banner.value = '/assets/853B243D-A1BF-6051-B1BF-23EDA8E32A09?width=2000&height=563&fit=cover'; + case "hello-world": + page_title.value = "Hello World"; + page_banner.value = + "/assets/853B243D-A1BF-6051-B1BF-23EDA8E32A09?width=2000&height=563&fit=cover"; page_cards.value = all_pages.value; - page_body.value = '

Lorem ipsum dolor sit amet

'; + page_body.value = "

Lorem ipsum dolor sit amet

"; break; - case 'contact': - page_title.value = 'Contact Us'; - page_banner.value = '/assets/91CE173D-A1AD-4104-A1EC-74FCB8F41B58?width=2000&height=563&fit=cover'; + case "contact": + page_title.value = "Contact Us"; + page_banner.value = + "/assets/91CE173D-A1AD-4104-A1EC-74FCB8F41B58?width=2000&height=563&fit=cover"; page_cards.value = []; - page_body.value = '

Lorem ipsum dolor sit amet

'; + page_body.value = "

Lorem ipsum dolor sit amet

"; break; default: - page_title.value = '404: Not Found'; + page_title.value = "404: Not Found"; } ``` @@ -485,19 +478,22 @@ Or from the internal API providing you have a table with the fields `title`, `ba (WYSIWYG field): ```js -api.get(`/items/pages?fields=title,banner,content&filter[uri][_eq]=${page}`).then((rsp) => { - if(rsp.data.data){ - rsp.data.data.forEach(item => { - page_title.value = item.title; - page_banner.value = `/assets/${item.banner}?width=2000&height=563&fit=cover`; - page_body.value = item.content; - }); - } else { - page_title.value = "404: Not Found"; - } -}).catch((error) => { - console.log(error); -}); +api + .get(`/items/pages?fields=title,banner,content&filter[uri][_eq]=${page}`) + .then((rsp) => { + if (rsp.data.data) { + rsp.data.data.forEach((item) => { + page_title.value = item.title; + page_banner.value = `/assets/${item.banner}?width=2000&height=563&fit=cover`; + page_body.value = item.content; + }); + } else { + page_title.value = "404: Not Found"; + } + }) + .catch((error) => { + console.log(error); + }); ``` ### Work With Images @@ -528,13 +524,15 @@ export default function useDirectusToken(directusApi) { queryParams.push(`${key}=${value}`); } - return path.includes('?') ? `${path}&${queryParams.join('&')}` : `${path}?${queryParams.join('&')}`; + return path.includes("?") + ? `${path}&${queryParams.join("&")}` + : `${path}?${queryParams.join("&")}`; } function getToken() { return ( - directusApi.defaults?.headers?.['Authorization']?.split(' ')[1] || - directusApi.defaults?.headers?.common?.['Authorization']?.split(' ')[1] || + directusApi.defaults?.headers?.["Authorization"]?.split(" ")[1] || + directusApi.defaults?.headers?.common?.["Authorization"]?.split(" ")[1] || null ); } @@ -546,7 +544,7 @@ export default function useDirectusToken(directusApi) { access_token: accessToken, }); } -}; +} ``` This will use the access token of the current user to render the images. Alternatively, you can enable Read permissions @@ -555,7 +553,7 @@ on the Public role for the image ID or images with a specific folder ID to remov Import the function into the `module.vue` file to make it available in your script: ```js -import useDirectusToken from './use-directus-token'; +import useDirectusToken from "./use-directus-token"; ``` Include the function `AddTokenToURL` as a variable from the new script. @@ -573,7 +571,9 @@ setup(props) { Then wrap any internal images with this function: ```js -page_banner.value = addTokenToURL(`/assets/${item.banner}?width=2000&height=563&fit=cover`); +page_banner.value = addTokenToURL( + `/assets/${item.banner}?width=2000&height=563&fit=cover`, +); ``` ::callout{icon="material-symbols:info-outline} @@ -597,7 +597,7 @@ the following SCSS: width: 100%; max-width: 1024px; - &> div { + & > div { margin-bottom: var(--content-padding); } } @@ -694,22 +694,22 @@ images from within Directus to surface on the page. From here you can create con of the Directus platform. ```js [index.js] -import ModuleComponent from './module.vue'; +import ModuleComponent from "./module.vue"; export default { - id: 'landing-page', - name: 'Landing Page', - icon: 'rocket_launch', + id: "landing-page", + name: "Landing Page", + icon: "rocket_launch", routes: [ { - name: 'home', - path: '', + name: "home", + path: "", props: true, component: ModuleComponent, }, { - name: 'page', - path: ':page', + name: "page", + path: ":page", props: true, component: ModuleComponent, }, @@ -720,21 +720,23 @@ export default { ```vue [module.vue] ``` ```vue [components/navigation.vue]