Compare commits

...

96 commits
main ... dev

Author SHA1 Message Date
Manuel Thalmann a2b7531ad4 Fix file permissions 2022-03-23 10:12:25 +00:00
Manuel Thalmann 04ee84d77e Debug theme chrome instead of edge 2022-03-23 09:49:27 +00:00
Manuel Thalmann 85b2635da3 Remove permission changing commands 2022-03-23 09:02:46 +00:00
Manuel Thalmann 99a7eb3b53 Update the remote user in the docker container 2022-03-23 09:02:09 +00:00
Manuel Thalmann bb217047a1 Allow the use of sudo in the docker container 2022-03-23 09:01:48 +00:00
Manuel Thalmann 9782d3499c Update the package-lock file 2022-03-23 09:00:34 +00:00
Manuel Thalmann 5b96fa38c2 Allow 3rd party plugins 2022-03-23 09:00:22 +00:00
Manuel Thalmann 983ce40397 Refactor bootstrap style 2022-03-01 15:05:12 +00:00
Manuel Thalmann 397d401d13 Wrap calculation in a calc() call 2022-03-01 15:05:01 +00:00
Manuel Thalmann 70208bf6cc Add missing extension 2022-03-01 15:04:50 +00:00
Manuel Thalmann 84f09ee473 Update all dependencies 2022-03-01 15:04:40 +00:00
Manuel Thalmann 1b0e3c0155 Update outdated extensions 2022-03-01 14:32:19 +00:00
Manuel Thalmann afc65d8cf3 Exclude recursive directory from intelephense
All checks were successful
continuous-integration/drone/push Build is passing
2021-05-14 04:05:26 +00:00
Manuel Thalmann 17ed8430c9 Move from Chrome to Edge
All checks were successful
continuous-integration/drone/push Build is passing
2021-05-12 21:47:10 +00:00
Manuel Thalmann e3dce4859b Migrate styles to bootstrap v5
All checks were successful
continuous-integration/drone/push Build is passing
2021-05-12 10:59:40 +00:00
Manuel Thalmann 60d2f273e4 Replace php intellisense with working extension 2021-05-12 10:59:26 +00:00
Manuel Thalmann 74698047ed Expose ports for localhost only
All checks were successful
continuous-integration/drone/push Build is passing
2021-05-12 09:20:13 +00:00
Manuel Thalmann 15c0e10c21 Fix incorrect task-settings
All checks were successful
continuous-integration/drone/push Build is passing
2021-05-11 19:59:49 +00:00
Manuel Thalmann d65760e437 Make scss-logs fancy 2021-05-11 19:55:14 +00:00
Manuel Thalmann 31ee457468 Refactor the scss-logs 2021-05-11 19:54:42 +00:00
Manuel Thalmann 7751bd0006 Move the TypeScript start message to the proper location 2021-05-11 19:52:09 +00:00
Manuel Thalmann fefbad1687 Normalize typescript-imports 2021-05-11 19:49:46 +00:00
Manuel Thalmann 7698a9aab3 Normalize the name of the fancy-log-import 2021-05-11 19:44:06 +00:00
Manuel Thalmann 46ce17d365 Fix the tsify-import 2021-05-11 19:41:05 +00:00
Manuel Thalmann b3107eb09a Add line-breaks to all file-endings 2021-05-11 19:39:53 +00:00
Manuel Thalmann 695efff492 Add a configuration for debugging the Watch task 2021-05-11 19:33:35 +00:00
Manuel Thalmann 992cd447ba Fix the execution-order of the Theme-task 2021-05-11 19:30:17 +00:00
Manuel Thalmann 25683a35fc Simplify the pcoess of creating js code 2021-05-11 19:26:03 +00:00
Manuel Thalmann 61627c2a6a Refactor the build-task 2021-05-11 18:32:34 +00:00
Manuel Thalmann ce34b2e9dc Update all packages 2021-05-11 17:19:24 +00:00
Manuel Thalmann b600414d9d Fix broken problem-matchers 2021-05-11 17:14:40 +00:00
Manuel Thalmann 706835d97c Fix broken pipeline 2021-05-11 17:14:28 +00:00
Manuel Thalmann 0c9694752e Set proper docker-images
All checks were successful
continuous-integration/drone/push Build is passing
2021-05-11 11:11:33 +00:00
Manuel Thalmann 1b2f5b46e5 Fill out the LICENSE-template
Some checks failed
continuous-integration/drone/push Build is failing
2021-05-11 11:07:09 +00:00
Manuel Thalmann 3f5fd10a84 Add drone-pipelines 2021-05-11 02:21:19 +00:00
Manuel Thalmann 351ce0cdad Refactor composer-archives 2021-05-11 02:20:42 +00:00
Manuel Thalmann 5f560e151e Fix further linting-errors 2021-05-11 01:00:27 +00:00
Manuel Thalmann c7157cc247 Fix incorrect typescript-setting 2021-05-11 00:59:05 +00:00
Manuel Thalmann 4ad39d69db Adjust settings accordingly 2021-05-11 00:58:24 +00:00
Manuel Thalmann b1b8b74134 Add missing EOL to the settings 2021-05-11 00:57:13 +00:00
Manuel Thalmann e336072b11 Refactor the lint-task 2021-05-11 00:57:03 +00:00
Manuel Thalmann cadbc594c0 Rename the gulp-directory 2021-05-11 00:56:38 +00:00
Manuel Thalmann 90bb091ae8 Remove incorrect eslint-setting 2021-05-11 00:45:32 +00:00
Manuel Thalmann d6fa484904 Add the sourceMaps-option to the launch-settings 2021-05-11 00:37:22 +00:00
Manuel Thalmann cdba678fe9 Remove unsupported setting 2021-05-11 00:36:22 +00:00
Manuel Thalmann c2fe374ccd Remove unnecessary comments from extensions.json 2021-05-11 00:10:16 +00:00
Manuel Thalmann c5137e520b Update the .gitignore file 2021-05-11 00:09:05 +00:00
Manuel Thalmann c14bedcb46 Add a changelog-file 2021-05-11 00:03:00 +00:00
Manuel Thalmann 75e22e02ce Add the UI port to the gulpfile explicitly 2021-05-11 00:02:52 +00:00
Manuel Thalmann 449d2553bf Fix incorrect xdebug-port 2021-05-10 23:59:52 +00:00
Manuel Thalmann 6ecfecbcbd Fix the code-format 2021-05-10 23:31:10 +00:00
Manuel Thalmann 1e6daaacd7 Move from tslint to eslint 2021-05-10 23:13:23 +00:00
Manuel Thalmann 1337771f59 Allow the project to be run in a docker-volume 2021-05-10 23:10:12 +00:00
Manuel Thalmann 3af6253c56 Update the test-website 2021-05-10 20:47:00 +00:00
Manuel Thalmann f1a35756b3 Fix broken .scss-code 2021-05-10 20:46:45 +00:00
Manuel Thalmann 2dceaf9520 Fix linting-messages 2021-05-10 20:46:32 +00:00
Manuel Thalmann 7015fa994a Fix watchers for windows running docker 2021-05-10 20:45:57 +00:00
Manuel Thalmann 9f9c0bc497 Move huge directories to volumes 2021-05-10 20:40:36 +00:00
Manuel Thalmann d468b58393 Add the silverstripe-extension to the devcontainer 2021-05-10 20:35:53 +00:00
Manuel Thalmann 0e59d2cd50 Update all npm-packages 2021-05-10 20:35:36 +00:00
Manuel Thalmann 55a2ff97d1 Update the composer.lock-file 2021-05-10 20:34:56 +00:00
Manuel Thalmann f00977b8bf Add a timeout to the composer-installation 2021-05-10 20:34:32 +00:00
Manuel Thalmann 56d8a6af3d Rearrange the mysql-variables 2021-05-10 20:34:21 +00:00
Manuel Thalmann 1ad03d1d41 Complete the ts-configuration of the app 2019-11-24 15:10:07 +00:00
Manuel Thalmann 2dd3a6161a Add the ESLint-extension 2019-11-22 13:19:43 +00:00
Manuel Thalmann 5cbb4cf411 Remove unnecessary extension 2019-11-22 13:17:22 +00:00
Manuel Thalmann 0b91e83df4 Add error-messages for node-sass 2019-11-22 13:14:49 +00:00
Manuel Thalmann 7d99223936 Update all packages 2019-11-22 13:14:33 +00:00
Manuel Thalmann 5bb5999cde Add a few style-changes 2019-11-22 13:12:55 +00:00
Manuel Thalmann 1543603447 Add a valid admin-password 2019-10-27 19:06:01 +00:00
Manuel Thalmann 428dcedea9 Add the form to the test-template 2019-10-27 19:05:27 +00:00
Manuel Thalmann 7d189ede99 Ensure the theme-path is created correctly 2019-10-27 19:05:14 +00:00
Manuel Thalmann c7b9118298 Ensure php is loaded from the correct path 2019-10-27 17:46:42 +00:00
Manuel Thalmann aeb85de82a Ensure line-endings aren't messed up 2019-10-27 17:37:07 +00:00
Manuel Thalmann 7777dee9f3 Add debug-configurations 2019-10-07 21:33:33 +00:00
Manuel Thalmann 1242bbdc90 Remove redundant tasks 2019-10-07 23:32:53 +02:00
Manuel Thalmann ed165b43e9 Add composer-tasks 2019-10-07 23:29:37 +02:00
Manuel Thalmann dbcfd2e148 Add tasks for building the project 2019-10-07 21:20:38 +00:00
Manuel Thalmann 0fee992b83 Add a task for cleaning the project 2019-10-07 21:17:44 +00:00
Manuel Thalmann 6b8c085976 Provide the functionality to auto-reload the website on build 2019-10-07 20:08:35 +00:00
Manuel Thalmann 2b44c6ac22 Fix typo 2019-10-07 20:05:07 +00:00
Manuel Thalmann b413318097 Simplify the theme-handling 2019-10-07 20:03:44 +00:00
Manuel Thalmann 683e09f236 Refactor the sass build process 2019-10-07 18:53:26 +00:00
Manuel Thalmann a027ba64a2 Refactor the watch-task 2019-10-07 18:44:32 +00:00
Manuel Thalmann ac76bf6715 Add templates for testing 2019-10-07 17:10:00 +00:00
Manuel Thalmann 6c72e6200f Add a task for building templates 2019-10-07 17:09:35 +00:00
Manuel Thalmann 68378b1e86 Add a task for compiling the theme 2019-10-07 16:59:23 +00:00
Manuel Thalmann 84ada4d843 Load the theme into the test-website 2019-10-07 17:50:06 +02:00
Manuel Thalmann f734303a26 Rename the env-file 2019-10-07 12:20:25 +00:00
Manuel Thalmann f1906b03cd Add tasks for building typescript-code 2019-10-07 11:48:01 +00:00
Manuel Thalmann bdb2e4e02f Remove redundant variables 2019-10-07 02:45:55 +00:00
Manuel Thalmann 7718b1dad7 Initialize a silverstripe-website for testing 2019-10-07 02:26:37 +00:00
Manuel Thalmann 2b347775c4 Add configuration-files for developing the project using docker 2019-10-07 00:24:57 +00:00
Manuel Thalmann 6e424a7710 Convert the project to a composer-project 2019-10-05 23:35:56 +02:00
Manuel Thalmann 5ebc689c95 Initialize a composer-module 2019-10-03 22:11:59 +02:00
Manuel Thalmann 434ca85b41 Initialize a new npm-module 2019-10-03 21:46:08 +02:00
48 changed files with 29078 additions and 4 deletions

