Compare commits

...

3 Commits

Author SHA1 Message Date
b328d0a8b7 added decoupled custom module, started mathallo theme, not tested yet 2025-12-02 11:20:31 +01:00
2e5260fed6 restored drupal_starter_kit submodule 2025-12-01 12:41:19 +01:00
09cde37fdb renamed web to web_main 2025-12-01 12:37:40 +01:00
46 changed files with 2280 additions and 242 deletions

30
.gitignore vendored
View File

@@ -1,24 +1,24 @@
# Ignore directories generated by Composer
/drush/contrib/
/vendor/
/web/core/
/web/modules/contrib/
/web/themes/contrib/
/web/profiles/contrib/
/web/libraries/
/web_main/core/
/web_main/modules/contrib/
/web_main/themes/contrib/
/web_main/profiles/contrib/
/web_main/libraries/
# Ignore sensitive information
/web/sites/*/settings.php
/web/sites/*/settings.local.php
/web/sites/*/services*.yml
/web/sites/*/salt.txt
/web/sites/development.services.yml
/web/sites/default/development.services.yml
/web_main/sites/*/settings.php
/web_main/sites/*/settings.local.php
/web_main/sites/*/services*.yml
/web_main/sites/*/salt.txt
/web_main/sites/development.services.yml
/web_main/sites/default/development.services.yml
# Ignore Drupal's file directory
/web/sites/*/files/
/web_main/sites/*/files/
# Ignore SimpleTest multi-site environment.
/web/sites/simpletest
/web_main/sites/simpletest
# Ignore files generated by PhpStorm
/.idea/
@@ -43,5 +43,7 @@ node_modules/
/update.php
/web.config
/web/.vscode/*
/web_main/.vscode/*
.vscode/*
/log

4
.gitmodules vendored
View File

@@ -1,3 +1,3 @@
[submodule "web/profiles/drupal-starterkit-profile"]
path = web/profiles/drupal-starterkit-profile
[submodule "web_main/profiles/drupal-starterkit-profile"]
path = web_main/profiles/drupal-starterkit-profile
url = https://figureslibres.io/gogs/bachir/drupal-starterkit-profile.git

View File

@@ -42,35 +42,35 @@
"extra": {
"drupal-scaffold": {
"locations": {
"web-root": "web/"
"web-root": "web_main/"
}
},
"installer-paths": {
"web/core": [
"web_main/core": [
"type:drupal-core"
],
"web/libraries/{$name}": [
"web_main/libraries/{$name}": [
"type:drupal-library"
],
"web/modules/contrib/{$name}": [
"web_main/modules/contrib/{$name}": [
"type:drupal-module"
],
"web/profiles/contrib/{$name}": [
"web_main/profiles/contrib/{$name}": [
"type:drupal-profile"
],
"web/themes/contrib/{$name}": [
"web_main/themes/contrib/{$name}": [
"type:drupal-theme"
],
"drush/Commands/contrib/{$name}": [
"type:drupal-drush"
],
"web/modules/custom/{$name}": [
"web_main/modules/custom/{$name}": [
"type:drupal-custom-module"
],
"web/profiles/custom/{$name}": [
"web_main/profiles/custom/{$name}": [
"type:drupal-custom-profile"
],
"web/themes/custom/{$name}": [
"web_main/themes/custom/{$name}": [
"type:drupal-custom-theme"
]
},
@@ -97,7 +97,7 @@
},
"merge-plugin": {
"include": [
"web/profiles/drupal-starterkit-profile/composer.json"
"web_main/profiles/drupal-starterkit-profile/composer.json"
],
"recurse": true,
"replace": false,

454
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,5 @@
name: 'decoupled'
type: module
description: 'helpers for progressive decoupling'
core_version_requirement: ^8.8 || ^9.2 || ^10.2
package: 'mathallo'

View File

@@ -0,0 +1,107 @@
<?php
/**
* @file
* Contains decoupled.module.
*/
use Drupal\Core\Routing\RouteMatchInterface;
// use Drupal\pathauto\PathautoPatternInterface;
// use Drupal\pathauto\PathautoPatternManagerInterface;
use Drupal\pathauto\Entity\PathautoPattern;
/**
* Implements hook_help().
*/
function decoupled_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
// Main module help for the decoupled module.
case 'help.page.decoupled':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('helpers for progressive decoupling') . '</p>';
return $output;
default:
}
}
/**
* Implements hook_page_attachments().
* @param array $attachments
*/
function decoupled_page_attachments(array &$attachments) {
$redirect = false;
$current_path = \Drupal::service('path.current')->getPath();
$route_name = \Drupal::routeMatch()->getRouteName();
$current_language = \Drupal::languageManager()->getCurrentLanguage()->getId();
$is_front = \Drupal::service('path.matcher')->isFrontPage();
if (!$is_front) {
$redirect = true;
}
if(preg_match('/^\/?user\/.*/', $current_path)){
$redirect = false;
}
$entity_type = null;
$entity_bundle = null;
$entity_id = null;
$entity_uuid = null;
$base_alias = null;
foreach (['node', 'taxonomy_term'] as $type) {
$entity = \Drupal::routeMatch()->getParameter($type);
if($entity){
$entity_type = $type;
$entity_bundle = $entity->bundle();
$entity_id = $entity->id();
$entity_uuid = $entity->uuid();
// $pathauto_patterns = \Drupal::entityTypeManager()->getStorage('pathauto_pattern')->loadByProperties(['type' => "canonical_entities:".$entity_type]);
// foreach ($pathauto_patterns as $id => $pattern) {
// $conditions = $pattern->getSelectionConditions();
// $condition_config = $conditions->getConfiguration();
// foreach ($condition_config as $key => $config) {
// $bundles = array_keys($config['bundles']);
// if (in_array($entity_bundle, $bundles)) {
// $motif = $pattern->getPattern();
// preg_match('/(\/.+)+\/\[[^]]+\]/', $motif, $matches);
// $base_alias = $matches[1];
// break 2;
// }
// }
// }
break;
}
}
// route_parameters:'".json_encode($route_parameters)."',\n
$js_str = "var drupalDecoupled = {\n
sys_path:'".$current_path."',\n
route_name:'".$route_name."',\n
is_front:".($is_front ? 'true':'false').",\n
base_alias:'".$base_alias."',\n
redirect:".($redirect ? 'true':'false').",\n
lang_code:'".$current_language."',\n
entity_type:'".$entity_type."',\n
entity_bundle:'".$entity_bundle."',\n
entity_id:'".$entity_id."',\n
entity_uuid:'".$entity_uuid."',\n
};";
$attachments['#attached']['html_head'][] = [
[
'#type' => 'html_tag',
'#tag' => 'script',
'#value' => $js_str,
'#weight' => -999,
'#group' => 'decoupled'
],
// A key, to make it possible to recognize this HTML element when altering.
'decoupled',
];
}

