Skip to content

Commit

Permalink
Added TailwindCSS-based scaffold to the create:theme command
Browse files Browse the repository at this point in the history
  • Loading branch information
LukeTowers committed May 16, 2022
1 parent 20ac7f6 commit 3862bf2
Show file tree
Hide file tree
Showing 34 changed files with 293 additions and 16 deletions.
71 changes: 56 additions & 15 deletions modules/cms/console/CreateTheme.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php namespace Cms\Console;

use Winter\Storm\Scaffold\GeneratorCommand;
use InvalidArgumentException;

class CreateTheme extends GeneratorCommand
{
Expand All @@ -14,7 +15,8 @@ class CreateTheme extends GeneratorCommand
*/
protected $signature = 'create:theme
{theme : The name of the theme to create. <info>(eg: MyTheme)</info>}
{--force : Overwrite existing files with generated files.}';
{scaffold? : The base theme scaffold to use <info>(eg: less, tailwind)</info>}
{--f|force : Overwrite existing files with generated files.}';

/**
* @var string The console command description.
Expand All @@ -32,21 +34,45 @@ class CreateTheme extends GeneratorCommand
protected $nameFrom = 'theme';

/**
* @var array A mapping of stub to generated file.
* @var array Available theme scaffolds and their types
*/
protected $stubs = [
'scaffold/theme/assets/js/app.stub' => 'assets/js/app.js',
'scaffold/theme/assets/less/theme.stub' => 'assets/less/theme.less',
'scaffold/theme/layouts/default.stub' => 'layouts/default.htm',
'scaffold/theme/pages/404.stub' => 'pages/404.htm',
'scaffold/theme/pages/error.stub' => 'pages/error.htm',
'scaffold/theme/pages/home.stub' => 'pages/home.htm',
'scaffold/theme/partials/meta/seo.stub' => 'partials/meta/seo.htm',
'scaffold/theme/partials/meta/styles.stub' => 'partials/meta/styles.htm',
'scaffold/theme/partials/site/header.stub' => 'partials/site/header.htm',
'scaffold/theme/partials/site/footer.stub' => 'partials/site/footer.htm',
'scaffold/theme/theme.stub' => 'theme.yaml',
'scaffold/theme/version.stub' => 'version.yaml',
protected $themeScaffolds = [
'less' => [
'scaffold/theme/less/assets/js/app.stub' => 'assets/js/app.js',
'scaffold/theme/less/assets/less/theme.stub' => 'assets/less/theme.less',
'scaffold/theme/less/layouts/default.stub' => 'layouts/default.htm',
'scaffold/theme/less/pages/404.stub' => 'pages/404.htm',
'scaffold/theme/less/pages/error.stub' => 'pages/error.htm',
'scaffold/theme/less/pages/home.stub' => 'pages/home.htm',
'scaffold/theme/less/partials/meta/seo.stub' => 'partials/meta/seo.htm',
'scaffold/theme/less/partials/meta/styles.stub' => 'partials/meta/styles.htm',
'scaffold/theme/less/partials/site/header.stub' => 'partials/site/header.htm',
'scaffold/theme/less/partials/site/footer.stub' => 'partials/site/footer.htm',
'scaffold/theme/less/theme.stub' => 'theme.yaml',
'scaffold/theme/less/version.stub' => 'version.yaml',
],
'tailwind' => [
'scaffold/theme/tailwind/assets/src/css/base.stub' => 'assets/src/css/base.css',
'scaffold/theme/tailwind/assets/src/css/custom.stub' => 'assets/src/css/custom.css',
'scaffold/theme/tailwind/assets/src/css/theme.stub' => 'assets/src/css/theme.css',
'scaffold/theme/tailwind/assets/src/js/theme.stub' => 'assets/src/js/theme.js',
'scaffold/theme/tailwind/lang/en/lang.stub' => 'lang/en/lang.php',
'scaffold/theme/tailwind/layouts/default.stub' => 'layouts/default.htm',
'scaffold/theme/tailwind/pages/404.stub' => 'pages/404.htm',
'scaffold/theme/tailwind/pages/error.stub' => 'pages/error.htm',
'scaffold/theme/tailwind/pages/home.stub' => 'pages/home.htm',
'scaffold/theme/tailwind/partials/meta/seo.stub' => 'partials/meta/seo.htm',
'scaffold/theme/tailwind/partials/meta/styles.stub' => 'partials/meta/styles.htm',
'scaffold/theme/tailwind/partials/site/header.stub' => 'partials/site/header.htm',
'scaffold/theme/tailwind/partials/site/footer.stub' => 'partials/site/footer.htm',
'scaffold/theme/tailwind/.gitignore.stub' => '.gitignore',
'scaffold/theme/tailwind/package.stub' => 'package.json',
'scaffold/theme/tailwind/readme.stub' => 'README.md',
'scaffold/theme/tailwind/tailwind.config.stub' => 'tailwind.config.js',
'scaffold/theme/tailwind/theme.stub' => 'theme.yaml',
'scaffold/theme/tailwind/version.stub' => 'version.yaml',
'scaffold/theme/tailwind/winter.mix.stub' => 'winter.mix.js',
],
];

/**
Expand All @@ -62,11 +88,26 @@ protected function getNameInput(): string
*/
protected function prepareVars(): array
{
$scaffold = $this->argument('scaffold') ?? 'less';
$validOptions = $this->suggestScaffoldValues();
if (!in_array($scaffold, $validOptions)) {
throw new InvalidArgumentException("$scaffold is not an available theme scaffold type (Available types: " . implode(', ', $validOptions) . ')');
}
$this->stubs = $this->themeScaffolds[$scaffold];

return [
'code' => $this->getNameInput(),
];
}

/**
* Auto suggest valid theme scaffold values
*/
public function suggestScaffoldValues(): array
{
return array_keys($this->themeScaffolds);
}

/**
* Get the plugin path from the input.
*/
Expand Down
2 changes: 2 additions & 0 deletions modules/cms/console/scaffold/theme/tailwind/.gitignore.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules/
dist/
9 changes: 9 additions & 0 deletions modules/cms/console/scaffold/theme/tailwind/README.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# {{code}} Winter CMS Theme

This theme uses [Winter Mix](https://wintercms.com/docs/console/asset-compilation) for asset compilation. It also uses [Tailwind CSS](https://tailwindcss.com/).

## Getting Started

1. Run [`artisan mix:install`](https://wintercms.com/docs/console/asset-compilation#mix-install) and agree when asked to modify the `package.json` file for your project in order to register & install this theme's dependencies.
2. Run [`artisan mix:compile -p theme-{{code}} --production`](https://wintercms.com/docs/console/asset-compilation#mix-compile) to compile the asset files for this theme.
3. Optionally, run [`artisan mix:watch theme-{{code}}`](https://wintercms.com/docs/console/asset-compilation#mix-watch) while actively working on the theme to have the assets automatically recompiled in the background for you every time you make a change.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/**
* Custom CSS for theme goes here
*/
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@import 'base.css';
@import 'custom.css';
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Application
*/
(function($) {
"use strict";

jQuery(document).ready(function($) {
/*-------------------------------
WINTER CMS FLASH MESSAGE HANDLING
---------------------------------*/
$(document).on('ajaxSetup', function(event, context) {
// Enable AJAX handling of Flash messages on all AJAX requests
context.options.flash = true;

// Enable the StripeLoadIndicator on all AJAX requests
context.options.loading = $.oc.stripeLoadIndicator;

// Handle Flash Messages
context.options.handleFlashMessage = function(message, type) {
$.oc.flashMsg({ text: message, class: type });
};

// Handle Error Messages
context.options.handleErrorMessage = function(message) {
$.oc.flashMsg({ text: message, class: 'error' });
};
});
});
}(jQuery));

if (typeof(gtag) !== 'function') {
gtag = function() { console.log('GoogleAnalytics not present.'); }
}
9 changes: 9 additions & 0 deletions modules/cms/console/scaffold/theme/tailwind/lang/en/lang.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

return [
'options' => [
'googleanalytics_id' => 'Google Analytics ID',
'color_primary' => 'Primary Color',
'color_secondary' => 'secondary Color',
],
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
description = "Default layout"
default = true
==
{% partial "site/header" %}

{% page %}

{% partial "site/footer" %}
12 changes: 12 additions & 0 deletions modules/cms/console/scaffold/theme/tailwind/package.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "{{code}}",
"private": true,
"version": "1.0.0",
"devDependencies": {
"postcss": "~8.4.x",
"postcss-import": "~14.1.x",
"tailwindcss": "~3.0.x"
},
"dependencies": {
}
}
8 changes: 8 additions & 0 deletions modules/cms/console/scaffold/theme/tailwind/pages/404.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
title = "Page not found (404)"
url = "/404"
layout = "default"
==
<div>
<h1>Page not found</h1>
<p>We're sorry, but the page you requested cannot be found.</p>
</div>
8 changes: 8 additions & 0 deletions modules/cms/console/scaffold/theme/tailwind/pages/error.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
title = "Error page (500)"
url = "/error"
layout = "default"
==
<div>
<h1>Error</h1>
<p>We're sorry, but something went wrong and the page cannot be displayed.</p>
</div>
7 changes: 7 additions & 0 deletions modules/cms/console/scaffold/theme/tailwind/pages/home.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
title = "Home"
url = "/"
layout = "default"
==
<div class="container mx-auto">
<h1><span class="text-primary">Home</span> <span class="text-secondary">Page</span></h1>
</div>
11 changes: 11 additions & 0 deletions modules/cms/console/scaffold/theme/tailwind/partials/meta/seo.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{% if this.theme.googleanalytics_id is not empty %}
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id={{ this.theme.googleanalytics_id }}"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());

gtag('config', '{{ this.theme.googleanalytics_id }}');
</script>
{% endif %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
==
<?php
use Cms\Classes\Asset;
use Cms\Classes\Theme;
function onStart() {
// Cache bust the main styles file
$styles = (new Asset(Theme::getActiveTheme()))->find('dist/css/theme.css');
if ($styles) {
$this['lastmodified'] = $styles->mtime;
} else {
throw new \Exception("Asset files were not detected, try running artisan mix:install && artisan mix:compile -p theme-{{code}}");
}
}
?>
==
<link rel="stylesheet" href="{{ 'assets/dist/css/theme.css' | theme }}?v={{ lastmodified }}">

<style>
:root {
--primary: {{ this.theme.color_primary }};
--secondary: {{ this.theme.color_secondary }};
}
</style>

{% styles %}
{% placeholder head %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!-- Scripts -->

{# jQuery AJAX Framework #}
<script src="{{ [
'@jquery',
'@framework',
'@framework.extras',
] | theme }}"></script>

{# Mix extracted assets #}
<script src="{{ 'assets/dist/js/theme.js' | theme }}"></script>

{% scripts %}

{% flash %}
<p data-control="flash-message" data-interval="7" class="flashmessage {{ type }}">
{{ message }}
</p>
{% endflash %}
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% placeholder page_title default %}{{ this.page.title }}{% endplaceholder %}</title>
{% partial "meta/styles" %}
{% partial "meta/seo" %}
<meta name="generator" content="Winter CMS">
</head>
{% set pageId = this.page.id %}
{% set pageTitle = this.page.title %}
{% if pageId is empty %}
{% set pageId = page.id %}
{% endif %}
{% if pageTitle is empty %}
{% set pageTitle = page.title %}
{% endif %}
<body class="page-{{ pageId }} layout-{{ this.layout.id }}">
17 changes: 17 additions & 0 deletions modules/cms/console/scaffold/theme/tailwind/tailwind.config.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module.exports = {
content: [
'./theme.yaml',
'./**/*.htm',
'./assets/src/js/**/*.{js,vue}'
],
theme: {
extend: {
colors: {
primary: 'var(--primary)',
secondary: 'var(--secondary)',
},
},
},
plugins: [
],
}
21 changes: 21 additions & 0 deletions modules/cms/console/scaffold/theme/tailwind/theme.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: "{{code}}"
description: "No description provided yet..."
author: "Winter CMS Scaffold"
homepage: "https://example.com"
code: "{{code}}"
form:
fields:
googleanalytics_id:
label: themes.{{code}}::lang.options.googleanalytics_id
type: text
span: full
color_primary:
label: themes.{{code}}::lang.options.color_primary
type: colorpicker
span: left
default: "#103141"
color_secondary:
label: themes.{{code}}::lang.options.color_secondary
type: colorpicker
span: right
default: "#2DA7C7"
1 change: 1 addition & 0 deletions modules/cms/console/scaffold/theme/tailwind/version.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1.0.0: 'Initial version'
15 changes: 15 additions & 0 deletions modules/cms/console/scaffold/theme/tailwind/winter.mix.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const mix = require('laravel-mix');

mix
.setPublicPath(__dirname)

// Render Tailwind style
.postCss('assets/src/css/theme.css', 'assets/dist/css/theme.css', [
require('postcss-import'),
require('tailwindcss'),
require('tailwindcss/nesting'),
require('autoprefixer'),
])

// Compile JS
.js('assets/src/js/theme.js', 'assets/dist/js/theme.js');
2 changes: 1 addition & 1 deletion modules/cms/twig/Extension.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ public function placeholderFunction(string $name, string $default = null): strin
* @param array|bool $parameters Route parameters to consider in the URL. If boolean will be used as the value for $routePersistence
* @param bool $routePersistence Set to false to exclude the existing routing parameters from the generated URL
*/
public function pageFilter(array $context, $name, $parameters = [], $routePersistence = true): string
public function pageFilter(array $context, $name, $parameters = [], $routePersistence = true): ?string
{
return $context['this']['controller']->pageUrl($name, $parameters, $routePersistence);
}
Expand Down

0 comments on commit 3862bf2

Please sign in to comment.