Initial Commit

This commit is contained in:
2018-09-13 21:15:47 +02:00
commit 09f406cba7
84 changed files with 6920 additions and 0 deletions
+7
View File
@@ -0,0 +1,7 @@
{
"dependencies": [
"./global/base.less",
"./global/colors.less",
"./global/navbar.less"
]
}
+51
View File
@@ -0,0 +1,51 @@
module.exports = class {
onCreate(input) {
this.state = {
src: input.src,
orientation: "portrait",
style: {
filter: `opacity(${input.opacity || 0.20})`
}
}
}
onInput(input) {
if (input.src != this.state.src) {
this.updateOrientation()
}
if (input.opacity != this.state.opacity) {
this.state.style.filter = `opacity(${input.opacity || 0.20})`
}
}
onMount() {
this.updateOrientation()
}
updateOrientation() {
const image = this.getEl("image", 0)
if (image.complete && typeof(image.naturalHeight) !== 'undefined' && image.naturalHeight !== 0) {
const width = image.naturalWidth
const height = image.naturalHeight
this.setLandscape(width > (height * 1.50))
} else {
image.onload = () => {
const width = image.naturalWidth
const height = image.naturalHeight
this.setLandscape(width > (height * 1.50))
}
}
}
setLandscape(value) {
const orientation = value ? "landscape" : "portrait"
if (orientation !== this.state.orientation) {
this.state.orientation = orientation
}
}
}
+1
View File
@@ -0,0 +1 @@
<img key="image" src=input.src style=state.style class=["background", state.orientation] />
+23
View File
@@ -0,0 +1,23 @@
.background {
/* Set rules to fill background */
width: 100%;
/* Set up proportionate scaling */
min-height: 100%;
height: auto;
/* Set up positioning */
position: fixed;
top: 0;
left: 0;
user-select: none;
-webkit-user-drag: none;
z-index: -1;
}
.background.landscape {
/* Set rules to fill background */
height: 100%;
/* Set up proportionate scaling */
min-width: 100%;
width: auto;
}
@@ -0,0 +1,52 @@
const moment = require("moment")
module.exports = class {
onCreate({kind, value, updated}) {
this.state = {text: null, color: "color-menu", tooltip: null}
if (value == null || value == "") {
return
}
switch (kind) {
case "date": {
const m = moment(value)
if (m.year() < 2) {
break
}
const dateStr = m.format("MMM D, YYYY")
this.state.text = dateStr
if (updated != null && Date.parse(updated) > Date.parse(value)) {
const m2 = moment(updated)
this.state.tooltip = "Originally posted: " + dateStr
this.state.text = m2.format("MMM D, YYYY") + " *"
}
break
}
case "tag": {
this.state.color = `color-tag-${value.kind.toLowerCase()}`
this.state.text = value.name
break
}
case "author": {
this.state.text = value
break
}
default: {
this.state.color = "color-menu"
this.state.text = value
break
}
}
}
}
@@ -0,0 +1,2 @@
<div if(state.text != null && state.text != "") class=["item-meta", input.kind, state.color] title=state.tooltip>${state.text}</div>
<div class="spc">&nbsp;</div>
@@ -0,0 +1,6 @@
<if(input.enableAllTags)>
<item-meta for(tag in input.tags) kind="tag" value=tag />
</if>
<else>
<item-meta kind="tag" value=(input.tags[0] || null) />
</else>
@@ -0,0 +1,15 @@
<tr class="content-list-item color-primary">
<td class="icon color-highlight-primary">${input.icon}</td>
<td class="content color-primary color-highlight-dark">
<div class="title">
<a class="color-primary" href=input.link>${input.name}</a>
</div>
<div class="description color-text">${input.description || ""}</div>
<div class="meta">
<item-meta kind="date" value=input.createdDate updated=input.updatedDate />
<item-meta kind="date" value=input.fictionalDate />
<item-tag-list tags=input.tags enableAllTags=input.enableAllTags />
<item-meta kind="author" value=input.author />
</div>
</td>
</tr>
@@ -0,0 +1,51 @@
tr.content-list-item {
user-select: none;
outline: 0.05px solid;
> td.icon {
font-size: 2.75em;
text-align: center;
width: 2.5ch;
outline: 0.05px solid;
}
> td.content {
padding: 0.25em;
padding-bottom: 0.33em;
margin: 0;
> .title {
padding: 0.25em 1ch;
user-select: text;
a {
font-size: 1.333em;
}
a:hover {
color: white;
}
}
> .description {
margin: 0 1ch;
p {
margin: 0;
}
}
> .meta {
> div {
display: inline-block;
padding: 0.25em 1ch;
user-select: text;
}
> div.spc {
padding: 0;
user-select: none;
}
}
}
}
@@ -0,0 +1,5 @@
<table class="content-list" cellSpacing="0px">
<tbody>
<include(input.renderBody)/>
</tbody>
</table>
+12
View File
@@ -0,0 +1,12 @@
table.content-list {
padding-bottom: 3em;
width: 99%;
max-width: 100ch;
padding-right: 1em;
margin: auto;
border-collapse: separate;
border-spacing: 0 1em;
}
@@ -0,0 +1,10 @@
<!-- style in marko/global/navbar.less -->
<nav class="layout-navbar color-primary">
<h1 class="color-primary">Aite RP</h1>
<div class="vr color-menu" />
<div class="options">
<a class=(input.site === "story" ? "color-primary" : "color-menu") href="/story/">Story</a>
<a class=(input.site === "logs" ? "color-primary" : "color-menu") href="/logs/">Logs</a>
</div>
</nav>
+39
View File
@@ -0,0 +1,39 @@
const MarkdownIt = require("markdown-it")
const md = new MarkdownIt({
html: true,
linkify: true,
typographer: false,
langPrefix: "language-",
})
md.use(require("markdown-it-container"), "green")
md.use(require("markdown-it-container"), "orange")
md.use(require("markdown-it-container"), "blue")
md.use(require("./plugins/wikilink"))
const renderer = md.renderer
module.exports = class {
onCreate(input) {
this.state = {
render: () => {},
}
this.render(input.source || "")
}
onInput(input) {
if (input.source) {
this.render(input.source)
}
}
render(source) {
this.state.render = (out) => {
if (out.w) {
out.w(md.render(source))
}
}
}
}
renderer.rules
+3
View File
@@ -0,0 +1,3 @@
<div class=["markdown-content", "color-text", input.class]>
<include(state.render) />
</div>
@@ -0,0 +1,40 @@
/*
Based on the markdown-it-wikilinks, which is distributed under the MIT license.
https://github.com/jsepia/markdown-it-wikilinks @ 79fe609a03917f7df11128231118a66a559076d0
Copyright (c) 2016 Julio Sepia
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
const Plugin = require('markdown-it-regexp')
module.exports = new Plugin(/\[\[([\w'\s/]+)(\|([\w'\s/]+))?\]\]/, match => {
let label = ""
let page = ""
if (match[3] != null) {
label = match[3]
page = encodeURIComponent(match[1])
} else {
label = match[1]
page = encodeURIComponent(label)
}
if (label == "" || page == "") {
return match.input
}
return `<a class="wiki-link" href="https://wiki.aiterp.net?title=${page}">${label}</a>`
}
)
+117
View File
@@ -0,0 +1,117 @@
div.markdown-content {
line-height: 1.333em;
font-size: 1.25em;
h1 {
font-size: 2em;
margin: 0;
margin-top: 0.75em;
line-height: 1.2em;
text-align: left;
border-bottom: 1px solid;
}
h1:first-child {
margin-top: 0;
}
h2 {
font-size: 1.5em;
margin: 0;
margin-top: 0.75em;
padding-bottom: 0.25em;
border-bottom: 1px solid;
}
h3 {
font-size: 1.25em;
margin: 0;
margin-top: 1em;
padding: 0;
margin-bottom: -0.25em;
}
h4 {
font-size: 1em;
margin-top: 1em;
margin-bottom: -0.5em;
padding: 0;
}
h5 {
font-size: 1em;
margin: 0;
margin-bottom: -0.5em;
}
h6 {
font-size: 1em;
opacity: 0.5;
margin: 0;
margin-bottom: -0.5em;
}
hr {
border: none;
margin: 2em 2ch;
border-bottom: 4px dotted;
opacity: 0.75;
}
ul, ol {
padding: 0.5em 3ch;
margin: 0;
}
p {
padding: 0.5em 0;
margin: 0;
}
p:first-child {
padding-top: 0.25em;
}
.orange, .blue, .green, blockquote {
h1, h2, h3, h4, h5, h6 {
margin: 0;
padding: 0.5em 0;
}
margin: 0.5em 0;
padding: 0.125em 0.5em 0 0.5em;
outline: 1px solid;
p {
padding: 0.5em 0;
margin: 0;
}
}
pre {
border: 1px solid;
padding: 0.5em;
}
table {
width: 100%;
border: 1px solid;
padding: 0em 0.5em;
th {
font-size: 0.75em;
padding: 0 1ch;
}
}
img {
width: 100%;
}
a {
opacity: 0.75;
}
a:hover {
opacity: 1;
}
}
+1
View File
@@ -0,0 +1 @@
<div class=["menu-blurb", input.class]><include(input.renderBody)/></div>
+7
View File
@@ -0,0 +1,7 @@
.menu-blurb {
opacity: 0.5;
padding: 0.25em 1.5ch;
}
.menu-blurb.error {
color: red;
}
+1
View File
@@ -0,0 +1 @@
<div class="menu-gap"></div>
+3
View File
@@ -0,0 +1,3 @@
.menu-gap {
padding: 0.25em;
}
+1
View File
@@ -0,0 +1 @@
<div class="menu-header color-menu"><include(input.renderBody)/></div>
+5
View File
@@ -0,0 +1,5 @@
.menu-header {
padding: 0.125em 1.5ch;
opacity: 0.5;
user-select: none;
}
+13
View File
@@ -0,0 +1,13 @@
module.exports = class {
onCreate(input) {
this.state = {
classes: ["menu-link", "color-menu", input.class],
}
this.state.classes.push(input.selected ? "selected" : "not-selected")
}
onClick() {
this.emit("click")
}
}
+8
View File
@@ -0,0 +1,8 @@
<a on-click("onClick") href=input.href>
<div class=state.classes>
<div class="icon color-primary">${input.icon}</div>
<div class=["text", input.selected ? "color-primary" : input.textClass]>
<include(input.renderBody) />
</div>
</div>
</a>
+28
View File
@@ -0,0 +1,28 @@
div.menu-link {
width: 100%;
padding-left: 0.5ch;
font-size: 1.1em;
cursor: pointer;
div.icon {
display: inline-block;
width: 3ch;
padding: 0.15em 0.125em;
text-align: center;
vertical-align: middle;
}
div.text {
display: inline-block;
max-width: 22ch;
white-space: nowrap;
overflow-x: hidden;
text-overflow: ellipsis;
vertical-align: middle;
span.weak {
opacity: 0.3333;
}
}
}
+12
View File
@@ -0,0 +1,12 @@
<div class="menu">
<include(input.renderBody) />
<if(input.user != null)>
<menu-gap />
<menu-header>User</menu-header>
<menu-link if(!input.user.loggedIn) icon="L" href="/auth/login">Login</menu-link>
<menu-link if(input.user.loggedIn) icon="L" href="/auth/logout">Logout <span class="weak">(${input.user.name})</span></menu-link>
</if>
<else-if(!input.allowNoUser)>
<menu-blurb class="error">input.user is missing!</menu-blurb>
</else-if>
</div>
+14
View File
@@ -0,0 +1,14 @@
.menu {
position: fixed;
top: 5.5em;
bottom: 0;
width: 28ch;
padding: 0.333em;
text-align: left;
user-select: none;
overflow-x: hidden;
overflow-y: auto;
}
+39
View File
@@ -0,0 +1,39 @@
body {
margin: 0;
padding: 0;
font-family: sans-serif;
background-color: black;
color: white;
main {
margin-left: 30ch; // See side-menu
width: calc(100% - 30ch);
margin-right: 0;
}
a {
text-decoration: none;
}
}
/*
* Less glaring chrome/ium scrollbars.
*/
::-webkit-scrollbar {
width: 2px;
/* for vertical scrollbars */
height: 2px;
/* for horizontal scrollbars */
}
::-webkit-scrollbar-button {
background-color: #555;
color: 000;
display: none;
}
::-webkit-scrollbar-track {
background-color: #222;
}
::-webkit-scrollbar-thumb {
background-color: #555;
color: #000;
}
+121
View File
@@ -0,0 +1,121 @@
body.theme-story {
.color-menu {
color: #789;
}
.menu-link.selected {
background-color: rgba(17, 187, 255, 0.125);
}
.menu-link:hover, .menu > .head-menu > a:hover {
background-color: rgba(17, 187, 255, 0.25);
}
.color-primary, .markdown-content h1, .markdown-content h2, .markdown-content h3, .markdown-content h4, .markdown-content hr, .markdown-content a {
color: #4BF;
}
.color-text {
color: #ABC;
}
.color-highlight-primary {
background-color: rgba(34, 187, 255, 0.25);
color: #4BF;
}
.color-highlight-dark {
background-color: rgba(0, 9, 18, 0.50);
}
}
body.theme-logs {
.color-menu {
color: #776;
}
.menu-link.selected {
background-color: rgba(255, 187, 17, 0.125);
}
.menu-link:hover, .Menu > .head-menu > a:hover {
background-color: rgba(255, 187, 17, 0.25);
}
.color-primary, .markdown-content h1, .markdown-content h2, .markdown-content h3, .markdown-content h4, .markdown-content hr, .markdown-content a {
color: #DA1;
}
.color-text {
color: #AAA;
}
.color-highlight-dark {
background-color: rgba(18, 9, 0, 0.50);
}
.color-highlight-primary {
background-color: rgba(255, 187, 15, 0.25);
color: #DA1;
}
}
.theme-mapp {
.color-menu {
color: #898;
}
.menu-link.selected {
background-color: rgba(35, 255, 128, 0.125);
}
.menu-link:hover, .menu > .head-menu > a:hover {
background-color: rgba(35, 255, 128, 0.25);
}
.color-primary, .markdown-content h1, .markdown-content h2, .markdown-content h3, .markdown-content h4, .markdown-content hr, .markdown-content a {
color: #1F8;
}
.color-text {
color: #ACB;
}
}
div.markdown-content .orange, body.theme-logs div.markdown-content blockquote, body.theme-logs div.markdown-content table, body.theme-logs div.markdown-content pre {
background-color: rgba(221, 170, 17, 0.125);
color: #DA1;
h1, h2, h3 {
color: #DA1;
}
}
div.markdown-content .blue, body.theme-story div.markdown-content blockquote, body.theme-story div.markdown-content table, body.theme-story div.markdown-content pre {
background-color: rgba(34, 187, 255, 0.125);
color: #4BF;
h1, h2, h3 {
color: #4BF; //
}
}
div.markdown-content .green, body.theme-mapp div.markdown-content blockquote, body.theme-mapp div.markdown-content table, body.theme-mapp div.markdown-content pre {
background-color: rgba(17,255,136, 0.125);
color: #1F8;
h1, h2, h3 {
color: #1F8;
}
}
/* Tag colors */
.color-tag-event {
color: #B77;
}
.color-tag-location {
color: #7B7;
}
.color-tag-organization {
color: #B7B;
}
.color-tag-series {
color: #BB7;
}
.color-tag-character {
color: #37B;
}
/* Danger */
.color-danger {
color: #FA3;
}
.color-error {
color: #D20;
}
.menu-link:hover, .menu-link:hover .text, .menu > .head-menu > a:hover {
color: #EEE !important;
}
+32
View File
@@ -0,0 +1,32 @@
nav.layout-navbar {
position: fixed;
top: 0;
bottom: 0;
width: 30ch;
text-align: center;
user-select: none;
h1 {
display: inline-block;
font-size: 2em;
padding: 0.5em 0 0 0;
margin: 0;
}
.options {
display: inline-block;
vertical-align: middle;
a {
display: inline-block;
padding: 0.25em;
margin: 0 0.25ch;
opacity: 0.666;
}
a:hover {
opacity: 1;
color: white;
}
}
}
+16
View File
@@ -0,0 +1,16 @@
<lasso-page package-path="../browser.json"/>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>${input.title ? `${input.title} - Aite RP` : "Aite RP"}</title>
<lasso-head/>
</head>
<body style={backgroundColor: "black"} class=("theme-" + input.site)>
<layout-navbar site=input.site />
<include(input.body) />
<lasso-body/>
<browser-refresh/>
</body>
</html>
@@ -0,0 +1,13 @@
import moment from "moment"
<content-list>
<content-list-item for(log in input.logs)
key=log.shortId
icon="L"
link=("/logs/" + log.id)
description=log.description
name=(log.title || (log.channelName + " - " + moment(log.date).format("MMMM D, YYYY")))
tags=[{kind: "Location", name: log.channelName}, {kind: "Event", name: log.event}]
enableAllTags=true
createdDate=log.date />
</content-list>
@@ -0,0 +1,10 @@
<menu user=input.user>
<menu-header>Logs</menu-header>
<menu-link selected=input.selected.index icon="L" href="/logs/">All</menu-link>
<menu-gap />
<menu-header>Filters</menu-header>
<menu-gap />
<menu-header>Data</menu-header>
<menu-link selected=input.selected.channels icon="C" href="/logs/characters/">Characters</menu-link>
<menu-link selected=input.selected.channels icon="#" href="/logs/channels">Channels</menu-link>
</menu>
@@ -0,0 +1,15 @@
const {logHeaderApi} = require("../../../../../rpdata/api/LogHeader")
module.exports = class {
onCreate(input) {
this.state = {
logs: input.logs
}
}
onMount() {
logHeaderApi.list({limit: 0}).then(logs => {
this.state.logs = logs
})
}
}
@@ -0,0 +1,5 @@
<background src="/assets/images/bg.png" opacity=0.25 />
<logs-menu key="menu" selected=(input.selected || {}) user=input.user />
<main>
<logs-list logs=state.logs />
</main>
+6
View File
@@ -0,0 +1,6 @@
<include("../layout", {title: "Logs", site: "logs"})>
<@body>
<!-- Page needed to get component.js functionality -->
<page logs=input.logs user=input.user selected=input.selected />
</@body>
</include>
@@ -0,0 +1,52 @@
const moment = require("moment")
module.exports = class {
onCreate({kind, weak, value, updated}) {
this.state = {text: null, color: "color-menu", href: null, tooltip: null}
if (value == null || value == "") {
return
}
switch (kind) {
case "date": {
const m = moment(value)
if (m.year() < 2) {
break
}
if (!weak) {
this.state.tooltip = `See all stories set during ${m.format("MMMM YYYY")}`
this.state.href = `/story/by-month/${m.format("YYYY-MM")}/`
}
const dateStr = m.format("MMM D, YYYY")
this.state.text = dateStr
if (updated != null && Date.parse(updated) > Date.parse(value)) {
const m2 = moment(updated)
this.state.tooltip = "Originally posted: " + dateStr
this.state.text = m2.format("MMM D, YYYY") + " *"
}
break
}
case "author": {
this.state.text = value
this.state.tooltip = "See all stories by " + value
this.state.href = `/story/by-author/${value}/`
break
}
default: {
this.state.color = "color-menu"
this.state.text = value
break
}
}
}
}
@@ -0,0 +1,6 @@
<if(state.text != null && state.text != "")>
<div class=["chapter-meta", input.kind, state.color, input.weak ? "weak" : null] title=state.tooltip>
<a if(state.href != null) href=state.href>${state.text}</a>
<span else>${state.text}</span>
</div>
</if>
@@ -0,0 +1,20 @@
div.chapter-meta {
display: inline-block;
padding: 0;
padding-right: 1em;
margin: 0;
user-select: none;
a {
color: inherit;
border-bottom: 0.25px dotted;
}
a:hover {
border-bottom: 0.5px solid;
}
}
div.chapter-meta.weak {
opacity: 0.5;
}
@@ -0,0 +1,5 @@
module.exports = class {
onCreate(input) {
this.state = Object.assign({}, input.chapter)
}
}
@@ -0,0 +1,10 @@
<div class="story-chapter">
<a class="anchor" id=state.id />
<div class="metadata">
<chapter-meta kind="title" value=state.title />
<chapter-meta kind="date" value=state.fictionalDate />
<chapter-meta weak kind="date" value=state.createdDate />
<chapter-meta weak kind="author" value=state.author />
</div>
<markdown class="chapter-content" source=state.source />
</div>
@@ -0,0 +1,14 @@
.story-chapter {
padding-bottom: 1em;
.metadata {
padding: 0;
margin: 0;
}
a.anchor {
display: block;
position: relative;
top: -8em;
}
}
@@ -0,0 +1,8 @@
<story-content-menu story=input.story selected=(input.selected || {}) user=input.user />
<main>
<div class="story-content">
<h1 class="color-primary">${input.story.name}</h1>
<story-tags tags=input.story.tags />
<chapter for(chapter in input.story.chapters) key=chapter.id chapter=chapter />
</div>
</main>
@@ -0,0 +1,9 @@
.story-content {
width: 90%;
max-width: 75ch;
margin: auto;
h1 {
text-align: center;
}
}
@@ -0,0 +1,40 @@
const moment = require("moment")
module.exports = class {
onCreate(input) {
this.state = {
chapterTitles: {},
fdateLink: "",
fdate: "",
selectedChapter: ""
}
}
onMount() {
this.state.selectedChapter = (window.location.hash||"#").slice(1)
}
onInput(input) {
if (input.story.fictionalDate && input.story.fictionalDate.getUTCFullYear() > 10) {
const fdate = input.story.fictionalDate
this.state.fdateLink = `/story/by-month/${moment(fdate).format("YYYY-MM")}`
this.state.fdate = moment(fdate).format("MMM D, YYYY")
}
for (const chapter of input.story.chapters) {
let title = "Chapter " + input.story.chapters.indexOf(chapter) + 1
if (chapter.title) {
title = chapter.title
} else if (chapter.fictionalDate && chapter.fictionalDate.getUTCFullYear() > 1) {
title = moment(chapter.fictionalDate).format("MMM D, YYYY")
}
this.state.chapterTitles[chapter.id] = title
}
}
selectChapter(id) {
this.state.selectedChapter = id
}
}
@@ -0,0 +1,9 @@
<menu user=input.user>
<if(input.story.chapters.length > 1)>
<menu-header>${input.story.name}</menu-header>
<for(chapter in input.story.chapters | status-var=loop)>
<menu-link on-click("selectChapter", chapter.id) href=("#" + chapter.id) selected=(state.selectedChapter === chapter.id) icon=(loop.getIndex()+1)>${state.chapterTitles[chapter.id]}</menu-link>
</for>
<menu-gap />
</if>
</menu>
@@ -0,0 +1,3 @@
<div class="story-tags">
<a for(tag in input.tags) href=("/story/by-tag/" + tag.kind + "/" + encodeURIComponent(tag.name)) class=["tag", "color-tag-" + tag.kind.toLowerCase()]>${tag.name}</a>
</div>
@@ -0,0 +1,20 @@
div.story-tags {
text-align: center;
margin-bottom: 1em;
margin-top: -1em;
a.tag {
display: inline-block;
margin: 0.5em 0.5ch;
padding: 0.0625em 0.5ch;
outline: 1px solid;
opacity: 0.75;
user-select: none;
}
a.tag:hover {
opacity: 1;
cursor: pointer;
}
}
+6
View File
@@ -0,0 +1,6 @@
<include("../layout", {title: "Stories", site: "story"})>
<@body>
<background src="/assets/images/bg.png" opacity=0.25 />
<page story=input.story user=input.user selected=input.selected />
</@body>
</include>
@@ -0,0 +1,11 @@
<content-list>
<content-list-item for(story in input.stories)
icon=story.category.charAt(0)
link=("/story/" + story.id)
name=story.name
createdDate=story.createdDate
fictionalDate=story.fictionalDate
updatedDate=story.updatedDate
tags=story.tags
author=story.author />
</content-list>
@@ -0,0 +1,11 @@
<menu user=input.user>
<menu-header>Story</menu-header>
<menu-link selected=input.selected.index icon="S" href="/story/">Stories</menu-link>
<menu-gap />
<menu-header>Categories</menu-header>
<menu-link for(category in (input.categories||[])) selected=(input.selected.category == category.name) href=`/story/by-category/${category.name}` icon=category.name.charAt(0)>${category.name}</menu-link>
<menu-gap />
<menu-header>Tags</menu-header>
<menu-link for(tag in (input.menuTags||[])) selected=(input.selected.tag === `${tag.kind}:${tag.name}`) href=`/story/by-tag/${tag.kind}/${tag.name}` textClass=`color-tag-${tag.kind.toLowerCase()}` icon=tag.kind.charAt(0)>${tag.name}</menu-link>
<menu-link selected=input.selected.tags icon="T" href="/story/tag-list/">Tags</menu-link>
</menu>
+9
View File
@@ -0,0 +1,9 @@
<include("../layout", {title: "Stories", site: "story"})>
<@body>
<background src="/assets/images/bg.png" opacity=0.25 />
<story-menu categories=input.categories selected=(input.selected || {}) menuTags=input.menuTags user=input.user />
<main>
<story-list stories=input.stories />
</main>
</@body>
</include>
+8
View File
@@ -0,0 +1,8 @@
<include("../layout", {title: "Stories", site: "story"})>
<@body>
<background src="/assets/images/bg.png" opacity=0.25 />
<story-menu categories=input.categories selected=(input.selected || {}) menuTags=input.menuTags user=input.user />
<main>
</main>
</@body>
</include>