Browse Source

package: Removed rpdata-ui.

1.1
Gisle Aune 6 years ago
parent
commit
929abfdbe4
  1. 21
      rpdata-ui/.gitignore
  2. 14
      rpdata-ui/README.md
  3. 12110
      rpdata-ui/package-lock.json
  4. 34
      rpdata-ui/package.json
  5. BIN
      rpdata-ui/public/assets/images/bg.png
  6. BIN
      rpdata-ui/public/favicon.ico
  7. 40
      rpdata-ui/public/index.html
  8. 15
      rpdata-ui/public/manifest.json
  9. 23
      rpdata-ui/src/App.js
  10. 13
      rpdata-ui/src/client.js
  11. 90
      rpdata-ui/src/colors.css
  12. 58
      rpdata-ui/src/common/Background.js
  13. 70
      rpdata-ui/src/common/List.js
  14. 13
      rpdata-ui/src/common/LoadingScreen.js
  15. 15
      rpdata-ui/src/common/Main.js
  16. 60
      rpdata-ui/src/common/Menu.js
  17. 22
      rpdata-ui/src/common/css/Background.css
  18. 50
      rpdata-ui/src/common/css/List.css
  19. 7
      rpdata-ui/src/common/css/LoadingScreen.css
  20. 3
      rpdata-ui/src/common/css/Main.css
  21. 75
      rpdata-ui/src/common/css/Menu.css
  22. 33
      rpdata-ui/src/index.css
  23. 21
      rpdata-ui/src/index.js
  24. 117
      rpdata-ui/src/registerServiceWorker.js
  25. 16
      rpdata-ui/src/routes/logs/LogsMenu.js
  26. 14
      rpdata-ui/src/routes/logs/LogsRoot.js
  27. 51
      rpdata-ui/src/routes/story-content/StoryContentMenu.js
  28. 44
      rpdata-ui/src/routes/story-content/StoryContentRoot.js
  29. 28
      rpdata-ui/src/routes/story-content/gql/StoryContentRoot.js
  30. 36
      rpdata-ui/src/routes/story/StoryList.js
  31. 33
      rpdata-ui/src/routes/story/StoryMenu.js
  32. 43
      rpdata-ui/src/routes/story/StoryRoot.js
  33. 34
      rpdata-ui/src/routes/story/StoryTags.js
  34. 16
      rpdata-ui/src/routes/story/gql/StoryList.js
  35. 12
      rpdata-ui/src/routes/story/gql/StoryRoot.js
  36. 10
      rpdata-ui/src/routes/story/gql/StoryTags.js

21
rpdata-ui/.gitignore

@ -1,21 +0,0 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.
# dependencies
/node_modules
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

14
rpdata-ui/README.md

@ -1,14 +0,0 @@
# User Interface
## Setup
This is a UI created with `create-react-app`, so the process of getting started on a new host is navigating to the directory and running these commands.
```sh
npm install
npm start
```
## Release
This is built and packaged with the parent project.

12110
rpdata-ui/package-lock.json
File diff suppressed because it is too large
View File

34
rpdata-ui/package.json

@ -1,34 +0,0 @@
{
"name": "rpdata-ui",
"version": "0.1.0",
"private": true,
"dependencies": {
"ajv": "^6.5.2",
"apollo-boost": "^0.1.10",
"apollo-cache-inmemory": "^1.3.0-beta.6",
"graphql": "^0.13.2",
"graphql-tag": "^2.9.2",
"moment": "^2.22.2",
"pluralize": "^7.0.0",
"react": "^16.4.1",
"react-apollo": "^2.1.9",
"react-dom": "^16.4.1",
"react-router": "^4.3.1",
"react-router-dom": "^4.3.1",
"react-scripts": "1.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"devDependencies": {
"@playlyfe/gql": "^2.6.0"
},
"proxy": {
"/graphql": {
"target": "http://10.32.7.1:17000"
}
}
}

BIN
rpdata-ui/public/assets/images/bg.png

Before

Width: 301  |  Height: 256  |  Size: 62 KiB

BIN
rpdata-ui/public/favicon.ico

