Browse Source

logs, logs-content: Added basic view of logs and added characters to logs

1.0
Gisle Aune 6 years ago
parent
commit
ed01006b21
  1. 5
      marko/components/annotation/style.less
  2. 10
      marko/components/content-list-item/index.marko
  3. 15
      marko/components/content-list-item/style.less
  4. 2
      marko/components/markdown/index.marko
  5. 3
      marko/components/markdown/style.less
  6. 9
      marko/components/menu-link/style.less
  7. 6
      marko/global/colors.less
  8. 8
      marko/page/logs-content/components/logs-content-menu/index.marko
  9. 17
      marko/page/logs-content/components/page/component.js
  10. 7
      marko/page/logs-content/components/page/index.marko
  11. 10
      marko/page/logs-content/components/page/style.less
  12. 50
      marko/page/logs-content/components/post-meta/component.js
  13. 6
      marko/page/logs-content/components/post-meta/index.marko
  14. 20
      marko/page/logs-content/components/post-meta/style.less
  15. 50
      marko/page/logs-content/components/post/component.js
  16. 20
      marko/page/logs-content/components/post/index.marko
  17. 36
      marko/page/logs-content/components/post/style.less
  18. 6
      marko/page/logs-content/view.marko
  19. 1
      marko/page/logs/components/logs-list/index.marko
  20. 2
      marko/page/story-content/components/chapter/index.marko
  21. 4
      marko/page/story-content/components/chapter/style.less
  22. 12
      routes/logs-content/index.js
  23. 17
      rpdata/api/Channel.js
  24. 29
      rpdata/api/Character.js
  25. 81
      rpdata/api/Log.js
  26. 26
      rpdata/api/Post.js
  27. 3
      server.js

5
marko/components/annotation/style.less

