started druapl theme leshed

This commit is contained in:
2026-07-13 16:24:52 +02:00
parent 688715e47f
commit 43113e662b
28 changed files with 3299 additions and 3 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -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
@@ -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
+121
View File
@@ -0,0 +1,121 @@
// import { createApp } from 'vue'
import '../scss/main.scss'
// import Content from './vuejs/Content.vue'
// import REST from './api/rest-axios'
// import LocomotiveScroll from 'locomotive-scroll';
// const scroll = new LocomotiveScroll();
// /**
// * @file
// * https://www.drupal.org/docs/drupal-apis/javascript-api/javascript-api-overview
// */
// (function (Drupal) {
// 'use strict';
// Drupal.behaviors.leshed = {
// attach: function (context, settings) {
// console.log('It works!');
// }
// };
// } (Drupal));
(function (Drupal, drupalSettings) {
const LeShedTheme = function () {
const _is_front = drupalSettings.path.isFront
console.log('drupalSettings', drupalSettings)
// ___ _ _
// |_ _|_ _ (_) |_
// | || ' \| | _|
// |___|_||_|_|\__|
function init () {
console.log('LeShedTheme init()')
// initVues()
}
function onWindowResize() {
_cardsForms.forEach(({card, forme, formepos}) => {
// console.log(`card`, card, 'forme', forme, 'formepos', formepos);
forme.style.top = `${card.offsetTop + formepos.top}px`;
forme.style.left = `${card.offsetLeft + formepos.left}px`;
})
}
// function initVues(){
// console.log('initVues');
// // initVueContent();
// }
// function initVueContent(){
// createApp(Content).mount('main[role="main"]');
// // 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 LeShedTheme()
LeShedTheme()
})(Drupal, drupalSettings)
@@ -0,0 +1,13 @@
<template>
<div>
hello HMR TROP TROP BIEN
</div>
</template>
<script>
</script>
<style>
</style>
@@ -0,0 +1,15 @@
@import "partials/colors";
@import "partials/fonts";
@import "partials/mixins";
a, a:visited{
text-decoration: none;
color: inherit;
transition: color 0.15s ease-out;
}
body{
margin: 0;
// background-color: green;
}
@@ -0,0 +1,3 @@
// $bleu_site: #1642bc;
// $bleu_typo: #0b1e52;
// $rose: #f661e2;
@@ -0,0 +1,29 @@
// @import "/assets/fonts/fredoka/stylesheet.css";
// @import "/assets/fonts/Schibsted_Grotesk/stylesheet.css";
// body{
// font-family: "Schibsted Grotesk";
// font-weight: normal;
// font-style: normal;
// color: $bleu_typo;
// }
// @mixin titre_h2{
// font-family: 'Fredoka';
// font-size: 3em;
// font-weight: 400;
// color: $bleu_typo;
// line-height: 1;
// }
// @mixin titre_h3{
// @include titre_h2();
// font-size: 2em;
// }
// @mixin titre_h4{
// @include titre_h2();
// font-size: 1.323em;
// }
@@ -0,0 +1,69 @@
@mixin menu-contenus{
ul,li{
padding: 0;
margin:0;
list-style: none;
}
.wrapper{
position: relative;
}
label{
color:$bleu_site;
font-weight: 600;
display: block;
font-size: 0.756em;
padding:0 0 0.25em 0;
transition: color 0.25s ease-out;
position: absolute;
z-index: 0;
&:has(+ a:hover){
color: $rose;
}
}
a{
font-size: 1.13em;
transition: color 0.15s ease-out;
display: block;
position: relative;
z-index: 1;
padding-top: 1em;
&:hover{
color: $bleu_site;
}
}
}
@mixin card{
position: relative;
background-color: #fff;
padding:2em;
box-shadow: 0 0 10px rgba(0,0,0,0.25);
max-width: 50em;
box-sizing: content-box;
margin: 30vh auto 0;
&[role="home-presentation"]{
margin-top: 10vh;
}
}
@mixin arrow{
display: block;
width:30px; height:30px;
border-radius: 15px;
background-repeat: no-repeat;
background-position: center center;
background-size: contain;
text-indent: 100px;
overflow: hidden;
}
@mixin arrow-white{
@include arrow();
background-image: url('/themes/custom/mathallo/assets/img/arrow-white.svg');
}
@mixin arrow-blue{
@include arrow();
background-image: url('/themes/custom/mathallo/assets/img/arrow-blue.svg');
}
+25
View File
@@ -0,0 +1,25 @@
name: Le Shed
type: theme
base theme: stark
description: leshed drupal theme based on stark
package: leshed
core: 0.x
core_version_requirement: ^8 || ^9 || ^10 || ^11
# libraries:
# - caravane/global
regions:
header_top: 'Header-top'
header_left: 'Header-left'
header_center: 'Header-center'
header_right: 'Header-right'
header_bottom: 'Header-bottom'
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'
@@ -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
+102
View File
@@ -0,0 +1,102 @@
<?php
/**
* @file
* Functions to support theming in the leshed theme.
*/
function leshed_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'][] = 'leshed/vitehmr';
}else{
$page['#attached']['library'][] = 'leshed/global';
}
}
/**
* Implements hook_preprocess_HOOK() for html.html.twig.
*/
function leshed_preprocess_html(&$variables) {
}
/**
* Implements hook_preprocess_HOOK() for page.html.twig.
*/
function leshed_preprocess_page(&$variables) {
}
function leshed_preprocess_region(&$variables) {
if (!isset($variables["attributes"]['class'])) {
$variables["attributes"]['class'] = [];
}
$variables["attributes"]['class'][] = "wrapper";
}
// function leshed_preprocess_block__leshed_contenu(&$variables) {
function leshed_preprocess_block__menu_block__contenu(&$variables) {
foreach ($variables['content']['#items'] as $key => $item) {
parse_menu_item($variables['content']['#items'], $key);
}
}
function parse_menu_item(&$items, $key){
if ($items[$key]['url']->getRouteName() === "entity.node.canonical") {
$nid = $items[$key]['url']->getRouteParameters()['node'];
$node = \Drupal\node\Entity\Node::load($nid);
// create prefix (label) for chapitres
if ($node->getType() === "chapitre") {
$chapitre = $node->get('field_chapitre_num')->getValue()[0]['value'];
$items[$key]['prefix'] = "Chapitre {$chapitre}";
}
// create prefix (label) for parties
if ($node->getType() === "partie") {
$partie = $node->get('field_partie')->getValue()[0]['value'];
$items[$key]['prefix'] = "Partie {$partie}";
}
// add active attribute
if ($items[$key]['in_active_trail']){
$items[$key]['attributes']->offsetSet('class', 'in-active-trail');
}
}
if (count($items[$key]['below']) > 0) {
foreach ($items[$key]['below'] as $key_b => $item_b) {
parse_menu_item($items[$key]['below'], $key_b);
}
}
}
/**
* Implements hook_preprocess_HOOK() for node.html.twig.
*/
function leshed_preprocess_node(&$variables) {
$node_type = $variables['node']->getType();
if (!isset($variables["attributes"]['class'])) {
$variables["attributes"]['class'] = [];
}
$variables["attributes"]['class'][] = "node-type-{$node_type}";
}
function leshed_preprocess_contanier(&$variables) {
}
/**
* Implements hook_preprocess_HOOK() for node.html.twig.
*/
function leshed_preprocess_field(&$variables) {
if (!isset($variables["title_attributes"]['class'])) {
$variables["title_attributes"]['class'] = [];
}
$variables['title_attributes']['class'][] = 'field-label';
if (!isset($variables["attributes"]['class'])) {
$variables["attributes"]['class'] = [];
}
$variables['attributes']['class'][] = $variables['field_name'];
}
File diff suppressed because it is too large Load Diff
+21
View File
@@ -0,0 +1,21 @@
{
"name": "leshed",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"axios": "^1.7.2",
"gsap": "^3.14.1",
"vue": "^3.4.29"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0.5",
"sass": "^1.77.8",
"vite": "^5.3.1"
}
}
+6
View File
@@ -0,0 +1,6 @@
Sass
```
npm install
npm run scss
```
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

@@ -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>
+48
View File
@@ -0,0 +1,48 @@
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: {
// The dev server must be reachable from the browser on the host.
host: 'localhost',
port: 5173,
strictPort: true,
// Since Vite 5.4.12 (CVE-2025-24010) CORS is disabled by default.
// Explicitly allow the origin(s) that serve the Drupal pages (vhost).
cors: {
origin: [/^https?:\/\/dev\.leshed\.fr(:\d+)?$/],
},
// Absolute base URL used by Vite to build asset/HMR URLs.
origin: 'http://localhost:5173',
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))
}
}
})