View File

@@ -0,0 +1 @@
body{background-color:red}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,32 @@
import axios from 'axios'
// https://github.com/alvar0hurtad0/drupal-vuejs-todo/blob/master/frontend/src/api/axiosInterceptor.js
// console.log('drupalSettings', drupalSettings)
console.log(window.location)
const JSONAPI = axios.create({
baseURL: `${window.location.origin}/jsonapi`,
withCredentials: true,
headers: {
Accept: 'application/vnd.api+json'
// Authorization: 'Basic {token}',
// 'Content-Type': 'application/json'
}
})
JSONAPI.interceptors.response.use(
response => {
return Promise.resolve(response)
},
error => {
const { status } = error.response
console.warn('error in json-axios', status)
// if (status === 403) {
// window.location = '/'
// }
return Promise.reject(error)
}
)
export default JSONAPI

View File

@@ -0,0 +1,45 @@
import axios from 'axios'
// https://github.com/alvar0hurtad0/drupal-vuejs-todo/blob/master/frontend/src/api/axiosInterceptor.js
// console.log('drupalSettings', drupalSettings)
// console.log('window.location.origin', window.location.origin)
// axios.interceptors.response.use(
// response => {
// return Promise.resolve(response)
// },
// error => {
// const { status } = error.response
// console.warn('error in rest-axios', status)
// if (status === 403) {
// window.location = '/'
// }
// return Promise.reject(error)
// }
// )
const REST = axios.create({
baseURL: `${window.location.origin}`,
withCredentials: true,
headers: {
// Authorization: 'Bearer {token}',
'Content-Type': 'application/json'
}
})
REST.interceptors.response.use(
response => {
return Promise.resolve(response)
},
error => {
const { status } = error.response
console.warn('error in rest-axios', status)
// if (status === 403) {
// window.location = '/'
// }
return Promise.reject(error)
}
)
export default REST

