Skip to content

Commit

Permalink
[#72] Implement new parts kit template code
Browse files Browse the repository at this point in the history
  • Loading branch information
joshuapease committed Dec 22, 2023
1 parent 9572db3 commit fa537b4
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 312 deletions.
10 changes: 0 additions & 10 deletions src/Module.php
Original file line number Diff line number Diff line change
Expand Up @@ -174,16 +174,6 @@ function (RegisterTemplateRootsEvent $e) {
}
}
);

Event::on(
UrlManager::class,
UrlManager::EVENT_REGISTER_SITE_URL_RULES,
function (RegisterUrlRulesEvent $event) {
$partsKitDir = self::$config['partsKit']['directory'];

$event->rules[$partsKitDir] = 'parts-kit/redirect-index';
}
);
}
}

Expand Down
16 changes: 0 additions & 16 deletions src/controllers/PartsKitController.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,6 @@ class PartsKitController extends \craft\web\Controller
{
protected array|int|bool $allowAnonymous = true;

/**
* Redirect to the first component in the parts kit
*
* @return Response
*/
public function actionRedirectIndex(): Response
{
$redirectUrl = Module::getInstance()->partsKit->getFirstNavUrl();

if (!$redirectUrl) {
throw new \Exception('Looks like you don’t have any parts kit components setup yet.');
}

return $this->redirect($redirectUrl, 301);
}

public function actionConfig(): Response
{
return $this->asJson([
Expand Down
2 changes: 1 addition & 1 deletion src/models/NavNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ class NavNode implements \JsonSerializable
{
public function __construct(
public string $title,
public string $url,
public string $path,
public ?string $url = null,
public array $children = [],
)
{}
Expand Down
146 changes: 23 additions & 123 deletions src/services/PartsKit.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
use craft\helpers\StringHelper;
use craft\helpers\FileHelper;
use craft\helpers\Template as TemplateHelper;
use craft\helpers\ArrayHelper;
use craft\elements\Asset;
use Twig\Markup;
use viget\base\models\NavNode;
Expand All @@ -27,6 +26,16 @@ public static function isRequest(): bool
return (Craft::$app->request->segments[0] ?? null) === self::getConfig('directory');
}

/**
* Determine if this is a request to the root of the parts kit
* @return bool
*/
public static function isRootRequest(): bool
{
$isRoot = count(Craft::$app->request->getSegments()) === 1;
return $isRoot && self::isRequest();
}

/**
* Get a config item either the default or from the config file
*
Expand All @@ -46,7 +55,8 @@ public static function getConfig(string $key)
public static function getNav(): array
{
$templatesPath = Craft::$app->getPath()->getSiteTemplatesPath();
$partsPath = $templatesPath . '/' . 'parts-kit' . '/';
$partsKitFolderName = self::getConfig('directory');
$partsPath = $templatesPath . '/' . $partsKitFolderName . '/';

// Combine and sort all files & directories in the parts kit
$directories = \yii\helpers\FileHelper::findDirectories($partsPath);
Expand All @@ -67,13 +77,15 @@ public static function getNav(): array
foreach ($templates as $templatePath) {
$path = str_replace($partsPath, '', $templatePath);
$pathParts = explode('/', $path);
// TODO format name
$title = end($pathParts);
$title = self::_formatTitle(end($pathParts));
$url = is_file($templatePath)
? '/' . $partsKitFolderName . '/' . self::_removeExtension($path)
: null;

$result[$path] = new NavNode(
title: $title,
url: $path, // TODO only use URL if there's a file
path: $path,
url: $url,
);
}

Expand All @@ -100,128 +112,13 @@ public static function getNav(): array
return array_values($result);
}

/**
* Get the first component's URL
*
* @return string|null
*/
public static function getFirstNavUrl(): ?string
{
$nav = self::getNav();
$firstUrl = ArrayHelper::firstValue($nav)['items'][0]['url'] ?? null;

if (!$firstUrl) return null;

return parse_url($firstUrl)['path'];
}

/**
* Get the CSS variables that power the theme
*
* @return string
*/
public static function getTheme(): string
{
$themes = [
'light' => [
'background' => '#ededed',
'main-background' => '#fff',
'text' => '#202020',
'nav-icon' => '#148bbe',
'nav-item-text-hover' => '#202020',
'nav-item-background-hover' => '#dbdbdb',
'nav-subitem-text-hover' => '#202020',
'nav-subitem-background-hover' => '#dbdbdb',
'nav-subitem-background-active' => '#148bbe',
'nav-subitem-text-active' => '#fff',
'controls-text' => '#a7a9ac',
'controls-border' => '#dbdbdb',
],

'dark' => [
'background' => '#2f2f2f',
'main-background' => '#333',
'text' => 'rgba(255, 255, 255, 0.8)',
'nav-icon' => '#1ea7fd',
'nav-item-text-hover' => '#fff',
'nav-item-background-hover' => 'rgba(250, 250, 252, 0.1)',
'nav-subitem-text-hover' => '#fff',
'nav-subitem-background-hover' => 'rgba(250, 250, 252, 0.1)',
'nav-subitem-background-active' => '#1ea7fd',
'nav-subitem-text-active' => '#fff',
'controls-text' => '#999',
'controls-border' => 'rgba(255, 255, 255, 0.1)',
],
];

$theme = self::getConfig('theme');

// If a theme name is passed instead of
// custom config, select that theme
if (!is_array($theme)) {
$theme = $themes[$theme] ?? $themes['light'];
}

$css = [];
foreach ($theme as $property => $value) {
$css[] = "--pk-{$property}: {$value};";
}
return implode('', $css);
}

/**
* Get templates in parts kit folder
*
* @param string $partsKitDir
* @return array
*/
private static function _getTemplates(string $partsKitDir): array
{
$templates = [];

$templatesPath = Craft::$app->getPath()->getSiteTemplatesPath();
$partsPath = $templatesPath . '/' . $partsKitDir . '/';

if (!is_dir($partsPath)) return [];

$files = FileHelper::findFiles($partsPath);

foreach ($files as $file) {
$file = str_replace($partsPath, '', $file);
$count = substr_count($file, '/');

// This doesn't fit the dir/file structure, so ignore
if ($count !== 1) continue;

$fileParts = explode('/', $file);
$dir = $fileParts[0];
$fileName = $fileParts[1];

// Don't include templates that are "hidden"
if ($fileName[0] === '_' || $fileName[0] === '.') continue;

// Key already exists, add to array
if (array_key_exists($dir, $templates)) {
$templates[$dir][] = self::_cleanFilename($fileName);
} else {
$templates[$dir] = [
self::_cleanFilename($fileName),
];
}
}

ksort($templates, SORT_NATURAL);

return $templates;
}

/**
* Remove extension from file name
*
* @param string $file
* @return string
*/
private static function _cleanFileName(string $file): string
private static function _removeExtension(string $file): string
{
$extensions = array_map(function($extension) {
return '.' . $extension;
Expand All @@ -236,9 +133,12 @@ private static function _cleanFileName(string $file): string
* @param string $str
* @return string
*/
private static function _formatName(string $str): string
private static function _formatTitle(string $str): string
{
return str_replace('-', ' ', StringHelper::humanize($str));
$str = self::_removeExtension($str);
$str = StringHelper::toKebabCase($str);
$str = StringHelper::humanize($str);
return str_replace('-', ' ', $str);
}

/**
Expand Down
16 changes: 16 additions & 0 deletions src/templates/_layouts/parts-kit-root.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Parts Kit</title>
<meta name="robots" content="none">
</head>
<body>
<script
type="module"
src="https://unpkg.com/@viget/parts-kit@^0/lib/parts-kit.js"
></script>
<parts-kit config-url="{{ actionUrl('parts-kit/config') }}"></parts-kit>
</body>
</html>
114 changes: 6 additions & 108 deletions src/templates/_layouts/parts-kit.html
Original file line number Diff line number Diff line change
@@ -1,111 +1,9 @@
{% extends craft.viget.partsKit.getConfig('layout') %}
{% extends craft.viget.partsKit.isRootRequest()
? 'viget-base/_layouts/parts-kit-root'
: craft.viget.partsKit.getConfig('layout')
%}

{% block content %}
<style>
.parts-kit {
{{ craft.viget.partsKit.getTheme() }}
}
</style>

<div class="parts-kit" data-parts-kit data-turbo="false">
<aside
class="parts-kit__sidebar"
data-sidebar
>
<h2 class="parts-kit__sr-only">Parts Navigation</h2>

<label class="parts-kit__sr-only" for="pk-search">Search parts kit</label>
<div class="parts-kit__search">
<input class="parts-kit__search-input"
id="pk-search"
type="search"
placeholder="Press / to search..."
data-focus-placeholder="Type to search..."
data-sidebar-search
>
{{ svg('@viget/base/resources/icons/search.svg') | attr({
class: 'parts-kit__search-icon',
}) }}
</div>

{% set navSections = craft.viget.partsKit.getNav() %}

{% if navSections %}
<ol class="parts-kit__nav">
{% for title, section in navSections %}
{% set id = "nav-section-#{loop.index}" %}

<li data-parts-kit-toggle
{% if section.isActive %}data-active-section{% endif %}
>
<button
class="parts-kit__button parts-kit__nav-button"
aria-controls="{{ id }}"
aria-expanded="{{ section.isActive ? 'true' : 'false' }}"
>
<div class="flex">
{{ svg('@viget/base/resources/icons/caret.svg') | attr({
class: 'parts-kit__nav-caret',
}) }}
{{ svg('@viget/base/resources/icons/pk-component.svg') | attr({
class: 'parts-kit__nav-component',
}) }}
<h3>{{ title | title }}</h3>
</div>
</button>

<ol
class="parts-kit__nav-sub-items {% if not section.isActive %}collapsed{% endif %}"
id="{{ id }}"
data-togglee
>
{% for item in section.items %}
<li data-section-item
data-search-text="{{ title ~ ' ' ~ item.title }}"
>
<a
href="{{ url(item.url) }}"
{% if item.isActive %}class="active"{% endif %}
>
<div class="flex">
{{ svg('@viget/base/resources/icons/pk-sidebar.svg') | attr({
class: 'parts-kit__nav-story',
}) }}
{{ item.title }}
</div>
</a>
</li>
{% endfor %}
</ol>
</li>
{% endfor %}
</ol>
{% endif %}
</aside>

<div class="parts-kit__main">
<div class="parts-kit__main-wrapper">
<div class="parts-kit__main-header">
<button
class="parts-kit__button hidden hover:text-robins-egg"
data-fullscreen-expand
>
<span class="parts-kit__sr-only">Expand</span>
{{ svg('@viget/base/resources/icons/pk-expand.svg') }}
</button>
<button
class="parts-kit__button hidden hover:text-robins-egg"
data-fullscreen-close
>
<span class="parts-kit__sr-only">Close</span>
{{ svg('@viget/base/resources/icons/close-circle.svg') }}
</button>
</div>

<div class="parts-kit__main-container">
{% block main %}{% endblock %}
</div>
</div>
</div>
</div>
{% block main %}
{% endblock %}
{% endblock %}
Loading

0 comments on commit fa537b4

Please sign in to comment.