diff --git a/app/_config/webpack.yml b/app/_config/webpack.yml index 7341a0c..0038d1f 100644 --- a/app/_config/webpack.yml +++ b/app/_config/webpack.yml @@ -10,4 +10,5 @@ Site\Templates\WebpackTemplateProvider: SRC: client/src DIST: client/dist TYPESJS: client/src/js/types - TYPESSCSS: client/src/scss/types \ No newline at end of file + TYPESSCSS: client/src/scss/types + webp: false diff --git a/app/src/Elements/MapElement.php b/app/src/Elements/MapElement.php index 1b21350..64451e4 100644 --- a/app/src/Elements/MapElement.php +++ b/app/src/Elements/MapElement.php @@ -74,7 +74,7 @@ class MapElement extends ElementContent return $fields; } - public function MapAPIKey(): string + public static function MapAPIKey(): string { $type = self::config()->get('map_type'); diff --git a/app/src/Extensions/LeftAndMainExtension.php b/app/src/Extensions/LeftAndMainExtension.php index dd22b81..86383a3 100644 --- a/app/src/Extensions/LeftAndMainExtension.php +++ b/app/src/Extensions/LeftAndMainExtension.php @@ -3,11 +3,24 @@ namespace Site\Extensions; +use SilverStripe\Core\Config\Config; use SilverStripe\Core\Extension; +use SilverStripe\FontAwesome\FontAwesomeField; +use SilverStripe\View\Requirements; +use Site\Templates\DeferredRequirements; class LeftAndMainExtension extends Extension { public function init() { + $config = Config::inst()->get(DeferredRequirements::class); + // App libs + if (!$config['nofontawesome']) { + $v = !isset($config['fontawesome_version']) || !$config['fontawesome_version'] + ? Config::inst()->get(FontAwesomeField::class, 'version') + : $config['fontawesome_version']; + + Requirements::css('//use.fontawesome.com/releases/v'.$v.'/css/all.css'); + } } -} \ No newline at end of file +} diff --git a/app/src/Templates/WebpackTemplateProvider.php b/app/src/Templates/WebpackTemplateProvider.php index d91a5a6..79826b1 100644 --- a/app/src/Templates/WebpackTemplateProvider.php +++ b/app/src/Templates/WebpackTemplateProvider.php @@ -31,6 +31,7 @@ class WebpackTemplateProvider implements TemplateGlobalProvider * @var string assets static files directory */ private static $dist = 'client/dist'; + private static $webp = false; /** * @return array @@ -81,7 +82,20 @@ class WebpackTemplateProvider implements TemplateGlobalProvider public static function resourcesURL($link = null): string { - return Controller::join_links(Director::baseURL(), '/resources/'.self::projectName().'/client/dist/img/', $link); + $cfg = self::config(); + + if ($cfg['webp'] && !self::isActive()) { + $link = str_replace(['.png','.jpg','.jpeg'], '.webp', $link); + } + + return Controller::join_links( + Director::baseURL(), + '/resources/', + self::projectName(), + $cfg['dist'], + 'img', + $link + ); } diff --git a/app/src/Tests/TestServer.php b/app/src/Tests/TestServer.php index db1bb7b..88c5721 100644 --- a/app/src/Tests/TestServer.php +++ b/app/src/Tests/TestServer.php @@ -80,6 +80,13 @@ class TestServer extends BuildTask echo self::error('Assets dir '.ASSETS_DIR.' dir is no writable!'); } + if (function_exists('imagewebp')) { + echo self::success('WebP is available'); + } else { + echo self::error('WebP is not available'); + } + + die(); } diff --git a/app/src/Traits/PaginatedListing.php b/app/src/Traits/PaginatedListing.php new file mode 100644 index 0000000..0f8a5df --- /dev/null +++ b/app/src/Traits/PaginatedListing.php @@ -0,0 +1,18 @@ +getRequest()->requestVars(); + $vars = array_filter($vars); + $vars['page'] = $pageID ? $pageID : '2'; + + return $this->Link('?'.http_build_query($vars)); + } +} diff --git a/app/templates/Includes/NavItem.ss b/app/templates/Includes/NavItem.ss index 6b1c772..f04a6c5 100644 --- a/app/templates/Includes/NavItem.ss +++ b/app/templates/Includes/NavItem.ss @@ -9,7 +9,6 @@ aria-haspopup="true" aria-expanded="false" href="{$Link}" - title="$Title.XML" > $MenuTitle.XML <% if $isCurrent || $isSection %>(current)<% end_if %> diff --git a/app/templates/Site/Objects/NotificationsList.ss b/app/templates/Site/Objects/NotificationsList.ss index 0b3e0e7..2b80975 100644 --- a/app/templates/Site/Objects/NotificationsList.ss +++ b/app/templates/Site/Objects/NotificationsList.ss @@ -3,11 +3,7 @@ <% loop $NotificationsToday %>
- - - - - <% if $Title %> + <% if $DisplayTitle && $Title %>

$Title

<% end_if %> @@ -25,6 +21,10 @@ <% end_with %> <% end_if %> + + + +
<% end_loop %> diff --git a/composer.json b/composer.json index b8556d7..ea97e78 100755 --- a/composer.json +++ b/composer.json @@ -44,7 +44,8 @@ "a2nt/silverstripe-font-awesome-field": "dev-master", "a2nt/silverstripe-mapboxfield": "dev-master", "a2nt/silverstripe-progressivewebapp": "dev-master", - "bummzack/sortablefile": "*" + "bummzack/sortablefile": "*", + "showpro/silverstripe-seo-images": "*" }, "require-dev": { "phpunit/phpunit": "^5.7", diff --git a/package.json b/package.json index 773deea..aaa1472 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ss-webpack-boilerplate", - "version": "2.2.1", + "version": "2.0.2", "description": "Lets you create SilverStripe faster", "author": "Tony Air ", "license": "MIT", @@ -32,7 +32,7 @@ ], "dependencies": { "@a2nt/meta-lightbox": "^2.2.1", - "@a2nt/ss-bootstrap-ui-webpack-boilerplate": "^2.2.1", + "@a2nt/ss-bootstrap-ui-webpack-boilerplate": "^2.3.1", "bootbox": "^4.4.0", "bootstrap": "^4.5.0", "bootstrap-confirmation2": "^4.1.0", @@ -40,6 +40,7 @@ "bootstrap-offcanvas": "^1.0.0", "bootstrap-table": "^1.16.0", "bootstrap-timepicker": "^0.5.2", + "exif-js": "^2.3.0", "font-awesome": "^4.7.0", "hammerjs": "^2.0.8", "inputmask": "^5.0.3", @@ -50,23 +51,25 @@ "jquery.appear": "^1.0.1", "mapbox-gl": "^1.11.0", "material-design-color": "^2.3.2", + "moment": "^2.27.0", + "offcanvas-bootstrap": "^2.5.2", "popper.js": "*", "select2": "^4.0.13", + "setimmediate": "^1.0.5", "smooth-scroll": "^14.2.1", "sticky-sidebar": "^3.3.1", + "tablednd": "^1.0.3", "yarn": "^1.22.4" }, "devDependencies": { "@a2nt/image-sprite-webpack-plugin": "^0.2.5", - "@babel/core": "^7.10.2", - "@babel/plugin-proposal-object-rest-spread": "^7.10.1", - "@babel/plugin-transform-react-jsx": "^7.10.1", - "@babel/preset-env": "^7.10.2", + "@babel/core": "^7.10.4", + "@babel/plugin-proposal-object-rest-spread": "^7.10.4", + "@babel/plugin-transform-react-jsx": "^7.10.4", + "@babel/preset-env": "^7.10.4", "@google/markerclusterer": "^1.0.3", "animate.css": "^3.7.2", - "ansi-html": "^0.0.7", - "ansi-regex": "^5.0.0", - "autoprefixer": "^9.8.0", + "autoprefixer": "^9.8.4", "babel-eslint": "^8.2.6", "babel-loader": "^8.1.0", "copy-webpack-plugin": "^4.6.0", @@ -74,21 +77,22 @@ "cross-env": "^5.2.1", "css-loader": "^3.6.0", "eslint": "^4.19.1", - "eslint-plugin-import": "^2.21.2", + "eslint-plugin-import": "^2.22.0", "eslint-plugin-jquery": "^1.5.1", - "eslint-plugin-react": "^7.20.0", + "eslint-plugin-react": "^7.20.3", "exports-loader": "^0.7.0", "favicons-webpack-plugin": "0.0.9", "file-loader": "^5.1.0", "font-awesome": "^4.7.0", "hard-source-webpack-plugin": "^0.13.1", - "html-entities": "^1.3.1", "html-webpack-plugin": "^4.3.0", "imagemin-gifsicle": "^7.0.0", "imagemin-jpegtran": "^6.0.0", "imagemin-optipng": "^7.1.0", "imagemin-svgo": "^7.1.0", + "imagemin-webp": "^6.0.0", "imagemin-webpack": "^5.1.1", + "img-optimize-loader": "^1.0.4", "loglevel": "^1.6.8", "mini-css-extract-plugin": "^0.9.0", "node-sass": "^4.14.1", @@ -102,8 +106,6 @@ "sass-lint-fix": "^1.12.1", "sass-loader": "^8.0.2", "script-ext-html-webpack-plugin": "^2.1.4", - "sockjs-client": "^1.4.0", - "strip-ansi": "^6.0.0", "style-loader": "^0.19.1", "svg-url-loader": "^2.3.3", "terser-webpack-plugin": "^2.3.7", diff --git a/test.php b/test.php index b686799..a1ec5b4 100644 --- a/test.php +++ b/test.php @@ -5,9 +5,9 @@ ini_set('display_startup_errors', 1); error_reporting(E_ALL); require_once('vendor/autoload.php'); -require_once('framework/core/Constants.php'); +//require_once('vendor/silverstripe/framework/src/Core/Constants.php'); -require_once('app/code/Tasks/TestServer.php'); +require_once('app/src/Tests/TestServer.php'); $req = new \SilverStripe\Control\NullHTTPRequest(); diff --git a/webpack.config.common.js b/webpack.config.common.js index 09a6ded..a52d9a2 100755 --- a/webpack.config.common.js +++ b/webpack.config.common.js @@ -12,7 +12,6 @@ const filesystem = require('fs'); const includes = {}; const modules = [ - path.resolve(__dirname, 'public'), path.resolve(__dirname, conf.APPDIR, 'client', 'src'), path.resolve(__dirname, conf.APPDIR, 'client', 'src', 'js'), path.resolve(__dirname, conf.APPDIR, 'client', 'src', 'scss'), @@ -20,9 +19,11 @@ const modules = [ path.resolve(__dirname, conf.APPDIR, 'client', 'src', 'thirdparty'), path.resolve(__dirname, conf.APPDIR, 'client', 'node_modules'), path.resolve(__dirname, 'node_modules'), + path.resolve(__dirname), + path.resolve(__dirname, 'public'), ]; -const _addAppFiles = theme => { +const _addAppFiles = (theme) => { const dirPath = path.resolve(__dirname, theme); const themeName = path.basename(theme); @@ -44,11 +45,11 @@ const _addAppFiles = theme => { modules.push(path.join(dirPath, 'client', 'src', 'img')); modules.push(path.join(dirPath, 'client', 'src', 'thirdparty')); - const _getAllFilesFromFolder = function(dir, includeSubFolders = true) { + const _getAllFilesFromFolder = function (dir, includeSubFolders = true) { const dirPath = path.resolve(__dirname, dir); let results = []; - filesystem.readdirSync(dirPath).forEach(file => { + filesystem.readdirSync(dirPath).forEach((file) => { if (file.charAt(0) === '_') { return; } @@ -72,7 +73,7 @@ const _addAppFiles = theme => { const typesJSPath = path.join(theme, conf.TYPESJS); if (filesystem.existsSync(typesJSPath)) { const pageScripts = _getAllFilesFromFolder(typesJSPath, true); - pageScripts.forEach(file => { + pageScripts.forEach((file) => { includes[`${themeName}_${path.basename(file, '.js')}`] = file; }); } @@ -81,7 +82,7 @@ const _addAppFiles = theme => { const typesSCSSPath = path.join(theme, conf.TYPESSCSS); if (filesystem.existsSync(typesSCSSPath)) { const scssIncludes = _getAllFilesFromFolder(typesSCSSPath, true); - scssIncludes.forEach(file => { + scssIncludes.forEach((file) => { includes[`${themeName}_${path.basename(file, '.scss')}`] = file; }); } @@ -90,7 +91,7 @@ const _addAppFiles = theme => { _addAppFiles(conf.APPDIR); // add themes -commonVariables.themes.forEach(theme => { +commonVariables.themes.forEach((theme) => { _addAppFiles(theme); }); diff --git a/webpack.config.dev.js b/webpack.config.dev.js index 2dbec6f..0bc214e 100755 --- a/webpack.config.dev.js +++ b/webpack.config.dev.js @@ -77,7 +77,7 @@ const config = merge.strategy({ ], }, { - test: /\.(gif|png|jpg|jpeg|ttf|otf|eot|svg|woff(2)?)$/, + test: /\.(gif|png|jpg|jpeg|ttf|otf|eot|svg|webp|woff(2)?)$/, use: [ { loader: 'file-loader', diff --git a/webpack.config.prod.js b/webpack.config.prod.js index cca6f5d..34d6766 100755 --- a/webpack.config.prod.js +++ b/webpack.config.prod.js @@ -102,10 +102,11 @@ let plugins = [ ], }, ], + ['webp', { quality: 100 }], ], }, }), - new ImageSpritePlugin({ + /*new ImageSpritePlugin({ exclude: /exclude|original|default-|icons|sprite/, commentOrigin: false, compress: true, @@ -115,11 +116,11 @@ let plugins = [ //outputPath: path.join(__dirname, conf.APPDIR, conf.DIST), outputFilename: 'img/sprite-[hash].png', padding: 0, - }), + }),*/ ]; // add themes favicons -commonVariables.themes.forEach(theme => { +commonVariables.themes.forEach((theme) => { const faviconPath = path.join(__dirname, theme, conf.SRC, 'favicon.png'); if (filesystem.existsSync(faviconPath)) { plugins.push( @@ -272,17 +273,24 @@ module.exports = merge(common, { ], }, { - test: /\.(png|jpg|jpeg|gif|svg)$/, + test: /\.(png|webp|jpg|jpeg|gif|svg)$/, + loader: 'img-optimize-loader', + options: { + compress: { + // This will take more time and get smaller images. + mode: 'high', // 'lossless', 'low' + disableOnDevelopment: true, + webp: conf['webp'], + }, + }, + }, + { + test: /\.(png|webp|jpg|jpeg|gif|svg)$/, loader: 'file-loader', options: { - name: '[name].[ext]', + name: conf['webp'] ? '[name].webp' : '[name].[ext]', outputPath: 'img/', publicPath: '../img/', - /*, - name(file) { - //return 'public/[path][name].[ext]'; - return '[hash].[ext]'; - },*/ }, }, ],