View File

@@ -0,0 +1,109 @@
import { createApp } from 'vue'
import '../scss/main.scss'
import Etape from './vuejs/Etape.vue'
import REST from './api/rest-axios'
// /**
// * @file
// * reha behaviors.
// * https://www.drupal.org/docs/drupal-apis/javascript-api/javascript-api-overview
// */
// (function (Drupal) {
// 'use strict';
// Drupal.behaviors.reha = {
// attach: function (context, settings) {
// console.log('It works!');
// }
// };
// } (Drupal));
(function (Drupal, drupalSettings) {
const MathalloTheme = function () {
const _is_front = drupalSettings.path.isFront
console.log('drupalSettings', drupalSettings)
// let _I18n
// ___ _ _
// |_ _|_ _ (_) |_
// | || ' \| | _|
// |___|_||_|_|\__|
function init () {
console.log('MathalloTheme init()')
initVues()
}
function initVues(){
// initVueEtapeModale();
}
// function initVueEtapeModale(){
// createApp(Etape).mount('#etape-modale');
// processEtapeLinks();
// }
// function onClickEtapeLink(e){
// e.preventDefault();
// let a = e.currentTarget;
// let nid = a.dataset.nodeNid;
// console.log(nid);
// getNodeData(nid);
// return null;
// }
// function processEtapeLinks(){
// let etape_link_fields = document.querySelectorAll('#etapes-liste div.views-field-title');
// etape_link_fields.forEach((field, index) => {
// let nid = null;
// let classList = field.classList;
// classList.forEach((classe) => {
// let reg = /data-node-(\d+)/;
// let result = classe.match(reg);
// if (result) {
// nid = result[1];
// console.log(nid);
// }
// })
// if (nid) {
// let a = field.querySelector('a');
// a.setAttribute('data-node-nid', nid);
// a.addEventListener('click', onClickEtapeLink);
// }
// })
// }
// function getNodeData(nid){
// const params = {
// }
// REST.get(`/node/${nid}?_format=json`, params)
// .then((data) => {
// console.log('user REST getUser data', data)
// })
// .catch(error => {
// console.warn('Issue with getNodedata', error)
// Promise.reject(error)
// })
// }
init()
} // end MathalloTheme()
MathalloTheme()
})(Drupal, drupalSettings)

View File

@@ -0,0 +1,13 @@
<template>
<div>
hello HMR TROP TROP BIEN \o/
</div>
</template>
<script>
</script>
<style>
</style>

View File

@@ -0,0 +1,3 @@
body{
background-color: purple;
}

View File

@@ -0,0 +1,21 @@
name: Mathallo
type: theme
base theme: stark
description: mathallo drupal theme based on stark
package: mathallo
core: 0.x
core_version_requirement: ^8 || ^9 || ^10
# libraries:
# - caravane/global
regions:
header: 'Header'
primary_menu: 'Primary menu'
secondary_menu: 'Secondary menu'
page_top: 'Page top'
page_bottom: 'Page bottom'
featured: 'Featured'
breadcrumb: 'Breadcrumb'
content: 'Content'
sidebar_first: 'Sidebar first'
sidebar_second: 'Sidebar second'
footer: 'Footer'

View File