40
rpdata-ui/public/index.html

@ -1,40 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>Aite RP</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

15
rpdata-ui/public/manifest.json

@ -1,15 +0,0 @@
{
"short_name": "Aite RP",
"name": "Aite RP Website (aiterp.net)",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": "./index.html",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#000000"
}

23
rpdata-ui/src/App.js

@ -1,23 +0,0 @@
import React, { Component } from 'react'
import { Route, Redirect, Switch } from "react-router-dom";
import StoryRoot from './routes/story/StoryRoot'
import StoryContentRoot from './routes/story-content/StoryContentRoot'
import LogsRoot from './routes/logs/LogsRoot'
export default class App extends Component {
render() {
return (
<div className="App">
<Switch>
<Redirect exact path="/" to="/story/" />
<Route path="/story/:id(S[0-9a-z]{15})" component={StoryContentRoot}/>
<Route path="/story/" component={StoryRoot}/>
<Route path="/logs/" component={LogsRoot}/>
</Switch>
</div>
);
}
}
/* See ./common/Menu.js to change the top navbar */

13
rpdata-ui/src/client.js

@ -1,13 +0,0 @@
import { ApolloClient } from "apollo-client"
import { HttpLink } from "apollo-link-http"
import { InMemoryCache } from "apollo-cache-inmemory"
const client = new ApolloClient({
link: new HttpLink({
uri: "/graphql"
}),
cache: new InMemoryCache(),
})
export default client

90
rpdata-ui/src/colors.css

@ -1,90 +0,0 @@
/* /story/ */
.theme-story .color-menu {
color: #789;
}
.theme-story .MenuLink.selected {
background-color: rgba(17, 187, 255, 0.125);
}
.theme-story .MenuLink:hover, .theme-story .Menu > .head-menu > a:hover {
background-color: rgba(17, 187, 255, 0.25);
}
.theme-story .color-primary {
color: #4BF;
}
.theme-story .color-text {
color: #ABC;
}
.theme-story .color-highlight-primary {
background-color: rgba(34, 187, 255, 0.25);
color: #4BF;
}
.theme-story .color-highlight-dark {
background-color: rgba(0, 9, 18, 0.50);
}
/* /logs/ */
.theme-logs .color-menu {
color: #998;
}
.theme-logs .MenuLink.selected {
background-color: rgba(255, 187, 17, 0.125);
}
.theme-logs .MenuLink:hover, .theme-logs .Menu > .head-menu > a:hover {
background-color: rgba(255, 187, 17, 0.25);
}
.theme-logs .color-primary {
color: #FB1;
}
.theme-logs .color-text {
color: #CCB;
}
.theme-logs .color-highlight-primary {
background-color: rgba(255, 187, 15, 0.25);
color: #FB1;
}
.theme-logs .color-highlight-dark {
background-color: rgba(18, 9, 0, 0.50);
}
/* /data/ */
.theme-data .color-menu {
color: #898;
}
.theme-data .MenuLink.selected {
background-color: rgba(35, 255, 128, 0.125);
}
.theme-data .MenuLink:hover, .theme-data .Menu > .head-menu > a:hover {
background-color: rgba(35, 255, 128, 0.25);
}
.theme-data .color-primary {
color: #1F8;
}
.theme-data .color-text {
color: #ACB;
}
/* 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;
}
.MenuLink:hover, .MenuLink:hover .text, .Menu > .head-menu > a:hover {
color: #EEE !important;
}

58
rpdata-ui/src/common/Background.js

@ -1,58 +0,0 @@
import React, { Component } from "react"
import "./css/Background.css"
/**
* Background renders a full-size image that detects whether the source is
* landscape or portrait. It's a react-ification of AiteStory's background.
*/
export default class Background extends Component {
constructor(props, ctx) {
super(props, ctx)
this.state = {
landscape: false,
}
}
/**
* @param {HTMLImageElement} img
*/
onRef(img) {
if (img == null) {
return
}
if (img.complete && typeof(img.naturalHeight) !== 'undefined' && img.naturalHeight !== 0) {
const width = img.naturalWidth
const height = img.naturalHeight
this.setLandscape(width > (height * 1.50))
} else {
img.onload = () => {
const width = img.naturalWidth
const height = img.naturalHeight
this.setLandscape(width > (height * 1.50))
}
}
}
/**
* Change the landscape setting of the image.
*
* @param {boolean} value Whether the image is landscape
*/
setLandscape(value) {
if (value !== this.state.landscape) {
this.setState({landscape: value})
}
}
render() {
const src = this.props.src || "/assets/images/bg.png"
const opacity = this.props.opacity || 0.20
const className = "Background" + (this.state.landscape ? " landscape" : "")
return <img alt="Background" style={{filter: `brightness(${(Number(opacity)) * 100}%)`}} ref={this.onRef.bind(this)} className={className} src={src} />
}
}

