-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
update content renderer to handle recursive layouts
- Loading branch information
1 parent
d3f4134
commit 7ce073a
Showing
1 changed file
with
94 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,87 +1,130 @@ | ||
import 'package:gengen/liquid/template.dart'; | ||
import 'package:gengen/logging.dart'; | ||
import 'package:gengen/md/md.dart'; | ||
import 'package:gengen/models/base.dart'; | ||
import 'package:gengen/sass/sass.dart'; | ||
import 'package:markdown/markdown.dart'; | ||
import 'package:gengen/site.dart'; | ||
import 'package:gengen/utilities.dart'; | ||
|
||
class Renderer { | ||
Base base; | ||
|
||
late String content; | ||
|
||
Renderer(this.base); | ||
|
||
Future<String> render() async { | ||
Renderer(this.base) { | ||
content = base.content; | ||
|
||
if (base.isMarkdown) { | ||
_renderMd(); | ||
if (containsMarkdown(content)) { | ||
content = renderMd(content); | ||
} | ||
} | ||
|
||
if (base.isAsset) { | ||
var result = compileSass( | ||
base.source, | ||
importPaths: [base.site.sassPath, base.site.theme.sassPath], | ||
); | ||
|
||
return result.css; | ||
Future<void> resolve() async { | ||
if (containsLiquid(content) || containsMarkdown(content)) { | ||
await _renderLiquid(); | ||
renderMd(content); | ||
} | ||
|
||
if (base.config.containsKey("layout")) { | ||
if (base.hasLiquid) { | ||
await _renderLiquid(); | ||
} | ||
content = await _renderWithLayout(content); | ||
} | ||
} | ||
|
||
var layouts = base.site.layouts; | ||
|
||
String? tmplKeyIndex; | ||
for (var key in layouts.keys) { | ||
if (key.startsWith( | ||
"${base.site.config.get<String>("layout_dir")}/${base.layout}", | ||
) || | ||
key.startsWith( | ||
"${base.site.theme.config.get<String>("layout_dir")}/${base.layout}", | ||
)) { | ||
tmplKeyIndex = key; | ||
} | ||
Future<String> render() async { | ||
if (base.isAsset) { | ||
try { | ||
var result = compileSass( | ||
base.source, | ||
importPaths: [Site.instance.sassPath, Site.instance.theme.sassPath], | ||
); | ||
return result.css; | ||
} catch (e) { | ||
log.severe(e.toString()); | ||
} | ||
return ""; | ||
} | ||
await resolve(); | ||
|
||
if (tmplKeyIndex == null) return ""; | ||
var tmpl = layouts[tmplKeyIndex]; | ||
return content; | ||
} | ||
|
||
tmpl?.data.addAll(base.data); | ||
tmpl?.data.addAll(base.site.data); | ||
Future<String> _renderWithLayout(String content, | ||
[String? initialLayoutName]) async { | ||
var layoutName = initialLayoutName ?? base.config["layout"] as String?; | ||
|
||
var template = Template.r( | ||
tmpl!.content, | ||
child: await _renderLiquid(), | ||
data: tmpl.data, | ||
contentRoot: ContentRoot(base.site), | ||
); | ||
if (layoutName == null) { | ||
return content; // No layout specified, return original content | ||
} | ||
|
||
return await template.render(); | ||
var layoutPath = _findLayoutPath(layoutName); | ||
|
||
if (layoutPath == null) { | ||
return content; // Layout not found, return original content | ||
} | ||
|
||
if (base.hasLiquid) { | ||
content = await _renderLiquid(); | ||
var tmpl = Site.instance.layouts[layoutPath]; | ||
if (tmpl == null) { | ||
return content; // Template is null, return original content | ||
} | ||
|
||
return content; | ||
// Add page data and site-wide data to the template's data | ||
tmpl.data.addAll({"page": base.to_liquid}); | ||
tmpl.data.addAll(Site.instance.data); | ||
|
||
// Render the current layout with its content | ||
var template = Template.r( | ||
tmpl.content, | ||
child: content, | ||
// Pass the current content as the child content to be included in the layout | ||
data: tmpl.data, | ||
contentRoot: ContentRoot(), | ||
); | ||
|
||
var renderedContent = await safeRender(template); | ||
|
||
// Check if the current layout specifies another layout | ||
var nestedLayoutName = tmpl.data["layout"] as String?; | ||
if (nestedLayoutName != null) { | ||
// If there's a nested layout, recursively render the content with the nested layout | ||
return _renderWithLayout(renderedContent, nestedLayoutName); | ||
} | ||
|
||
return renderedContent; | ||
} | ||
|
||
void _renderMd() { | ||
content = markdownToHtml(content); | ||
Future<String> safeRender(Template template) async { | ||
try { | ||
return await template.render(); | ||
} catch (err, st) { | ||
log.severe("Error rendering template: ${base.filePath}"); | ||
log.severe(err); | ||
log.severe(st); | ||
return ''; | ||
} | ||
} | ||
|
||
Future<String> _renderLiquid() async { | ||
Future<void> _renderLiquid() async { | ||
var template = Template.r( | ||
content, | ||
data: { | ||
...base.data, | ||
...base.site.data, | ||
"page": base.to_liquid, | ||
...Site.instance.data, | ||
}, | ||
contentRoot: ContentRoot(base.site), | ||
contentRoot: ContentRoot(), | ||
); | ||
|
||
return await template.render(); | ||
content = await safeRender(template); | ||
} | ||
|
||
String? _findLayoutPath(String layoutName) { | ||
var layoutDir = Site.instance.config.get<String>("layout_dir"); | ||
var themeLayoutDir = Site.instance.theme.config.get<String>("layout_dir"); | ||
var possiblePaths = [ | ||
"$layoutDir/$layoutName", | ||
"$themeLayoutDir/$layoutName", | ||
]; | ||
|
||
return Site.instance.layouts.keys.firstWhere( | ||
(k) => possiblePaths.contains(k), | ||
orElse: () => '', | ||
); | ||
} | ||
} |