Merge branch 'master' of github.com:roots/sage
This commit is contained in:
41
app/lib/Sage/Assets/JsonManifest.php
Normal file
41
app/lib/Sage/Assets/JsonManifest.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Roots\Sage\Assets;
|
||||
|
||||
/**
|
||||
* Class JsonManifest
|
||||
* @package Roots\Sage
|
||||
* @author QWp6t
|
||||
*/
|
||||
class JsonManifest implements ManifestInterface
|
||||
{
|
||||
/** @var array */
|
||||
public $manifest;
|
||||
|
||||
/** @var string */
|
||||
public $dist;
|
||||
|
||||
/**
|
||||
* JsonManifest constructor
|
||||
*
|
||||
* @param string $manifestPath Local filesystem path to JSON-encoded manifest
|
||||
* @param string $distUri Remote URI to assets root
|
||||
*/
|
||||
public function __construct($manifestPath, $distUri)
|
||||
{
|
||||
$this->manifest = file_exists($manifestPath) ? json_decode(file_get_contents($manifestPath), true) : [];
|
||||
$this->dist = $distUri;
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function get($asset)
|
||||
{
|
||||
return isset($this->manifest[$asset]) ? $this->manifest[$asset] : $asset;
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function getUri($asset)
|
||||
{
|
||||
return "{$this->dist}/{$this->get($asset)}";
|
||||
}
|
||||
}
|
||||
31
app/lib/Sage/Assets/ManifestInterface.php
Normal file
31
app/lib/Sage/Assets/ManifestInterface.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Roots\Sage\Assets;
|
||||
|
||||
/**
|
||||
* Interface ManifestInterface
|
||||
* @package Roots\Sage
|
||||
* @author QWp6t
|
||||
*/
|
||||
interface ManifestInterface
|
||||
{
|
||||
/**
|
||||
* Get the cache-busted filename
|
||||
*
|
||||
* If the manifest does not have an entry for $asset, then return $asset
|
||||
*
|
||||
* @param string $asset The original name of the file before cache-busting
|
||||
* @return string
|
||||
*/
|
||||
public function get($asset);
|
||||
|
||||
/**
|
||||
* Get the cache-busted URI
|
||||
*
|
||||
* If the manifest does not have an entry for $asset, then return URI for $asset
|
||||
*
|
||||
* @param string $asset The original name of the file before cache-busting
|
||||
* @return string
|
||||
*/
|
||||
public function getUri($asset);
|
||||
}
|
||||
8
app/lib/Sage/Config.php
Normal file
8
app/lib/Sage/Config.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Roots\Sage;
|
||||
|
||||
class Config extends \Illuminate\Config\Repository
|
||||
{
|
||||
|
||||
}
|
||||
10
app/lib/Sage/Container.php
Normal file
10
app/lib/Sage/Container.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Roots\Sage;
|
||||
|
||||
use Illuminate\Container\Container as BaseContainer;
|
||||
|
||||
class Container extends BaseContainer
|
||||
{
|
||||
|
||||
}
|
||||
133
app/lib/Sage/PostCreateProject.php
Executable file
133
app/lib/Sage/PostCreateProject.php
Executable file
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
namespace Roots\Sage;
|
||||
|
||||
use Composer\Script\Event;
|
||||
|
||||
class PostCreateProject
|
||||
{
|
||||
public static function updateHeaders(Event $event)
|
||||
{
|
||||
// @codingStandardsIgnoreStart
|
||||
$io = $event->getIO();
|
||||
|
||||
if ($io->isInteractive()) {
|
||||
$io->write('<info>Define theme headers. Press enter key for default.</info>');
|
||||
|
||||
$theme_headers_default = [
|
||||
'name' => 'Sage Starter Theme',
|
||||
'uri' => 'https://roots.io/sage/',
|
||||
'description' => 'Sage is a WordPress starter theme.',
|
||||
'version' => '9.0.0-beta.3',
|
||||
'author' => 'Roots',
|
||||
'author_uri' => 'https://roots.io/'
|
||||
];
|
||||
$theme_headers = [
|
||||
'name' => $io->ask('<info>Theme Name [<comment>'.$theme_headers_default['name'].'</comment>]:</info> ', $theme_headers_default['name']),
|
||||
'uri' => $io->ask('<info>Theme URI [<comment>'.$theme_headers_default['uri'].'</comment>]:</info> ', $theme_headers_default['uri']),
|
||||
'description' => $io->ask('<info>Theme Description [<comment>'.$theme_headers_default['description'].'</comment>]:</info> ', $theme_headers_default['description']),
|
||||
'version' => $io->ask('<info>Theme Version [<comment>'.$theme_headers_default['version'].'</comment>]:</info> ', $theme_headers_default['version']),
|
||||
'author' => $io->ask('<info>Theme Author [<comment>'.$theme_headers_default['author'].'</comment>]:</info> ', $theme_headers_default['author']),
|
||||
'author_uri' => $io->ask('<info>Theme Author URI [<comment>'.$theme_headers_default['author_uri'].'</comment>]:</info> ', $theme_headers_default['author_uri'])
|
||||
];
|
||||
|
||||
file_put_contents('resources/style.css', str_replace($theme_headers_default, $theme_headers, file_get_contents('resources/style.css')));
|
||||
}
|
||||
}
|
||||
|
||||
public static function selectFramework(Event $event)
|
||||
{
|
||||
$io = $event->getIO();
|
||||
$default_framework_pattern = '"bootstrap": ".*"';
|
||||
|
||||
$files_to_clear = [
|
||||
'resources/assets/styles/components/_comments.scss',
|
||||
'resources/assets/styles/components/_forms.scss',
|
||||
'resources/assets/styles/components/_wp-classes.scss',
|
||||
'resources/assets/styles/layouts/_header.scss',
|
||||
];
|
||||
|
||||
|
||||
if ($io->isInteractive()) {
|
||||
$frameworks = [
|
||||
'Bootstrap',
|
||||
'Foundation',
|
||||
'Tachyons',
|
||||
'None'
|
||||
];
|
||||
$framework = $io->select('<info>Select a CSS framework</info> <comment>(Default: Bootstrap)</comment>', $frameworks, 0);
|
||||
|
||||
switch($framework) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
file_put_contents('package.json', preg_replace("/{$default_framework_pattern}/", '"foundation-sites": "6.3.0"', file_get_contents('package.json')));
|
||||
file_put_contents('resources/assets/styles/main.scss', str_replace('@import "~bootstrap/scss/bootstrap";' . "\n", '@import "~foundation-sites/scss/foundation";' . "\n" . '@include foundation-everything;' . "\n", file_get_contents('resources/assets/styles/main.scss')));
|
||||
file_put_contents('resources/assets/scripts/main.js', str_replace("import 'bootstrap';\n", "import 'foundation-sites/dist/js/foundation';\n", file_get_contents('resources/assets/scripts/main.js')));
|
||||
foreach($files_to_clear as $file) {
|
||||
file_put_contents($file, '');
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
file_put_contents('package.json', preg_replace("/{$default_framework_pattern}/", '"tachyons-sass": "^4.7.1"', file_get_contents('package.json')));
|
||||
file_put_contents('assets/styles/main.scss', str_replace('@import "~bootstrap/scss/bootstrap";' . "\n", '@import "~tachyons-sass/tachyons";' . "\n", file_get_contents('assets/styles/main.scss')));
|
||||
file_put_contents('assets/scripts/main.js', str_replace("import 'bootstrap';\n", '', file_get_contents('assets/scripts/main.js')));
|
||||
foreach($files_to_clear as $file) {
|
||||
file_put_contents($file, '');
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
file_put_contents('package.json', preg_replace("/\s+{$default_framework_pattern},/", '', file_get_contents('package.json')));
|
||||
file_put_contents('resources/assets/styles/main.scss', str_replace('@import "~bootstrap/scss/bootstrap";' . "\n", '', file_get_contents('resources/assets/styles/main.scss')));
|
||||
file_put_contents('resources/assets/scripts/main.js', str_replace("import 'bootstrap';\n", '', file_get_contents('resources/assets/scripts/main.js')));
|
||||
foreach($files_to_clear as $file) {
|
||||
file_put_contents($file, '');
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function addFontAwesome(Event $event)
|
||||
{
|
||||
$io = $event->getIO();
|
||||
|
||||
if ($io->isInteractive()) {
|
||||
if ($io->askConfirmation('<info>Add Font Awesome?</info> [<comment>y,N</comment>]? ', false)) {
|
||||
$package = json_decode(file_get_contents('package.json'), true);
|
||||
$dependencies = $package['dependencies'];
|
||||
$dependencies = array_merge($dependencies, ['font-awesome' => '^4.7.0']);
|
||||
$package['dependencies'] = $dependencies;
|
||||
$package = str_replace(' ', ' ', json_encode($package, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n");
|
||||
file_put_contents('package.json', $package);
|
||||
|
||||
$import_dep_str = '// Import npm dependencies' . "\n";
|
||||
file_put_contents('resources/assets/styles/main.scss', str_replace($import_dep_str, $import_dep_str . '@import "~font-awesome/scss/font-awesome";' . "\n", file_get_contents('resources/assets/styles/main.scss')));
|
||||
file_put_contents('resources/assets/styles/common/_variables.scss', "\n" . '$fa-font-path: \'~font-awesome/fonts\';' . "\n", FILE_APPEND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function buildOptions(Event $event)
|
||||
{
|
||||
$io = $event->getIO();
|
||||
|
||||
if ($io->isInteractive()) {
|
||||
$io->write('<info>Configure build settings. Press enter key for default.</info>');
|
||||
|
||||
$browsersync_settings_default = [
|
||||
'publicPath' => '/app/themes/'.basename(getcwd()),
|
||||
'devUrl' => 'http://example.dev'
|
||||
];
|
||||
|
||||
$browsersync_settings = [
|
||||
'publicPath' => $io->ask('<info>Path to theme directory (eg. /wp-content/themes/sage) [<comment>'.$browsersync_settings_default['publicPath'].'</comment>]:</info> ', $browsersync_settings_default['publicPath']),
|
||||
'devUrl' => $io->ask('<info>Local development URL of WP site [<comment>'.$browsersync_settings_default['devUrl'].'</comment>]:</info> ', $browsersync_settings_default['devUrl'])
|
||||
];
|
||||
|
||||
file_put_contents('resources/assets/config.json', str_replace('/app/themes/sage', $browsersync_settings['publicPath'], file_get_contents('resources/assets/config.json')));
|
||||
file_put_contents('resources/assets/config.json', str_replace($browsersync_settings_default['devUrl'], $browsersync_settings['devUrl'], file_get_contents('resources/assets/config.json')));
|
||||
}
|
||||
}
|
||||
// @codingStandardsIgnoreEnd
|
||||
}
|
||||
129
app/lib/Sage/Template/Blade.php
Normal file
129
app/lib/Sage/Template/Blade.php
Normal file
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
namespace Roots\Sage\Template;
|
||||
|
||||
use Illuminate\Contracts\Container\Container as ContainerContract;
|
||||
use Illuminate\Contracts\View\Factory as FactoryContract;
|
||||
use Illuminate\View\Engines\CompilerEngine;
|
||||
use Illuminate\View\Engines\EngineInterface;
|
||||
use Illuminate\View\ViewFinderInterface;
|
||||
|
||||
/**
|
||||
* Class BladeProvider
|
||||
* @method \Illuminate\View\View file($file, $data = [], $mergeData = [])
|
||||
* @method \Illuminate\View\View make($file, $data = [], $mergeData = [])
|
||||
*/
|
||||
class Blade
|
||||
{
|
||||
/** @var ContainerContract */
|
||||
protected $app;
|
||||
|
||||
public function __construct(FactoryContract $env, ContainerContract $app)
|
||||
{
|
||||
$this->env = $env;
|
||||
$this->app = $app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the compiler
|
||||
*
|
||||
* @return \Illuminate\View\Compilers\BladeCompiler
|
||||
*/
|
||||
public function compiler()
|
||||
{
|
||||
static $engineResolver;
|
||||
if (!$engineResolver) {
|
||||
$engineResolver = $this->app->make('view.engine.resolver');
|
||||
}
|
||||
return $engineResolver->resolve('blade')->getCompiler();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $view
|
||||
* @param array $data
|
||||
* @param array $mergeData
|
||||
* @return string
|
||||
*/
|
||||
public function render($view, $data = [], $mergeData = [])
|
||||
{
|
||||
/** @var \Illuminate\Contracts\Filesystem\Filesystem $filesystem */
|
||||
$filesystem = $this->app['files'];
|
||||
return $this->{$filesystem->exists($view) ? 'file' : 'make'}($view, $data, $mergeData)->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
* @param array $data
|
||||
* @param array $mergeData
|
||||
* @return string
|
||||
*/
|
||||
public function compiledPath($file, $data = [], $mergeData = [])
|
||||
{
|
||||
$rendered = $this->file($file, $data, $mergeData);
|
||||
/** @var EngineInterface $engine */
|
||||
$engine = $rendered->getEngine();
|
||||
|
||||
if (!($engine instanceof CompilerEngine)) {
|
||||
// Using PhpEngine, so just return the file
|
||||
return $file;
|
||||
}
|
||||
|
||||
$compiler = $engine->getCompiler();
|
||||
$compiledPath = $compiler->getCompiledPath($rendered->getPath());
|
||||
if ($compiler->isExpired($compiledPath)) {
|
||||
$compiler->compile($file);
|
||||
}
|
||||
return $compiledPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
* @return string
|
||||
*/
|
||||
public function normalizeViewPath($file)
|
||||
{
|
||||
// Convert `\` to `/`
|
||||
$view = str_replace('\\', '/', $file);
|
||||
|
||||
// Add namespace to path if necessary
|
||||
$view = $this->applyNamespaceToPath($view);
|
||||
|
||||
// Remove unnecessary parts of the path
|
||||
$view = str_replace(array_merge($this->app['config']['view.paths'], ['.blade.php', '.php']), '', $view);
|
||||
|
||||
// Remove superfluous and leading slashes
|
||||
return ltrim(preg_replace('%//+%', '/', $view), '/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert path to view namespace
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
public function applyNamespaceToPath($path)
|
||||
{
|
||||
/** @var ViewFinderInterface $finder */
|
||||
$finder = $this->app['view.finder'];
|
||||
if (!method_exists($finder, 'getHints')) {
|
||||
return $path;
|
||||
}
|
||||
$delimiter = $finder::HINT_PATH_DELIMITER;
|
||||
$hints = $finder->getHints();
|
||||
$view = array_reduce(array_keys($hints), function ($view, $namespace) use ($delimiter, $hints) {
|
||||
return str_replace($hints[$namespace], $namespace.$delimiter, $view);
|
||||
}, $path);
|
||||
return preg_replace("%{$delimiter}[\\/]*%", $delimiter, $view);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass any method to the view Factory instance.
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $params
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call($method, $params)
|
||||
{
|
||||
return call_user_func_array([$this->env, $method], $params);
|
||||
}
|
||||
}
|
||||
91
app/lib/Sage/Template/BladeProvider.php
Normal file
91
app/lib/Sage/Template/BladeProvider.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace Roots\Sage\Template;
|
||||
|
||||
use Illuminate\Container\Container;
|
||||
use Illuminate\Contracts\Container\Container as ContainerContract;
|
||||
use Illuminate\Events\Dispatcher;
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
use Illuminate\View\ViewServiceProvider;
|
||||
|
||||
/**
|
||||
* Class BladeProvider
|
||||
*/
|
||||
class BladeProvider extends ViewServiceProvider
|
||||
{
|
||||
/**
|
||||
* @param ContainerContract $container
|
||||
* @param array $config
|
||||
* @SuppressWarnings(PHPMD.StaticAccess)
|
||||
*/
|
||||
public function __construct(ContainerContract $container = null, $config = [])
|
||||
{
|
||||
/** @noinspection PhpParamsInspection */
|
||||
parent::__construct($container ?: Container::getInstance());
|
||||
|
||||
$this->app->bindIf('config', function () use ($config) {
|
||||
return $config;
|
||||
}, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind required instances for the service provider.
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
$this->registerFilesystem();
|
||||
$this->registerEvents();
|
||||
$this->registerEngineResolver();
|
||||
$this->registerViewFinder();
|
||||
$this->registerFactory();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Filesystem
|
||||
*/
|
||||
public function registerFilesystem()
|
||||
{
|
||||
$this->app->bindIf('files', Filesystem::class, true);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the events dispatcher
|
||||
*/
|
||||
public function registerEvents()
|
||||
{
|
||||
$this->app->bindIf('events', Dispatcher::class, true);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function registerEngineResolver()
|
||||
{
|
||||
parent::registerEngineResolver();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function registerFactory()
|
||||
{
|
||||
parent::registerFactory();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the view finder implementation.
|
||||
*/
|
||||
public function registerViewFinder()
|
||||
{
|
||||
$this->app->bindIf('view.finder', function ($app) {
|
||||
$config = $this->app['config'];
|
||||
$paths = $config['view.paths'];
|
||||
$namespaces = $config['view.namespaces'];
|
||||
$finder = new FileViewFinder($app['files'], $paths);
|
||||
array_map([$finder, 'addNamespace'], array_keys($namespaces), $namespaces);
|
||||
return $finder;
|
||||
}, true);
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
40
app/lib/Sage/Template/FileViewFinder.php
Normal file
40
app/lib/Sage/Template/FileViewFinder.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Roots\Sage\Template;
|
||||
|
||||
class FileViewFinder extends \Illuminate\View\FileViewFinder
|
||||
{
|
||||
const FALLBACK_PARTS_DELIMITER = '-';
|
||||
|
||||
/**
|
||||
* Get an array of possible view files from a single file name.
|
||||
*
|
||||
* @param string $name
|
||||
* @return array
|
||||
*/
|
||||
public function getPossibleViewFiles($name)
|
||||
{
|
||||
$parts = explode(self::FALLBACK_PARTS_DELIMITER, $name);
|
||||
$templates[] = array_shift($parts);
|
||||
foreach ($parts as $i => $part) {
|
||||
$templates[] = $templates[$i].self::FALLBACK_PARTS_DELIMITER.$part;
|
||||
}
|
||||
rsort($templates);
|
||||
return $this->getPossibleViewFilesFromTemplates($templates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of possible view files from an array of templates
|
||||
*
|
||||
* @param array $templates
|
||||
* @return array
|
||||
*/
|
||||
public function getPossibleViewFilesFromTemplates($templates)
|
||||
{
|
||||
return call_user_func_array('array_merge', array_map(function ($template) {
|
||||
return array_map(function ($extension) use ($template) {
|
||||
return str_replace('.', '/', $template).'.'.$extension;
|
||||
}, $this->extensions);
|
||||
}, $templates));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user