Compare commits
96 commits
Author | SHA1 | Date | |
---|---|---|---|
Manuel Thalmann | a2b7531ad4 | ||
Manuel Thalmann | 04ee84d77e | ||
Manuel Thalmann | 85b2635da3 | ||
Manuel Thalmann | 99a7eb3b53 | ||
Manuel Thalmann | bb217047a1 | ||
Manuel Thalmann | 9782d3499c | ||
Manuel Thalmann | 5b96fa38c2 | ||
Manuel Thalmann | 983ce40397 | ||
Manuel Thalmann | 397d401d13 | ||
Manuel Thalmann | 70208bf6cc | ||
Manuel Thalmann | 84f09ee473 | ||
Manuel Thalmann | 1b0e3c0155 | ||
Manuel Thalmann | afc65d8cf3 | ||
Manuel Thalmann | 17ed8430c9 | ||
Manuel Thalmann | e3dce4859b | ||
Manuel Thalmann | 60d2f273e4 | ||
Manuel Thalmann | 74698047ed | ||
Manuel Thalmann | 15c0e10c21 | ||
Manuel Thalmann | d65760e437 | ||
Manuel Thalmann | 31ee457468 | ||
Manuel Thalmann | 7751bd0006 | ||
Manuel Thalmann | fefbad1687 | ||
Manuel Thalmann | 7698a9aab3 | ||
Manuel Thalmann | 46ce17d365 | ||
Manuel Thalmann | b3107eb09a | ||
Manuel Thalmann | 695efff492 | ||
Manuel Thalmann | 992cd447ba | ||
Manuel Thalmann | 25683a35fc | ||
Manuel Thalmann | 61627c2a6a | ||
Manuel Thalmann | ce34b2e9dc | ||
Manuel Thalmann | b600414d9d | ||
Manuel Thalmann | 706835d97c | ||
Manuel Thalmann | 0c9694752e | ||
Manuel Thalmann | 1b2f5b46e5 | ||
Manuel Thalmann | 3f5fd10a84 | ||
Manuel Thalmann | 351ce0cdad | ||
Manuel Thalmann | 5f560e151e | ||
Manuel Thalmann | c7157cc247 | ||
Manuel Thalmann | 4ad39d69db | ||
Manuel Thalmann | b1b8b74134 | ||
Manuel Thalmann | e336072b11 | ||
Manuel Thalmann | cadbc594c0 | ||
Manuel Thalmann | 90bb091ae8 | ||
Manuel Thalmann | d6fa484904 | ||
Manuel Thalmann | cdba678fe9 | ||
Manuel Thalmann | c2fe374ccd | ||
Manuel Thalmann | c5137e520b | ||
Manuel Thalmann | c14bedcb46 | ||
Manuel Thalmann | 75e22e02ce | ||
Manuel Thalmann | 449d2553bf | ||
Manuel Thalmann | 6ecfecbcbd | ||
Manuel Thalmann | 1e6daaacd7 | ||
Manuel Thalmann | 1337771f59 | ||
Manuel Thalmann | 3af6253c56 | ||
Manuel Thalmann | f1a35756b3 | ||
Manuel Thalmann | 2dceaf9520 | ||
Manuel Thalmann | 7015fa994a | ||
Manuel Thalmann | 9f9c0bc497 | ||
Manuel Thalmann | d468b58393 | ||
Manuel Thalmann | 0e59d2cd50 | ||
Manuel Thalmann | 55a2ff97d1 | ||
Manuel Thalmann | f00977b8bf | ||
Manuel Thalmann | 56d8a6af3d | ||
Manuel Thalmann | 1ad03d1d41 | ||
Manuel Thalmann | 2dd3a6161a | ||
Manuel Thalmann | 5cbb4cf411 | ||
Manuel Thalmann | 0b91e83df4 | ||
Manuel Thalmann | 7d99223936 | ||
Manuel Thalmann | 5bb5999cde | ||
Manuel Thalmann | 1543603447 | ||
Manuel Thalmann | 428dcedea9 | ||
Manuel Thalmann | 7d189ede99 | ||
Manuel Thalmann | c7b9118298 | ||
Manuel Thalmann | aeb85de82a | ||
Manuel Thalmann | 7777dee9f3 | ||
Manuel Thalmann | 1242bbdc90 | ||
Manuel Thalmann | ed165b43e9 | ||
Manuel Thalmann | dbcfd2e148 | ||
Manuel Thalmann | 0fee992b83 | ||
Manuel Thalmann | 6b8c085976 | ||
Manuel Thalmann | 2b44c6ac22 | ||
Manuel Thalmann | b413318097 | ||
Manuel Thalmann | 683e09f236 | ||
Manuel Thalmann | a027ba64a2 | ||
Manuel Thalmann | ac76bf6715 | ||
Manuel Thalmann | 6c72e6200f | ||
Manuel Thalmann | 68378b1e86 | ||
Manuel Thalmann | 84ada4d843 | ||
Manuel Thalmann | f734303a26 | ||
Manuel Thalmann | f1906b03cd | ||
Manuel Thalmann | bdb2e4e02f | ||
Manuel Thalmann | 7718b1dad7 | ||
Manuel Thalmann | 2b347775c4 | ||
Manuel Thalmann | 6e424a7710 | ||
Manuel Thalmann | 5ebc689c95 | ||
Manuel Thalmann | 434ca85b41 |
7
.devcontainer/devcontainer.env
Normal file
7
.devcontainer/devcontainer.env
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
MYSQL_DATABASE=SilverStripe
|
||||||
|
SS_DATABASE_NAME=SilverStripe
|
||||||
|
|
||||||
|
MYSQL_USER=silverstripe
|
||||||
|
SS_DATABASE_USERNAME=silverstripe
|
||||||
|
MYSQL_PASSWORD=Sup3rS3cr3tP@ssw0rd
|
||||||
|
SS_DATABASE_PASSWORD=Sup3rS3cr3tP@ssw0rd
|
19
.devcontainer/devcontainer.json
Normal file
19
.devcontainer/devcontainer.json
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"name": "SilverStripe Environment",
|
||||||
|
"dockerComposeFile": "docker-compose.yml",
|
||||||
|
"service": "silverstripe",
|
||||||
|
"workspaceFolder": "/shared-workspaces/mantra",
|
||||||
|
"remoteUser": "vscode",
|
||||||
|
"extensions": [
|
||||||
|
"adrianhumphreys.silverstripe",
|
||||||
|
"bmewburn.vscode-intelephense-client",
|
||||||
|
"dbaeumer.vscode-eslint",
|
||||||
|
"mikestead.dotenv",
|
||||||
|
"neilbrayfield.php-docblocker",
|
||||||
|
"xdebug.php-debug"
|
||||||
|
],
|
||||||
|
"settings": {
|
||||||
|
"php.executablePath": null
|
||||||
|
},
|
||||||
|
"postCreateCommand": "bash ./.devcontainer/post-create.sh"
|
||||||
|
}
|
39
.devcontainer/docker-compose.yml
Normal file
39
.devcontainer/docker-compose.yml
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
silverstripe:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: web.Dockerfile
|
||||||
|
env_file: devcontainer.env
|
||||||
|
environment:
|
||||||
|
- SS_ENVIRONMENT_TYPE=dev
|
||||||
|
- SS_BASE_URL=http://localhost:8080
|
||||||
|
- SS_DATABASE_CLASS=MySQLPDODatabase
|
||||||
|
- SS_DATABASE_SERVER=db
|
||||||
|
- SS_DEFAULT_ADMIN_USERNAME=root
|
||||||
|
- SS_DEFAULT_ADMIN_PASSWORD=password
|
||||||
|
ports:
|
||||||
|
- 127.0.0.1:8080:80
|
||||||
|
- 127.0.0.1:3000:3000
|
||||||
|
- 127.0.0.1:3001:3001
|
||||||
|
- 127.0.0.1:9003:9003
|
||||||
|
working_dir: /shared-workspaces/mantra
|
||||||
|
volumes:
|
||||||
|
- ..:/shared-workspaces/mantra
|
||||||
|
- main-node:/shared-workspaces/mantra/node_modules/
|
||||||
|
- main-composer:/shared-workspaces/mantra/vendor/
|
||||||
|
db:
|
||||||
|
image: mysql:5
|
||||||
|
env_file: devcontainer.env
|
||||||
|
environment:
|
||||||
|
- MYSQL_RANDOM_ROOT_PASSWORD=yes
|
||||||
|
volumes:
|
||||||
|
- mysql-data:/var/lib/mysql
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
main-node:
|
||||||
|
resources:
|
||||||
|
main-composer:
|
||||||
|
test-composer:
|
||||||
|
mysql-data:
|
6
.devcontainer/post-create.sh
Normal file
6
.devcontainer/post-create.sh
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#!/bin/bash
|
||||||
|
echo '* text=auto eol=lf' > $(git rev-parse --git-dir)/info/attributes
|
||||||
|
sudo rm -rf /var/www/html
|
||||||
|
sudo ln -sT $(pwd)/test/website /var/www/html
|
||||||
|
sudo chown vscode:vscode node_modules
|
||||||
|
sudo chown vscode:vscode vendor
|
13
.devcontainer/web.Dockerfile
Normal file
13
.devcontainer/web.Dockerfile
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
FROM manuth/silverstripe-dev
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get -y install sudo && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
RUN userdel node; \
|
||||||
|
adduser --disabled-password --gecos '' vscode && \
|
||||||
|
sed -i /etc/sudoers -re 's/^%sudo.*/%sudo ALL=(ALL:ALL) NOPASSWD: ALL/g' && \
|
||||||
|
sed -i /etc/sudoers -re 's/^root.*/root ALL=(ALL:ALL) NOPASSWD: ALL/g' && \
|
||||||
|
echo 'vscode ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers
|
||||||
|
|
||||||
|
USER vscode
|
79
.drone.yml
Normal file
79
.drone.yml
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
name: mantra
|
||||||
|
kind: pipeline
|
||||||
|
type: docker
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: install
|
||||||
|
image: manuth/silverstripe-dev
|
||||||
|
commands:
|
||||||
|
- composer install
|
||||||
|
- name: build
|
||||||
|
image: manuth/silverstripe-dev
|
||||||
|
commands:
|
||||||
|
- composer build
|
||||||
|
- name: lint
|
||||||
|
image: manuth/silverstripe-dev
|
||||||
|
commands:
|
||||||
|
- composer lint
|
||||||
|
# - name: test
|
||||||
|
# image: manuth/silverstripe-dev
|
||||||
|
# commands:
|
||||||
|
# - composer test
|
||||||
|
# - name: publish package
|
||||||
|
# image: manuth/silverstripe-dev
|
||||||
|
# environment:
|
||||||
|
# NPM_TOKEN:
|
||||||
|
# from_secret: npm_token
|
||||||
|
# commands:
|
||||||
|
# - echo "//registry.npmjs.org/:_authToken=$${NPM_TOKEN}" > ~/.npmrc
|
||||||
|
# - npm publish
|
||||||
|
# when:
|
||||||
|
# event:
|
||||||
|
# - tag
|
||||||
|
# ref:
|
||||||
|
# - refs/tags/v[0-9]*.[0-9]*.[0-9]*
|
||||||
|
- name: prepare release
|
||||||
|
image: manuth/silverstripe-dev
|
||||||
|
commands:
|
||||||
|
- composer archive
|
||||||
|
- npm install escape-string-regexp --no-save
|
||||||
|
- node -e "console.log(require('escape-string-regexp')('${DRONE_TAG}'))" > TagName.txt
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
- tag
|
||||||
|
- name: prepare release notes
|
||||||
|
image: alpine
|
||||||
|
commands:
|
||||||
|
- export TagName=$$(cat TagName.txt)
|
||||||
|
- export TagHeading="/## \(.* \($${TagName}\|\[$${TagName}\]\)\)\$/"
|
||||||
|
- export HeadingPattern='/## \(.* \(v[0-9.]*\|\[.*\]\)\)/'
|
||||||
|
- cp -f CHANGELOG.md ReleaseNotes.md
|
||||||
|
- sed -i "1,$${TagHeading}{ $${TagHeading}P ; d } ; $${HeadingPattern},\$d" ReleaseNotes.md
|
||||||
|
- cp -f ReleaseNotes.md ReleaseTitle.md
|
||||||
|
- sed -i "2,\$d ; s$${HeadingPattern}\\\\1/" ReleaseTitle.md
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
- tag
|
||||||
|
- name: publish release
|
||||||
|
image: plugins/github-release
|
||||||
|
commands: []
|
||||||
|
settings:
|
||||||
|
api_key:
|
||||||
|
from_secret: github_publish_token
|
||||||
|
files:
|
||||||
|
- "*.tar"
|
||||||
|
title: ReleaseTitle.md
|
||||||
|
note: ReleaseNotes.md
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
- tag
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
ref:
|
||||||
|
- refs/heads/**
|
||||||
|
- refs/pull/**
|
||||||
|
- refs/tags/**
|
||||||
|
event:
|
||||||
|
- push
|
||||||
|
- pull_request
|
||||||
|
- tag
|
20
.eslintrc.js
Normal file
20
.eslintrc.js
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
const { join } = require("path");
|
||||||
|
|
||||||
|
let appRoot = join(__dirname, "src", "App");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
extends: [
|
||||||
|
"plugin:@manuth/typescript/recommended-requiring-type-checking"
|
||||||
|
],
|
||||||
|
env: {
|
||||||
|
node: true,
|
||||||
|
es6: true
|
||||||
|
},
|
||||||
|
parserOptions: {
|
||||||
|
project: [
|
||||||
|
join(__dirname, "tsconfig.json"),
|
||||||
|
join(__dirname, "tsconfig.eslint.json"),
|
||||||
|
join(appRoot, "tsconfig.json")
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
45
.gitignore
vendored
45
.gitignore
vendored
|
@ -1,9 +1,20 @@
|
||||||
|
# Build results
|
||||||
|
/javascript/
|
||||||
|
/css/
|
||||||
|
/templates/
|
||||||
|
/assets/
|
||||||
|
/test/website/themes/mantra
|
||||||
|
|
||||||
# Logs
|
# Logs
|
||||||
logs
|
logs
|
||||||
*.log
|
*.log
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
|
||||||
# Runtime data
|
# Runtime data
|
||||||
pids
|
pids
|
||||||
|
@ -16,6 +27,7 @@ lib-cov
|
||||||
|
|
||||||
# Coverage directory used by tools like istanbul
|
# Coverage directory used by tools like istanbul
|
||||||
coverage
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
# nyc test coverage
|
# nyc test coverage
|
||||||
.nyc_output
|
.nyc_output
|
||||||
|
@ -35,42 +47,69 @@ build/Release
|
||||||
# Dependency directories
|
# Dependency directories
|
||||||
node_modules/
|
node_modules/
|
||||||
jspm_packages/
|
jspm_packages/
|
||||||
|
vendor/
|
||||||
|
|
||||||
# TypeScript v1 declaration files
|
# TypeScript v1 declaration files
|
||||||
typings/
|
typings/
|
||||||
|
|
||||||
|
# TypeScript cache
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
# Optional npm cache directory
|
# Optional npm cache directory
|
||||||
.npm
|
.npm
|
||||||
|
|
||||||
# Optional eslint cache
|
# Optional eslint cache
|
||||||
.eslintcache
|
.eslintcache
|
||||||
|
|
||||||
|
# Microbundle cache
|
||||||
|
.rpt2_cache/
|
||||||
|
.rts2_cache_cjs/
|
||||||
|
.rts2_cache_es/
|
||||||
|
.rts2_cache_umd/
|
||||||
|
|
||||||
# Optional REPL history
|
# Optional REPL history
|
||||||
.node_repl_history
|
.node_repl_history
|
||||||
|
|
||||||
# Output of 'npm pack'
|
# Output of 'npm pack'
|
||||||
*.tgz
|
*.tgz
|
||||||
|
|
||||||
|
# Output of 'composer archive'
|
||||||
|
*.tar
|
||||||
|
|
||||||
# Yarn Integrity file
|
# Yarn Integrity file
|
||||||
.yarn-integrity
|
.yarn-integrity
|
||||||
|
|
||||||
# dotenv environment variables file
|
# dotenv environment variables file
|
||||||
.env
|
.env
|
||||||
|
.env.test
|
||||||
|
|
||||||
# parcel-bundler cache (https://parceljs.org/)
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
.cache
|
.cache
|
||||||
|
|
||||||
# next.js build output
|
# Next.js build output
|
||||||
.next
|
.next
|
||||||
|
|
||||||
# nuxt.js build output
|
# Nuxt.js build / generate output
|
||||||
.nuxt
|
.nuxt
|
||||||
|
dist
|
||||||
|
|
||||||
|
# Gatsby files
|
||||||
|
.cache/
|
||||||
|
# Comment in the public line in if your project uses Gatsby and *not* Next.js
|
||||||
|
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||||
|
# public
|
||||||
|
|
||||||
# vuepress build output
|
# vuepress build output
|
||||||
.vuepress/dist
|
.vuepress/dist
|
||||||
|
|
||||||
# Serverless directories
|
# Serverless directories
|
||||||
.serverless
|
.serverless/
|
||||||
|
|
||||||
# FuseBox cache
|
# FuseBox cache
|
||||||
.fusebox/
|
.fusebox/
|
||||||
|
|
||||||
|
# DynamoDB Local files
|
||||||
|
.dynamodb/
|
||||||
|
|
||||||
|
# TernJS port file
|
||||||
|
.tern-port
|
||||||
|
|
11
.vscode/extensions.json
vendored
Normal file
11
.vscode/extensions.json
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"adrianhumphreys.silverstripe",
|
||||||
|
"bmewburn.vscode-intelephense-client",
|
||||||
|
"dbaeumer.vscode-eslint",
|
||||||
|
"mikestead.dotenv",
|
||||||
|
"ms-vscode-remote.remote-containers",
|
||||||
|
"neilbrayfield.php-docblocker",
|
||||||
|
"xdebug.php-debug"
|
||||||
|
]
|
||||||
|
}
|
57
.vscode/launch.json
vendored
Normal file
57
.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"args": [
|
||||||
|
"Watch"
|
||||||
|
],
|
||||||
|
"name": "Execute Watch Task",
|
||||||
|
"program": "${workspaceFolder}/node_modules/gulp/bin/gulp.js",
|
||||||
|
"request": "launch",
|
||||||
|
"skipFiles": [
|
||||||
|
"<node_internals>/**"
|
||||||
|
],
|
||||||
|
"type": "pwa-node",
|
||||||
|
"sourceMaps": true,
|
||||||
|
"outFiles": [
|
||||||
|
"${workspaceFolder}/gulpfile.ts",
|
||||||
|
"${workspaceFolder}/gulp/**/*.ts",
|
||||||
|
"!**/node_modules/**"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "pwa-chrome",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Launch Chrome",
|
||||||
|
"url": "http://localhost:3000",
|
||||||
|
"webRoot": "${workspaceFolder}/test/website/public",
|
||||||
|
"pathMapping": {
|
||||||
|
"/_resources/themes/mantra": "${workspaceFolder}"
|
||||||
|
},
|
||||||
|
"sourceMaps": true,
|
||||||
|
"preLaunchTask": "Watch Debug",
|
||||||
|
"postDebugTask": "Stop Debug"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Listen for XDebug",
|
||||||
|
"type": "php",
|
||||||
|
"request": "launch",
|
||||||
|
"port": 9003,
|
||||||
|
"pathMappings": {
|
||||||
|
"/var/www/html": "${workspaceFolder}/test/website"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"compounds": [
|
||||||
|
{
|
||||||
|
"name": "Debug Theme",
|
||||||
|
"configurations": [
|
||||||
|
"Launch Chrome",
|
||||||
|
"Listen for XDebug"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
21
.vscode/settings.json
vendored
Normal file
21
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"javascript.format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": false,
|
||||||
|
"javascript.format.placeOpenBraceOnNewLineForControlBlocks": true,
|
||||||
|
"javascript.format.placeOpenBraceOnNewLineForFunctions": true,
|
||||||
|
"typescript.format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": false,
|
||||||
|
"typescript.format.placeOpenBraceOnNewLineForControlBlocks": true,
|
||||||
|
"typescript.format.placeOpenBraceOnNewLineForFunctions": true,
|
||||||
|
"intelephense.files.exclude": [
|
||||||
|
"**/.git/**",
|
||||||
|
"**/.svn/**",
|
||||||
|
"**/.hg/**",
|
||||||
|
"**/CVS/**",
|
||||||
|
"**/.DS_Store/**",
|
||||||
|
"**/node_modules/**",
|
||||||
|
"**/bower_components/**",
|
||||||
|
"**/vendor/**/{Tests,tests}/**",
|
||||||
|
"**/.history/**",
|
||||||
|
"**/vendor/**/vendor/**",
|
||||||
|
"test/website/themes/mantra/**"
|
||||||
|
]
|
||||||
|
}
|
130
.vscode/tasks.json
vendored
Normal file
130
.vscode/tasks.json
vendored
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
{
|
||||||
|
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||||
|
// for the documentation about the tasks.json format
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "Debug",
|
||||||
|
"type": "npm",
|
||||||
|
"script": "build",
|
||||||
|
"problemMatcher": [
|
||||||
|
"$gulp-tsc",
|
||||||
|
"$node-sass"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Release",
|
||||||
|
"type": "npm",
|
||||||
|
"script": "release",
|
||||||
|
"group": "build",
|
||||||
|
"problemMatcher": [
|
||||||
|
"$gulp-tsc",
|
||||||
|
"$node-sass"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Watch Debug",
|
||||||
|
"type": "npm",
|
||||||
|
"script": "watch",
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
},
|
||||||
|
"problemMatcher": [
|
||||||
|
{
|
||||||
|
"base": "$gulp-tsc",
|
||||||
|
"background": {
|
||||||
|
"activeOnStart": true,
|
||||||
|
"beginsPattern": "(Starting compilation in watch mode|File change detected. Starting incremental compilation)",
|
||||||
|
"endsPattern": "Found \\d+ errors. Watching for file changes."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"base": "$node-sass",
|
||||||
|
"background": {
|
||||||
|
"activeOnStart": true,
|
||||||
|
"beginsPattern": "Building scss-code.",
|
||||||
|
"endsPattern": "Building scss-code finished."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isBackground": true,
|
||||||
|
"presentation": {
|
||||||
|
"reveal": "never"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Watch Release",
|
||||||
|
"type": "npm",
|
||||||
|
"script": "watch-release",
|
||||||
|
"group": "build",
|
||||||
|
"problemMatcher": [
|
||||||
|
{
|
||||||
|
"base": "$gulp-tsc",
|
||||||
|
"background": {
|
||||||
|
"activeOnStart": false,
|
||||||
|
"beginsPattern": "(Starting compilation in watch mode|File change detected. Starting incremental compilation)",
|
||||||
|
"endsPattern": "Found \\d+ errors. Watching for file changes."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"base": "$node-sass",
|
||||||
|
"background": {
|
||||||
|
"activeOnStart": false,
|
||||||
|
"beginsPattern": "Building scss-code.",
|
||||||
|
"endsPattern": "Building scss-code finished."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isBackground": true,
|
||||||
|
"presentation": {
|
||||||
|
"reveal": "never"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Stop Debug",
|
||||||
|
"type": "npm",
|
||||||
|
"script": "stop",
|
||||||
|
"problemMatcher": [],
|
||||||
|
"presentation": {
|
||||||
|
"reveal": "never"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Stop Release",
|
||||||
|
"type": "npm",
|
||||||
|
"script": "stop-release",
|
||||||
|
"problemMatcher": [],
|
||||||
|
"presentation": {
|
||||||
|
"reveal": "never"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Rebuild",
|
||||||
|
"type": "npm",
|
||||||
|
"script": "rebuild",
|
||||||
|
"problemMatcher": [
|
||||||
|
"$gulp-tsc",
|
||||||
|
"$node-sass"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Rebuild Release",
|
||||||
|
"type": "npm",
|
||||||
|
"script": "rebuild-release",
|
||||||
|
"problemMatcher": [
|
||||||
|
"$gulp-tsc",
|
||||||
|
"$node-sass"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Lint",
|
||||||
|
"type": "npm",
|
||||||
|
"script": "lint-ide",
|
||||||
|
"problemMatcher": "$eslint-stylish",
|
||||||
|
"presentation": {
|
||||||
|
"reveal": "never"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
8
CHANGELOG.md
Normal file
8
CHANGELOG.md
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# Changelog
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## mantra [Unreleased]
|
||||||
|
- Initial release
|
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) <year> <copyright holders>
|
Copyright (c) 2021 Manuel Thalmann
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
93
composer.json
Normal file
93
composer.json
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
{
|
||||||
|
"name": "manuth/mantra",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "A SilverStripe-theme called \"mantra\".",
|
||||||
|
"type": "silverstripe-theme",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Manuel Thalmann",
|
||||||
|
"email": "m@nuth.ch"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"keywords": [
|
||||||
|
"SilverStripe",
|
||||||
|
"Theme",
|
||||||
|
"m@nuth",
|
||||||
|
"mantra"
|
||||||
|
],
|
||||||
|
"repositories": [
|
||||||
|
{
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/manuth/mantra.git"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"homepage": "https://github.com/manuth/mantra#readme",
|
||||||
|
"scripts-descriptions": {
|
||||||
|
"build": "Builds the project.",
|
||||||
|
"release": "Performs a release-build.",
|
||||||
|
"rebuild": "Rebuilds the project.",
|
||||||
|
"rebuild-release": "Rebuilds the project in release-mode.",
|
||||||
|
"watch": "Builds the project in watch-mode.",
|
||||||
|
"watch-release": "Performs a release-build in watch-mode.",
|
||||||
|
"stop": "Stops building the project in watch-mode.",
|
||||||
|
"stop-release": "Stops performing the release-build in watch-mode.",
|
||||||
|
"clean": "Cleans the project",
|
||||||
|
"lint": "Lints the project."
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "npm run build",
|
||||||
|
"release": "npm run release",
|
||||||
|
"rebuild": "npm run rebuild",
|
||||||
|
"rebuild-release": "npm run rebuild-release",
|
||||||
|
"watch": "npm run watch",
|
||||||
|
"watch-release": "npm run watch-release",
|
||||||
|
"stop": "npm run stop",
|
||||||
|
"stop-release": "npm run stop-release",
|
||||||
|
"clean": "npm run clean",
|
||||||
|
"lint": "npm run lint"
|
||||||
|
},
|
||||||
|
"require": {},
|
||||||
|
"require-dev": {
|
||||||
|
"neronmoon/scriptsdev": "^0.1.6"
|
||||||
|
},
|
||||||
|
"archive": {
|
||||||
|
"exclude": [
|
||||||
|
"/*.tar",
|
||||||
|
".devcontainer",
|
||||||
|
".drone.yml",
|
||||||
|
".eslintrc.js",
|
||||||
|
".gitignore",
|
||||||
|
".vscode/",
|
||||||
|
"composer.lock",
|
||||||
|
"gulp",
|
||||||
|
"gulpfile.ts",
|
||||||
|
"node_modules/",
|
||||||
|
"package-lock.json",
|
||||||
|
"package.json",
|
||||||
|
"src/",
|
||||||
|
"tsconfig.json",
|
||||||
|
"tsconfig.*.json",
|
||||||
|
"/test/",
|
||||||
|
"!/assets/",
|
||||||
|
"!/css/",
|
||||||
|
"!/javascript/",
|
||||||
|
"!/templates/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"scripts-dev": {
|
||||||
|
"post-install-cmd": [
|
||||||
|
"npm install",
|
||||||
|
"@rebuild",
|
||||||
|
"Composer\\Config::disableProcessTimeout",
|
||||||
|
"composer --working-dir=./test/website install"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"allow-plugins": {
|
||||||
|
"neronmoon/scriptsdev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
73
composer.lock
generated
Normal file
73
composer.lock
generated
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
{
|
||||||
|
"_readme": [
|
||||||
|
"This file locks the dependencies of your project to a known state",
|
||||||
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
|
"This file is @generated automatically"
|
||||||
|
],
|
||||||
|
"content-hash": "b15849e437a86cbdc34d3ee8a6ad53c2",
|
||||||
|
"packages": [],
|
||||||
|
"packages-dev": [
|
||||||
|
{
|
||||||
|
"name": "neronmoon/scriptsdev",
|
||||||
|
"version": "v0.1.9",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/neronmoon/scriptsdev.git",
|
||||||
|
"reference": "e812b334bc662cccc4a965c245812b59ae2157cb"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/neronmoon/scriptsdev/zipball/e812b334bc662cccc4a965c245812b59ae2157cb",
|
||||||
|
"reference": "e812b334bc662cccc4a965c245812b59ae2157cb",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"composer-plugin-api": "^1.0 || ^2.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"composer/composer": "~1.0@dev || ~2.0@dev"
|
||||||
|
},
|
||||||
|
"type": "composer-plugin",
|
||||||
|
"extra": {
|
||||||
|
"class": "ScriptsDev\\Plugin"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"ScriptsDev\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Vitaliy Krasnoperov",
|
||||||
|
"email": "alistar.neron@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Scripts-dev behaviour for Composer",
|
||||||
|
"homepage": "https://github.com/neronmoon/scriptsdev",
|
||||||
|
"keywords": [
|
||||||
|
"commands",
|
||||||
|
"commands execution",
|
||||||
|
"composer",
|
||||||
|
"dev",
|
||||||
|
"scripts"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/neronmoon/scriptsdev/issues",
|
||||||
|
"source": "https://github.com/neronmoon/scriptsdev/tree/v0.1.9"
|
||||||
|
},
|
||||||
|
"time": "2020-12-16T08:02:02+00:00"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"aliases": [],
|
||||||
|
"minimum-stability": "stable",
|
||||||
|
"stability-flags": [],
|
||||||
|
"prefer-stable": false,
|
||||||
|
"prefer-lowest": false,
|
||||||
|
"platform": [],
|
||||||
|
"platform-dev": [],
|
||||||
|
"plugin-api-version": "2.0.0"
|
||||||
|
}
|
259
gulp/Settings.ts
Normal file
259
gulp/Settings.ts
Normal file
|
@ -0,0 +1,259 @@
|
||||||
|
import { dirname, join } from "upath";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides settings for building the project.
|
||||||
|
*/
|
||||||
|
export class Settings
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* A value indicating whether the project should be built in watched mode.
|
||||||
|
*/
|
||||||
|
public Watch = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The target of the project-build.
|
||||||
|
*/
|
||||||
|
public Target: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The path to the source-code root.
|
||||||
|
*/
|
||||||
|
private sourceRoot = "src";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The path to the root of the typescript-project.
|
||||||
|
*/
|
||||||
|
private typeScriptProjectRoot = "App";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The path to the root of the typescript-source.
|
||||||
|
*/
|
||||||
|
private typeScriptSourceRoot = "src";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The path to save the javascript-code to.
|
||||||
|
*/
|
||||||
|
private libraryPath = "javascript";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The path to the root of the theme-source.
|
||||||
|
*/
|
||||||
|
private themeSource = "Theme";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The path to save the css-code to.
|
||||||
|
*/
|
||||||
|
private stylePath = "css";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The path to the root of the template-source.
|
||||||
|
*/
|
||||||
|
private templateSource = "Templates";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The path to save the templates to.
|
||||||
|
*/
|
||||||
|
private templatePath = "templates";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The path to the test-directory.
|
||||||
|
*/
|
||||||
|
private testPath = "test";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The path to the test-website.
|
||||||
|
*/
|
||||||
|
private testWebsitePath = "website";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the theme.
|
||||||
|
*/
|
||||||
|
private themeName = "mantra";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a new instance of the `Settings` class.
|
||||||
|
*
|
||||||
|
* @param target
|
||||||
|
* The target of the project-build.
|
||||||
|
*/
|
||||||
|
public constructor(target: string)
|
||||||
|
{
|
||||||
|
this.Target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A value indicating whether the debug-mode is enabled.
|
||||||
|
*/
|
||||||
|
public get Debug(): boolean
|
||||||
|
{
|
||||||
|
return this.Target === "Debug";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a path relative to the root of the solution.
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* The path to join.
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
* The joined path.
|
||||||
|
*/
|
||||||
|
public RootPath(...path: string[]): string
|
||||||
|
{
|
||||||
|
return join(dirname(__dirname), ...path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a path relative to the root of the source-code.
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* The path to join.
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
* The joined path.
|
||||||
|
*/
|
||||||
|
public SourceRoot(...path: string[]): string
|
||||||
|
{
|
||||||
|
return this.RootPath(this.sourceRoot, ...path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a path relative to the root of the typescript-project.
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* The path to join.
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
* The joined path.
|
||||||
|
*/
|
||||||
|
public TypeScriptProjectRoot(...path: string[]): string
|
||||||
|
{
|
||||||
|
return this.SourceRoot(this.typeScriptProjectRoot, ...path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a path relative to the root of the typescript-source.
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* The path to join.
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
* The joined path.
|
||||||
|
*/
|
||||||
|
public TypeScriptSourceRoot(...path: string[]): string
|
||||||
|
{
|
||||||
|
return this.TypeScriptProjectRoot(this.typeScriptSourceRoot, ...path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a path relative to the directory to save the javascript-code to.
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* The path to join.
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
* The joined path.
|
||||||
|
*/
|
||||||
|
public LibraryPath(...path: string[]): string
|
||||||
|
{
|
||||||
|
return this.RootPath(this.libraryPath, ...path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a path relative to the root of the theme-source.
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* The path to join.
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
* The joined path.
|
||||||
|
*/
|
||||||
|
public ThemeSource(...path: string[]): string
|
||||||
|
{
|
||||||
|
return this.SourceRoot(this.themeSource, ...path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a path relative to the directory to save the css-code to.
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* The path to join.
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
* The joined path.
|
||||||
|
*/
|
||||||
|
public StylePath(...path: string[]): string
|
||||||
|
{
|
||||||
|
return this.RootPath(this.stylePath, ...path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a path relative to the root of the template-source.
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* The path to join.
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
* The joined path.
|
||||||
|
*/
|
||||||
|
public TemplateSource(...path: string[]): string
|
||||||
|
{
|
||||||
|
return this.SourceRoot(this.templateSource, ...path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a path relative to the directory to save the templates to.
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* The path to join.
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
* The joined path.
|
||||||
|
*/
|
||||||
|
public TemplatePath(...path: string[]): string
|
||||||
|
{
|
||||||
|
return this.RootPath(this.templatePath, ...path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a path relative to the test-directory.
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* The path to join.
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
* The joined path.
|
||||||
|
*/
|
||||||
|
public TestPath(...path: string[]): string
|
||||||
|
{
|
||||||
|
return this.RootPath(this.testPath, ...path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a path relative to the test-website.
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* The path to join.
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
* The joined path.
|
||||||
|
*/
|
||||||
|
public TestWebsitePath(...path: string[]): string
|
||||||
|
{
|
||||||
|
return this.TestPath(this.testWebsitePath, ...path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a path relative to the test-theme.
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* The path to join.
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
* The joined path.
|
||||||
|
*/
|
||||||
|
public TestThemePath(...path: string[]): string
|
||||||
|
{
|
||||||
|
return this.TestWebsitePath("themes", this.themeName, ...path);
|
||||||
|
}
|
||||||
|
}
|
16
gulp/TaskFunction.ts
Normal file
16
gulp/TaskFunction.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { TaskFunction } from "gulp";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
declare global
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Represents a gulp-task.
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
|
interface Function extends Partial<TaskFunction>
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|
||||||
|
export {};
|
480
gulpfile.ts
Normal file
480
gulpfile.ts
Normal file
|
@ -0,0 +1,480 @@
|
||||||
|
import { Server, Socket } from "net";
|
||||||
|
import browserSync = require("browser-sync");
|
||||||
|
import browserify = require("browserify");
|
||||||
|
import logger = require("fancy-log");
|
||||||
|
import { emptyDir, mkdirp, pathExists, remove } from "fs-extra";
|
||||||
|
import { dest, parallel, series, src, TaskFunction, watch } from "gulp";
|
||||||
|
import gulpIf = require("gulp-if");
|
||||||
|
import rename = require("gulp-rename");
|
||||||
|
import sass = require("gulp-sass");
|
||||||
|
import terser = require("gulp-terser");
|
||||||
|
import merge = require("merge-stream");
|
||||||
|
import minimist = require("minimist");
|
||||||
|
import * as dartSass from "sass";
|
||||||
|
import { parseArgsStringToArgv } from "string-argv";
|
||||||
|
import tsify = require("tsify");
|
||||||
|
import { changeExt, dirname, join, parse, relative } from "upath";
|
||||||
|
import buffer = require("vinyl-buffer");
|
||||||
|
import vinylSourceStream = require("vinyl-source-stream");
|
||||||
|
import Watchify = require("watchify");
|
||||||
|
import { Settings } from "./gulp/Settings";
|
||||||
|
import "./gulp/TaskFunction";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The port to listen for stop-requests.
|
||||||
|
*/
|
||||||
|
const watchConnectorPort = 50958;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object for syncing browsers.
|
||||||
|
*/
|
||||||
|
let syncer = browserSync.create();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message that is printed when starting the compilation in watch mode.
|
||||||
|
*/
|
||||||
|
const watchStartMessage = "Starting compilation in watch mode...";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message that is printed when starting an incremental compilation.
|
||||||
|
*/
|
||||||
|
const incrementalMessage = "File change detected. Starting incremental compilation...";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the message that is printed after finishing a compilation in watch mode.
|
||||||
|
*
|
||||||
|
* @param errorCount
|
||||||
|
* The number of errors which occurred.
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
* The formatted message.
|
||||||
|
*/
|
||||||
|
const watchFinishMessage = (errorCount: number): string =>
|
||||||
|
{
|
||||||
|
return `Found ${errorCount} errors. Watching for file changes.`;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The arguments passed by the user.
|
||||||
|
*/
|
||||||
|
let options = ParseArgs(process.argv.slice(2));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the specified arguments.
|
||||||
|
*
|
||||||
|
* @param args
|
||||||
|
* The arguments to parse.
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
* The parsed arguments.
|
||||||
|
*/
|
||||||
|
function ParseArgs(args: string[]): minimist.ParsedArgs
|
||||||
|
{
|
||||||
|
return minimist(
|
||||||
|
args,
|
||||||
|
{
|
||||||
|
string: [
|
||||||
|
"target"
|
||||||
|
],
|
||||||
|
alias: {
|
||||||
|
target: "t"
|
||||||
|
},
|
||||||
|
default: {
|
||||||
|
target: "Debug"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The settings for building the project.
|
||||||
|
*/
|
||||||
|
let settings = new Settings(options["target"]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleans the project.
|
||||||
|
*/
|
||||||
|
export async function Clean(): Promise<void>
|
||||||
|
{
|
||||||
|
let directories = [
|
||||||
|
"javascript",
|
||||||
|
"css",
|
||||||
|
"templates",
|
||||||
|
"assets"
|
||||||
|
];
|
||||||
|
|
||||||
|
for (let directory of directories)
|
||||||
|
{
|
||||||
|
await emptyDir(settings.RootPath(directory));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (await pathExists(settings.TestThemePath()))
|
||||||
|
{
|
||||||
|
await remove(settings.TestThemePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
await mkdirp(settings.TestThemePath());
|
||||||
|
await remove(settings.TestThemePath());
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
|
await require("create-symlink")(settings.RootPath(), settings.TestThemePath(), { type: "junction" });
|
||||||
|
}
|
||||||
|
|
||||||
|
Clean.description = "Cleans the project.";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds the project in watched mode.
|
||||||
|
*
|
||||||
|
* @param done
|
||||||
|
* A callback which is executed once the task has finished.
|
||||||
|
*/
|
||||||
|
export let Watch: TaskFunction = (done) =>
|
||||||
|
{
|
||||||
|
settings.Watch = true;
|
||||||
|
Build();
|
||||||
|
|
||||||
|
let server = new Server(
|
||||||
|
(socket) =>
|
||||||
|
{
|
||||||
|
socket.on(
|
||||||
|
"data",
|
||||||
|
(data) =>
|
||||||
|
{
|
||||||
|
let args = parseArgsStringToArgv(data.toString());
|
||||||
|
socket.destroy();
|
||||||
|
|
||||||
|
if (args[0] === "stop")
|
||||||
|
{
|
||||||
|
let options = ParseArgs(args.slice(1));
|
||||||
|
|
||||||
|
if (options["target"] === settings.Target)
|
||||||
|
{
|
||||||
|
syncer.exit();
|
||||||
|
server.close();
|
||||||
|
done();
|
||||||
|
process.exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
server.listen(watchConnectorPort);
|
||||||
|
};
|
||||||
|
|
||||||
|
Watch.description = "Builds the project in watched mode.";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reloads all browsers using `browser-sync`.
|
||||||
|
*
|
||||||
|
* @param filePath
|
||||||
|
* A glob-path which points to the files which must be reloaded.
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
* The actual task.
|
||||||
|
*/
|
||||||
|
function BrowserSync(filePath?: string): TaskFunction
|
||||||
|
{
|
||||||
|
let BrowserSync: TaskFunction = (done) =>
|
||||||
|
{
|
||||||
|
if (filePath)
|
||||||
|
{
|
||||||
|
syncer.reload(filePath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
syncer.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
|
||||||
|
return BrowserSync;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds the project.
|
||||||
|
*/
|
||||||
|
export async function Build(): Promise<void>
|
||||||
|
{
|
||||||
|
return new Promise(
|
||||||
|
(resolve, reject) =>
|
||||||
|
{
|
||||||
|
if (settings.Watch)
|
||||||
|
{
|
||||||
|
syncer.init({
|
||||||
|
open: false,
|
||||||
|
proxy: "http://localhost",
|
||||||
|
port: 3000,
|
||||||
|
ui: {
|
||||||
|
port: 3001
|
||||||
|
},
|
||||||
|
ghostMode: false,
|
||||||
|
online: false
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(settings.ThemeSource("**"), { usePolling: true }, series(Theme, BrowserSync("*.css")));
|
||||||
|
watch(settings.TemplateSource("**"), { usePolling: true }, series(Templates, BrowserSync()));
|
||||||
|
}
|
||||||
|
|
||||||
|
parallel(Library, Theme, Templates)(
|
||||||
|
(error) =>
|
||||||
|
{
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds the TypeScript- and JavaScript-library.
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
* The pipeline to execute.
|
||||||
|
*/
|
||||||
|
export function Library(): NodeJS.ReadWriteStream
|
||||||
|
{
|
||||||
|
let errorMessages: string[] = [];
|
||||||
|
let streams: NodeJS.ReadWriteStream[] = [];
|
||||||
|
let queue: NodeJS.ReadWriteStream[] = [];
|
||||||
|
let tsConfigFile = settings.TypeScriptProjectRoot("tsconfig.json");
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
|
let tsConfig = require(tsConfigFile);
|
||||||
|
|
||||||
|
let optionBase: browserify.Options = {
|
||||||
|
...Watchify.args,
|
||||||
|
node: true,
|
||||||
|
ignoreMissing: true,
|
||||||
|
debug: settings.Debug
|
||||||
|
};
|
||||||
|
|
||||||
|
let files = (tsConfig.files as string[]).map(
|
||||||
|
(file) => relative(settings.TypeScriptSourceRoot(), settings.TypeScriptProjectRoot(file)));
|
||||||
|
|
||||||
|
if (settings.Watch)
|
||||||
|
{
|
||||||
|
logger.info(watchStartMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let file of files)
|
||||||
|
{
|
||||||
|
let builder = (): NodeJS.ReadWriteStream =>
|
||||||
|
{
|
||||||
|
let stream: NodeJS.ReadWriteStream;
|
||||||
|
|
||||||
|
let bundler = browserify(
|
||||||
|
{
|
||||||
|
...optionBase,
|
||||||
|
basedir: settings.LibraryPath(dirname(file)),
|
||||||
|
entries: [
|
||||||
|
settings.TypeScriptSourceRoot(file)
|
||||||
|
],
|
||||||
|
standalone: join(dirname(file), parse(file).name)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (settings.Watch)
|
||||||
|
{
|
||||||
|
bundler = Watchify(bundler, { poll: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
bundler.plugin(
|
||||||
|
tsify,
|
||||||
|
{
|
||||||
|
project: tsConfigFile
|
||||||
|
});
|
||||||
|
|
||||||
|
stream = bundler.bundle().on(
|
||||||
|
"error",
|
||||||
|
(error) =>
|
||||||
|
{
|
||||||
|
let message: string = error.message;
|
||||||
|
|
||||||
|
if (!errorMessages.includes(message))
|
||||||
|
{
|
||||||
|
let result = new RegExp(`^(${error["fileName"]})\\((\\d+|\\d+(,\\d+){1,3})\\): .* TS([\\d]+): (.*)$`).exec(message);
|
||||||
|
errorMessages.push(message);
|
||||||
|
console.log(`${relative(process.cwd(), result[1])}(${result[2]}): ${result[4]} ${result[5]}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).pipe(
|
||||||
|
vinylSourceStream(changeExt(file, "js"))
|
||||||
|
).pipe(
|
||||||
|
buffer()
|
||||||
|
).pipe(
|
||||||
|
gulpIf(
|
||||||
|
!settings.Debug,
|
||||||
|
terser()
|
||||||
|
)
|
||||||
|
).pipe(
|
||||||
|
dest(settings.LibraryPath())
|
||||||
|
).on(
|
||||||
|
"end",
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
if (settings.Watch)
|
||||||
|
{
|
||||||
|
if (queue.includes(stream))
|
||||||
|
{
|
||||||
|
queue.splice(queue.indexOf(stream), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queue.length === 0)
|
||||||
|
{
|
||||||
|
logger.info(watchFinishMessage(errorMessages.length));
|
||||||
|
|
||||||
|
if (errorMessages.length === 0)
|
||||||
|
{
|
||||||
|
syncer.reload("*.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
errorMessages.splice(0, errorMessages.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (settings.Watch)
|
||||||
|
{
|
||||||
|
bundler.once(
|
||||||
|
"update",
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
console.log(`Update called for ${file}: ${queue.length}`);
|
||||||
|
|
||||||
|
if (queue.length === 0)
|
||||||
|
{
|
||||||
|
logger.info(incrementalMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
queue.push(builder());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
};
|
||||||
|
|
||||||
|
let stream = builder();
|
||||||
|
queue.push(stream);
|
||||||
|
streams.push(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
return merge(streams);
|
||||||
|
}
|
||||||
|
|
||||||
|
Library.description = "Builds the TypeScript- and JavaScript-library.";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds the theme.
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
* The pipeline to execute.
|
||||||
|
*/
|
||||||
|
export function Theme(): NodeJS.ReadWriteStream
|
||||||
|
{
|
||||||
|
if (settings.Watch)
|
||||||
|
{
|
||||||
|
logger.info("Building scss-code.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return src(
|
||||||
|
settings.ThemeSource("main.scss"),
|
||||||
|
{
|
||||||
|
sourcemaps: settings.Debug,
|
||||||
|
base: settings.StylePath()
|
||||||
|
}).pipe(
|
||||||
|
sass(dartSass).sync(
|
||||||
|
{
|
||||||
|
importer: require("node-sass-tilde-importer")
|
||||||
|
}
|
||||||
|
).on("error",
|
||||||
|
(error) =>
|
||||||
|
{
|
||||||
|
console.log(
|
||||||
|
JSON.stringify(
|
||||||
|
{
|
||||||
|
status: error.status,
|
||||||
|
file: error.file,
|
||||||
|
line: error.line,
|
||||||
|
column: error.column,
|
||||||
|
message: error.messageOriginal,
|
||||||
|
formatted: error.formatted
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
4));
|
||||||
|
})
|
||||||
|
).pipe(
|
||||||
|
rename(
|
||||||
|
(parsedPath) =>
|
||||||
|
{
|
||||||
|
parsedPath.dirname = "";
|
||||||
|
parsedPath.basename = "mantra";
|
||||||
|
})
|
||||||
|
).pipe(
|
||||||
|
dest(
|
||||||
|
settings.StylePath(),
|
||||||
|
settings.Debug ?
|
||||||
|
{
|
||||||
|
sourcemaps: true
|
||||||
|
} :
|
||||||
|
undefined)
|
||||||
|
).on(
|
||||||
|
"end",
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
if (settings.Watch)
|
||||||
|
{
|
||||||
|
logger.info("Building scss-code finished.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Theme.description = "Builds the theme.";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds the templates.
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
* The pipeline to execute.
|
||||||
|
*/
|
||||||
|
export function Templates(): NodeJS.ReadWriteStream
|
||||||
|
{
|
||||||
|
return src(
|
||||||
|
settings.TemplateSource("**")).pipe(
|
||||||
|
dest(settings.TemplatePath()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Templates.description = "Builds the templates.";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops a watch-task.
|
||||||
|
*/
|
||||||
|
export async function Stop(): Promise<void>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await new Promise(
|
||||||
|
(resolve, reject) =>
|
||||||
|
{
|
||||||
|
let client = new Socket();
|
||||||
|
|
||||||
|
client.connect(
|
||||||
|
watchConnectorPort,
|
||||||
|
"localhost",
|
||||||
|
async () =>
|
||||||
|
{
|
||||||
|
client.write(`stop -t ${settings.Target}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
client.on("close", resolve);
|
||||||
|
client.on("error", reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
logger.info("The specified task is not running.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Stop.description = "Stops a watch-task";
|
21535
package-lock.json
generated
Normal file
21535
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
77
package.json
Normal file
77
package.json
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
{
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"build": "gulp Build -t Debug",
|
||||||
|
"release": "gulp Build -t Release",
|
||||||
|
"rebuild": "npm run clean && npm run build",
|
||||||
|
"rebuild-release": "npm run clean && npm run release",
|
||||||
|
"watch": "gulp Watch -t Debug",
|
||||||
|
"watch-release": "gulp Watch -t Release",
|
||||||
|
"stop": "gulp Stop -t Debug",
|
||||||
|
"stop-release": "gulp Stop -t Release",
|
||||||
|
"clean": "gulp Clean",
|
||||||
|
"lint": "npm run lint-gulp && npm run lint-project",
|
||||||
|
"lint-base": "eslint --max-warnings 0 --ignore-pattern \"!.eslintrc.js\"",
|
||||||
|
"lint-gulp": "npm run lint-base -- --ext .ts ./gulp gulpfile.ts",
|
||||||
|
"lint-project": "npm run lint-base -- --ext .js,.jsx,.ts,.tsx ./src/App/src",
|
||||||
|
"lint-ide": "npm run lint || exit 0",
|
||||||
|
"prepare": "npm run rebuild"
|
||||||
|
},
|
||||||
|
"dependencies": {},
|
||||||
|
"devDependencies": {
|
||||||
|
"@manuth/eslint-plugin-typescript": "^3.2.6",
|
||||||
|
"@manuth/tsconfig": "^3.0.0",
|
||||||
|
"@manuth/typescript-eslint-plugin": "^1.3.5",
|
||||||
|
"@types/bootstrap": "^5.1.9",
|
||||||
|
"@types/browser-sync": "^2.26.3",
|
||||||
|
"@types/browserify": "^12.0.37",
|
||||||
|
"@types/fancy-log": "^1.3.1",
|
||||||
|
"@types/fs-extra": "^9.0.13",
|
||||||
|
"@types/gulp": "^4.0.9",
|
||||||
|
"@types/gulp-if": "0.0.34",
|
||||||
|
"@types/gulp-rename": "2.0.1",
|
||||||
|
"@types/gulp-sass": "^5.0.0",
|
||||||
|
"@types/gulp-terser": "^1.2.1",
|
||||||
|
"@types/jquery": "^3.5.14",
|
||||||
|
"@types/merge-stream": "^1.1.2",
|
||||||
|
"@types/minimist": "^1.2.2",
|
||||||
|
"@types/node": "^17.0.21",
|
||||||
|
"@types/vinyl-buffer": "^1.0.0",
|
||||||
|
"@types/vinyl-source-stream": "0.0.30",
|
||||||
|
"@types/watchify": "^3.11.1",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.13.0",
|
||||||
|
"@typescript-eslint/eslint-plugin-tslint": "^5.13.0",
|
||||||
|
"@typescript-eslint/parser": "^5.13.0",
|
||||||
|
"bootstrap": "^5.1.3",
|
||||||
|
"browser-sync": "^2.27.7",
|
||||||
|
"browserify": "^17.0.0",
|
||||||
|
"create-symlink": "^1.0.0",
|
||||||
|
"eslint": "^8.10.0",
|
||||||
|
"eslint-plugin-deprecation": "^1.3.2",
|
||||||
|
"eslint-plugin-import": "^2.25.4",
|
||||||
|
"eslint-plugin-jsdoc": "^37.9.5",
|
||||||
|
"fancy-log": "^2.0.0",
|
||||||
|
"fs-extra": "^10.0.1",
|
||||||
|
"gulp": "^4.0.2",
|
||||||
|
"gulp-if": "^3.0.0",
|
||||||
|
"gulp-rename": "^2.0.0",
|
||||||
|
"gulp-sass": "^5.1.0",
|
||||||
|
"gulp-terser": "^2.1.0",
|
||||||
|
"jquery": "^3.6.0",
|
||||||
|
"merge-stream": "^2.0.0",
|
||||||
|
"minimist": "^1.2.5",
|
||||||
|
"node-sass-tilde-importer": "^1.0.2",
|
||||||
|
"popper.js": "^1.16.0",
|
||||||
|
"sass": "^1.49.9",
|
||||||
|
"string-argv": "^0.3.1",
|
||||||
|
"ts-node": "^10.5.0",
|
||||||
|
"tsify": "^5.0.4",
|
||||||
|
"tslint": "^6.1.3",
|
||||||
|
"typescript": "^4.6.2",
|
||||||
|
"typescript-tslint-plugin": "^1.0.1",
|
||||||
|
"upath": "^2.0.1",
|
||||||
|
"vinyl-buffer": "^1.0.1",
|
||||||
|
"vinyl-source-stream": "^2.0.0",
|
||||||
|
"watchify": "^4.0.0"
|
||||||
|
}
|
||||||
|
}
|
3
src/App/src/main.ts
Normal file
3
src/App/src/main.ts
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
import "bootstrap";
|
||||||
|
import "jquery";
|
||||||
|
import "popper.js";
|
16
src/App/tsconfig.json
Normal file
16
src/App/tsconfig.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"rootDir": "src",
|
||||||
|
"lib": [
|
||||||
|
"ES2020",
|
||||||
|
"DOM"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"src/main.ts"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"./src/tests/**/*"
|
||||||
|
]
|
||||||
|
}
|
0
src/Templates/Layout/Page.ss
Normal file
0
src/Templates/Layout/Page.ss
Normal file
61
src/Templates/Page.ss
Normal file
61
src/Templates/Page.ss
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html class="h-100">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
|
<% base_tag %>
|
||||||
|
$MetaTags(false)
|
||||||
|
<title><% if $Title %>$Title ● <% end_if %>$SiteConfig.Title</title>
|
||||||
|
<% require themedCSS("mantra") %>
|
||||||
|
<% require themedJavascript("main") %>
|
||||||
|
</head>
|
||||||
|
<body class="d-flex flex-column h-100">
|
||||||
|
<nav class="navbar navbar-expand-md fixed-top navbar-dark bg-dark">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<a class="navbar-brand" href="$AbsoluteBaseURL">
|
||||||
|
<div class="navbar-title">$SiteConfig.Title</div>
|
||||||
|
<div class="navbar-tagline">$SiteConfig.Tagline</div>
|
||||||
|
</a>
|
||||||
|
<% if $Menu(1) %>
|
||||||
|
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#mainNav" aria-controls="mainNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<div class="collapse navbar-collapse" id="mainNav">
|
||||||
|
<ul class="navbar-nav">
|
||||||
|
<% loop $Menu(1) %>
|
||||||
|
<% if $Children %>
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<a class="nav-link dropdown-toggle<% if $isCurrent || $isSection %> active <% end_if %>" href="#" id="mainNav_$URLSegment" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
$MenuTitle
|
||||||
|
</a>
|
||||||
|
<div class="dropdown-menu" aria-labelledby="mainNav_$URLSegment">
|
||||||
|
<a class="dropdown-item<% if $isCurrent %> active <% end_if %>" href="$Link">
|
||||||
|
$MenuTitle<% if $isCurrent %><span class="visually-hidden"> (current)</span><% end_if %>
|
||||||
|
</a>
|
||||||
|
<div class="dropdown-divider"></div>
|
||||||
|
<% loop $Children %>
|
||||||
|
<a class="dropdown-item<% if $isCurrent %> active<% end_if %>" href="$Link">
|
||||||
|
$MenuTitle
|
||||||
|
</a>
|
||||||
|
<% end_loop %>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<% else %>
|
||||||
|
<li class="nav-item<% if $isCurrent %> active<% end_if %>">
|
||||||
|
<a class="nav-link" href="$Link">
|
||||||
|
$MenuTitle<% if $isCurrent %><span class="visually-hidden"> (current)</span><% end_if %>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<% end_if %>
|
||||||
|
<% end_loop %>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<% end_if %>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<main role="main" class="container-fluid col-11 flex-shrink-0" style="padding-top: 4.5rem">
|
||||||
|
$Content
|
||||||
|
$Form
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
37
src/Theme/_nav.scss
Normal file
37
src/Theme/_nav.scss
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
.navbar {
|
||||||
|
.navbar-nav {
|
||||||
|
.nav-link {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: ' ';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
margin-top: -$navbar-padding-y;
|
||||||
|
margin-bottom: -$navbar-padding-y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.active > .nav-link, .nav-link.active {
|
||||||
|
&::before {
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-brand {
|
||||||
|
.navbar-title {
|
||||||
|
@extend .d-inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-tagline {
|
||||||
|
@extend .text-muted;
|
||||||
|
@extend .d-none;
|
||||||
|
@extend .d-lg-inline-block;
|
||||||
|
font-size: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
1
src/Theme/_variables.scss
Normal file
1
src/Theme/_variables.scss
Normal file
|
@ -0,0 +1 @@
|
||||||
|
$tagline-font-size: calc($small-font-size / 2);
|
3
src/Theme/main.scss
Normal file
3
src/Theme/main.scss
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
@import "~bootstrap/scss/bootstrap";
|
||||||
|
@import "variables";
|
||||||
|
@import "nav";
|
6
test/website/.gitignore
vendored
Normal file
6
test/website/.gitignore
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
/silverstripe-cache/
|
||||||
|
/.env
|
||||||
|
/vendor/
|
||||||
|
/themes/simple/
|
||||||
|
/_resources/
|
||||||
|
/public/_resources/
|
2
test/website/.htaccess
Normal file
2
test/website/.htaccess
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
RewriteEngine On
|
||||||
|
RewriteRule ^(.*)$ public/$1
|
3
test/website/app/.htaccess
Normal file
3
test/website/app/.htaccess
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<FilesMatch "\.(php|php3|php4|php5|phtml|inc)$">
|
||||||
|
Require all denied
|
||||||
|
</FilesMatch>
|
9
test/website/app/_config.php
Normal file
9
test/website/app/_config.php
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use SilverStripe\Security\PasswordValidator;
|
||||||
|
use SilverStripe\Security\Member;
|
||||||
|
|
||||||
|
// remove PasswordValidator for SilverStripe 5.0
|
||||||
|
$validator = PasswordValidator::create();
|
||||||
|
// Settings are registered via Injector configuration - see passwords.yml in framework
|
||||||
|
Member::set_password_validator($validator);
|
26
test/website/app/_config/assets.yml
Normal file
26
test/website/app/_config/assets.yml
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
# SilverStripe 4.4 changes the way files are resolved. `silverstripe-assets` resolves files using a variety of formats
|
||||||
|
# by default. When starting a brand new project on SilverStripe 4.4 or greater, those extra formats are not needed and
|
||||||
|
# will slowdown file resolution requests a bit. This config removes those redundant formats.
|
||||||
|
|
||||||
|
---
|
||||||
|
Name: project-assetsflysystem
|
||||||
|
After: '#assetsflysystem'
|
||||||
|
---
|
||||||
|
SilverStripe\Core\Injector\Injector:
|
||||||
|
# Define public resolution strategy
|
||||||
|
SilverStripe\Assets\FilenameParsing\FileResolutionStrategy.public:
|
||||||
|
class: SilverStripe\Assets\FilenameParsing\FileIDHelperResolutionStrategy
|
||||||
|
properties:
|
||||||
|
ResolutionFileIDHelpers:
|
||||||
|
- '%$SilverStripe\Assets\FilenameParsing\HashFileIDHelper'
|
||||||
|
- '%$SilverStripe\Assets\FilenameParsing\NaturalFileIDHelper'
|
||||||
|
DefaultFileIDHelper: '%$SilverStripe\Assets\FilenameParsing\NaturalFileIDHelper'
|
||||||
|
VersionedStage: Live
|
||||||
|
# Define protected resolution strategy
|
||||||
|
SilverStripe\Assets\FilenameParsing\FileResolutionStrategy.protected:
|
||||||
|
class: SilverStripe\Assets\FilenameParsing\FileIDHelperResolutionStrategy
|
||||||
|
properties:
|
||||||
|
DefaultFileIDHelper: '%$SilverStripe\Assets\FilenameParsing\HashFileIDHelper'
|
||||||
|
ResolutionFileIDHelpers:
|
||||||
|
- '%$SilverStripe\Assets\FilenameParsing\HashFileIDHelper'
|
||||||
|
VersionedStage: Stage
|
9
test/website/app/_config/mimevalidator.yml
Normal file
9
test/website/app/_config/mimevalidator.yml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
---
|
||||||
|
Name: app-mimeuploadvalidator
|
||||||
|
After: '#mimeuploadvalidator'
|
||||||
|
Only:
|
||||||
|
moduleexists: 'silverstripe/mimevalidator'
|
||||||
|
---
|
||||||
|
SilverStripe\Core\Injector\Injector:
|
||||||
|
SilverStripe\Assets\Upload_Validator:
|
||||||
|
class: SilverStripe\MimeValidator\MimeUploadValidator
|
16
test/website/app/_config/mysite.yml
Normal file
16
test/website/app/_config/mysite.yml
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
---
|
||||||
|
Name: myproject
|
||||||
|
---
|
||||||
|
SilverStripe\Core\Manifest\ModuleManifest:
|
||||||
|
project: app
|
||||||
|
|
||||||
|
# UTF8MB4 has limited support in older MySQL versions.
|
||||||
|
# Remove this configuration if you experience issues.
|
||||||
|
---
|
||||||
|
Name: myproject-database
|
||||||
|
---
|
||||||
|
SilverStripe\ORM\Connect\MySQLDatabase:
|
||||||
|
connection_charset: utf8mb4
|
||||||
|
connection_collation: utf8mb4_unicode_ci
|
||||||
|
charset: utf8mb4
|
||||||
|
collation: utf8mb4_unicode_ci
|
8
test/website/app/_config/theme.yml
Normal file
8
test/website/app/_config/theme.yml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
Name: mytheme
|
||||||
|
---
|
||||||
|
SilverStripe\View\SSViewer:
|
||||||
|
themes:
|
||||||
|
- 'mantra'
|
||||||
|
- '$public'
|
||||||
|
- '$default'
|
13
test/website/app/src/Page.php
Normal file
13
test/website/app/src/Page.php
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
use SilverStripe\CMS\Model\SiteTree;
|
||||||
|
|
||||||
|
class Page extends SiteTree
|
||||||
|
{
|
||||||
|
private static $db = [];
|
||||||
|
|
||||||
|
private static $has_one = [];
|
||||||
|
}
|
||||||
|
}
|
33
test/website/app/src/PageController.php
Normal file
33
test/website/app/src/PageController.php
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
use SilverStripe\CMS\Controllers\ContentController;
|
||||||
|
|
||||||
|
class PageController extends ContentController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* An array of actions that can be accessed via a request. Each array element should be an action name, and the
|
||||||
|
* permissions or conditions required to allow the user to access it.
|
||||||
|
*
|
||||||
|
* <code>
|
||||||
|
* [
|
||||||
|
* 'action', // anyone can access this action
|
||||||
|
* 'action' => true, // same as above
|
||||||
|
* 'action' => 'ADMIN', // you must have ADMIN permissions to access this action
|
||||||
|
* 'action' => '->checkAction' // you can only access this action if $this->checkAction() returns true
|
||||||
|
* ];
|
||||||
|
* </code>
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private static $allowed_actions = [];
|
||||||
|
|
||||||
|
protected function init()
|
||||||
|
{
|
||||||
|
parent::init();
|
||||||
|
// You can include any CSS or JS required by your project here.
|
||||||
|
// See: https://docs.silverstripe.org/en/developer_guides/templates/requirements/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
54
test/website/composer.json
Normal file
54
test/website/composer.json
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
{
|
||||||
|
"name": "silverstripe/installer",
|
||||||
|
"type": "silverstripe-recipe",
|
||||||
|
"description": "The SilverStripe Framework Installer",
|
||||||
|
"require": {
|
||||||
|
"php": "^7.1 || ^8",
|
||||||
|
"silverstripe/recipe-plugin": "^1.2",
|
||||||
|
"silverstripe/recipe-cms": "4.7.3@stable",
|
||||||
|
"silverstripe-themes/simple": "~3.2.0",
|
||||||
|
"silverstripe/login-forms": "4.3.0@stable"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^9.5"
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"expose": [
|
||||||
|
"themes/mantra/assets",
|
||||||
|
"themes/mantra/css",
|
||||||
|
"themes/mantra/javascript"
|
||||||
|
],
|
||||||
|
"project-files": [
|
||||||
|
"app/_config/*",
|
||||||
|
".env.example"
|
||||||
|
],
|
||||||
|
"public-files": [
|
||||||
|
"assets/*",
|
||||||
|
"favicon.ico"
|
||||||
|
],
|
||||||
|
"resources-dir": "_resources",
|
||||||
|
"project-files-installed": [
|
||||||
|
"app/.htaccess",
|
||||||
|
"app/_config.php",
|
||||||
|
"app/_config/mimevalidator.yml",
|
||||||
|
"app/_config/mysite.yml",
|
||||||
|
"app/src/Page.php",
|
||||||
|
"app/src/PageController.php"
|
||||||
|
],
|
||||||
|
"public-files-installed": [
|
||||||
|
".htaccess",
|
||||||
|
"index.php",
|
||||||
|
"web.config"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"process-timeout": 600,
|
||||||
|
"allow-plugins": {
|
||||||
|
"composer/installers": true,
|
||||||
|
"silverstripe/recipe-plugin": true,
|
||||||
|
"silverstripe/vendor-plugin": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"prefer-stable": true,
|
||||||
|
"minimum-stability": "dev"
|
||||||
|
}
|
5646
test/website/composer.lock
generated
Normal file
5646
test/website/composer.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
47
test/website/public/.htaccess
Normal file
47
test/website/public/.htaccess
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
### SILVERSTRIPE START ###
|
||||||
|
|
||||||
|
# Deny access to templates (but allow from localhost)
|
||||||
|
<Files *.ss>
|
||||||
|
Require ip 127.0.0.1
|
||||||
|
</Files>
|
||||||
|
|
||||||
|
# Deny access to IIS configuration
|
||||||
|
<Files web.config>
|
||||||
|
Require all denied
|
||||||
|
</Files>
|
||||||
|
|
||||||
|
# Deny access to YAML configuration files which might include sensitive information
|
||||||
|
<Files ~ "\.ya?ml$">
|
||||||
|
Require all denied
|
||||||
|
</Files>
|
||||||
|
|
||||||
|
# Route errors to static pages automatically generated by SilverStripe
|
||||||
|
ErrorDocument 404 /assets/error-404.html
|
||||||
|
ErrorDocument 500 /assets/error-500.html
|
||||||
|
|
||||||
|
<IfModule mod_rewrite.c>
|
||||||
|
|
||||||
|
# Turn off index.php handling requests to the homepage fixes issue in apache >=2.4
|
||||||
|
<IfModule mod_dir.c>
|
||||||
|
DirectoryIndex disabled
|
||||||
|
DirectorySlash On
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
SetEnv HTTP_MOD_REWRITE On
|
||||||
|
RewriteEngine On
|
||||||
|
|
||||||
|
# Enable HTTP Basic authentication workaround for PHP running in CGI mode
|
||||||
|
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
|
||||||
|
|
||||||
|
# Deny access to potentially sensitive files and folders
|
||||||
|
RewriteRule ^vendor(/|$) - [F,L,NC]
|
||||||
|
RewriteRule ^\.env - [F,L,NC]
|
||||||
|
RewriteRule silverstripe-cache(/|$) - [F,L,NC]
|
||||||
|
RewriteRule composer\.(json|lock) - [F,L,NC]
|
||||||
|
RewriteRule (error|silverstripe|debug)\.log - [F,L,NC]
|
||||||
|
|
||||||
|
# Process through SilverStripe if no file with the requested name exists.
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
|
RewriteRule .* index.php
|
||||||
|
</IfModule>
|
||||||
|
### SILVERSTRIPE END ###
|
4
test/website/public/assets/.gitignore
vendored
Normal file
4
test/website/public/assets/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
/**/*
|
||||||
|
!.gitignore
|
||||||
|
!.htaccess
|
||||||
|
!web.config
|
35
test/website/public/assets/.htaccess
Normal file
35
test/website/public/assets/.htaccess
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#
|
||||||
|
# Whitelist appropriate assets files.
|
||||||
|
# This file is automatically generated via File.allowed_extensions configuration
|
||||||
|
# See AssetAdapter::renderTemplate() for reference.
|
||||||
|
#
|
||||||
|
|
||||||
|
# We disable PHP via several methods
|
||||||
|
# Replace the handler with the default plaintext handler
|
||||||
|
AddHandler default-handler php phtml php3 php4 php5 inc
|
||||||
|
|
||||||
|
<IfModule mod_php5.c>
|
||||||
|
# Turn the PHP engine off
|
||||||
|
php_flag engine off
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
<IfModule mod_rewrite.c>
|
||||||
|
<IfModule mod_env.c>
|
||||||
|
SetEnv HTTP_MOD_REWRITE On
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
RewriteEngine On
|
||||||
|
|
||||||
|
# Allow error pages
|
||||||
|
RewriteCond %{REQUEST_FILENAME} -f
|
||||||
|
RewriteRule error[^\\/]*\.html$ - [L]
|
||||||
|
|
||||||
|
# Allow specific file extensions
|
||||||
|
RewriteCond %{REQUEST_URI} !^[^.]*[^\/]*\.(?i:css|js|ace|arc|arj|asf|au|avi|bmp|bz2|cab|cda|csv|dmg|doc|docx|dotx|flv|gif|gpx|gz|hqx|ico|jpeg|jpg|kml|m4a|m4v|mid|midi|mkv|mov|mp3|mp4|mpa|mpeg|mpg|ogg|ogv|pages|pcx|pdf|png|pps|ppt|pptx|potx|ra|ram|rm|rtf|sit|sitx|tar|tgz|tif|tiff|txt|wav|webm|wma|wmv|xls|xlsx|xltx|zip|zipx|graphql)$
|
||||||
|
RewriteRule .* - [F]
|
||||||
|
|
||||||
|
# Non existant files passed to requesthandler
|
||||||
|
RewriteCond %{REQUEST_URI} ^(.*)$
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
|
RewriteRule .* ../index.php [QSA]
|
||||||
|
</IfModule>
|
BIN
test/website/public/favicon.ico
Normal file
BIN
test/website/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
25
test/website/public/index.php
Normal file
25
test/website/public/index.php
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use SilverStripe\Control\HTTPApplication;
|
||||||
|
use SilverStripe\Control\HTTPRequestBuilder;
|
||||||
|
use SilverStripe\Core\CoreKernel;
|
||||||
|
|
||||||
|
// Find autoload.php
|
||||||
|
if (file_exists(__DIR__ . '/../vendor/autoload.php')) {
|
||||||
|
require __DIR__ . '/../vendor/autoload.php';
|
||||||
|
} elseif (file_exists(__DIR__ . '/vendor/autoload.php')) {
|
||||||
|
require __DIR__ . '/vendor/autoload.php';
|
||||||
|
} else {
|
||||||
|
header('HTTP/1.1 500 Internal Server Error');
|
||||||
|
echo "autoload.php not found";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build request and detect flush
|
||||||
|
$request = HTTPRequestBuilder::createFromEnvironment();
|
||||||
|
|
||||||
|
// Default application
|
||||||
|
$kernel = new CoreKernel(BASE_PATH);
|
||||||
|
$app = new HTTPApplication($kernel);
|
||||||
|
$response = $app->handle($request);
|
||||||
|
$response->output();
|
16
tsconfig.base.json
Normal file
16
tsconfig.base.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"extends": "@manuth/tsconfig/recommended",
|
||||||
|
"compilerOptions": {
|
||||||
|
"declaration": true,
|
||||||
|
"module": "CommonJS",
|
||||||
|
"lib": [
|
||||||
|
"ES2020"
|
||||||
|
],
|
||||||
|
"plugins": [
|
||||||
|
{
|
||||||
|
"name": "@manuth/typescript-eslint-plugin"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"target": "ES6"
|
||||||
|
}
|
||||||
|
}
|
9
tsconfig.eslint.json
Normal file
9
tsconfig.eslint.json
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"noEmit": true
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"./.eslintrc.js"
|
||||||
|
]
|
||||||
|
}
|
10
tsconfig.json
Normal file
10
tsconfig.json
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"noEmit": true
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"./gulp/**/*.*",
|
||||||
|
"./gulpfile.ts"
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in a new issue