70
rpdata-ui/src/common/List.js

@ -1,70 +0,0 @@
import React, { Component } from "react"
import { Link } from "react-router-dom"
import moment from "moment"
import "./css/List.css"
export default class List extends Component {
render() {
return (
<table className="List" cellSpacing="0px">
<tbody>
{this.props.children}
</tbody>
</table>
)
}
}
export function Item({link, name, icon, author, description, tags, fictionalDate, createdDate}) {
return [
<tr className="ListItem color-primary">
<td className="icon color-highlight-primary">{icon}</td>
<td className="content color-primary color-highlight-dark">
<div className="title">
<Link className="color-primary" to={link}>{name}</Link>
</div>
<div className="description color-text">{description}</div>
<div className="meta">
<ItemMeta key="D2" kind="date" value={createdDate} />
<ItemMeta key="D1" kind="date" value={fictionalDate} />
<ItemMeta key="T" kind="tag" value={tags[0] || null} />
<ItemMeta key="A" kind="author" value={author} />
</div>
</td>
</tr>,
<tr className="ListItem-spacer">
<td></td>
</tr>
]
}
function ItemMeta({kind, value, className}) {
// Hide empty fields
if (value == null || value === "") {
return null
}
switch (kind) {
case "date": {
const m = moment(value)
if (m.year() < 2) {
return null
}
return <div className="date color-menu">{m.format("MMM D, YYYY")}</div>
}
case "tag": {
return <div className={`tag color-tag-${value.kind.toLowerCase()}`}>{value.name}</div>
}
case "author": {
return <div className="author color-menu">{value}</div>
}
default: {
return null;
}
}
}

13
rpdata-ui/src/common/LoadingScreen.js

@ -1,13 +0,0 @@
import React from "react"
import Background from "./Background"
import './css/LoadingScreen.css'
export function LoadingScreen({className}) {
return (
<div className={`Loading ${className}`}>
<Background />
<div className="text color-primary">Loading...</div>
</div>
)
}

15
rpdata-ui/src/common/Main.js

@ -1,15 +0,0 @@
import React, { Component } from "react"
import './css/Main.css'
export default class Main extends Component {
render() {
const { children, className } = this.props
return (
<main className={`Main ${className}`}>
{ children }
</main>
)
}
}

60
rpdata-ui/src/common/Menu.js

@ -1,60 +0,0 @@
import React, { Component } from "react"
import { Link } from "react-router-dom"
import './css/Menu.css'
export default class Menu extends Component {
render() {
const { children } = this.props
return (
<nav className="Menu">
<h1 className="color-primary">Aite RP</h1>
<div className="head-menu">
<HeadMenuLink to="/story/">Story</HeadMenuLink>
<HeadMenuLink to="/logs/">Logs</HeadMenuLink>
</div>
<div className="content">
{ children }
</div>
</nav>
)
}
}
export function MenuLink({ icon, children, tagKind, to, onClick }) {
const isSelected = window.location.pathname === to
const className = isSelected ? "selected" : "not-selected"
const textClass = isSelected ? "color-primary" : `color-tag-${(tagKind||"none").toLowerCase()}`
const body = (
<div className={`MenuLink color-menu ${className}`} onClick={onClick}>
<div className="icon color-primary">{icon}</div>
<div className={`text ${textClass}`}>{children}</div>
</div>
)
if (to == null) {
return body
} else {
return <Link to={to}>{body}</Link>
}
}
export function MenuGap() {
return <div className="MenuGap"></div>
}
export function MenuHeader({children}) {
return <div className="MenuHeader color-menu">{children}</div>
}
export function HeadMenuLink({to, children}) {
const className = (window.location.pathname.startsWith(to) ? "color-primary" : "color-menu")
return <Link className={className} to={to}>{children}</Link>
}
export function MenuBlurb({children}) {
return <div className="MenuBlurb">{children}</div>
}

