Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: nested sections support #1704

Draft
wants to merge 44 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
30de27f
test: enhances fixtures
ArnaudLigny May 28, 2023
3c678cf
test: add fixtures
ArnaudLigny May 28, 2023
7209c31
feat: nested sections support
ArnaudLigny May 28, 2023
b681d62
Merge branch 'master' into nested-sections
ArnaudLigny May 29, 2023
33f466a
Update Load.php
ArnaudLigny May 29, 2023
bca272e
Update Create.php
ArnaudLigny May 29, 2023
30b3853
Update Pagination.php
ArnaudLigny May 29, 2023
6be1b24
Update Page.php
ArnaudLigny May 29, 2023
54d13d6
Merge branch 'master' into nested-sections
ArnaudLigny May 30, 2023
96df21c
WIP
ArnaudLigny May 30, 2023
af1a404
Update Section.php
ArnaudLigny May 30, 2023
c50b4c8
Update Pagination.php
ArnaudLigny May 30, 2023
d99b671
chore: update deps
ArnaudLigny May 31, 2023
c5be500
Update Page.php
ArnaudLigny May 31, 2023
8f2194a
Update Create.php
ArnaudLigny May 31, 2023
497226e
Update Page.php
ArnaudLigny May 31, 2023
2d40b2f
WIP
ArnaudLigny May 31, 2023
7dbf342
Merge branch 'master' into nested-sections
ArnaudLigny Feb 12, 2024
e2100c0
fix: comments in fixture template
ArnaudLigny Feb 12, 2024
5bb2cd1
fix: errors during main branch merging
ArnaudLigny Feb 12, 2024
025782b
WIP
ArnaudLigny Feb 13, 2024
6180fc8
WIP
ArnaudLigny Feb 13, 2024
cd3fad1
Update Section.php
ArnaudLigny Feb 15, 2024
59af3d4
Update page.html.twig
ArnaudLigny Feb 15, 2024
a4ed2d5
Create breadcrumb.html.twig
ArnaudLigny Feb 15, 2024
dbb56fa
Update page.html.twig
ArnaudLigny Feb 15, 2024
d69b646
Update Create.php
ArnaudLigny Feb 15, 2024
ab19a16
Update Load.php
ArnaudLigny Feb 15, 2024
8e6510f
Update Page.php
ArnaudLigny Feb 20, 2024
91a2d50
WIP
ArnaudLigny Feb 21, 2024
8937900
It works \o/
ArnaudLigny Feb 22, 2024
5b8e96e
Apply fixes from StyleCI (#1911)
ArnaudLigny Feb 22, 2024
f128a7b
Update Render.php
ArnaudLigny Feb 22, 2024
dd421e1
Merge branch 'nested-sections' of https://github.com/Cecilapp/Cecil i…
ArnaudLigny Feb 22, 2024
4e9d53e
Merge branch 'master' into nested-sections
ArnaudLigny Feb 23, 2024
595b145
fix ancestors
ArnaudLigny Feb 23, 2024
ed4badf
Update Render.php
ArnaudLigny Feb 23, 2024
37f3027
test: update fixtures
ArnaudLigny Feb 23, 2024
a6db179
Update Page.php
ArnaudLigny Feb 23, 2024
6ff6f77
Update Render.php
ArnaudLigny Feb 23, 2024
299e068
Update intl.html.twig
ArnaudLigny Feb 23, 2024
54b7bb0
test: update fixtures
ArnaudLigny Feb 23, 2024
264585e
Update Section.php
ArnaudLigny Feb 23, 2024
d5a8b93
Update Section.php
ArnaudLigny Feb 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions resources/layouts/_default/page.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,22 @@
nav a:hover:not(main) {
text-decoration: underline;
}
nav.breadcrumb ol {
display: flex;
flex-wrap: wrap;
list-style: none;
margin: 0;
padding: 0;
}
nav.breadcrumb li {
margin: 0;
font-size: 0.875rem;
}
nav.breadcrumb li:not(:last-child)::after {
margin: .25rem;
content: "›";
opacity: .5;
}
main header {
background: unset;
border-bottom: unset;
Expand Down Expand Up @@ -157,6 +173,7 @@
{%- endblock header ~%}
</header>
<main>
{%- include 'partials/breadcrumb.html.twig' with {page: page} only ~%}
{%- block content ~%}
{{ page.content }}
{%- endblock content ~%}
Expand Down
19 changes: 19 additions & 0 deletions resources/layouts/partials/breadcrumb.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{%- if page.type != 'homepage' and page.ancestors|default([])|length > 0 ~%}
<nav aria-label="breadcrumb" class="breadcrumb">
<ol>
{%- for item in page.ancestors|reverse ~%}
<li>
{%- if loop.index == 1 ~%}
<a aria-label="{% trans %}Home page{% endtrans %}" href="{{ url(site.home) }}">
{%- else ~%}
<a href="{{ url(item) }}">
{%- endif ~%}
{{ item.title }}</a>
</li>
{%- endfor ~%}
<li class="active">
<a aria-current="page" href="{{ url(page) }}">{{ page.title }}</a>
</li>
</ol>
</nav>
{%- endif ~%}
107 changes: 75 additions & 32 deletions src/Collection/Page/Page.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ class Page extends Item
/** @var \Cecil\Collection\Taxonomy\Vocabulary Terms of a vocabulary. */
protected $terms;

/** @var self Parent page of a PAGE page or a SECTION page */
protected $parent;

/** @var Slugify */
private static $slugifier;

Expand Down Expand Up @@ -118,20 +121,18 @@ public static function slugify(string $path): string
*/
public static function createIdFromFile(SplFileInfo $file): string
{
$relativePath = self::slugify(str_replace(DIRECTORY_SEPARATOR, '/', $file->getRelativePath()));
$basename = self::slugify(PrefixSuffix::subPrefix($file->getBasename('.' . $file->getExtension())));
// if file is "README.md", ID is "index"
$basename = (string) str_ireplace('readme', 'index', $basename);
// if file is section's index: "section/index.md", ID is "section"
$relativePath = self::slugify(self::getFileComponents($file)['path']);
$basename = self::slugify(PrefixSuffix::subPrefix(self::getFileComponents($file)['name']));
// if file is a section's index: "<section>/index.md", "<section>" is the ID
if (!empty($relativePath) && PrefixSuffix::sub($basename) == 'index') {
// case of a localized section's index: "section/index.fr.md", ID is "fr/section"
// case of a localized section's index: "<section>/index.fr.md", "<fr/section>" is the ID
if (PrefixSuffix::hasSuffix($basename)) {
return PrefixSuffix::getSuffix($basename) . '/' . $relativePath;
}

return $relativePath;
}
// localized page
// localized page: "<page>.fr.md" -> "fr/<page>"
if (PrefixSuffix::hasSuffix($basename)) {
return trim(Util::joinPath(PrefixSuffix::getSuffix($basename), $relativePath, PrefixSuffix::sub($basename)), '/');
}
Expand Down Expand Up @@ -163,15 +164,8 @@ public function setFile(SplFileInfo $file): self
/*
* File path components
*/
$fileRelativePath = str_replace(DIRECTORY_SEPARATOR, '/', $this->file->getRelativePath());
$fileExtension = $this->file->getExtension();
$fileName = $this->file->getBasename('.' . $fileExtension);
// renames "README" to "index"
$fileName = (string) str_ireplace('readme', 'index', $fileName);
// case of "index" = home page
if (empty($this->file->getRelativePath()) && PrefixSuffix::sub($fileName) == 'index') {
$this->setType(Type::HOMEPAGE->value);
}
$fileRelativePath = self::getFileComponents($file)['path'];
$fileName = self::getFileComponents($file)['name'];
/*
* Set page properties and variables
*/
Expand All @@ -184,9 +178,16 @@ public function setFile(SplFileInfo $file): self
'updated' => (new \DateTime())->setTimestamp($this->file->getMTime()),
'filepath' => $this->file->getRelativePathname(),
]);
/*
* Set specific variables
*/
// is a section?
if (PrefixSuffix::sub($fileName) == 'index') {
$this->setType(Type::SECTION->value);
$this->setVariable('title', ucfirst(explode('/', $fileRelativePath)[\count(explode('/', $fileRelativePath)) - 1]));
// is the home page?
if (empty($this->getFolder())) {
$this->setType(Type::HOMEPAGE->value);
$this->setVariable('title', 'Homepage');
}
}
// is file has a prefix?
if (PrefixSuffix::hasPrefix($fileName)) {
$prefix = PrefixSuffix::getPrefix($fileName);
Expand Down Expand Up @@ -336,37 +337,29 @@ public function getSlug(): string
public function setPath(string $path): self
{
$path = trim($path, '/');

// case of homepage
if ($path == 'index') {
$this->path = '';

return $this;
}

// case of custom sections' index (ie: section/index.md -> section)
if (substr($path, -6) == '/index') {
$path = substr($path, 0, \strlen($path) - 6);
}
$this->path = $path;

$lastslash = strrpos($this->path, '/');

// case of root/top-level pages
if ($lastslash === false) {
$this->slug = $this->path;

return $this;
}

// case of sections' pages: set section
if (!$this->virtual && $this->getSection() === null) {
$this->section = explode('/', $this->path)[0];
}
// set/update folder and slug
$this->folder = substr($this->path, 0, $lastslash);
$this->slug = substr($this->path, -(\strlen($this->path) - $lastslash - 1));

return $this;
}

Expand Down Expand Up @@ -665,6 +658,46 @@ public function getFmVariables(): array
return $this->fmVariables;
}

/**
* Set parent page.
*/
public function setParent(self $page): self
{
$this->parent = $page;

return $this;
}

/**
* Returns parent page if exists.
*/
public function getParent(): ?self
{
return $this->parent;
}

/**
* Returns array of ancestors pages.
*/
public function getAncestors(): array
{
$ancestors = [];
$currentPage = $this;
while ($currentPage->getParent() !== null) {
$ancestors[] = $currentPage = $currentPage->getParent();
}

return $ancestors;
}

/**
* {@inheritdoc}
*/
public function setId(string $id): self
{
return parent::setId($id);
}

/**
* Cast "boolean" string (or array of strings) to boolean.
*
Expand All @@ -683,10 +716,20 @@ private function filterBool(&$value)
}

/**
* {@inheritdoc}
*/
public function setId(string $id): self
{
return parent::setId($id);
* Get file components.
*
* [
* path => relative path,
* name => name,
* ext => extension,
* ]
*/
private static function getFileComponents(SplFileInfo $file): array
{
return [
'path' => str_replace(DIRECTORY_SEPARATOR, '/', $file->getRelativePath()),
'name' => (string) str_ireplace('readme', 'index', $file->getBasename('.' . $file->getExtension())),
'ext' => $file->getExtension(),
];
}
}
9 changes: 7 additions & 2 deletions src/Generator/Section.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,21 @@ public function generate(): void
{
$sections = [];

// identifying sections from all pages
// identifying sections from pages collection
/** @var Page $page */
foreach ($this->builder->getPages() as $page) {
// top level (root) sections
if ($page->getSection()) {
// do not add "not published" and "not excluded" pages to its section
// do not add "draft" and "excluded" pages to its section
if ($page->getVariable('published') !== true || $page->getVariable('exclude')) {
continue;
}
// $sections[section][language][] = $page
$sections[$page->getSection()][$page->getVariable('language', $this->config->getLanguageDefault())][] = $page;
// nested sections
/*if ($page->getParent() !== null) {
$sections[$page->getParent()->getId()][$page->getVariable('language', $this->config->getLanguageDefault())][] = $page;
}*/
}
}

Expand Down
3 changes: 1 addition & 2 deletions src/Step/Pages/Create.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ public function process(): void

$total = \count($this->builder->getPagesFiles());
$count = 0;

foreach ($this->builder->getPagesFiles() as $file) {
$count++;
// create a page from its (Markdown) file
Expand Down Expand Up @@ -110,7 +109,7 @@ public function process(): void
$this->builder->getPages()->add($page);
}

$message = sprintf('Page "%s" created', $page->getId());
$message = sprintf('Page "%s" (%s) created', $page->getId(), $page->getType());
$this->builder->getLogger()->info($message, ['progress' => [$count, $total]]);
}
}
Expand Down
9 changes: 8 additions & 1 deletion src/Step/Pages/Load.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ public function process(): void
->files()
->in($this->config->getPagesPath())
->sort(function (SplFileInfo $a, SplFileInfo $b): int {
// root pages first
if (empty($a->getRelativePath()) && !empty($b->getRelativePath())) {
return -1;
}
if (empty($b->getRelativePath()) && !empty($a->getRelativePath())) {
return 1;
}
// section's index first
if ($a->getRelativePath() == $b->getRelativePath() && $a->getBasename('.' . $a->getExtension()) == 'index') {
return -1;
Expand All @@ -66,7 +73,7 @@ public function process(): void
return 1;
}
// sort by name
return strnatcasecmp($a->getRealPath(), $b->getRealPath());
return strnatcasecmp($a->getRelativePath(), $b->getRelativePath());
});
// load only one page?
if ($this->page) {
Expand Down
Loading