Integrated scss style building in Grunt extension
This commit is contained in:
parent
413f5c3e4f
commit
64f9b8b043
9 changed files with 2299 additions and 793 deletions
101
Gruntfile.js
Normal file
101
Gruntfile.js
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
// This file is part of Moodle - http://moodle.org/
|
||||||
|
//
|
||||||
|
// Moodle is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Moodle is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
/* jshint node: true, browser: false */
|
||||||
|
/* eslint-env node */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Grunt configuration for local_treestudyplan
|
||||||
|
*
|
||||||
|
* @copyright 2023 P.M. Kuipers
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Grunt configuration.
|
||||||
|
*
|
||||||
|
* @param {Grunt} grunt
|
||||||
|
*/
|
||||||
|
module.exports = function(grunt) {
|
||||||
|
const path = require('path');
|
||||||
|
const process = require('process');
|
||||||
|
const sass = require('sass');
|
||||||
|
|
||||||
|
// Import grunt configuration for moodle base
|
||||||
|
process.chdir("../.."); // change dir to moodle base
|
||||||
|
require(path.resolve(`./Gruntfile.js`))(grunt); // Run Gruntfile module from moodle base
|
||||||
|
|
||||||
|
grunt.registerTask('scssplugin','Compile scss/*.sccs into styles.css and css/devstyles.css', () => {
|
||||||
|
|
||||||
|
const devoutput = 'css/devstyles.css';
|
||||||
|
const prodoutput = 'styles.css';
|
||||||
|
|
||||||
|
// Get full path of compenent and scss folder
|
||||||
|
const componentPath = path.join(grunt.moodleEnv.gruntFilePath,grunt.moodleEnv.componentDirectory);
|
||||||
|
const scssPath = path.join(componentPath, 'scss','styles.scss');
|
||||||
|
console.log(`Compiling ${scssPath} including any imported files therein`);
|
||||||
|
|
||||||
|
process.chdir(path.join(componentPath, 'scss'));
|
||||||
|
const result = sass.compile(scssPath);
|
||||||
|
if ( result ) {
|
||||||
|
console.info("got result");
|
||||||
|
|
||||||
|
// Some regex processing to match moodle stylelint styles
|
||||||
|
|
||||||
|
// change tab indent to 4 instead of 2
|
||||||
|
let css = result.css.replace(/^ ([^ ])/gm ," $1");
|
||||||
|
|
||||||
|
// insert a newline after every comma in a css selector
|
||||||
|
// (only combined selectors will get that long)
|
||||||
|
css = css.replace(/^[^ ].*[\{,]$/gm , (m) => { // Find CSS selector lines
|
||||||
|
return m.replace(/, /g,",\n"); // replace comma followed by space with comma newline
|
||||||
|
});
|
||||||
|
|
||||||
|
// replace hex color codes with lowercase (convenience function since I don't really care for the hex codes lowercase only rule)
|
||||||
|
const hexCodeToLower = (match, m1, m2) => {
|
||||||
|
return '#'+m1.toLowerCase()+m2;
|
||||||
|
}
|
||||||
|
css = css.replace(/#([A-F0-9a-f]{3})([^A-F0-9a-f]?)/gm , hexCodeToLower); // 3 digit color codes
|
||||||
|
css = css.replace(/#([A-F0-9a-f]{6})([^A-F0-9a-f]?)/gm , hexCodeToLower); // 6 digit color codes
|
||||||
|
css = css.replace(/#([A-F0-9a-f]{8})([^A-F0-9a-f]?)/gm , hexCodeToLower); // 8 digit color codes (with alpha)
|
||||||
|
|
||||||
|
// All other errors should really be fixed in the scss files :)
|
||||||
|
|
||||||
|
[devoutput,prodoutput].forEach((output) => {
|
||||||
|
console.info(`Storing ${output}`);
|
||||||
|
grunt.file.write(path.join(componentPath, output),css);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// Rebuild on changes in the scss files when using 'grunt watch'
|
||||||
|
grunt.config.merge({
|
||||||
|
watch: {
|
||||||
|
scssplugin: {
|
||||||
|
files: ['scss/*.scss'],
|
||||||
|
tasks: ['scssplugin']
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Remove gherkinlint from the startup list, since it exits with an error because of errors in moodle's own code
|
||||||
|
grunt.moodleEnv.startupTasks.splice(grunt.moodleEnv.startupTasks.indexOf("gherkinlint"),1);
|
||||||
|
|
||||||
|
// Add the 'scssplugin' task as a startup task.
|
||||||
|
grunt.moodleEnv.startupTasks.push('scssplugin');
|
||||||
|
|
||||||
|
|
||||||
|
};
|
1
build.sh
1
build.sh
|
@ -14,6 +14,7 @@ $SCRIPTDIR/vuemode.sh prod
|
||||||
# so we can be sure all javascript is properly built from the most recent source
|
# so we can be sure all javascript is properly built from the most recent source
|
||||||
cd $SCRIPTDIR
|
cd $SCRIPTDIR
|
||||||
grunt amd
|
grunt amd
|
||||||
|
grunt scssplugin # plugin specific scss task to compile styles.css from scss files
|
||||||
|
|
||||||
# run the build php script
|
# run the build php script
|
||||||
php ${SCRIPTDIR}/build.php $@
|
php ${SCRIPTDIR}/build.php $@
|
||||||
|
|
1582
css/devstyles.css
1582
css/devstyles.css
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
||||||
.path-local-treestudyplan {
|
.path-local-treestudyplan {
|
||||||
div.tab-pane:target {
|
div.tab-pane:target {
|
||||||
margin-top: 0px;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
[v-cloak] {
|
[v-cloak] {
|
||||||
|
@ -12,4 +12,8 @@
|
||||||
margin: auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.special {
|
||||||
|
color: gold;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -5,16 +5,16 @@ quite hard to maintain.
|
||||||
Unfortunately, moodle does not extend the sass/scss compiler support to plugins
|
Unfortunately, moodle does not extend the sass/scss compiler support to plugins
|
||||||
that are not a theme.
|
that are not a theme.
|
||||||
|
|
||||||
To alleviate this, this plugin includes it's own scss compiler script that compiles
|
To alleviate this, this plugin extends moodle's Gruntfile.js scripts
|
||||||
all scss files in this directory into one css file - css/devstyles.css
|
to compile 'scss/styles.scss' into 'css/devstyles.css' (and 'styles.css')
|
||||||
|
|
||||||
This files is used instead of styles.css in order to avoid having to clear the theme
|
'css/devstyles.css' is used instead of styles.css in order to avoid having to clear the theme
|
||||||
cache every time a style rule is changed during development.
|
cache every time a style rule is changed during development.
|
||||||
|
|
||||||
Once I devise a method to use styles.css in production environtments and css/devstyles.css
|
Once I devise a method to use styles.css in production environtments and css/devstyles.css
|
||||||
production environments, the compiler will compile it into both css/devstyles.css
|
production environments, the compiler will compile it into both css/devstyles.css
|
||||||
and styles.css
|
and styles.css
|
||||||
|
|
||||||
Call the plugin's scss compiler by running scssbuild.sh in the plugin's root.
|
The grunt command to compile is 'grunt scssplugin'
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-auto-flow: column;
|
grid-auto-flow: column;
|
||||||
/*border-bottom-style: solid;*/
|
/*border-bottom-style: solid;*/
|
||||||
border-color: #cccccc;
|
border-color: #ccc;
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@
|
||||||
|
|
||||||
.t-studyline .t-studyline-editmode-content {
|
.t-studyline .t-studyline-editmode-content {
|
||||||
border-right-style: solid;
|
border-right-style: solid;
|
||||||
border-color: #cccccc;
|
border-color: #ccc;
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,19 +233,19 @@
|
||||||
|
|
||||||
.t-studyline-slot.t-studyline-slot-0 .t-slot-drop.filter .t-slot-item,
|
.t-studyline-slot.t-studyline-slot-0 .t-slot-drop.filter .t-slot-item,
|
||||||
.r-studyline-slot.r-studyline-slot-0 .r-item-base {
|
.r-studyline-slot.r-studyline-slot-0 .r-item-base {
|
||||||
margin-left: 0px;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.t-studyline-slot.gradable.current.odd,
|
.t-studyline-slot.gradable.current.odd,
|
||||||
.r-studyline-slot.gradable.current.odd {
|
.r-studyline-slot.gradable.current.odd {
|
||||||
--hlcol: color-mix(in srgb, var(--less-light) , var(--highlight) var(--highlight-mix));
|
--hlcol: color-mix(in srgb, var(--less-light), var(--highlight) var(--highlight-mix));
|
||||||
background-color: var(--hlcol);
|
background-color: var(--hlcol);
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.t-studyline-slot.gradable.current.odd:before,
|
.t-studyline-slot.gradable.current.odd:before,
|
||||||
.r-studyline-slot.gradable.current.odd:before {
|
.r-studyline-slot.gradable.current.odd:before {
|
||||||
--hlcol: color-mix(in srgb, var(--less-light) , var(--highlight) var(--highlight-mix));
|
--hlcol: color-mix(in srgb, var(--less-light), var(--highlight) var(--highlight-mix));
|
||||||
box-shadow: -20px 0 10px -7px var(--hlcol) inset;
|
box-shadow: -20px 0 10px -7px var(--hlcol) inset;
|
||||||
content: " ";
|
content: " ";
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -257,7 +257,7 @@
|
||||||
|
|
||||||
.t-studyline-slot.gradable.current.odd:after,
|
.t-studyline-slot.gradable.current.odd:after,
|
||||||
.r-studyline-slot.gradable.current.odd:after {
|
.r-studyline-slot.gradable.current.odd:after {
|
||||||
--hlcol: color-mix(in srgb, var(--less-light) , var(--highlight) var(--highlight-mix));
|
--hlcol: color-mix(in srgb, var(--less-light), var(--highlight) var(--highlight-mix));
|
||||||
box-shadow: 20px 0 10px -7px var(--hlcol) inset;
|
box-shadow: 20px 0 10px -7px var(--hlcol) inset;
|
||||||
content: " ";
|
content: " ";
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -272,7 +272,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.s-studyline-header-period.current {
|
.s-studyline-header-period.current {
|
||||||
--hlcol: color-mix(in srgb, var(--white) , var(--highlight) var(--highlight-mix));
|
--hlcol: color-mix(in srgb, var(--white), var(--highlight) var(--highlight-mix));
|
||||||
box-shadow: 0 0 10px 10px var(--hlcol);
|
box-shadow: 0 0 10px 10px var(--hlcol);
|
||||||
background-color: var(--hlcol);
|
background-color: var(--hlcol);
|
||||||
border-top-left-radius: 16px;
|
border-top-left-radius: 16px;
|
||||||
|
@ -285,14 +285,14 @@
|
||||||
|
|
||||||
.t-studyline-slot.gradable.current.even,
|
.t-studyline-slot.gradable.current.even,
|
||||||
.r-studyline-slot.gradable.current.even {
|
.r-studyline-slot.gradable.current.even {
|
||||||
--hlcol: color-mix(in srgb, var(--white) , var(--highlight) var(--highlight-mix));
|
--hlcol: color-mix(in srgb, var(--white), var(--highlight) var(--highlight-mix));
|
||||||
background-color: var(--hlcol);
|
background-color: var(--hlcol);
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.t-studyline-slot.gradable.current.even:before,
|
.t-studyline-slot.gradable.current.even:before,
|
||||||
.r-studyline-slot.gradable.current.even:before {
|
.r-studyline-slot.gradable.current.even:before {
|
||||||
--hlcol: color-mix(in srgb, var(--white) , var(--highlight) var(--highlight-mix));
|
--hlcol: color-mix(in srgb, var(--white), var(--highlight) var(--highlight-mix));
|
||||||
box-shadow: -20px 0 10px -7px var(--hlcol) inset;
|
box-shadow: -20px 0 10px -7px var(--hlcol) inset;
|
||||||
content: " ";
|
content: " ";
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -308,7 +308,7 @@
|
||||||
|
|
||||||
.t-studyline-slot.gradable.current.even:after,
|
.t-studyline-slot.gradable.current.even:after,
|
||||||
.r-studyline-slot.gradable.current.even:after {
|
.r-studyline-slot.gradable.current.even:after {
|
||||||
--hlcol: color-mix(in srgb, var(--white) , var(--highlight) var(--highlight-mix));
|
--hlcol: color-mix(in srgb, var(--white), var(--highlight) var(--highlight-mix));
|
||||||
box-shadow: 20px 0 10px -7px var(--hlcol) inset;
|
box-shadow: 20px 0 10px -7px var(--hlcol) inset;
|
||||||
content: " ";
|
content: " ";
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -361,7 +361,7 @@
|
||||||
.t-item-deletebox.drop-in {
|
.t-item-deletebox.drop-in {
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
background-color: #FFCCCC;
|
background-color: #FCC;
|
||||||
color: #a00;
|
color: #a00;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -401,7 +401,7 @@
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: calc(50% - 5px);
|
top: calc(50% - 5px);
|
||||||
right: -1px;
|
right: -1px;
|
||||||
line-height: 0px;
|
line-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.t-item-connector-start svg rect {
|
.t-item-connector-start svg rect {
|
||||||
|
@ -421,7 +421,7 @@
|
||||||
top: 50%;
|
top: 50%;
|
||||||
transform: translate(0, -50%);
|
transform: translate(0, -50%);
|
||||||
left: -1px;
|
left: -1px;
|
||||||
line-height: 0px;
|
line-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.t-item-connector-end svg rect {
|
.t-item-connector-end svg rect {
|
||||||
|
@ -458,7 +458,7 @@
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translate(-50%, 100%);
|
transform: translate(-50%, 100%);
|
||||||
bottom: 0px;
|
bottom: 0;
|
||||||
z-index: 25;
|
z-index: 25;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -474,7 +474,7 @@
|
||||||
.t-item-filter {
|
.t-item-filter {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
height: 1em;
|
height: 1em;
|
||||||
padding: 0px;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
font-size: 2em;
|
font-size: 2em;
|
||||||
|
@ -545,7 +545,7 @@
|
||||||
|
|
||||||
|
|
||||||
a.t-item-course-config {
|
a.t-item-course-config {
|
||||||
font-size: 16pt;
|
font-size: 21px /*16pt*/;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
float: right;
|
float: right;
|
||||||
margin-right: 2px;
|
margin-right: 2px;
|
||||||
|
@ -698,7 +698,7 @@
|
||||||
|
|
||||||
.r-item-filter {
|
.r-item-filter {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 0px;
|
padding: 0;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
font-size: 2em;
|
font-size: 2em;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
|
@ -799,14 +799,14 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.r-course-grading {
|
.r-course-grading {
|
||||||
font-size: 16pt;
|
font-size: 21px /*16pt*/;
|
||||||
margin-right: 2px;
|
margin-right: 2px;
|
||||||
vertical-align: bottom;
|
vertical-align: bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
.r-course-graded,
|
.r-course-graded,
|
||||||
.r-course-result {
|
.r-course-result {
|
||||||
font-size: 16pt;
|
font-size: 21px /*16pt*/;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
float: right;
|
float: right;
|
||||||
margin-right: 2px;
|
margin-right: 2px;
|
||||||
|
@ -819,7 +819,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.r-completion-detail-header {
|
.r-completion-detail-header {
|
||||||
font-size: 20pt;
|
font-size: 26px /*20pt*/;
|
||||||
}
|
}
|
||||||
|
|
||||||
.r-item-finish.completion-incomplete,
|
.r-item-finish.completion-incomplete,
|
||||||
|
@ -1019,7 +1019,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.s-studyplan-card-title-buttons {
|
.s-studyplan-card-title-buttons {
|
||||||
font-size: 12pt;
|
font-size: 16px /*12pt*/;
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
.s-studyplan-card-title-buttons > * {
|
.s-studyplan-card-title-buttons > * {
|
||||||
|
@ -1115,9 +1115,14 @@
|
||||||
margin-right: 1em;
|
margin-right: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.s-edit-mod-form [data-fieldtype=submit] { display: none ! important; }
|
.s-edit-mod-form [data-fieldtype=submit] {
|
||||||
.s-edit-mod-form.genericonly form > fieldset:not(#id_general) { display: none ! important; }
|
/* if not working, make selector more specific */
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.s-edit-mod-form.genericonly form > fieldset:not(#id_general) {
|
||||||
|
/* if not working, make selector more specific */
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
.border-grey {
|
.border-grey {
|
||||||
border-color: #aaa;
|
border-color: #aaa;
|
||||||
}
|
}
|
||||||
|
|
4
scss/styles.scss
Normal file
4
scss/styles.scss
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
@import "colors.scss";
|
||||||
|
@import "generic.scss";
|
||||||
|
@import "invitemanager.scss";
|
||||||
|
@import "studyplan.scss"
|
63
scssbuild.js
63
scssbuild.js
|
@ -1,63 +0,0 @@
|
||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
// This file is part of the Studyplan plugin for Moodle
|
|
||||||
//
|
|
||||||
// Moodle is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Moodle is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Moodle. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
/**
|
|
||||||
* This file compiles the scss files in the scss/ folder into either the main
|
|
||||||
* styles.css for production upon build or css/devstyles.css for development
|
|
||||||
*
|
|
||||||
* Most nice would be to integrate this action with grunt watch, but I am
|
|
||||||
* not familiar enough with grunt to know if I can extend moodle's grunt actions
|
|
||||||
* from a Gruntfile.js in this directory without modifying Moodle's Gruntfile.js
|
|
||||||
*
|
|
||||||
* @package local_treestudyplan
|
|
||||||
* @copyright 2023 P.M. Kuipers
|
|
||||||
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
||||||
*/
|
|
||||||
|
|
||||||
const sass = require('sass');
|
|
||||||
const path = require('path');
|
|
||||||
const fs = require('fs');
|
|
||||||
|
|
||||||
const output = 'css/devstyles.css';
|
|
||||||
|
|
||||||
let css = "";
|
|
||||||
let map = "";
|
|
||||||
//joining path of directory
|
|
||||||
const directoryPath = path.join(__dirname, 'scss');
|
|
||||||
//passsing directoryPath and callback function
|
|
||||||
fs.readdir(directoryPath, function (err, files) {
|
|
||||||
//handling error
|
|
||||||
if (err) {
|
|
||||||
return console.log('Unable to scan directory: ' + err);
|
|
||||||
}
|
|
||||||
//listing all files using forEach
|
|
||||||
files.forEach(function (file) {
|
|
||||||
if (file.endsWith(".scss")) {
|
|
||||||
const result = sass.compile(file);
|
|
||||||
console.info(`Processing ${file}...`)
|
|
||||||
if ( result ) {
|
|
||||||
css = css + `/**** ${file} ****/\n` + result.css + "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
console.info(`Storing ${output}`);
|
|
||||||
fs.writeFile(path.join(__dirname, output),css,(err) => {
|
|
||||||
if (err) throw err;
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
1274
styles.css
1274
styles.css
File diff suppressed because it is too large
Load diff
Reference in a new issue