View 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

View 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"
}

View 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:

View 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

View 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
View 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
View 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
View file

@ -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
View 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
View 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
View 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
View 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
View 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

View file

@ -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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

77
package.json Normal file
View 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
View file

@ -0,0 +1,3 @@
import "bootstrap";
import "jquery";
import "popper.js";

16
src/App/tsconfig.json Normal file
View file

@ -0,0 +1,16 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"rootDir": "src",
"lib": [
"ES2020",
"DOM"
]
},
"files": [
"src/main.ts"
],
"exclude": [
"./src/tests/**/*"
]
}

View file

61
src/Templates/Page.ss Normal file
View 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
View 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;
}
}

View file

@ -0,0 +1 @@
$tagline-font-size: calc($small-font-size / 2);

3
src/Theme/main.scss Normal file
View file

@ -0,0 +1,3 @@
@import "~bootstrap/scss/bootstrap";
@import "variables";
@import "nav";

6
test/website/.gitignore vendored Normal file
View file

@ -0,0 +1,6 @@
/silverstripe-cache/
/.env
/vendor/
/themes/simple/
/_resources/
/public/_resources/

2
test/website/.htaccess Normal file
View file

@ -0,0 +1,2 @@
RewriteEngine On
RewriteRule ^(.*)$ public/$1

View file

@ -0,0 +1,3 @@
<FilesMatch "\.(php|php3|php4|php5|phtml|inc)$">
Require all denied
</FilesMatch>

View 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);

View 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

View 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

View 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

View file

@ -0,0 +1,8 @@
---
Name: mytheme
---
SilverStripe\View\SSViewer:
themes:
- 'mantra'
- '$public'
- '$default'

View file

@ -0,0 +1,13 @@
<?php
namespace {
use SilverStripe\CMS\Model\SiteTree;
class Page extends SiteTree
{
private static $db = [];
private static $has_one = [];
}
}

View 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/
}
}
}

View 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

File diff suppressed because it is too large Load diff

View 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
View file

@ -0,0 +1,4 @@
/**/*
!.gitignore
!.htaccess
!web.config

View 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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View 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
View 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
View file

@ -0,0 +1,9 @@
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"noEmit": true
},
"include": [
"./.eslintrc.js"
]
}

10
tsconfig.json Normal file
View file

@ -0,0 +1,10 @@
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"noEmit": true
},
"include": [
"./gulp/**/*.*",
"./gulpfile.ts"
]
}