@@ -0,0 +1,20 @@
# Main theme library.
global:
js:
assets/dist/main.js: {}
# assets/js/main.js: {}
css:
theme:
assets/dist/main.css: {}
# assets/scss/main.css: {}
vitehmr:
js:
http://localhost:5173/@vite/client:
type: external
attributes:
type: module
http://localhost:5173/assets/js/main.js:
type: external
attributes:
type: module

View File

@@ -0,0 +1,57 @@
<?php
/**
* @file
* Functions to support theming in the mathallo theme.
*/
function mathallo_page_attachments_alter(&$page) {
if (getenv('APP_ENV') === 'development') {
// $attachments['#attached']['html_head'][] = [['src' => 'http://localhost:5173/@vite/client', 'type' => 'module'],'vite-client'];
// $page['#attached']['library'][] = 'http://localhost:5173/@vite/client';
// $attachments['#attached']['html_head'][] = [['src' => 'http://localhost:5173/assets/js/main.js', 'type' => 'module'],'vite-main'];
// $page['#attached']['library'][] = 'http://localhost:5173/assets/js/main.js';
$page['#attached']['library'][] = 'mathallo/vitehmr';
}else{
$page['#attached']['library'][] = 'mathallo/global';
}
}
/**
* Implements hook_preprocess_HOOK() for html.html.twig.
*/
function mathallo_preprocess_html(&$variables) {
}
/**
* Implements hook_preprocess_HOOK() for page.html.twig.
*/
function mathallo_preprocess_page(&$variables) {
}
/**
* Implements hook_preprocess_HOOK() for node.html.twig.
*/
function mathallo_preprocess_node(&$variables) {
}
function mathallo_preprocess_contanier(&$variables) {
}
// function A(){
// $attr = 6;
// B($attr);
// print($attr);
// }
// function B($attr){
// $attr = 3;
// print($attr);
// }
// A();

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,20 @@
{
"name": "mathallo",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"axios": "^1.7.2",
"vue": "^3.4.29"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0.5",
"sass": "^1.77.8",
"vite": "^5.3.1"
}
}

View File