@ -12,11 +12,12 @@ div.annotation {
padding-bottom: 0.25em;
}
p {
p, div.markdown-content > p {
margin-top: 0.5em;
}
p:first-of-type {
p:first-of-type, div.markdown-content > p:first-of-type {
margin: 0;
padding: 0;
}
}

10
marko/components/content-list-item/index.marko

@ -4,7 +4,15 @@
<div class="title">
<a class="color-primary" href=input.link>${input.name}</a>
</div>
<div class="description color-text">${input.description || ""}</div>
<div if(input.description) class="description color-text">
<div class="content">${input.description}</div>
</div>
<div if(input.characters) class="characters">
<div for(character in (input.characters || [])) class="character color-menu">
<span class="name">${input.characters.length > 6 ? character.shortName : character.name}</span>
<span class="comma">,</span>
</div>
</div>
<div class="meta">
<item-meta kind="date" value=input.createdDate updated=input.updatedDate />
<item-meta kind="date" value=input.fictionalDate />

15
marko/components/content-list-item/style.less

@ -34,6 +34,21 @@ tr.content-list-item {
}
}
> .characters {
margin: 0 1ch;
> .character {
display: inline-block;
margin-right: 1ch;
}
> .character:last-of-type {
.comma {
display: none;
}
}
}
> .meta {
> div {
display: inline-block;

2
marko/components/markdown/index.marko

@ -1,3 +1,3 @@
<div class=["markdown-content", "color-text", input.class]>
<div class=["markdown-content", input.class]>
<include(state.render) />
</div>

3
marko/components/markdown/style.less

@ -1,6 +1,5 @@
div.markdown-content {
line-height: 1.333em;
font-size: 1.25em;
line-height: 1.40em;
h1 {
font-size: 2em;

9
marko/components/menu-link/style.less

@ -3,6 +3,8 @@ div.menu-link {
padding-left: 0.5ch;
font-size: 1.1em;
white-space: nowrap;
cursor: pointer;
div.icon {
@ -26,6 +28,13 @@ div.menu-link {
}
}
}
div.menu-link:hover {
div.text {
span.weak {
opacity: 0.75;
}
}
}
div.menu-link.dark {
opacity: 0.5;
}

6
marko/global/colors.less

@ -28,7 +28,7 @@ body.theme-logs {
color: #776;
}
.menu-link.selected {
background-color: rgba(255, 187, 17, 0.125);
background-color: rgba(255, 183, 0, 0.226);
}
.menu-link:hover, .Menu > .head-menu > a:hover {
background-color: rgba(255, 187, 17, 0.25);
@ -37,13 +37,13 @@ body.theme-logs {
color: #DA1;
}
.color-text, input, textarea, select {
color: #AAA;
color: #BBB;
}
.color-highlight-dark {
background-color: rgba(18, 9, 0, 0.50);
}
.color-highlight-primary {
background-color: rgba(255, 187, 15, 0.25);
background-color: rgba(255, 187, 17, 0.25);
color: #DA1;
}
}

8
marko/page/logs-content/components/logs-content-menu/index.marko

@ -0,0 +1,8 @@
<menu user=input.user>
<menu-header>Log</menu-header>
<menu-link href=("/logs/?channels="+input.log.channel.name) icon="#">${input.log.channel.name}</menu-link>
<menu-link if(input.log.channel.eventName) href=("/logs/?channels="+input.log.channel.eventName) icon="E">${input.log.channel.eventName}</menu-link>
<for(character in input.log.characters)>
<menu-link href=("/logs/?characters="+character.id) icon="C">${character.name} <span class="weak">(${character.author})</span></menu-link>
</for>
</menu>

17
marko/page/logs-content/components/page/component.js

@ -0,0 +1,17 @@
const moment = require("moment")
module.exports = class {
onCreate(input) {
this.state = {
log: input.log
}
}
get title() {
if (this.state.log.title) {
return this.state.log.title
}
return `${this.state.log.channel.name}${moment(this.state.log.date).format("MMMM D, YYYY")}`
}
}

7
marko/page/logs-content/components/page/index.marko

@ -0,0 +1,7 @@
<logs-content-menu user=input.user log=state.log />
<main>
<div class="logs-content">
<h1 class="color-primary">${component.title}</h1>
<post for(post in state.log.posts) post=post characters=state.log.characters />
</div>
</main>

10
marko/page/logs-content/components/page/style.less

@ -0,0 +1,10 @@
div.logs-content {
width: 90%;
max-width: 75ch;
margin: auto;
h1 {
font-weight: 200;
text-align: center;
}
}

50
marko/page/logs-content/components/post-meta/component.js

@ -0,0 +1,50 @@
const moment = require("moment")
module.exports = class {
onCreate() {
this.state = {text: null, color: "color-menu", href: null, tooltip: null}
}
onInput(input) {
if (this.state != null) {
this.updateState(input)
}
}
updateState({kind, weak, value, updated}) {
this.state = {text: null, color: "color-menu", href: null, tooltip: null}
if (value == null || value == "") {
return
}
switch (kind) {
case "timestamp": {
const m = moment(value)
if (m.year() < 2) {
break
}
this.state.tooltip = m.format("YYYY-MM-DD HH:mm:ss")
this.state.text = `[${m.format("HH:mm")}]`
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
}
}
}
}

6
marko/page/logs-content/components/post-meta/index.marko

@ -0,0 +1,6 @@
<if(state.text != null && state.text != "")>
<div class=["post-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>

20
marko/page/logs-content/components/post-meta/style.less

@ -0,0 +1,20 @@
div.post-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.post-meta.weak {
opacity: 0.5;
}

50
marko/page/logs-content/components/post/component.js

@ -0,0 +1,50 @@
module.exports = class {
onCreate(input) {
this.state = {
shortName: "",
name: "",
text: "",
}
this.updatePost(input)
}
onInput(input) {
if (this.state == null) {
return
}
this.updatePost(input)
}
updatePost(input) {
this.state.shortName = input.post.nick.split("_").shift()
this.state.name = input.post.nick
this.state.text = input.post.text.replace(/\x02/g, "**")
if (input.post.kind === "text" && !this.state.text.includes("\"")) {
this.state.text = '"' + this.state.text + '"'
}
if (!input.post.nick.startsWith("=")) {
const postNick = input.post.nick.replace("'s", "").replace("s'", "s")
for (const character of input.characters) {
for (const nick of character.nicks) {
if (nick === postNick) {
this.state.shortName = character.shortName
return
}
}
}
}
}
kindClass(prefix) {
if (this.input.post == null) {
return
}
return `${prefix}${this.input.post.kind.replace(".", "-")}`
}
}

20
marko/page/logs-content/components/post/index.marko

@ -0,0 +1,20 @@
<div class=["post", component.kindClass("post-type")]>
<div class="post-meta-row">
<post-meta kind="timestamp" value=input.post.time />
<post-meta kind="nick" value=input.post.nick />
</div>
<div if(input.post.kind.startsWith("annotation.")) class="post-body" >
<annotation level=(input.post.kind.substring(11))>
<markdown class="post-content" source=state.text />
</annotation>
</div>
<div if(input.post.kind === "scene") class="post-body color-text">
<markdown class="post-content post-scene" source=state.text />
</div>
<div if(input.post.kind === "action") class="post-body color-text">
<markdown class="post-content post-action" source=(state.shortName + " " + state.text) />
</div>
<div if(input.post.kind === "text") class="post-body color-text">
<markdown class="post-content post-text" source=state.text />
</div>
</div>

36
marko/page/logs-content/components/post/style.less

@ -0,0 +1,36 @@
div.post {
margin-bottom: 1ch;
.post-meta-row {
padding: 0;
margin: 0;
}
div.post-body {
font-size: 1.25em;
div.nick-wrapper {
display: inline;
.nick-decoration {
display: inline;
}
.nick {
display: inline;
}
}
div.post-content {
display: inline;
}
div.annotation {
margin-top: 0.33em;
}
}
div.post-body p:first-of-type {
margin-top: 0;
padding-top: 0;
}
}

6
marko/page/logs-content/view.marko

@ -0,0 +1,6 @@
<include("../layout", {title: "Logs", site: "logs"})>
<@body>
<background src="/assets/images/bg.png" opacity=0.25 />
<page log=input.log user=input.user selected=input.selected />
</@body>
</include>

1
marko/page/logs/components/logs-list/index.marko

@ -6,6 +6,7 @@ import moment from "moment"
icon="L"
link=("/logs/" + log.id)
description=log.description
characters=log.characters
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

2
marko/page/story-content/components/chapter/index.marko

@ -12,7 +12,7 @@ import moment from "moment"
<chapter-meta weak kind="date" value=input.chapter.createdDate />
<chapter-meta weak kind="author" value=input.chapter.author />
</div>
<markdown class="chapter-content" source=input.chapter.source />
<markdown class="chapter-content color-text" source=input.chapter.source />
<edit-chapter-modal enabled=(state.modal === "edit") chapter=input.chapter on-close("close") on-edit("updateChapter") />
<remove-chapter-modal enabled=(state.modal === "remove") chapter=input.chapter on-close("close") on-remove("removeChapter") />

4
marko/page/story-content/components/chapter/style.less

@ -31,4 +31,8 @@
opacity: 1;
}
}
div.chapter-content {
font-size: 1.25em;
}
}

12
routes/logs-content/index.js

@ -0,0 +1,12 @@
const express = require("express")
const {logsApi} = require("../../rpdata/api/Log")
const viewTemplate = require("../../marko/page/logs-content/view.marko")
module.exports = async(req, res, next) => {
res.markoAsync(viewTemplate, {
log: logsApi.find(req.params.id),
selected: {index: true},
})
}

17
rpdata/api/Channel.js

@ -0,0 +1,17 @@
const {query} = require("../client")
class Channel {
constructor(name, logged, hub, eventName, locationName) {
this.name = name
this.logged = logged
this.hub = hub
this.eventName = eventName
this.locationName = locationName
}
static fromData(data) {
return new Channel(data.name, data.logged, data.hub, data.eventName, data.locationName)
}
}
module.exports = { Channel }

29
rpdata/api/Character.js

@ -1,5 +1,30 @@
const {query} = require("../client")
class Character {
}
/**
* @param {string} id
* @param {string[]} nicks
* @param {string} author
* @param {string} name
* @param {string} shortName
* @param {string} description
*/
constructor(id, nicks, author, name, shortName, description) {
this.id = id
this.nicks = nicks
this.nick = this.nicks[0] || null
this.author = author
this.name = name
this.shortName = shortName
this.description = description
}
/**
* Create a character object from data.
*/
static fromData(data) {
return new Character(data.id, data.nicks, data.author, data.name, data.shortName, data.description)
}
}
module.exports = { Character }

81
rpdata/api/Log.js

@ -0,0 +1,81 @@
const {query} = require("../client")
const {Character} = require("./Character")
const {Channel} = require("./Channel")
const {Post} = require("./Post")
class Log {
/**
* @param {string} id
* @param {string} shortId
* @param {Date | string | number} date
* @param {string} title
* @param {string} eventName
* @param {string} description
* @param {string} open
* @param {any} channel
* @param {any[]} characters
* @param {any[]} posts
*/
constructor(id, shortId, date, title, eventName, description, open, channel, characters, posts) {
this.id = id
this.shortId = shortId
this.date = date
this.title = title
this.eventName = eventName
this.description = description
this.open = open
this.channel = Channel.fromData(channel)
this.characters = characters.map(c => Character.fromData(c))
this.posts = posts.map(p => Post.fromData(p))
}
static fromData(data) {
return new Log(data.id, data.shortId, data.date, data.title, data.eventName, data.description, data.open, data.channel, data.characters, data.posts)
}
}
const logsApi = {
find(id) {
return query(`
query FindLog($id: String!) {
log(id: $id) {
id
shortId
date
title
eventName
description
open
channel {
name
logged
hub
eventName
locationName
}
characters {
id
nicks
author
name
shortName
description
}
posts {
id
position
time
kind
nick
text
}
}
}
`, {id}).then(({log}) => {
return Log.fromData(log)
})
},
}
module.exports = { Log, logsApi }

26
rpdata/api/Post.js

@ -0,0 +1,26 @@
const {query} = require("../client")
class Post {
/**
* @param {string} id
* @param {number} position
* @param {Date | string | number} time
* @param {string} kind
* @param {string} nick
* @param {string} text
*/
constructor(id, position, time, kind, nick, text) {
this.id = id
this.position = position
this.time = new Date(time)
this.kind = kind
this.nick = nick
this.text = text
}
static fromData(data) {
return new Post(data.id, data.position, data.time, data.kind, data.nick, data.text)
}
}
module.exports = {Post}

3
server.js

@ -76,7 +76,8 @@ app.use("/story/by-tag/", require("./routes/story/by-tag"))
app.use("/story/tag-list/", require("./routes/story/tag-list"))
app.use("/story/:id(S[0-9a-z]{15})/", require("./routes/story-content"))
app.use("/logs/", require("./routes/logs"))
app.use("/logs/:id([0-9]{4}-[0-1][0-9]-[0-3][0-9]_[0-9]{9}_[A-Za-z\,\']{2,})/", require("./routes/logs-content"))
// 2018-03-10_035344747_Miner'sRespite
// Entry point
app.get("/", function(req, res) {
res.redirect("/story/")

Loading…
Cancel
Save