22
rpdata-ui/src/common/css/Background.css

@ -1,22 +0,0 @@
img.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;
z-index: -1;
user-select: none;
-webkit-user-drag: none;
}
img.Background.landscape {
/* Set rules to fill background */
height: 100%;
/* Set up proportionate scaling */
min-width: 100%;
width: auto;
}

50
rpdata-ui/src/common/css/List.css

@ -1,50 +0,0 @@
.List {
padding: 1em 1ch;
width: 100%;
max-width: 140ch;
margin: auto;
margin-top: 0.75em;
}
.ListItem {
user-select: none;
outline: 0.05px solid;
}
.ListItem td.icon {
font-size: 2.75em;
text-align: center;
width: 2.5ch;
outline: 0.05px solid;
margin: 0;
}
.ListItem td.content {
padding: 0.25em;
padding-bottom: 0.33em;
margin: 0;
}
.ListItem td.content .title {
padding: 0.25em 1ch;
}
.ListItem td.content a {
font-size: 1.333em;
}
.ListItem td.content a:hover {
color: white;
}
.ListItem td.content .description {
margin: 0 1ch;
}
.ListItem td.content p {
margin: 0;
}
.ListItem td.content .meta {
}
.ListItem td.content .meta > div {
display: inline-block;
padding: 0.25em 1ch;
}
.ListItem-spacer td {
height: 0.75em;
}

7
rpdata-ui/src/common/css/LoadingScreen.css

@ -1,7 +0,0 @@
.Loading .text {
width: 100%;
margin-top: 6em;
font-size: 3em;
opacity: 0.5;
text-align: center;
}

3
rpdata-ui/src/common/css/Main.css

@ -1,3 +0,0 @@
.Main {
margin-left: 30ch;
}

75
rpdata-ui/src/common/css/Menu.css

@ -1,75 +0,0 @@
.Menu {
position: fixed;
width: 28ch;
top: 0;
bottom: 0;
overflow-x: hidden;
overflow-y: auto;
text-align: center;
user-select: none;
}
.Menu > .head-menu {
padding: 0 2ch;
padding-bottom: 0.5em;
}
.Menu > .head-menu > a {
display: inline-block;
padding: 0.25em 1ch;
font-size: 0.75em;
}
.Menu > h1 {
padding: 1em 0 0em 0;
margin: 0;
font-size: 2.5em;
user-select: none;
}
.Menu > .content {
margin-top: 1em;
text-align: left;
}
.MenuLink {
width: 100%;
padding-left: 0.5ch;
font-size: 1.1em;
cursor: pointer;
}
.MenuLink .icon {
display: inline-block;
width: 3ch;
padding: 0.15em 0.125em;
text-align: center;
vertical-align: middle;
}
.MenuLink .text {
display: inline-block;
max-width: 22ch;
white-space: nowrap;
overflow-x: hidden;
text-overflow: ellipsis;
vertical-align: middle;
}
.MenuGap {
padding: 0.25em;
}
.MenuHeader {
opacity: 0.5;
user-select: none;
padding: 0.125em 1.5ch;
}
.MenuBlurb {
opacity: 0.5;
padding: 0.25em 1.5ch;
}

33
rpdata-ui/src/index.css

@ -1,33 +0,0 @@
body {
margin: 0;
padding: 0;
font-family: sans-serif;
background-color: black;
color: white;
}
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;
}

21
rpdata-ui/src/index.js

