diff --git a/.gitignore b/.gitignore index d5f19d89b308d36ee9e27b912015b0f75ec2f03f..ef3772b6f531544de87cd3e34a35e9742db8cc73 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules package-lock.json +apps/content-browser/node_modules diff --git a/apps/content-browser/.eslintrc.cjs b/apps/content-browser/.eslintrc.cjs new file mode 100644 index 0000000000000000000000000000000000000000..3e212e1d4307a332e8511f530bc48a4ad5ed6f95 --- /dev/null +++ b/apps/content-browser/.eslintrc.cjs @@ -0,0 +1,21 @@ +module.exports = { + root: true, + env: { browser: true, es2020: true }, + extends: [ + 'eslint:recommended', + 'plugin:react/recommended', + 'plugin:react/jsx-runtime', + 'plugin:react-hooks/recommended', + ], + ignorePatterns: ['dist', '.eslintrc.cjs'], + parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, + settings: { react: { version: '18.2' } }, + plugins: ['react-refresh'], + rules: { + 'react/jsx-no-target-blank': 'off', + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + }, +} diff --git a/apps/content-browser/.gitignore b/apps/content-browser/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..a547bf36d8d11a4f89c59c144f24795749086dd1 --- /dev/null +++ b/apps/content-browser/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/apps/content-browser/README.md b/apps/content-browser/README.md new file mode 100644 index 0000000000000000000000000000000000000000..f768e33fc946e6074d6bd3ce5d454853adb3615e --- /dev/null +++ b/apps/content-browser/README.md @@ -0,0 +1,8 @@ +# React + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh diff --git a/apps/content-browser/index.html b/apps/content-browser/index.html new file mode 100644 index 0000000000000000000000000000000000000000..0c589eccd4d48e270e161a1ab91baee5e5f4b4bc --- /dev/null +++ b/apps/content-browser/index.html @@ -0,0 +1,13 @@ +<!doctype html> +<html lang="en"> + <head> + <meta charset="UTF-8" /> + <link rel="icon" type="image/svg+xml" href="/vite.svg" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Vite + React</title> + </head> + <body> + <div id="root"></div> + <script type="module" src="/src/main.jsx"></script> + </body> +</html> diff --git a/apps/content-browser/package.json b/apps/content-browser/package.json new file mode 100644 index 0000000000000000000000000000000000000000..5cce2706551b1033d80550f48cd495a46aa0f9f4 --- /dev/null +++ b/apps/content-browser/package.json @@ -0,0 +1,29 @@ +{ + "name": "content-browser", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", + "preview": "vite preview" + }, + "dependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@types/react": "^18.2.56", + "@types/react-dom": "^18.2.19", + "@vitejs/plugin-react": "^4.2.1", + "autoprefixer": "^10.4.17", + "eslint": "^8.56.0", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.5", + "postcss": "^8.4.35", + "tailwindcss": "^3.4.1", + "vite": "^5.1.4" + } +} diff --git a/apps/content-browser/postcss.config.js b/apps/content-browser/postcss.config.js new file mode 100644 index 0000000000000000000000000000000000000000..2e7af2b7f1a6f391da1631d93968a9d487ba977d --- /dev/null +++ b/apps/content-browser/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/apps/content-browser/public/vite.svg b/apps/content-browser/public/vite.svg new file mode 100644 index 0000000000000000000000000000000000000000..e7b8dfb1b2a60bd50538bec9f876511b9cac21e3 --- /dev/null +++ b/apps/content-browser/public/vite.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg> \ No newline at end of file diff --git a/apps/content-browser/src/App.css b/apps/content-browser/src/App.css new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/apps/content-browser/src/App.jsx b/apps/content-browser/src/App.jsx new file mode 100644 index 0000000000000000000000000000000000000000..bf2fe419b327d5cb776a1f2391ea4d0517ff005a --- /dev/null +++ b/apps/content-browser/src/App.jsx @@ -0,0 +1,98 @@ +import { useState, useEffect } from 'react'; +import './App.css'; + +function App() { + const [posts, setPosts] = useState([]); + const [searchTerm, setSearchTerm] = useState(''); + const [selectedNodeType, setSelectedNodeType] = useState(''); + const [iframeUrl, setIframeUrl] = useState(''); // State to hold the URL for the iframe + + useEffect(() => { + const fetchPosts = async () => { + let apiUrl = 'https://netnode.nodehive.app.ddev.site/nodehive/api/content-browser'; + let queryParts = []; + + if (searchTerm) { + queryParts.push(`search=${searchTerm}`); + } + + if (selectedNodeType) { + queryParts.push(`type=${selectedNodeType}`); + } + + if (queryParts.length) { + apiUrl += '?' + queryParts.join('&'); + } + + try { + const response = await fetch(apiUrl); + const data = await response.json(); + setPosts(data); + } catch (error) { + console.error('Error fetching data: ', error); + } + }; + + fetchPosts(); + }, [searchTerm, selectedNodeType]); + + return ( + <> + <div className='flex max-w-full'> + {/* Left side - Iframe */} + {iframeUrl && ( + <iframe + src={iframeUrl} + style={{ width: '100vw', height: '100vh' }} + title="Content Edit" + ></iframe> + )} + + {/* Right side - Content Browser */} + <div className='w-96 bg-slate-400 p-4 overflow-auto'> + <h2 className='text-3xl text-center mb-4'>Content Browser</h2> + <select + value={selectedNodeType} + onChange={(e) => setSelectedNodeType(e.target.value)} + className="mb-4 p-2" + > + <option value="">All Types</option> + <option value="article">Article</option> + <option value="page">Page</option> + </select> + <input + type="text" + placeholder="Search by title..." + className="mb-4 p-2 w-full" + value={searchTerm} + onChange={(e) => setSearchTerm(e.target.value)} + /> + <ul> + {posts.map((post, index) => ( + <li key={index} className='bg-slate-300 rounded-md p-2 my-2 flex justify-between items-center'> + <h3 className='text-xl'>{post.nid} {post.title}</h3> + <div> + + <span> + <a + href="#" + onClick={(e) => { + e.preventDefault(); + setIframeUrl(`https://netnode.nodehive.app.ddev.site/node/${post.nid}/edit`); + }} + className="text-blue-600 hover:text-blue-800" + > + Edit + </a> + </span> {post.type} + </div> + </li> + ))} + </ul> + </div> + </div> + </> + ); +} + +export default App; diff --git a/apps/content-browser/src/assets/react.svg b/apps/content-browser/src/assets/react.svg new file mode 100644 index 0000000000000000000000000000000000000000..6c87de9bb3358469122cc991d5cf578927246184 --- /dev/null +++ b/apps/content-browser/src/assets/react.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg> \ No newline at end of file diff --git a/apps/content-browser/src/index.css b/apps/content-browser/src/index.css new file mode 100644 index 0000000000000000000000000000000000000000..b5c61c956711f981a41e95f7fcf0038436cfbb22 --- /dev/null +++ b/apps/content-browser/src/index.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/apps/content-browser/src/main.jsx b/apps/content-browser/src/main.jsx new file mode 100644 index 0000000000000000000000000000000000000000..54b39dd1d900e866bb91ee441d372a8924b9d87a --- /dev/null +++ b/apps/content-browser/src/main.jsx @@ -0,0 +1,10 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.jsx' +import './index.css' + +ReactDOM.createRoot(document.getElementById('root')).render( + <React.StrictMode> + <App /> + </React.StrictMode>, +) diff --git a/apps/content-browser/tailwind.config.js b/apps/content-browser/tailwind.config.js new file mode 100644 index 0000000000000000000000000000000000000000..d37737fc01752cf4b395862b2aaebf67b4cdf596 --- /dev/null +++ b/apps/content-browser/tailwind.config.js @@ -0,0 +1,12 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: [ + "./index.html", + "./src/**/*.{js,ts,jsx,tsx}", + ], + theme: { + extend: {}, + }, + plugins: [], +} + diff --git a/apps/content-browser/vite.config.js b/apps/content-browser/vite.config.js new file mode 100644 index 0000000000000000000000000000000000000000..5a33944a9b41b59a9cf06ee4bb5586c77510f06b --- /dev/null +++ b/apps/content-browser/vite.config.js @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], +}) diff --git a/css/menu-icons.css b/css/menu-icons.css index 9b11dd0253825600c358abb0e2d8dca321214a92..176fc5ba2a704856970a7a1281d6f0f38c1b349b 100644 --- a/css/menu-icons.css +++ b/css/menu-icons.css @@ -23,6 +23,11 @@ a[data-drupal-link-system-path="admin/structure/types"]::before { -webkit-mask-image: url(/themes/contrib/gin/dist/media/sprite.svg#structure-view) !important; } +a[data-drupal-link-system-path="nodehive/models"]::before { + mask-image: url(/themes/contrib/gin/dist/media/sprite.svg#structure-view); + -webkit-mask-image: url(/themes/contrib/gin/dist/media/sprite.svg#structure-view) !important; +} + a[data-drupal-link-system-path="admin/config"]::before { mask-image: url(/themes/contrib/gin/dist/media/sprite.svg#config-view); -webkit-mask-image: url(/themes/contrib/gin/dist/media/sprite.svg#config-view) !important; diff --git a/modules/nodehive_core_beekeeper/config/beekeeper/nodehive/beekeeper.menu.yml b/modules/nodehive_core_beekeeper/config/beekeeper/nodehive/beekeeper.menu.yml index 8ed3843e5432f361bf6de6f5160404f9fc591ec4..e80ea4565f8d58ec2c94064b402b4b6c73199789 100644 --- a/modules/nodehive_core_beekeeper/config/beekeeper/nodehive/beekeeper.menu.yml +++ b/modules/nodehive_core_beekeeper/config/beekeeper/nodehive/beekeeper.menu.yml @@ -52,8 +52,8 @@ nodehive-admin: link: "internal:/admin/content/space" weight: -1 data: - title: "Content" - link: "internal:/admin/content" + title: "Content Manager" + link: "internal:/nodehive/content" weight: 2 children: all_content: @@ -75,8 +75,8 @@ nodehive-admin: title: "All Webforms" link: "internal:/admin/structure/webform" data_models: - title: "Data Models" - link: "internal:/admin/structure/types" + title: "Content Models" + link: "internal:/nodehive/models" weight: 3 children: content_types: diff --git a/nodehive_core.routing.yml b/nodehive_core.routing.yml index 7a7e4041f136d2d4c7b9d557be434e337c7ec86f..5c709d0ffa18888b6a18c45b8f733594f00c8db9 100644 --- a/nodehive_core.routing.yml +++ b/nodehive_core.routing.yml @@ -37,3 +37,28 @@ nodehive.jsonapi_translated_paths: methods: [GET] requirements: _permission: 'access content' + +nodehive_core.data_modeller: + path: '/nodehive/models' + defaults: + _controller: '\Drupal\nodehive_core\Controller\DataModelsController::dataModeller' + _title: 'Data Modeller' + requirements: + _permission: 'access content' + +nodehive_core.content_browser: + path: '/nodehive/content' + defaults: + _controller: '\Drupal\nodehive_core\Controller\ContentBrowserController::contentBrowser' + _title: 'Content Browser' + requirements: + _permission: 'access content' + +nodehive_core.content_browser_api: + path: '/nodehive/api/content-browser' + defaults: + _controller: '\Drupal\nodehive_core\Controller\ContentBrowserController::content' + _title: 'Content Browser API' + methods: [GET] + requirements: + _permission: 'access content' diff --git a/src/Controller/ContentBrowserController.php b/src/Controller/ContentBrowserController.php new file mode 100644 index 0000000000000000000000000000000000000000..ed2089a18402086fd795f09d1079df075ae6b6fd --- /dev/null +++ b/src/Controller/ContentBrowserController.php @@ -0,0 +1,45 @@ +<?php + +namespace Drupal\nodehive_core\Controller; + +use Drupal\Core\Controller\ControllerBase; +use Drupal\Core\Database\Database; +use Symfony\Component\HttpFoundation\JsonResponse; + +class ContentBrowserController extends ControllerBase { + + public function contentBrowser() { + return []; + } + public function content() { + + $search = ''; + if (isset($_GET['search'])) { + $search = $_GET['search']; + } + // Database connection + $connection = Database::getConnection(); + $query = $connection->select('node_field_data', 'n'); + $query->fields('n', ['nid', 'title', 'type']); + + // Add search filter if $search parameter is provided + if (!empty($search)) { + $query->condition('n.title', '%' . $connection->escapeLike($search) . '%', 'LIKE'); + } + + $query->range(0, 50); // Limit to 50 results for example + $result = $query->execute()->fetchAll(); + + $data = []; + foreach ($result as $row) { + $data[] = [ + 'nid' => $row->nid, + 'title' => $row->title, + 'type' => $row->type, + ]; + } + + return new JsonResponse($data); + } + +} diff --git a/src/Controller/DataModelsController.php b/src/Controller/DataModelsController.php new file mode 100644 index 0000000000000000000000000000000000000000..065cc99f0d91794dc27a760668421138dffcf3a7 --- /dev/null +++ b/src/Controller/DataModelsController.php @@ -0,0 +1,148 @@ +<?php + +namespace Drupal\nodehive_core\Controller; + +use Drupal\Core\Controller\ControllerBase; +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** + * Defines DataModelsController class for the NodeHive module. + */ +class DataModelsController extends ControllerBase +{ + + /** + * Display the custom page with NodeHive quick links. + * + * @return array + * A render array for a Drupal page. + */ + public function dataModeller() + { + $create_links = $this->getQuickLinks(); + $build = $this->renderLinks('create', $create_links); + + // Attach the library for styling and JavaScript if needed. + $build['#attached']['library'][] = 'nodehive_core/quick_links'; + + return $build; + } + + /** + * Get the array of quick links to be rendered. + * + * @return array + * The quick links configuration. + */ + private function getQuickLinks() + { + // Define your links here, similar to how they were defined in the block plugin. + // This example uses a simplified structure for demonstration. + $create_links = [ + 'configure_content_types' => [ + 'title' => $this->t('Configure Content Types'), + 'description' => $this->t('Configure your custom content types like Page, Article or Event.'), + 'url' => '/admin/structure/types', + 'link_text' => 'Configure Content Types', + 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"> + <rect x="4" y="4" width="16" height="16" rx="2" stroke-linecap="round" stroke-linejoin="round" /> + <path stroke-linecap="round" stroke-linejoin="round" d="M8 8h8M8 12h5M8 16h3" /> + </svg> + ' + ], + 'configure_paragraph_types' => [ + 'title' => $this->t('Configure Paragraph Types'), + 'description' => $this->t('Configure your paragraph types like a Text Section, Gallery Section or Teaser List.'), + 'url' => '/admin/structure/paragraphs_type', + 'link_text' => 'Configure Paragraph Types', + 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"> + <path stroke-linecap="round" stroke-linejoin="round" d="M4 7h16M4 11h16M4 15h16" /> + <circle cx="18" cy="19" r="2" fill="currentColor" /> + </svg> ' + ], + + 'configure_taxonomy' => [ + 'title' => $this->t('Configure Taxonomy'), + 'description' => $this->t('Configure your taxonomies like Article categories, Event Types or Blog Post Tags.'), + 'url' => '/admin/structure/taxonomy', + 'link_text' => 'Configure Taxonomies', + 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"> + <path stroke-linecap="round" stroke-linejoin="round" d="M9.568 3H5.25A2.25 2.25 0 0 0 3 5.25v4.318c0 .597.237 1.17.659 1.591l9.581 9.581c.699.699 1.78.872 2.607.33a18.095 18.095 0 0 0 5.223-5.223c.542-.827.369-1.908-.33-2.607L11.16 3.66A2.25 2.25 0 0 0 9.568 3Z" /> + <path stroke-linecap="round" stroke-linejoin="round" d="M6 6h.008v.008H6V6Z" /> + </svg> + ' + ], + 'configure_fragment_types' => [ + 'title' => $this->t('Configure Fragement Types'), + 'description' => $this->t('Configure your fragment types like social media links, global CTAs and reusable content.'), + 'url' => '/admin/structure/fragment_type', + 'link_text' => 'Configure Fragment Types', + 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"> + <path stroke-linecap="round" stroke-linejoin="round" d="M3 10h4v4H3zM17 10h4v4h-4zM10 3h4v4h-4zM10 17h4v4h-4z" /> + </svg>' + ], + + + 'configure_area' => [ + 'title' => $this->t('Configure Areas'), + 'description' => $this->t('Configure your areas to place fragments in the header, footer or anywhere you need them.'), + 'url' => '/admin/content/area', + 'link_text' => 'Configure Areas', + 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"> + <path stroke-linecap="round" stroke-linejoin="round" d="M6 3h12M6 21h12M3 6v12M21 6v12M6 6h12v12H6z" /> + </svg>' + ], + + 'configure_menus' => [ + 'title' => $this->t('Configure Menus'), + 'description' => $this->t('Configure navigation menus with links and attributes.'), + 'url' => '/admin/structure/menu', + 'link_text' => 'Configure Menus', + 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"> + <path stroke-linecap="round" stroke-linejoin="round" d="M3 6h18M3 12h12m-12 6h9" /> + </svg>' + ] + + ]; + return $create_links; + } + + /** + * Render the links into a structured array for Drupal rendering system. + * + * @param array $links + * The links to render. + * + * @return array + * The renderable array of links. + */ + function renderLinks($section, $links) + { + $build[$section] = [ + '#type' => 'container', + '#attributes' => ['class' => ['gin-layer-wrapper', 'quick-links', 'quick-links-grid']], + ]; + foreach ($links as $key => $info) { + $build[$section][$key] = [ + '#type' => 'fieldset', + '#title' => $info['title'], + '#open' => TRUE, + ]; + + $icon_markup = !empty($info['icon']) ? $info['icon'] : ''; + + $build[$section][$key]['content'] = [ + '#type' => 'item', + '#markup' => + '<div class="link-content">' . + '<div class="icon-container">' . $icon_markup . '</div>' . + '<div>' . $info['description'] . '</div>' . + '</div>' . + '<p><a href="' . $info['url'] . '" class="button button--small">' . $info['link_text'] . '</a></p>', + + '#allowed_tags' => ['div', 'p', 'a', 'svg', 'path', 'rect', 'circle'], // Add more allowed tags as needed. + ]; + } + return $build; + } +} diff --git a/src/Form/NodeHiveSettingsForm.php b/src/Form/NodeHiveSettingsForm.php index e5ffcb5f5cf3e167671c926ed8ab04bac2d8af1c..3fd5b98a3e57eaea8a6fbd14662050e369e7296d 100644 --- a/src/Form/NodeHiveSettingsForm.php +++ b/src/Form/NodeHiveSettingsForm.php @@ -190,23 +190,6 @@ class NodeHiveSettingsForm extends ConfigFormBase { '#description' => t('Only applied if users may set their own time zone.'), ]; - $form['subscription'] = [ - '#type' => 'details', - '#title' => $this->t('Subscription and limits'), - '#tree' => TRUE, - '#open' => TRUE, - ]; - - $subscription = $config->get('subscription'); - $form['subscription']['key'] = [ - '#type' => 'radios', - '#title' => t('NodeHive Subscription'), - '#default_value' => isset($subscription['key']) ? $subscription['key'] : "trial", - '#options' => [ - 'trial' => t('Trial') - ], - ]; - return parent::buildForm($form, $form_state); } @@ -221,7 +204,6 @@ class NodeHiveSettingsForm extends ConfigFormBase { $this->config('nodehive_core.settings') ->set('company_name', $form_state->getValue('company_name')) ->set('ckeditor_styles_url', $ckeditor_styles_url) - ->set('subscription', $subscription) ->save(); // Parse the new css file. diff --git a/src/Plugin/DashboardBlock/NodeHiveQuickLinkContentModelBlock.php b/src/Plugin/DashboardBlock/NodeHiveQuickLinkContentModelBlock.php index 93238b7d28482c42d42e337ea5780ab8eb046467..a0fba347d0c95077e5ec66c006250b7790fca852 100644 --- a/src/Plugin/DashboardBlock/NodeHiveQuickLinkContentModelBlock.php +++ b/src/Plugin/DashboardBlock/NodeHiveQuickLinkContentModelBlock.php @@ -134,7 +134,7 @@ class NodeHiveQuickLinkContentModelBlock extends DashboardBlockBase implements C '</div>' . '<p><a href="' . $info['url'] . '" class="button button--small">' . $info['link_text'] . '</a></p>', - '#allowed_tags' => ['p', 'a', 'path', 'svg', 'rect', 'div', 'text', 'line', 'circle', 'g', 'title'], + '#allowed_tags' => ['div', 'p', 'a', 'svg', 'path', 'rect', 'circle'], // Add more allowed tags as needed. ]; } return $build;