mirror of
https://github.com/webrecorder/pywb.git
synced 2025-03-24 06:59:52 +01:00
vueui: add highlighting for current snapshot and its parent period to both timeline and calendar full-view/linear-view
This commit is contained in:
parent
ed3ed1281d
commit
2ac83c61fd
File diff suppressed because one or more lines are too long
@ -38,7 +38,7 @@
|
|||||||
<div>{{ config.url }}</div>
|
<div>{{ config.url }}</div>
|
||||||
<div v-if="currentSnapshot && !showFullView">
|
<div v-if="currentSnapshot && !showFullView">
|
||||||
<span v-if="config.title">{{ config.title }}</span>
|
<span v-if="config.title">{{ config.title }}</span>
|
||||||
{{currentSnapshot.getTimeDateFormatted()}}
|
Current capture: {{currentSnapshot.getTimeDateFormatted()}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<CalendarYear v-if="showFullView"
|
<CalendarYear v-if="showFullView"
|
||||||
|
@ -17,6 +17,9 @@
|
|||||||
background-color: #fff7ce;
|
background-color: #fff7ce;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
|
.calendar-month.contains-current-snapshot {
|
||||||
|
border: solid 1px red;
|
||||||
|
}
|
||||||
.calendar-month > h3 {
|
.calendar-month > h3 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
@ -59,6 +62,10 @@
|
|||||||
background-color: rgba(166, 205, 245, .85);
|
background-color: rgba(166, 205, 245, .85);
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
.calendar-month .day.contains-current-snapshot .size {
|
||||||
|
background-color: rgba(255, 100, 100, .85);
|
||||||
|
}
|
||||||
|
|
||||||
.calendar-month .day .day-id {
|
.calendar-month .day .day-id {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
@ -83,19 +90,21 @@
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="calendar-month" :class="{current: isCurrent}">
|
<div class="calendar-month" :class="{current: isCurrent, 'contains-current-snapshot': containsCurrentSnapshot}">
|
||||||
<h3>{{month.getReadableId()}} <span v-if="month.snapshotCount">({{ month.snapshotCount }})</span></h3>
|
<h3>{{month.getReadableId()}} <span v-if="month.snapshotCount">({{ month.snapshotCount }})</span></h3>
|
||||||
<div v-if="month.snapshotCount">
|
<div v-if="month.snapshotCount">
|
||||||
<span v-for="(day) in ['S', 'M', 'T', 'W', 'H', 'F', 'S']" class="day" :style="dayStyle">{{day}}</span><br/>
|
<span v-for="(day) in ['S', 'M', 'T', 'W', 'H', 'F', 'S']" class="day" :style="dayStyle">{{day}}</span><br/>
|
||||||
<span v-for="(day,i) in days"><br v-if="i && i % 7===0"/><span class="day" :class="{empty: !day || !day.snapshotCount}" :style="dayStyle" @click="gotoDay(day, $event)"><template v-if="day"><span class="size" v-if="day.snapshotCount" :style="getDayCountCircleStyle(day.snapshotCount)"> </span><span class="day-id">{{day.id}}</span><span v-if="day.snapshotCount" class="count">{{day.snapshotCount}} capture<span v-if="day.snapshotCount!==1">s</span></span></template><template v-else v-html="' '"></template></span></span>
|
<span v-for="(day,i) in days"><br v-if="i && i % 7===0"/><span class="day" :class="{empty: !day || !day.snapshotCount, 'contains-current-snapshot':dayContainsCurrentSnapshot(day)}" :style="dayStyle" @click="gotoDay(day, $event)"><template v-if="day"><span class="size" v-if="day.snapshotCount" :style="getDayCountCircleStyle(day.snapshotCount)"> </span><span class="day-id">{{day.id}}</span><span v-if="day.snapshotCount" class="count">{{day.snapshotCount}} capture<span v-if="day.snapshotCount!==1">s</span></span></template><template v-else v-html="' '"></template></span></span>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="empty">no captures</div>
|
<div v-else class="empty">no captures</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import {PywbPeriod} from "../model";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ["month", "year", "isCurrent", "hasCurrentSnapshot"],
|
props: ["month", "year", "isCurrent", "yearContainsCurrentSnapshot", "currentSnapshot"],
|
||||||
data: function() {
|
data: function() {
|
||||||
return {
|
return {
|
||||||
maxInDay: 0,
|
maxInDay: 0,
|
||||||
@ -127,6 +136,10 @@ export default {
|
|||||||
days.push(null);
|
days.push(null);
|
||||||
}
|
}
|
||||||
return days;
|
return days;
|
||||||
|
},
|
||||||
|
containsCurrentSnapshot() {
|
||||||
|
return this.currentSnapshot &&
|
||||||
|
this.month.contains(this.currentSnapshot);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -150,6 +163,9 @@ export default {
|
|||||||
// background-color: hsl(${scaledColorHue}, 100%, 50%, .2)
|
// background-color: hsl(${scaledColorHue}, 100%, 50%, .2)
|
||||||
|
|
||||||
return `width: ${scaledSize}px; height: ${scaledSize}px; top: ${margin}px; left: ${margin}px; border-radius: ${scaledSize/2}px;`;
|
return `width: ${scaledSize}px; height: ${scaledSize}px; top: ${margin}px; left: ${margin}px; border-radius: ${scaledSize/2}px;`;
|
||||||
|
},
|
||||||
|
dayContainsCurrentSnapshot(day) {
|
||||||
|
return !!day && day.snapshotCount > 0 && this.containsCurrentSnapshot && day.contains(this.currentSnapshot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -30,8 +30,8 @@
|
|||||||
:key="month.id"
|
:key="month.id"
|
||||||
:month="month"
|
:month="month"
|
||||||
:year="year"
|
:year="year"
|
||||||
|
:current-snapshot="containsCurrentSnapshot ? currentSnapshot : null"
|
||||||
:is-current="month === currentMonth"
|
:is-current="month === currentMonth"
|
||||||
:has-current-snapshot="month === currentMonth"
|
|
||||||
@goto-period="$emit('goto-period', $event)"
|
@goto-period="$emit('goto-period', $event)"
|
||||||
@show-day-timeline="setCurrentTimeline"
|
@show-day-timeline="setCurrentTimeline"
|
||||||
></CalendarMonth>
|
></CalendarMonth>
|
||||||
@ -39,6 +39,7 @@
|
|||||||
<Tooltip :position="currentTimelinePos" v-if="currentTimelinePeriod" ref="timelineLinearTooltip">
|
<Tooltip :position="currentTimelinePos" v-if="currentTimelinePeriod" ref="timelineLinearTooltip">
|
||||||
<TimelineLinear
|
<TimelineLinear
|
||||||
:period="currentTimelinePeriod"
|
:period="currentTimelinePeriod"
|
||||||
|
:current-snapshot="containsCurrentSnapshot ? currentSnapshot : null"
|
||||||
@goto-period="gotoPeriod"
|
@goto-period="gotoPeriod"
|
||||||
></TimelineLinear>
|
></TimelineLinear>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@ -67,9 +68,14 @@ export default {
|
|||||||
computed: {
|
computed: {
|
||||||
year() { // the year that the timeline period is in
|
year() { // the year that the timeline period is in
|
||||||
let year = null;
|
let year = null;
|
||||||
|
// if timeline is showing all year
|
||||||
if (this.period.type === PywbPeriod.Type.all) {
|
if (this.period.type === PywbPeriod.Type.all) {
|
||||||
// if timeline is showing all year => pick the LAST YEAR
|
// if no current snapshot => pick the LAST YEAR
|
||||||
year = this.period.children[this.period.children.length-1];
|
if (!this.currentSnapshot) {
|
||||||
|
year = this.period.children[this.period.children.length-1];
|
||||||
|
} else {
|
||||||
|
year = this.period.findByFullId(String(this.currentSnapshot.year));
|
||||||
|
}
|
||||||
} else if (this.period.type === PywbPeriod.Type.year) {
|
} else if (this.period.type === PywbPeriod.Type.year) {
|
||||||
year = this.period;
|
year = this.period;
|
||||||
} else {
|
} else {
|
||||||
@ -88,6 +94,10 @@ export default {
|
|||||||
month = this.period.getParents().filter(p => p.type === PywbPeriod.Type.month)[0];
|
month = this.period.getParents().filter(p => p.type === PywbPeriod.Type.month)[0];
|
||||||
}
|
}
|
||||||
return month;
|
return month;
|
||||||
|
},
|
||||||
|
containsCurrentSnapshot() {
|
||||||
|
return this.currentSnapshot &&
|
||||||
|
this.year.contains(this.currentSnapshot);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -21,14 +21,14 @@
|
|||||||
<div v-for="subPeriod in period.children"
|
<div v-for="subPeriod in period.children"
|
||||||
:key="subPeriod.id"
|
:key="subPeriod.id"
|
||||||
class="period"
|
class="period"
|
||||||
:class="{empty: !subPeriod.snapshotCount, highlight: highlightPeriod === subPeriod, 'last-level': !canZoom}"
|
:class="{empty: !subPeriod.snapshotCount, highlight: highlightPeriod === subPeriod, 'last-level': !canZoom, 'contains-current-snapshot': containsCurrentSnapshot(subPeriod) }"
|
||||||
>
|
>
|
||||||
<div class="histo">
|
<div class="histo">
|
||||||
<div class="line"
|
<div class="line"
|
||||||
v-for="histoPeriod in subPeriod.children"
|
v-for="histoPeriod in subPeriod.children"
|
||||||
:key="histoPeriod.id"
|
:key="histoPeriod.id"
|
||||||
:style="{height: getHistoLineHeight(histoPeriod.snapshotCount)}"
|
:style="{height: getHistoLineHeight(histoPeriod.snapshotCount)}"
|
||||||
:class="{'has-single-snapshot': histoPeriod.snapshotCount === 1}"
|
:class="{'has-single-snapshot': histoPeriod.snapshotCount === 1, 'contains-current-snapshot': containsCurrentSnapshot(histoPeriod)}"
|
||||||
@click="changePeriod(histoPeriod, $event)"
|
@click="changePeriod(histoPeriod, $event)"
|
||||||
@mouseover="setTooltipPeriod(histoPeriod, $event)"
|
@mouseover="setTooltipPeriod(histoPeriod, $event)"
|
||||||
@mouseout="setTooltipPeriod(null, $event)"
|
@mouseout="setTooltipPeriod(null, $event)"
|
||||||
@ -93,12 +93,18 @@ export default{
|
|||||||
},
|
},
|
||||||
isTooltipPeriodDayOrHour() {
|
isTooltipPeriodDayOrHour() {
|
||||||
return this.tooltipPeriod.type >= PywbPeriod.Type.day;
|
return this.tooltipPeriod.type >= PywbPeriod.Type.day;
|
||||||
|
},
|
||||||
|
iContainCurrentSnapshot() {
|
||||||
|
return this.currentSnapshot && this.period.contains(this.currentSnapshot);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
updated() {
|
updated() {
|
||||||
// do something on update
|
// do something on update
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
containsCurrentSnapshot(period) {
|
||||||
|
return this.iContainCurrentSnapshot && period.contains(this.currentSnapshot);
|
||||||
|
},
|
||||||
addEmptySubPeriods() {
|
addEmptySubPeriods() {
|
||||||
this.period.fillEmptyChildPeriods(true);
|
this.period.fillEmptyChildPeriods(true);
|
||||||
},
|
},
|
||||||
@ -315,6 +321,9 @@ export default{
|
|||||||
.timeline .period:hover {
|
.timeline .period:hover {
|
||||||
background-color: #eeeeee;
|
background-color: #eeeeee;
|
||||||
}
|
}
|
||||||
|
.timeline .period.contains-current-snapshot, .timeline .period.contains-current-snapshot:hover {
|
||||||
|
background-color: #f7def4;
|
||||||
|
}
|
||||||
|
|
||||||
/* empty period */
|
/* empty period */
|
||||||
.timeline .period.empty {
|
.timeline .period.empty {
|
||||||
@ -399,6 +408,10 @@ export default{
|
|||||||
background-color: #f5a6eb;
|
background-color: #f5a6eb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.timeline .period .histo .line.contains-current-snapshot {
|
||||||
|
background-color: red;
|
||||||
|
}
|
||||||
|
|
||||||
/* Period that contains ONE snapshot only will show snapshot info*/
|
/* Period that contains ONE snapshot only will show snapshot info*/
|
||||||
.timeline .period-tooltip {
|
.timeline .period-tooltip {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
@ -7,7 +7,8 @@
|
|||||||
|
|
||||||
<div class="list">
|
<div class="list">
|
||||||
<div v-for="period in snapshotPeriods">
|
<div v-for="period in snapshotPeriods">
|
||||||
<span class="link" @click="gotoPeriod(period)">{{period.snapshot.getTimeFormatted()}}</span>
|
<span class="link" @click="gotoPeriod(period)" >{{period.snapshot.getTimeFormatted()}}</span>
|
||||||
|
<span v-if="currentSnapshot.id === period.snapshot.id" class="current">current</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -16,10 +17,14 @@
|
|||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: "TimelineLinear",
|
name: "TimelineLinear",
|
||||||
props: ['period'],
|
props: ['period', 'currentSnapshot'],
|
||||||
computed: {
|
computed: {
|
||||||
snapshotPeriods() {
|
snapshotPeriods() {
|
||||||
return this.period.getSnapshotPeriodsFlat();
|
return this.period.getSnapshotPeriodsFlat();
|
||||||
|
},
|
||||||
|
containsCurrentSnapshot() {
|
||||||
|
return this.currentSnapshot &&
|
||||||
|
this.period.contains(this.currentSnapshot);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -56,4 +61,9 @@ export default {
|
|||||||
color: lightseagreen;
|
color: lightseagreen;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
.timeline-linear .current {
|
||||||
|
background-color: deeppink;
|
||||||
|
color: white;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
@ -64,6 +64,17 @@ class CDXLoader {
|
|||||||
|
|
||||||
app.$mount("#app");
|
app.$mount("#app");
|
||||||
|
|
||||||
|
// TODO (Ilya): make this work with in-page snapshot/capture/replay updates!
|
||||||
|
// app.$on("show-snapshot", snapshot => {
|
||||||
|
// const replayUrl = app.config.url;
|
||||||
|
// const url = location.href.replace('/'+replayUrl, '').replace(/\d+$/, '') + snapshot.id + '/' + replayUrl;
|
||||||
|
// window.history.pushState({url: replayUrl, timestamp: snapshot.id}, document.title, url);
|
||||||
|
// if (!window.onpopstate) {
|
||||||
|
// window.onpopstate = (ev) => {
|
||||||
|
// updateSnapshot(ev.state.url, ev.state.timestamp);
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
// });
|
||||||
if (loadCallback) {
|
if (loadCallback) {
|
||||||
app.$on("show-snapshot", loadCallback);
|
app.$on("show-snapshot", loadCallback);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
const PywbMonthLabels = {1:"Jan", 2:"Feb",3:"Mar",4:"Apr",5:"May",6:"Jun",7:"Jul",8:"Aug",9:"Sep",10:"Oct",11:"Nov",12:"Dec"};
|
const PywbMonthLabels = {1:"Jan", 2:"Feb",3:"Mar",4:"Apr",5:"May",6:"Jun",7:"Jul",8:"Aug",9:"Sep",10:"Oct",11:"Nov",12:"Dec"};
|
||||||
|
const PywbPeriodIdDelimiter = '-';
|
||||||
export function PywbData(rawSnaps) {
|
export function PywbData(rawSnaps) {
|
||||||
const allTimePeriod = new PywbPeriod({type: PywbPeriod.Type.all, id: "all"});
|
const allTimePeriod = new PywbPeriod({type: PywbPeriod.Type.all, id: "all"});
|
||||||
const snapshots = [];
|
const snapshots = [];
|
||||||
@ -98,6 +98,14 @@ export class PywbSnapshot {
|
|||||||
getTimeFormatted() {
|
getTimeFormatted() {
|
||||||
return (this.hour < 13 ? this.hour : (this.hour % 12)) + ":" + ((this.minute < 10 ? "0":"")+this.minute) + ":" + ((this.second < 10 ? "0":"")+this.second) + " " + (this.hour < 12 ? "am":"pm");
|
return (this.hour < 13 ? this.hour : (this.hour % 12)) + ":" + ((this.minute < 10 ? "0":"")+this.minute) + ":" + ((this.second < 10 ? "0":"")+this.second) + " " + (this.hour < 12 ? "am":"pm");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getParentIds() {
|
||||||
|
return [this.year, this.month, this.day, Math.ceil((this.hour + .0001) / (24/8))];
|
||||||
|
}
|
||||||
|
|
||||||
|
getFullId() {
|
||||||
|
return [this.year, this.month, this.day, Math.ceil((this.hour + .0001) / (24/8)), this.id].join(PywbPeriodIdDelimiter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------- PERIOD object ----------------- */
|
/* ---------------- PERIOD object ----------------- */
|
||||||
@ -318,8 +326,17 @@ PywbPeriod.prototype.getParents = function(skipAllTime=false) {
|
|||||||
return parents;
|
return parents;
|
||||||
};
|
};
|
||||||
|
|
||||||
PywbPeriod.prototype.contains = function(period) {
|
PywbPeriod.prototype.contains = function(periodOrSnapshot) {
|
||||||
return !!period.getParents().find(p => p === this);
|
if (this.type === 0) {
|
||||||
|
return true; // all-time contains everything
|
||||||
|
}
|
||||||
|
if (periodOrSnapshot instanceof PywbPeriod) {
|
||||||
|
return periodOrSnapshot.getParents(true).slice(0,this.type).join(PywbPeriodIdDelimiter) === this.fullId;
|
||||||
|
}
|
||||||
|
if (periodOrSnapshot instanceof PywbSnapshot) {
|
||||||
|
return periodOrSnapshot.getParentIds(true).slice(0,this.type).join(PywbPeriodIdDelimiter) === this.fullId;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
PywbPeriod.prototype.snapshot = null;
|
PywbPeriod.prototype.snapshot = null;
|
||||||
@ -376,13 +393,13 @@ PywbPeriod.prototype.getSnapshotPeriodsFlat = function(flatArray=false) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the "full" id, which includes all parents ID and self ID, delimited by a hyphen "-"
|
* Return the "full" id, which includes all parents ID and self ID, delimited by a ${PywbPeriodIdDelimiter}
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
PywbPeriod.prototype.initFullId = function() {
|
PywbPeriod.prototype.initFullId = function() {
|
||||||
const ids = this.getParents(true).map(p => p.id);
|
const ids = this.getParents(true).map(p => p.id);
|
||||||
ids.push(this.id);
|
ids.push(this.id);
|
||||||
this.fullId = ids.join("-");
|
this.fullId = ids.join(PywbPeriodIdDelimiter);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -395,7 +412,7 @@ PywbPeriod.prototype.findByFullId = function(fullId) {
|
|||||||
if (this.type !== PywbPeriod.Type.all) {
|
if (this.type !== PywbPeriod.Type.all) {
|
||||||
parent = this.getParents()[0];
|
parent = this.getParents()[0];
|
||||||
}
|
}
|
||||||
const ids = fullId.split('-');
|
const ids = fullId.split(PywbPeriodIdDelimiter);
|
||||||
|
|
||||||
let found = false;
|
let found = false;
|
||||||
for(let i=0; i<ids.length; i++) {
|
for(let i=0; i<ids.length; i++) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user