@ -1,21 +0,0 @@
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom"
import { ApolloProvider } from "react-apollo";
import client from "./client";
import App from "./App"
import registerServiceWorker from "./registerServiceWorker"
import "./index.css"
import "./colors.css";
ReactDOM.render((
<ApolloProvider client={client}>
<BrowserRouter>
<App />
</BrowserRouter>
</ApolloProvider>
), document.getElementById('root'))
registerServiceWorker();

117
rpdata-ui/src/registerServiceWorker.js

@ -1,117 +0,0 @@
// In production, we register a service worker to serve assets from local cache.
// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on the "N+1" visit to a page, since previously
// cached resources are updated in the background.
// To learn more about the benefits of this model, read https://goo.gl/KwvDNy.
// This link also includes instructions on opting out of this behavior.
const isLocalhost = Boolean(
window.location.hostname === 'localhost' ||
// [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' ||
// 127.0.0.1/8 is considered localhost for IPv4.
window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
)
);
export default function register() {
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
// The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(process.env.PUBLIC_URL, window.location);
if (publicUrl.origin !== window.location.origin) {
// Our service worker won't work if PUBLIC_URL is on a different origin
// from what our page is served on. This might happen if a CDN is used to
// serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374
return;
}
window.addEventListener('load', () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
if (isLocalhost) {
// This is running on localhost. Lets check if a service worker still exists or not.
checkValidServiceWorker(swUrl);
// Add some additional logging to localhost, pointing developers to the
// service worker/PWA documentation.
navigator.serviceWorker.ready.then(() => {
console.log(
'This web app is being served cache-first by a service ' +
'worker. To learn more, visit https://goo.gl/SC7cgQ'
);
});
} else {
// Is not local host. Just register service worker
registerValidSW(swUrl);
}
});
}
}
function registerValidSW(swUrl) {
navigator.serviceWorker
.register(swUrl)
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the old content will have been purged and
// the fresh content will have been added to the cache.
// It's the perfect time to display a "New content is
// available; please refresh." message in your web app.
console.log('New content is available; please refresh.');
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.');
}
}
};
};
})
.catch(error => {
console.error('Error during service worker registration:', error);
});
}
function checkValidServiceWorker(swUrl) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl)
.then(response => {
// Ensure service worker exists, and that we really are getting a JS file.
if (
response.status === 404 ||
response.headers.get('content-type').indexOf('javascript') === -1
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then(registration => {
registration.unregister().then(() => {
window.location.reload();
});
});
} else {
// Service worker found. Proceed as normal.
registerValidSW(swUrl);
}
})
.catch(() => {
console.log(
'No internet connection found. App is running in offline mode.'
);
});
}
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(registration => {
registration.unregister();
});
}
}

16
rpdata-ui/src/routes/logs/LogsMenu.js

@ -1,16 +0,0 @@
import React, { Component } from "react"
import Menu, { MenuHeader, MenuLink, MenuGap } from '../../common/Menu'
export default class LogsMenu extends Component {
render() {
return (
<Menu>
<MenuHeader>Logs</MenuHeader>
<MenuLink to="/logs/" icon="R">Recent</MenuLink>
<MenuGap />
<MenuHeader>Options</MenuHeader>
<MenuLink icon="+">Create Log</MenuLink>
</Menu>
)
}
}

14
rpdata-ui/src/routes/logs/LogsRoot.js

@ -1,14 +0,0 @@
import React, { Component } from "react"
import Background from "../../common/Background"
import LogsMenu from "./LogsMenu"
export default class LogsRoot extends Component {
render() {
return (
<div className="LogsRoot theme-logs">
<Background />
<LogsMenu />
</div>
)
}
}

51
rpdata-ui/src/routes/story-content/StoryContentMenu.js

