Skip to content

Commit 1398ffe

Browse files
jackmcdadeJayGeorgeduncanmcclean
authored
Redesign (#1477)
Co-authored-by: Jay George <[email protected]> Co-authored-by: Duncan McClean <[email protected]>
1 parent 6642886 commit 1398ffe

File tree

395 files changed

+12779
-18759
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

395 files changed

+12779
-18759
lines changed

.env.example

+15-9
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,28 @@ REDIS_HOST=127.0.0.1
2323
REDIS_PASSWORD=null
2424
REDIS_PORT=6379
2525

26-
MAIL_DRIVER=smtp
27-
MAIL_HOST=smtp.mailtrap.io
26+
MAIL_MAILER=log
27+
MAIL_SCHEME=null
28+
MAIL_HOST=127.0.0.1
2829
MAIL_PORT=2525
2930
MAIL_USERNAME=null
3031
MAIL_PASSWORD=null
31-
MAIL_ENCRYPTION=null
32+
MAIL_FROM_ADDRESS="[email protected]"
33+
MAIL_FROM_NAME="${APP_NAME}"
3234

3335
AWS_ACCESS_KEY_ID=
3436
AWS_SECRET_ACCESS_KEY=
3537
AWS_DEFAULT_REGION=us-east-1
3638
AWS_BUCKET=
39+
AWS_USE_PATH_STYLE_ENDPOINT=false
3740

38-
PUSHER_APP_ID=
39-
PUSHER_APP_KEY=
40-
PUSHER_APP_SECRET=
41-
PUSHER_APP_CLUSTER=mt1
41+
VITE_APP_NAME="${APP_NAME}"
4242

43-
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
44-
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
43+
TORCHLIGHT_TOKEN=
44+
45+
GITHUB_CLIENT_ID=
46+
GITHUB_CLIENT_SECRET=
47+
48+
SEARCH_DRIVER=local
49+
MEILISEARCH_HOST=
50+
MEILISEARCH_KEY=

.gitignore

-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
/node_modules
33
/public/hot
44
/public/storage
5-
/public/css
65
/public/vendor/statamic
76
/public/js
87
/storage/*.key

app/Http/View/Composers/SideNavComposer.php

-43
This file was deleted.

app/Markdown/Hint/Hint.php

+4
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ public function getTitle(): ?string
2626
return 'Hot Tip!';
2727
}
2828

29+
if ($words[0] === 'hint') {
30+
return 'Hinty Hint!';
31+
}
32+
2933
if ($words[0] === 'warning') {
3034
return 'Warning!';
3135
}

app/Markdown/Hint/HintRenderer.php

+12-10
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ public function render(Node $node, ChildNodeRendererInterface $childRenderer): \
2121
Hint::assertInstanceOf($node);
2222

2323
$attrs = $node->data->get('attributes');
24-
isset($attrs['class']) ? $attrs['class'] .= ' hint' : $attrs['class'] = 'hint';
24+
isset($attrs['class']) ? $attrs['class'] .= ' hint' : $attrs['class'] = 'c-tip';
2525

2626
if ($type = $node->getType()) {
2727
$attrs['class'] = isset($attrs['class']) ? $attrs['class'].' ' : '';
28-
$attrs['class'] .= $type;
28+
$attrs['class'] .= $type.' c-tip--'.$type;
2929
}
3030

3131
if ($type === 'watch') {
@@ -41,18 +41,20 @@ public function render(Node $node, ChildNodeRendererInterface $childRenderer): \
4141
)
4242
: '';
4343

44-
$content = new HtmlElement(
45-
'p',
46-
['class' => 'hint-content'],
47-
$childRenderer->renderNodes($node->children())
48-
);
44+
$content = $childRenderer->renderNodes($node->children());
45+
46+
// Add mascot image for tips and best practices
47+
$mascot = in_array($type, ['tip', 'hint', 'best-practice', 'warning'])
48+
? '<img src="/img/tip-troll.webp" class="c-tip__mascot" alt="A troll pointing a teaching stick" width="242" height="293" />'
49+
: '';
4950

5051
return new HtmlElement(
5152
'div',
5253
$attrs,
5354
"\n".
5455
$title."\n".
5556
$content.
57+
$mascot.
5658
"\n"
5759
);
5860
}
@@ -68,10 +70,10 @@ private function renderWatch(Hint $node, ChildNodeRendererInterface $childRender
6870
return new HtmlElement(
6971
'div',
7072
$attrs,
71-
'<div class="embed">'.
73+
'<figure class="c-video">'.
7274
'<iframe src="'.$node->getTitle().'"></iframe>'.
73-
'</div>'.
74-
$caption
75+
'<figcaption>'.$caption.'</figcaption>'.
76+
'</figure>'
7577
);
7678
}
7779
}

app/Markdown/Tabs/TabsRenderer.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public function render(Node $node, ChildNodeRendererInterface $childRenderer)
2525

2626
$attrs = $node->data->get('attributes');
2727

28-
$attrs['class'] = 'doc-tabs';
28+
$attrs['class'] = 'c-doc-tabs';
2929

3030
$tabs = [];
3131

app/Modifiers/Toc.php

+49-59
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
namespace App\Modifiers;
44

5+
use Illuminate\Support\Arr;
56
use Statamic\Modifiers\Modifier;
7+
use Statamic\Statamic;
68

79
class Toc extends Modifier
810
{
@@ -11,57 +13,68 @@ class Toc extends Modifier
1113
/**
1214
* Modify a value
1315
*
14-
* @param mixed $value The value to be modified
15-
* @param array $params Any parameters used in the modifier
16-
* @param array $context Contextual values
16+
* @param mixed $value The value to be modified
17+
* @param array $params Any parameters used in the modifier
18+
* @param array $context Contextual values
1719
* @return mixed
1820
*/
1921
public function index($value, $params, $context)
2022
{
2123
$this->context = $context;
2224

23-
$creatingIds = array_get($params, 0) == 'ids';
25+
$creatingIds = Arr::get($params, 0) == 'ids';
2426

25-
list($toc, $content) = $this->create($value, $creatingIds ? 5 : 3);
27+
// Here maxHeadingLevels is set to either 5 (when creating IDs) or 3 (for TOC)
28+
[$toc, $content] = $this->create($value, $creatingIds ? 5 : 3);
2629

2730
return $creatingIds ? $content : $toc;
2831
}
2932

3033
// Good golly this thing is ugly.
3134
private function create($content, $maxHeadingLevels)
3235
{
33-
preg_match_all('/<h([1-'.$maxHeadingLevels.'])([^>]*)>(.*)<\/h[1-'.$maxHeadingLevels.']>/i', $content, $matches, PREG_SET_ORDER);
36+
// First try with h2-hN headings
37+
preg_match_all('/<h([2-'.$maxHeadingLevels.'])([^>]*)>(.*)<\/h[2-'.$maxHeadingLevels.']>/i', $content, $matches, PREG_SET_ORDER);
38+
39+
// If we don't have enough entries, include h1 headings as well
40+
if (count($matches) < 3) {
41+
preg_match_all('/<h([1-'.$maxHeadingLevels.'])([^>]*)>(.*)<\/h[1-'.$maxHeadingLevels.']>/i', $content, $matches, PREG_SET_ORDER);
42+
}
3443

3544
if (! $matches) {
3645
return [null, $content];
3746
}
3847

48+
// Track unique anchor IDs across the document
3949
global $anchors;
50+
$anchors = [];
4051

41-
$anchors = array();
42-
$toc = '<ol class="toc">'."\n";
52+
// Initialize TOC with an unordered list
53+
$toc = '<ul class="o-scroll-spy-timeline__toc js__scroll-spy-toc">'."\n";
4354
$i = 0;
44-
45-
// Wangjangle params, vars, and options in there.
46-
$matches = $this->appendDetails($matches);
55+
$tiCounter = 1; // Add counter for --ti values
4756

4857
foreach ($matches as $heading) {
58+
// Track the starting heading level for proper list nesting
4959
if ($i == 0) {
50-
$startlvl = $heading[1];
60+
$startlvl = ($heading[1] == '1') ? '2' : $heading[1];
5161
}
5262

53-
$lvl = $heading[1];
63+
// Normalize h1 to same level as h2
64+
$lvl = ($heading[1] == '1') ? '2' : $heading[1];
5465

66+
// Check if heading already has an ID attribute
5567
$ret = preg_match('/id=[\'|"](.*)?[\'|"]/i', stripslashes($heading[2]), $anchor);
5668

5769
if ($ret && $anchor[1] != '') {
5870
$anchor = trim(stripslashes($anchor[1]));
5971
$add_id = false;
6072
} else {
61-
$anchor = preg_replace('/\s+/', '-', trim(preg_replace('/[^a-z\s]/', '', strtolower(strip_tags($heading[3])))));
73+
// Generate an ID from the heading text
74+
$anchor = $this->slugify($heading[3]);
6275
$add_id = true;
6376
}
64-
77+
// Ensure anchor ID is unique by adding numeric suffixes if needed
6578
if (! in_array($anchor, $anchors)) {
6679
$anchors[] = $anchor;
6780
} else {
@@ -74,10 +87,12 @@ private function create($content, $maxHeadingLevels)
7487
$anchors[] = $anchor;
7588
}
7689

90+
// Add ID to the heading in content if it didn't have one
7791
if ($add_id) {
7892
$content = substr_replace($content, '<h'.$lvl.' id="'.$anchor.'"'.$heading[2].'>'.$heading[3].'</h'.$lvl.'>', strpos($content, $heading[0]), strlen($heading[0]));
7993
}
8094

95+
// Extract title from title attribute or use heading text
8196
$ret = preg_match('/title=[\'|"](.*)?[\'|"]/i', stripslashes($heading[2]), $title);
8297

8398
if ($ret && $title[1] != '') {
@@ -88,22 +103,28 @@ private function create($content, $maxHeadingLevels)
88103

89104
$title = trim(strip_tags($title));
90105

106+
// Handle nested list structure based on heading levels
91107
if ($i > 0) {
92108
if ($prevlvl < $lvl) {
93-
$toc .= "\n"."<ol>"."\n";
109+
// Start a new nested list wrapped in li, don't increment counter for parent li
110+
$toc .= "\n".'<li><ul>'."\n";
94111
} elseif ($prevlvl > $lvl) {
112+
// Close current item and any nested lists
95113
$toc .= '</li>'."\n";
96114
while ($prevlvl > $lvl) {
97-
$toc .= "</ol>"."\n".'</li>'."\n";
115+
$toc .= '</ul></li>'."\n".'</li>'."\n";
98116
$prevlvl--;
99117
}
100118
} else {
119+
// Close current item at same level
101120
$toc .= '</li>'."\n";
102121
}
103122
}
104123

105-
$j = 0;
106-
$toc .= '<li><a href="#'.$anchor.'">'.$title.'</a>';
124+
// Add TOC entry with --ti style (only for leaf nodes)
125+
$toc .= '<li style="--ti: --'.$tiCounter.'"><a href="#'.$anchor.'">'.$title.'</a>';
126+
$tiCounter++;
127+
107128
$prevlvl = $lvl;
108129

109130
$i++;
@@ -112,19 +133,19 @@ private function create($content, $maxHeadingLevels)
112133
unset($anchors);
113134

114135
while ($lvl > $startlvl) {
115-
$toc .= "\n</ol>";
136+
$toc .= "\n</ul>";
116137
$lvl--;
117138
}
118139

119140
$toc .= '</li>'."\n";
120-
$toc .= '</ol>'."\n";
121-
122-
// A tiny TOC is a lame TOC
123-
$toc = (count($matches) < 3) ? null : $toc;
141+
$toc .= '</ul>'."\n";
124142

125143
return [$toc, $content];
126144
}
127145

146+
/**
147+
* Safely extracts value from Statamic Value objects
148+
*/
128149
private function valueGet($value)
129150
{
130151
if ($value instanceof \Statamic\Fields\Value) {
@@ -134,41 +155,10 @@ private function valueGet($value)
134155
return $value;
135156
}
136157

137-
private function appendDetails($matches)
158+
private function slugify($text)
138159
{
139-
$parameters = $this->valueGet($this->context['parameters'] ?? null);
140-
141-
if ($parameters && count($parameters) > 0) {
142-
$matches[] = [
143-
'<h2 id="parameters">Parameters</h2>',
144-
'2',
145-
' id="parameters"',
146-
'Parameters'
147-
];
148-
}
149-
150-
$variables = $this->valueGet($this->context['variables'] ?? null);
151-
152-
if ($variables && count($variables) > 0) {
153-
$matches[] = [
154-
'<h2 id="variables">Variables</h2>',
155-
'2',
156-
' id="variables"',
157-
'Variables'
158-
];
159-
}
160-
161-
$options = $this->valueGet($this->context['options'] ?? null);
162-
163-
if ($options && count($options) > 0) {
164-
$matches[] = [
165-
'<h2 id="options">Options</h2>',
166-
'2',
167-
' id="options"',
168-
'Options'
169-
];
170-
}
171-
172-
return $matches;
160+
$slugified = Statamic::modify($text)->replace('&amp;', '')->slugify()->stripTags();
161+
// Remove 'code-code' from the slugified text e.g. Otherwise "the `@` ignore symbol" gets converted to `the-code-code-ignore-symbol`
162+
return str_replace('code-code-', '', $slugified);
173163
}
174164
}

app/ViewModels/Fieldtypes.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ class Fieldtypes extends ViewModel
88
{
99
public function data(): array
1010
{
11-
return ['title' => ucwords($this->cascade->get('title')) . ' Fieldtype'];
11+
return ['title' => ucwords($this->cascade->get('title')).' Fieldtype'];
1212
}
1313
}

app/ViewModels/Tags.php

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace App\ViewModels;
4+
5+
use Statamic\View\ViewModel;
6+
7+
class Tags extends ViewModel
8+
{
9+
public function data(): array
10+
{
11+
return ['title' => ucwords($this->cascade->get('slug')).' Tag'];
12+
}
13+
}

0 commit comments

Comments
 (0)