rename curated-lists -> story, split pages into own top-level tab again

pages also has sidebar for filtering by list
pages, lists, curatedPages loaded on collection init
curated list only store page id and optional desc, resolved to pages at runtime
This commit is contained in:
Ilya Kreymer
2020-05-29 23:32:22 -07:00
parent eebe66cbf5
commit fb3d137d24
9 changed files with 723 additions and 570 deletions
+1 -1
View File
@@ -252,7 +252,7 @@ class CollIndex extends LitElement
<div class="sort-header is-small">
<a @click=${(e) => this.hideHeader = !this.hideHeader} class="collapse button is-small">
<span class="icon"><fa-icon .svg=${this.hideHeader ? fasArrowDown : fasArrowUp}></span>
<span>${this.hideHeader ? 'Expand' : 'Collapse'}</span>
<span>${this.hideHeader ? 'Collapse List' : 'Expand List'}</span>
</a>
</div>
<nav class="panel is-light">
+35 -15
View File
@@ -3,8 +3,10 @@ import { wrapCss, IS_APP } from './misc';
import { sourceToId } from './pageutils';
import fasBook from '@fortawesome/fontawesome-free/svgs/solid/book.svg';
import farListAlt from '@fortawesome/fontawesome-free/svgs/regular/list-alt.svg';
import fasResources from '@fortawesome/fontawesome-free/svgs/regular/file-code.svg';
import farResources from '@fortawesome/fontawesome-free/svgs/regular/file-code.svg';
import farPlayCircle from '@fortawesome/fontawesome-free/svgs/regular/play-circle.svg';
@@ -32,7 +34,9 @@ class Coll extends LitElement
this.tabData = {};
this.tabNames = ["pages", "resources", "replay"];
this.tabNames = ["pages", "story", "resources", "replay"];
this.hasStory = false;
}
static get properties() {
@@ -44,6 +48,7 @@ class Coll extends LitElement
collInfo: { type: Object, attribute: false },
coll: { type: String },
hasStory: { type: Boolean },
tabData: { type: Object, attribute: false },
@@ -106,7 +111,7 @@ class Coll extends LitElement
const apiPrefix = this.baseApiPrefix + "/" + coll;
const replayPrefix = this.baseReplayPrefix + "/" + coll;
const resp = await fetch(apiPrefix);
const resp = await fetch(apiPrefix + "?all=1");
if (resp.status != 200) {
this.collInfo = {};
@@ -121,6 +126,8 @@ class Coll extends LitElement
this.collInfo.title = this.collInfo.filename;
}
this.hasStory = this.collInfo.desc || this.collInfo.lists.length;
this.dispatchEvent(new CustomEvent("coll-loaded", {detail: {
collInfo: this.collInfo,
alreadyLoaded: true
@@ -146,9 +153,10 @@ class Coll extends LitElement
}
if (this.collInfo.coll && !this.tabNames.includes(this.tabData.view)) {
const view = this.hasStory ? "story" : (this.collInfo.pages.length ? "pages" : "resources");
this.tabData = {
...this.tabData,
view: this.collInfo.numPages || this.collInfo.numLists ? "pages" : "resources"
...this.tabData, view
};
}
}
@@ -165,6 +173,7 @@ class Coll extends LitElement
this.tabData = {view: this.tabData.view, ...event.detail.data};
this._replaceLoc = !this._locUpdateNeeded && event.detail.replaceLoc;
this._locUpdateNeeded = true;
console.log(this.tabData);
}
}
@@ -228,12 +237,6 @@ class Coll extends LitElement
display: flex;
flex-direction: column;
}
wr-coll-replay, wr-coll-resources, wr-coll-curated, wr-coll-pages {
height: 100%;
display: flex;
flex-direction: column;
}
`);
}
@@ -250,6 +253,14 @@ class Coll extends LitElement
${!this.embed ? html`
<div class="main tabs has-background-info is-centered">
<ul>
${this.hasStory ? html`
<li class="${this.tabData.view === 'story' ? 'is-active' : ''}">
<a @click="${this.onTabClick}" href="#story" class="is-size-6">
<span class="icon"><fa-icon .svg="${fasBook}"></fa-icon></span>
<span class="tab-label" title="Story">Story View</span>
</a>
</li>` : ``}
<li class="${this.tabData.view === 'pages' ? 'is-active' : ''}">
<a @click="${this.onTabClick}" href="#pages" class="is-size-6">
<span class="icon"><fa-icon .svg="${farListAlt}"></fa-icon></span>
@@ -259,7 +270,7 @@ class Coll extends LitElement
<li class="${this.tabData.view === 'resources' ? 'is-active' : ''}">
<a @click="${this.onTabClick}" href="#resources" class="is-size-6">
<span class="icon"><fa-icon .svg="${fasResources}"></fa-icon></span>
<span class="icon"><fa-icon .svg="${farResources}"></fa-icon></span>
<span class="tab-label" title="URL Resources">Page Resources</span>
</a>
</li>
@@ -280,18 +291,27 @@ class Coll extends LitElement
}
renderCollTabs() {
const isStory = this.tabData.view === 'story';
const isPages = this.tabData.view === 'pages';
const isResources = this.tabData.view === 'resources';
const isReplay = this.tabData.view === 'replay';
return html`
<wr-coll-curated .collInfo="${this.collInfo}"
${this.hasStory ? html`
<wr-coll-story .collInfo="${this.collInfo}"
.active="${isStory}"
currList="${this.tabData.currList || 0}"
@coll-tab-nav="${this.onCollTabNav}" id="story"
class="${isStory ? '' : 'is-hidden'}">
</wr-coll-story>` : ''}
<wr-page-view .collInfo="${this.collInfo}"
.active="${isPages}"
currList="${this.tabData.currList === undefined ? "pages" : this.tabData.currList}"
currList="${this.tabData.currList || 0}"
query="${this.tabData.query || ""}"
@coll-tab-nav="${this.onCollTabNav}" id="pages"
class="${isPages ? '' : 'is-hidden'}">
</wr-coll-curated>
</wr-page-view>
<wr-coll-resources .collInfo="${this.collInfo}"
.active="${isResources}"
-356
View File
@@ -1,356 +0,0 @@
import { LitElement, html, css } from 'lit-element';
import { wrapCss } from './misc';
import { unsafeHTML } from 'lit-html/directives/unsafe-html';
import marked from 'marked';
import { getTS } from './pageutils';
// ===========================================================================
class CuratedLists extends LitElement
{
constructor() {
super();
this.active = false;
this.collInfo = null;
this.query = "";
this.currList = "pages";
this.lists = [];
this.curatedPages = {};
this.offset = 0;
this.lastST = 0;
this.clickTime = 0;
this.hasNarrative = false;
}
static get properties() {
return {
active: { type: Boolean },
collInfo: { type: Object },
query: { type: String },
lists: { type: Array },
curatedPages: { type: Object },
currList: { type: String },
hasNarrative: { type: Boolean },
}
}
firstUpdated() {
//this.doLoadCurated();
}
updated(changedProperties) {
if (changedProperties.has("collInfo")) {
this.doLoadCurated();
}
if (changedProperties.has("currList") || changedProperties.has("query")) {
this.sendChangeEvent({
currList: this.currList,
query: this.query
});
}
}
async doLoadCurated() {
this.hasNarrative = this.collInfo.desc || this.collInfo.numLists;
if (!this.collInfo.numLists) {
this.total = 0;
this.curatedPages = {};
this.lists = [];
this.currList = "pages";
return;
}
const resp = await fetch(`${this.collInfo.apiPrefix}/curatedPages?offset=${this.offset}&count=10000`);
const json = await resp.json();
this.total = json.total;
this.curatedPages = {};
this.lists = json.lists;
for (const curated of json.curatedPages) {
if (!this.curatedPages[curated.list]) {
this.curatedPages[curated.list] = [];
}
this.curatedPages[curated.list].push(curated);
}
this.scrollToList();
}
static get styles() {
return wrapCss(css`
:host {
justify-content: flex-start;
align-items: center;
}
.columns {
width: 100%;
justify-self: stretch;
}
.column.main-content {
margin: 12px 0px 0px 0px;
padding: 0px;
max-height: calc(100% - 0.75em);
display: flex;
flex-direction: column;
height: min-content;
padding-left: 0.75em;
}
.column.main-content.main-scroll {
padding-right: 0.75em;
word-break: break-all;
}
.column.main-content.pages {
height: calc(100% - 1.2em);
}
ul.menu-list a.is-active {
background-color: #55be6f;
}
@media screen and (min-width: 768px) {
.columns {
max-height: 100%;
height: 100%;
margin-top: 0.75em;
}
.column.sidebar {
max-height: 100%;
overflow-y: auto;
}
}
@media screen and (max-width: 767px) {
.columns {
position: relative;
max-height: 100%;
height: 100%;
}
.column.sidebar {
max-height: 150px;
overflow-y: auto;
margin-top: 0.75em;
}
.column.main-content {
position: relative;
overflow-y: auto;
border-top: 1px solid black;
width: 100%;
height: 100%;
max-height: calc(100% - 150px - 0.75em);
}
.menu {
font-size: 0.80rem;
}
}
`);
}
render() {
const currListNum = Number(this.currList);
return html`
<div class="columns">
<div class="column sidebar is-one-fifth">
<aside class="menu">
<p class="menu-label">${this.collInfo.title}</p>
<ul class="menu-list">
<li><a class="${this.currList === 'pages' ? 'is-active' : ''}" data-list="all-pages" @click=${this.onClickPages}>Page Search</a></li>
</ul>
${this.hasNarrative ? html`
<ul class="menu-list">
<li>
<a href="#list-0" data-list="0" class="${currListNum === 0 ? 'is-active' : ''}"
@click=${this.onClickScroll}>Narrative</a>
<ul class="menu-list">${this.lists.map(list => html`
<li>
<a @click=${this.onClickScroll} href="#list-${list.id}"
data-list="${list.id}"
class="${currListNum === list.id ? 'is-active' : ''}">${list.title}</a>
</li>`)}
</ul>
</li>
</ul>` : ``}
</aside>
</div>
${this.renderPages()}
${this.renderLists()}
</div>
`;
}
renderPages() {
return html`
<div class="column main-content pages ${this.currList === "pages" ? '' : 'is-hidden'}">
<wr-page-view
.active="${this.active && this.currList === "pages"}"
query="${this.query}" .collInfo="${this.collInfo}"
@coll-tab-nav="${this.onCollTabNav}">
</wr-page-view>
</div>
`;
}
onCollTabNav(event) {
if (event.detail.data && event.detail.data.query !== undefined) {
this.query = event.detail.data.query;
}
}
renderLists() {
if (!this.hasNarrative) {
return;
}
return html`
<div @scroll=${this.onScroll} class="${this.currList !== "pages" ? '' : 'is-hidden'} column main-content main-scroll">
<section id="list-0" class="">
<h2 class="has-text-centered title is-3">${this.collInfo.title}</h2>
${this.collInfo.desc ? unsafeHTML(marked(this.collInfo.desc)) : ''}
</section>
${this.lists.map((list, i) => html`
<article id="list-${list.id}">
<div class="content">
<hr/>
<h3>${list.title}</h3>
<p>${list.desc}</p>
<ol style="margin-left: 30px">
${this.curatedPages[list.id] ? this.curatedPages[list.id].map((p) => html`
<li>
<div class="content">
<a @click="${this.onReplay}" data-url="${p.url}" data-ts="${getTS(p.date)}" href="#">
<p class="is-size-6 has-text-weight-bold has-text-link">${p.title || p.url}</p>
<p class="has-text-dark">${p.url}</p>
</a>
<p>${new Date(p.date).toLocaleString()}</p>
<p>${p.desc}</p>
</div>
<hr/>
</li>
`) : html``}
</ol>
</div>
</article>
`)}
</div>
`;
}
onReplay(event) {
event.preventDefault();
const data = {
url: event.currentTarget.getAttribute("data-url"),
ts: event.currentTarget.getAttribute("data-ts"),
view: "replay"
};
this.sendChangeEvent(data);
return false;
}
sendChangeEvent(data) {
this.dispatchEvent(new CustomEvent("coll-tab-nav", {detail: {data}}));
}
onClickPages(event) {
event.preventDefault();
//this.pageView = true;
this.currList = "pages";
return false;
}
onClickScroll(event) {
event.preventDefault();
//this.pageView = false;
this.currList = event.currentTarget.getAttribute("data-list");
this.scrollToList();
return false;
}
scrollToList() {
if (this.currList === "pages") {
return;
}
// lists are 1 based, 0 is header, 1 is first list
if (Number(this.currList) > this.lists.length) {
this.currList = "0";
}
const opts = {behavior: "smooth", block: "nearest", inline: "nearest"};
this.clickTime = new Date().getTime();
const curr = this.renderRoot.getElementById("list-" + this.currList);
if (curr) {
curr.scrollIntoView(opts);
}
}
onScroll(event) {
const scrollable = event.currentTarget;
const curr = this.renderRoot.getElementById("list-" + this.currList);
if (!curr) {
return;
}
let next = curr;
const target = scrollable.offsetTop;
const currST = scrollable.scrollTop;
if (currST > this.lastST) {
while (next.nextElementSibling && next.nextElementSibling.getBoundingClientRect().top < target) {
next = next.nextElementSibling;
}
} else {
while (next.previousElementSibling && next.previousElementSibling.getBoundingClientRect().bottom >= target) {
next = next.previousElementSibling;
}
}
this.lastST = currST;
if (next && next != curr) {
if (next.id.startsWith("list-")) {
this.currList = next.id.slice(5);
}
}
if ((new Date().getTime() - this.clickTime) < 1000) {
return;
}
const sel = this.renderRoot.querySelector(`a[data-list="${this.currList}"]`);
if (sel) {
const opts = {behavior: "smooth", block: "nearest", inline: "nearest"};
sel.scrollIntoView(opts);
}
}
}
customElements.define("wr-coll-curated", CuratedLists);
export { CuratedLists };
+134 -28
View File
@@ -7,7 +7,6 @@ import { getTS } from './pageutils';
import FlexSearch from 'flexsearch';
import "keyword-mark-element/lib/keyword-mark.js";
//const FlexSearch = Object;
import fasSearch from '@fortawesome/fontawesome-free/svgs/solid/search.svg';
@@ -17,7 +16,6 @@ class Pages extends LitElement
{
constructor() {
super();
this.pages = [];
this.filteredPages = [];
this.sortedPages = [];
this.query = "";
@@ -25,6 +23,8 @@ class Pages extends LitElement
this.newQuery = null;
this.loading = false;
this.currList = 0;
this.active = false;
this.changeNeeded = false;
}
@@ -47,20 +47,17 @@ class Pages extends LitElement
active: { type: Boolean},
collInfo: { type: Object },
pages: { type: Array },
currList: { type: Number },
filteredPages: { type: Array },
sortedPages: { type: Array },
query: { type: String },
loading: { type: Boolean },
}
}
firstUpdated() {
//this._ival = window.setInterval(() => {
//}, 10000);
}
_timedUpdate() {
if (this.newQuery !== null) {
this.query = this.newQuery;
@@ -71,8 +68,9 @@ class Pages extends LitElement
updated(changedProperties) {
if (changedProperties.has("collInfo")) {
this.doUpdate();
} else if (changedProperties.has("query")) {
this.updateTextSearch();
this.filter();
} else if (changedProperties.has("query") || changedProperties.has("currList")) {
this.filter();
}
if (changedProperties.has("active") && this.active) {
@@ -82,15 +80,6 @@ class Pages extends LitElement
}
}
async doUpdate() {
const result = await fetch(`${this.collInfo.apiPrefix}/pages`);
const json = await result.json();
this.pages = json.pages || [];
this.updateTextSearch();
this.filter();
}
onChangeQuery(event) {
this.newQuery = event.currentTarget.value;
//this.loading = true;
@@ -112,14 +101,35 @@ class Pages extends LitElement
const result = await this.flex.search(this.query);
this.filteredPages = result;
} else {
this.filteredPages = this.pages;
this.filteredPages = this.collInfo.pages;
}
if (this.currList !== 0) {
await this.filterCurated();
}
this.loading = false;
this.changeNeeded = false;
const data = {query: this.query};
const data = {query: this.query, currList: this.currList};
this.sendChangeEvent(data);
}
async filterCurated() {
const resp = await fetch(`${this.collInfo.apiPrefix}/curated/${this.currList}`);
const json = await resp.json();
this.sortedPages = [];
for (const c of json.curated) {
for (const p of this.filteredPages) {
if (p.id === c.page) {
this.sortedPages.push(p);
break;
}
}
}
}
sendChangeEvent(data) {
this.dispatchEvent(new CustomEvent("coll-tab-nav", {detail: {data}}));
}
@@ -133,7 +143,7 @@ class Pages extends LitElement
async: true
});
this.flex.add(this.pages);
this.flex.add(this.collInfo.pages);
}
static get styles() {
@@ -143,7 +153,63 @@ class Pages extends LitElement
height: 100%;
display: flex;
flex-direction: column;
padding: 0 0.75rem 0.75rem 0;
}
.columns {
width: 100%;
justify-self: stretch;
margin-left: 0;
}
.column.main-content {
margin: 12px 0px 0px 0px;
padding: 0 0.75em 0 0.75em;
max-height: calc(100% - 0.75em);
display: flex;
flex-direction: column;
height: calc(100% - 1.2em);
}
@media screen and (min-width: 768px) {
.columns {
max-height: 100%;
height: 100%;
margin-top: 0.75em;
}
.column.sidebar {
max-height: 100%;
overflow-y: auto;
}
}
@media screen and (max-width: 767px) {
.columns {
position: relative;
max-height: 100%;
height: 100%;
}
.column.sidebar {
max-height: 150px;
overflow-y: auto;
margin-top: 0.75em;
}
.column.main-content {
position: relative;
overflow-y: auto;
border-top: 1px solid black;
width: 100%;
height: 100%;
max-height: calc(100% - 150px - 0.75em);
padding: 0px;
}
.menu {
font-size: 0.80rem;
}
}
.scroller {
@@ -177,10 +243,47 @@ class Pages extends LitElement
`);
}
onSelectList(event) {
event.preventDefault();
this.currList = Number(event.currentTarget.getAttribute("data-list"));
}
render() {
const currList = this.currList;
return html`
<div class="columns">
<div class="column sidebar is-one-fifth">
<aside class="menu">
<ul class="menu-list">
<li>
<a href="#list-0" data-list="0" class="${currList === 0 ? 'is-active' : ''}"
@click=${this.onSelectList}>All Pages</a>
${this.collInfo.lists.length ? html`
<p class="menu-label">Page Lists</p>
<ul class="menu-list">${this.collInfo.lists.map(list => html`
<li>
<a @click=${this.onSelectList} href="#list-${list.id}"
data-list="${list.id}"
class="${currList === list.id ? 'is-active' : ''}">${list.title}</a>
</li>`)}
</ul>` : ``}
</li>
</ul>
</aside>
</div>
<div class="column main-content">
${this.renderPages()}
</div>
</div>`
}
renderPages() {
const name = this.currList === 0 ? "All Pages" : this.collInfo.lists[this.currList - 1].title;
return html`
<nav class="panel">
<div class="panel-heading light-blue">Pages for: ${this.collInfo.title}</div>
<div class="panel-heading light-blue">${this.collInfo.title} - ${name}</div>
<div class="panel-block">
<div class="control has-icons-left ${this.loading ? 'is-loading' : ''}">
<input type="text" class="input" @input="${this.onChangeQuery}" .value="${this.query}" type="text"
@@ -190,13 +293,16 @@ class Pages extends LitElement
</div>
<div class="panel-block status">
<span class="num-results">${this.formatResults()}</span>
${this.currList === 0 ? html`
<wr-sorter id="pages"
defaultKey="title"
.sortKeys="${Pages.sortKeys}"
.data="${this.filteredPages}"
@sort-changed="${(e) => this.sortedPages = e.detail.sortedData}"
class="${this.filteredPages.length ? '' : 'is-hidden'}">
</wr-sorter>
</wr-sorter>` : ``}
</div>
<div class="scroller" @scroll="${this.onScroll}">
${this.sortedPages.map((p) => html`
@@ -207,7 +313,7 @@ class Pages extends LitElement
}
formatResults() {
if (!this.collInfo || !this.collInfo.numPages) {
if (!this.collInfo || !this.collInfo.pages.length) {
return html`No Pages defined this archive. Check out <a href="#view=resources">Page Resources</a> to search by URL.`;
}
@@ -216,7 +322,7 @@ class Pages extends LitElement
}
if (!this.sortedPages.length) {
return "No Pages Found."
return this.query ? "No Pages Found. Try changing the search query." : "No Pages Found";
} else if (this.sortedPages.length === 1) {
return "1 Page";
} else {
+3 -1
View File
@@ -181,8 +181,10 @@ class Replay extends LitElement
static get styles() {
return wrapCss(css`
host: {
:host {
display: flex;
flex-direction: column;
height: 100%;
}
iframe {
+304
View File
@@ -0,0 +1,304 @@
import { LitElement, html, css } from 'lit-element';
import { wrapCss } from './misc';
import { unsafeHTML } from 'lit-html/directives/unsafe-html';
import marked from 'marked';
import { getTS } from './pageutils';
// ===========================================================================
class Story extends LitElement
{
constructor() {
super();
this.collInfo = null;
this.curatedPageMap = {};
this.currList = 0;
this.active = false;
this.lastST = 0;
this.clickTime = 0;
}
static get properties() {
return {
collInfo: { type: Object },
active: { type: Boolean },
curatedPageMap: { type: Object },
currList: { type: Number },
}
}
updated(changedProperties) {
if (changedProperties.has("collInfo")) {
this.doLoadCurated();
}
if (changedProperties.has("currList") && this.active) {
this.sendChangeEvent({
currList: this.currList,
});
}
}
async doLoadCurated() {
this.curatedPageMap = {};
const pageMap = {};
for (const page of this.collInfo.pages) {
pageMap[page.id] = page;
}
for (const curated of this.collInfo.curatedPages) {
if (!this.curatedPageMap[curated.list]) {
this.curatedPageMap[curated.list] = [];
}
const page = pageMap[curated.page];
if (!page) {
console.log("No Page with id: " + page);
continue;
}
const url = page.url;
const ts = page.ts;
const title = page.title || page.url;
const desc = curated.desc;
this.curatedPageMap[curated.list].push({url, ts, title, desc});
}
this.scrollToList();
}
static get styles() {
return wrapCss(css`
:host {
justify-content: flex-start;
align-items: center;
}
.columns {
width: 100%;
justify-self: stretch;
margin-left: 0;
}
.column.main-content {
margin: 12px 0px 0px 0px;
padding: 0px;
max-height: calc(100% - 0.75em);
display: flex;
flex-direction: column;
height: min-content;
padding-left: 0.75em;
}
.column.main-content.main-scroll {
padding-right: 0.75em;
word-break: break-all;
}
ul.menu-list a.is-active {
background-color: #55be6f;
}
@media screen and (min-width: 768px) {
.columns {
max-height: 100%;
height: 100%;
margin-top: 0.75em;
}
.column.sidebar {
max-height: 100%;
overflow-y: auto;
}
}
@media screen and (max-width: 767px) {
.columns {
position: relative;
max-height: 100%;
height: 100%;
}
.column.sidebar {
max-height: 150px;
overflow-y: auto;
margin-top: 0.75em;
}
.column.main-content {
position: relative;
overflow-y: auto;
border-top: 1px solid black;
width: 100%;
height: 100%;
max-height: calc(100% - 150px - 0.75em);
}
.menu {
font-size: 0.80rem;
}
}
`);
}
render() {
const currListNum = this.currList;
return html`
<div class="columns">
<div class="column sidebar is-one-fifth">
<aside class="menu">
<ul class="menu-list">
<li>
<a href="#list-0" data-list="0" class="${currListNum === 0 ? 'is-active' : ''}"
@click=${this.onClickScroll}>${this.collInfo.title}</a>
<ul class="menu-list">${this.collInfo.lists.map(list => html`
<li>
<a @click=${this.onClickScroll} href="#list-${list.id}"
data-list="${list.id}"
class="${currListNum === list.id ? 'is-active' : ''}">${list.title}</a>
</li>`)}
</ul>
</li>
</ul>
</aside>
</div>
<div @scroll=${this.onScroll} class="column main-content main-scroll">
<section id="list-0" class="">
<h2 class="has-text-centered title is-3">${this.collInfo.title}</h2>
${this.collInfo.desc ? unsafeHTML(marked(this.collInfo.desc)) : ''}
</section>
${this.renderLists()}
</div>
</div>
`;
}
renderLists() {
return html`
${this.collInfo.lists.map((list, i) => html`
<article id="list-${list.id}">
<div class="content">
<hr/>
<h3>${list.title}</h3>
<p>${list.desc}</p>
<ol style="margin-left: 30px">
${this.curatedPageMap[list.id] ? this.curatedPageMap[list.id].map((p) => this.renderCPage(p)) : html``}
</ol>
</div>
</article>
`)}`;
}
renderCPage(p) {
const date = new Date(p.ts);
return html`
<li>
<div class="content">
<a @click="${this.onReplay}" data-url="${p.url}" data-ts="${getTS(date.toISOString())}" href="#">
<p class="is-size-6 has-text-weight-bold has-text-link">${p.title}</p>
<p class="has-text-dark">${p.url}</p>
</a>
<p>${date.toLocaleString()}</p>
<p>${p.desc}</p>
</div>
<hr/>
</li>`;
}
onReplay(event) {
event.preventDefault();
const data = {
url: event.currentTarget.getAttribute("data-url"),
ts: event.currentTarget.getAttribute("data-ts"),
view: "replay"
};
this.sendChangeEvent(data);
return false;
}
sendChangeEvent(data) {
this.dispatchEvent(new CustomEvent("coll-tab-nav", {detail: {data}}));
}
onClickScroll(event) {
event.preventDefault();
//this.pageView = false;
this.currList = Number(event.currentTarget.getAttribute("data-list"));
this.scrollToList();
return false;
}
scrollToList() {
// lists are 1 based, 0 is header, 1 is first list
if (this.currList > this.collInfo.lists.length) {
this.currList = 0;
}
const opts = {behavior: "smooth", block: "nearest", inline: "nearest"};
this.clickTime = new Date().getTime();
const curr = this.renderRoot.getElementById("list-" + this.currList);
if (curr) {
curr.scrollIntoView(opts);
}
}
onScroll(event) {
const scrollable = event.currentTarget;
const curr = this.renderRoot.getElementById("list-" + this.currList);
if (!curr) {
return;
}
let next = curr;
const target = scrollable.offsetTop;
const currST = scrollable.scrollTop;
if (currST > this.lastST) {
while (next.nextElementSibling && next.nextElementSibling.getBoundingClientRect().top < target) {
next = next.nextElementSibling;
}
} else {
while (next.previousElementSibling && next.previousElementSibling.getBoundingClientRect().bottom >= target) {
next = next.previousElementSibling;
}
}
this.lastST = currST;
if (next && next != curr) {
if (next.id.startsWith("list-")) {
this.currList = Number(next.id.slice(5));
}
}
if ((new Date().getTime() - this.clickTime) < 1000) {
return;
}
const sel = this.renderRoot.querySelector(`a[data-list="${this.currList}"]`);
if (sel) {
const opts = {behavior: "smooth", block: "nearest", inline: "nearest"};
sel.scrollIntoView(opts);
}
}
}
customElements.define("wr-coll-story", Story);
export { Story };
+1 -1
View File
@@ -2,7 +2,7 @@ import { App } from './appmain';
import { Chooser } from './chooser';
import { CollIndex } from './coll-index';
import { Coll } from './coll';
import { CuratedList } from './curated-lists';
import { Story } from './story';
import { GDrive } from './gdrive';
import { Loader } from './loader';
import { Pages } from './pages';
+4 -4
View File
File diff suppressed because one or more lines are too long
+221 -144
View File
File diff suppressed because one or more lines are too long