@ -1,51 +0,0 @@
import React, { Component } from "react"
import moment from "moment"
import Menu, { MenuHeader, MenuLink, MenuGap } from '../../common/Menu'
export default class StoryContentMenu extends Component {
render() {
const { story } = this.props
console.log(story.tags)
return (
<Menu>
<MenuHeader>Chapters</MenuHeader>
<ChapterMenu storyId={story.id} chapters={story.chapters} />
<MenuGap />
<MenuHeader>Tags</MenuHeader>
<TagMenu tags={story.tags} />
<MenuGap />
<MenuHeader>Story</MenuHeader>
<MonthMenuItem date={story.fictionalDate} />
<MenuLink to={`/story/author/${story.author}`} icon="A">{story.author}</MenuLink>
<MenuGap />
</Menu>
)
}
}
function ChapterMenu({chapters, storyId}) {
return chapters.map((chapter, index) => (
<MenuLink to={`/story/${storyId}/${chapter.id}`} icon={index + 1}>{chapter.title}</MenuLink>
))
}
function TagMenu({tags}) {
return tags.map(tag => (
<MenuLink tagKind={tag.kind} to={`/story/tag/${tag.kind}/${tag.name}`} icon={tag.kind.charAt(0)}>{tag.name}</MenuLink>
))
}
function MonthMenuItem({date}) {
const fictionalDate = moment.utc(date)
if (fictionalDate.year() < 100) {
return null
}
const monthKey = fictionalDate.format("YYYY-MM")
const monthText = fictionalDate.format("MMM D, YYYY")
return <MenuLink to={`/story/month/${monthKey}`} icon="D">{monthText}</MenuLink>
}

44
rpdata-ui/src/routes/story-content/StoryContentRoot.js

@ -1,44 +0,0 @@
import React, { Component } from "react"
import { Route, Switch, Redirect } from "react-router-dom";
import { Query } from "react-apollo"
import Background from "../../common/Background"
import { LoadingScreen } from "../../common/LoadingScreen"
import StoryContentMenu from "./StoryContentMenu"
import storyContentRoot from "./gql/StoryContentRoot";
class StoryContentRoot extends Component {
render() {
const story = this.props.story
const chapterRedirect = story.chapters.length > 0 ? (
<Redirect exact from={`/story/${story.id}/`} to={`/story/${story.id}/${story.chapters[0].id}`} />
) : null
return (
<div className="StoryContentRoot theme-story">
<Background />
<StoryContentMenu story={this.props.story} />
<Switch>
{chapterRedirect}
</Switch>
</div>
)
}
}
export default ({id, match}) => (
<Query query={storyContentRoot} variables={{id: id || match.params.id}}>
{({ loading, error, data }) => {
if (loading) {
return <LoadingScreen className="theme-story" />
}
if (error) {
return `Error! ${error.message}`
}
return <StoryContentRoot {...data} />
}}
</Query>
)

28
rpdata-ui/src/routes/story-content/gql/StoryContentRoot.js

@ -1,28 +0,0 @@
import gql from "graphql-tag"
export default gql`
query StoryContentRoot($id: String!) {
story(id: $id) {
id
name
author
category
createdDate
fictionalDate
updatedDate
tags {
kind
name
}
chapters {
id
title
author
source
createdDate
fictionalDate
editedDate
}
}
}
`

36
rpdata-ui/src/routes/story/StoryList.js

@ -1,36 +0,0 @@
import React, { Component } from "react"
import { Query } from "react-apollo"
import { LoadingScreen } from "../../common/LoadingScreen"
import Main from "../../common/Main"
import List, {Item} from "../../common/List"
import storyListQuery from "./gql/StoryList";
export class StoryList extends Component {
render() {
const { stories } = this.props
const items = stories.map(story => <Item key={story.id} link={`/story/${story.id}`} icon={story.category.charAt(0)} {...story} />)
return (
<Main className="StoryList">
<List>{items}</List>
</Main>
)
}
}
export default ({filter}) => (
<Query query={storyListQuery} variables={{filter}}>
{({ loading, error, data }) => {
if (loading) {
return <LoadingScreen className="theme-story" />
}
if (error) {
return `Error! ${error.message}`
}
return <StoryList {...data} />
}}
</Query>
)

33
rpdata-ui/src/routes/story/StoryMenu.js

