├── .gitignore ├── screenshots ├── main.png ├── example_form.png └── example_settings.png ├── extension.config.js ├── src ├── shims.d.ts ├── assets │ ├── layout.svg │ └── preview.svg ├── index.ts ├── interface.vue └── components │ └── group-layout.vue ├── tsconfig.json ├── LICENSE ├── package.json ├── README.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | dist 4 | -------------------------------------------------------------------------------- /screenshots/main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ptkio/directus-extension-group-layout-sidebar/HEAD/screenshots/main.png -------------------------------------------------------------------------------- /extension.config.js: -------------------------------------------------------------------------------- 1 | import InlineSvg from 'rollup-plugin-inline-svg'; 2 | 3 | export default { 4 | plugins: [InlineSvg()], 5 | }; 6 | -------------------------------------------------------------------------------- /screenshots/example_form.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ptkio/directus-extension-group-layout-sidebar/HEAD/screenshots/example_form.png -------------------------------------------------------------------------------- /screenshots/example_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ptkio/directus-extension-group-layout-sidebar/HEAD/screenshots/example_settings.png -------------------------------------------------------------------------------- /src/shims.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import { DefineComponent } from 'vue'; 3 | const component: DefineComponent<{}, {}, any>; 4 | export default component; 5 | } 6 | declare module '*.svg'; 7 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2019", 4 | "lib": ["ES2019", "DOM"], 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "noFallthroughCasesInSwitch": true, 8 | "esModuleInterop": true, 9 | "noImplicitAny": true, 10 | "noImplicitThis": true, 11 | "noImplicitReturns": true, 12 | "noUnusedLocals": true, 13 | "noUncheckedIndexedAccess": true, 14 | "noUnusedParameters": true, 15 | "alwaysStrict": true, 16 | "strictNullChecks": true, 17 | "strictFunctionTypes": true, 18 | "strictBindCallApply": true, 19 | "strictPropertyInitialization": true, 20 | "resolveJsonModule": false, 21 | "skipLibCheck": true, 22 | "forceConsistentCasingInFileNames": true, 23 | "allowSyntheticDefaultImports": true, 24 | "isolatedModules": true, 25 | "rootDir": "./src" 26 | }, 27 | "include": ["./src/**/*.ts"] 28 | } 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Paul Tecchio 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "directus-extension-group-layout-sidebar", 3 | "description": "Group layout sidebar is an interface for Directus that provides field organization with a docked sidebar.\n", 4 | "icon": "web", 5 | "version": "1.1.0", 6 | "license": "MIT", 7 | "author": { 8 | "email": "paul.tecchio@gmail.com", 9 | "name": "ptkio" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/ptkio/directus-extension-group-layout-sidebar.git" 14 | }, 15 | "keywords": [ 16 | "directus", 17 | "directus-extension", 18 | "directus-custom-interface", 19 | "group", 20 | "sidebar", 21 | "docked", 22 | "layout" 23 | ], 24 | "type": "module", 25 | "directus:extension": { 26 | "type": "interface", 27 | "path": "dist/index.js", 28 | "source": "src/index.ts", 29 | "host": "^10.3.3", 30 | "sandbox": { 31 | "enabled": true, 32 | "requestedScopes": {} 33 | } 34 | }, 35 | "files": [ 36 | "dist" 37 | ], 38 | "scripts": { 39 | "build-publish": "directus-extension build && npm publish", 40 | "build": "directus-extension build", 41 | "dev": "directus-extension build -w --no-minify", 42 | "link": "directus-extension link" 43 | }, 44 | "devDependencies": { 45 | "@directus/extensions-sdk": "10.3.3", 46 | "typescript": "^5.3.3", 47 | "vue": "^3.4.19" 48 | }, 49 | "dependencies": { 50 | "rollup-plugin-inline-svg": "^3.0.3", 51 | "vue-i18n": "^9.9.1" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/assets/layout.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/preview.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Group layout sidebar interface for Directus 2 | Group layout sidebar is an interface for Directus that provides field organization with a docked sidebar. 3 | 4 |  5 | 6 | ## Layout Organization 7 | You have 5 available sections: 8 | 9 | - **Top:** Fields will be placed at the top, suitable for fields such as title. 10 | - **Sidebar:** Fields will be positioned in a docked sidebar, ideal for fields like status, slug, etc. 11 | - **Before Content:** Fields will be placed before the main fields. 12 | - **Content:** This is designated for main fields. 13 | - **After Content:** This section is reserved for secondary fields such as SEO or other accessory fields. 14 | 15 | All sections have a small spacing between them to differentiate each one. 16 | 17 |  18 | 19 | ### It's Mobile-Friendly 20 | In responsive scenarios, such as on mobile devices or in a drawer layout, the sidebar will be positioned after the "Top" layout group. 21 | 22 | ## How to Use This Interface 23 | 24 | 1. **Initiate by Creating a Layout Wrapper:** 25 | - Add a new field using this interface and set the layout option to "layout wrapper". 26 | 27 | 2. **Create Layout-Specific Fields:** 28 | - Add new fields with this interface, setting the layout option as "top", "sidebar", "content", etc., according to your needs. 29 | 30 | 3. **Organize Fields Within the Layout Wrapper:** 31 | - Place fields designated as "top", "sidebar", "content", ..., inside the field marked as "layout wrapper". 32 | 33 | 4. **Subgroup Placement:** 34 | - Insert your fields into the corresponding subgroups (e.g., "top", "sidebar", "content"). 35 | 36 | ### Tips 37 | **Identify Groups with Key Fields:** 38 | 39 | Utilize the key field of each group for easier identification within the editor. 40 | **Example:** grp_sidebar 41 | 42 | ## Enhancements and Bugs 43 | This is the first release. 44 | 45 | Please feel free to report any bugs or suggestions, and I will look into addressing them. 46 | 47 | ## Recommended extension 48 | **Compact Theme:** 49 | https://github.com/ptkio/directus-extension-theme-clean-compact-light 50 | 51 | ## Screenshots: 52 | #### Example 1: The user form 53 |  54 | 55 | #### Example 2: The settings form 56 |  57 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { defineInterface } from '@directus/extensions-sdk'; 2 | import InterfaceComponent from './interface.vue'; 3 | import PreviewSVG from './assets/preview.svg'; 4 | import LayoutSVG from './assets/layout.svg'; 5 | 6 | export default defineInterface({ 7 | id: 'ptkio-group-layout', 8 | name: 'Group layout sidebar', 9 | icon: 'web', 10 | hideLabel: true, 11 | description: 'Group layout with sidebar', 12 | component: InterfaceComponent, 13 | types: ['alias'], 14 | localTypes: ['group'], 15 | group: 'group', 16 | preview: PreviewSVG, 17 | options: [ 18 | { 19 | field: 'layout_part', 20 | name: 'Layout', 21 | type: 'string', 22 | schema: { 23 | default_value: 'layout', 24 | }, 25 | meta: { 26 | interface: 'select-dropdown', 27 | width: 'full', 28 | options: { 29 | choices: [ 30 | { 31 | text: 'Layout wrapper (centered)', 32 | value: 'layout-center', 33 | }, 34 | { 35 | text: 'Layout wrapper', 36 | value: 'layout', 37 | }, 38 | { 39 | text: 'Top', 40 | value: 'top', 41 | }, 42 | { 43 | text: 'Sidebar', 44 | value: 'aside', 45 | }, 46 | { 47 | text: 'Before content', 48 | value: 'before', 49 | }, 50 | { 51 | text: 'Content', 52 | value: 'content', 53 | }, 54 | { 55 | text: 'After content', 56 | value: 'after', 57 | }, 58 | ], 59 | }, 60 | }, 61 | }, 62 | { 63 | field: 'background', 64 | name: 'Background color', 65 | schema: { 66 | default_value: '', 67 | }, 68 | meta: { 69 | width: 'half', 70 | interface: 'select-dropdown', 71 | options: { 72 | allowNone: true, 73 | choices: [ 74 | { 75 | value: 'background', 76 | text: 'Background', 77 | }, 78 | { 79 | value: 'background-accent', 80 | text: 'Background (Accent)', 81 | }, 82 | { 83 | value: 'background-subdued', 84 | text: 'Background (Subdued)', 85 | }, 86 | ], 87 | }, 88 | }, 89 | }, 90 | { 91 | field: 'border', 92 | name: 'Border color', 93 | schema: { 94 | default_value: '', 95 | }, 96 | meta: { 97 | width: 'half', 98 | interface: 'select-dropdown', 99 | options: { 100 | allowNone: true, 101 | choices: [ 102 | { 103 | value: 'border', 104 | text: 'Border', 105 | }, 106 | { 107 | value: 'border-accent', 108 | text: 'Border (Accent)', 109 | }, 110 | { 111 | value: 'border-subdued', 112 | text: 'Border (Subdued)', 113 | }, 114 | ], 115 | }, 116 | }, 117 | }, 118 | { 119 | field: 'guide', 120 | name: 'Information', 121 | type: 'alias', 122 | meta: { 123 | interface: 'presentation-notice', 124 | width: 'full', 125 | options: { 126 | text: 127 | '
- Start by creating a "Layout Wrapper" group.
' + 130 | '- Create subgroups with layouts for the top, sidebar, content, etc., and place them inside the Layout Wrapper.
' + 131 | '- Place your fields inside the subgroups.
' + 132 | 'Use the key field of each group to identify them in the editor. Example : grp_sidebar
' + 133 | '- Start by creating a "Layout Wrapper" group.
- Create subgroups with layouts for the top, sidebar, content, etc., and place them inside the Layout Wrapper.
- Place your fields inside the subgroups.
Use the key field of each group to identify them in the editor. Example : grp_sidebar