@@ -0,0 +1,6 @@
Sass
```
npm install
npm run scss
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

View File

@@ -0,0 +1,30 @@
{#
/**
* @file
* Default theme implementation of a container used to wrap child elements.
*
* Used for grouped form items. Can also be used as a theme wrapper for any
* renderable element, to surround it with a <div> and HTML attributes.
* See \Drupal\Core\Render\Element\RenderElement for more
* information on the #theme_wrappers render array property, and
* \Drupal\Core\Render\Element\container for usage of the container render
* element.
*
* Available variables:
* - attributes: HTML attributes for the containing element.
* - children: The rendered child elements of the container.
* - has_parent: A flag to indicate that the container has one or more parent
containers.
*
* @see template_preprocess_container()
*
* @ingroup themeable
*/
#}
{%
set classes = [
has_parent ? 'js-form-wrapper',
has_parent ? 'form-wrapper',
]
%}
<div{{ attributes.addClass(classes) }}>{{ children }}</div>

View File

@@ -0,0 +1,49 @@
{#
/**
* @file
* Default theme implementation for the basic structure of a single Drupal page.
*
* Variables:
* - logged_in: A flag indicating if user is logged in.
* - root_path: The root path of the current page (e.g., node, admin, user).
* - node_type: The content type for the current node, if the page is a node.
* - head_title: List of text elements that make up the head_title variable.
* May contain one or more of the following:
* - title: The title of the page.
* - name: The name of the site.
* - slogan: The slogan of the site.
* - page_top: Initial rendered markup. This should be printed before 'page'.
* - page: The rendered page markup.
* - page_bottom: Closing rendered markup. This variable should be printed after
* 'page'.
* - db_offline: A flag indicating if the database is offline.
* - placeholder_token: The token for generating head, css, js and js-bottom
* placeholders.
*
* @see template_preprocess_html()
*
* @ingroup themeable
*/
#}
<!DOCTYPE html>
<html{{ html_attributes }}>
<head>
<head-placeholder token="{{ placeholder_token }}">
<title>{{ head_title|safe_join(' | ') }}</title>
<css-placeholder token="{{ placeholder_token }}">
<js-placeholder token="{{ placeholder_token }}">
</head>
<body{{ attributes }}>
{#
Keyboard navigation/accessibility link to main content section in
page.html.twig.
#}
<a href="#main-content" class="visually-hidden focusable">
{{ 'Skip to main content'|t }}
</a>
{{ page_top }}
{{ page }}
{{ page_bottom }}
<js-bottom-placeholder token="{{ placeholder_token }}">
</body>
</html>

View File

@@ -0,0 +1,91 @@
{#
/**
* @file
* Default theme implementation to display a single page.
*
* The doctype, html, head and body tags are not in this template. Instead they
* can be found in the html.html.twig template in this directory.
*
* Available variables:
*
* General utility variables:
* - base_path: The base URL path of the Drupal installation. Will usually be
* "/" unless you have installed Drupal in a sub-directory.
* - is_front: A flag indicating if the current page is the front page.
* - logged_in: A flag indicating if the user is registered and signed in.
* - is_admin: A flag indicating if the user has permission to access
* administration pages.
*
* Site identity:
* - front_page: The URL of the front page. Use this instead of base_path when
* linking to the front page. This includes the language domain or prefix.
*
* Page content (in order of occurrence in the default page.html.twig):
* - messages: Status and error messages. Should be displayed prominently.
* - node: Fully loaded node, if there is an automatically-loaded node
* associated with the page and the node ID is the second argument in the
* page's path (e.g. node/12345 and node/12345/revisions, but not
* comment/reply/12345).
*
* Regions:
* - page.header: Items for the header region.
* - page.primary_menu: Items for the primary menu region.
* - page.secondary_menu: Items for the secondary menu region.
* - page.highlighted: Items for the highlighted content region.
* - page.help: Dynamic help text, mostly for admin pages.
* - page.content: The main content of the current page.
* - page.sidebar_first: Items for the first sidebar.
* - page.sidebar_second: Items for the second sidebar.
* - page.footer: Items for the footer region.
* - page.breadcrumb: Items for the breadcrumb region.
*
* @see template_preprocess_page()
* @see html.html.twig
*
* @ingroup themeable
*/
#}
<div class="layout-container">
<header role="banner">
{{ page.header }}
</header>
{{ page.primary_menu }}
{{ page.secondary_menu }}
{{ page.breadcrumb }}
{{ page.highlighted }}
{{ page.help }}
<main role="main">
<a id="main-content" tabindex="-1"></a>{# link is in html.html.twig #}
<div class="layout-content">
{{ page.content }}
</div>{# /.layout-content #}
{% if page.sidebar_first %}
<aside class="layout-sidebar-first" role="complementary">
{{ page.sidebar_first }}
</aside>
{% endif %}
{% if page.sidebar_second %}
<aside class="layout-sidebar-second" role="complementary">
{{ page.sidebar_second }}
</aside>
{% endif %}
<div id="etape-modale"></div>
</main>
{% if page.footer %}
<footer role="contentinfo">
{{ page.footer }}
</footer>
{% endif %}
</div>{# /.layout-container #}

View File

@@ -0,0 +1,37 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { fileURLToPath, URL } from 'node:url'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
server: {
hmr: {
host: 'localhost',
},
watch: {
usePolling: true,
},
},
build: {
outDir: 'assets/dist',
rollupOptions: {
input: 'assets/js/main.js',
output: {
entryFileNames: 'main.js',
assetFileNames: 'main.css'
}
}
},
resolve: {
alias: {
'@api': fileURLToPath(new URL('api', import.meta.url)),
// '@': fileURLToPath(new URL('./src', import.meta.url)),
// '@stores': fileURLToPath(new URL('./src/stores', import.meta.url)),
// '@components': fileURLToPath(new URL('./src/components', import.meta.url)),
// '@views': fileURLToPath(new URL('./src/views', import.meta.url)),
// // '@icons': fileURLToPath(new URL('./node_modules/vue-material-design-icons', import.meta.url)),
// '@node_modules': fileURLToPath(new URL('./node_modules', import.meta.url))
}
}
})