@ -1,33 +0,0 @@
import React, { Component } from "react"
import Menu, { MenuHeader, MenuLink, MenuGap } from "../../common/Menu"
import pluralize from "pluralize"
export default class StoryMenu extends Component {
render() {
return (
<Menu>
<MenuHeader>Story</MenuHeader>
<MenuLink to="/story/" icon="A">All</MenuLink>
<MenuLink to="/story/open" icon="O">Open</MenuLink>
<MenuGap />
<MenuHeader>By Category</MenuHeader>
<CategoryLinks categories={this.props.categories} />
<MenuGap />
<MenuHeader>By Tag</MenuHeader>
<MenuLink to="/story/tags/" icon="T">All Tags</MenuLink>
<MenuGap />
<MenuHeader>Options</MenuHeader>
<MenuLink icon="+">Create Story</MenuLink>
</Menu>
)
}
}
function CategoryLinks({categories}) {
return categories.map(category => {
const icon = category.charAt(0).toUpperCase()
const label = pluralize(category)
return <MenuLink to={`/story/category/${category}`} icon={icon}>{label}</MenuLink>
})
}

43
rpdata-ui/src/routes/story/StoryRoot.js

@ -1,43 +0,0 @@
import React, { Component } from "react"
import { Route, Switch } from "react-router-dom";
import { Query } from "react-apollo"
import StoryMenu from "./StoryMenu"
import Background from "../../common/Background"
import { LoadingScreen } from "../../common/LoadingScreen"
import storyRootQuery from "./gql/StoryRoot"
import StoryList from "./StoryList";
import StoryTags from "./StoryTags";
export class StoryIndex extends Component {
render() {
const categories = this.props.categoryType.enumValues.map(ev => ev.name).sort()
return (
<div className="StoryIndex theme-story">
<Background />
<StoryMenu categories={categories} />
<Switch>
<Route exact path="/story/" component={() => <StoryList filter={{}} />} />
<Route exact path="/story/open/" component={() => <StoryList filter={{open: true}} />} />
<Route exact path="/story/tags/" component={StoryTags} />
<Route exact path="/story/tag/:kind/:name/" component={({match}) => <StoryList filter={{tags: [match.params]}} />} />
<Route exact path="/story/category/:category/" component={({match: {params: {category}}}) => <StoryList filter={{category}} />} />
</Switch>
</div>
)
}
}
export default () => (
<Query query={storyRootQuery}>
{({ loading, error, data }) => {
if (loading) return <LoadingScreen className="theme-story" />
if (error) return `Error! ${error.message}`
return <StoryIndex {...data} />
}}
</Query>
)

34
rpdata-ui/src/routes/story/StoryTags.js

@ -1,34 +0,0 @@
import React, { Component } from "react"
import { Query } from "react-apollo"
import { LoadingScreen } from "../../common/LoadingScreen"
import Main from "../../common/Main"
import storyTagsQuery from "./gql/StoryTags";
export class StoryTags extends Component {
render() {
const { tags } = this.props
return (
<Main className="StoryTags">
{ tags.map(s => <h1>{s.name}</h1>) }
</Main>
)
}
}
export default () => (
<Query query={storyTagsQuery}>
{({ loading, error, data }) => {
if (loading) {
return <LoadingScreen className="theme-story" />
}
if (error) {
return `Error! ${error.message}`
}
return <StoryTags {...data} />
}}
</Query>
)

16
rpdata-ui/src/routes/story/gql/StoryList.js

@ -1,16 +0,0 @@
import gql from "graphql-tag"
export default gql`
query StoryList($filter: StoriesFilter) {
stories(filter: $filter) {
id
name
author
category
tags { kind name }
createdDate
fictionalDate
updatedDate
}
}
`

12
rpdata-ui/src/routes/story/gql/StoryRoot.js

@ -1,12 +0,0 @@
import gql from "graphql-tag"
export default gql`
query StoryRoot {
categoryType: __type(name: "StoryCategory") {
enumValues {
name
description
}
}
}
`

10
rpdata-ui/src/routes/story/gql/StoryTags.js

@ -1,10 +0,0 @@
import gql from "graphql-tag"
export default gql`
query StoryTags {
tags {
kind
name
}
}
`
Loading…
Cancel
Save