tournament calendar WIP
parent
90b7f3938c
commit
dc0fa84519
|
@ -237,4 +237,10 @@ object Tournament extends LilaController {
|
||||||
_ <- Env.user.lightUserApi preloadMany history.userIds
|
_ <- Env.user.lightUserApi preloadMany history.userIds
|
||||||
} yield html.tournament.shields(history)
|
} yield html.tournament.shields(history)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def calendar = Open { implicit ctx =>
|
||||||
|
env.api.calendar map { tours =>
|
||||||
|
Ok(html.tournament.calendar(env.scheduleJsonView calendar tours))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
@(json: play.api.libs.json.JsObject)(implicit ctx: Context)
|
||||||
|
|
||||||
|
@moreCss = {
|
||||||
|
@cssTag("tournament_calendar.css")
|
||||||
|
}
|
||||||
|
|
||||||
|
@moreJs = {
|
||||||
|
@jsAt(s"compiled/lichess.tournament-calendar${isProd??(".min")}.js")
|
||||||
|
@embedJs {
|
||||||
|
var app = LichessTournamentCalendar.app(document.getElementById('tournament_calendar'), {
|
||||||
|
data: @safeJson(json),
|
||||||
|
i18n: @jsI18n()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@base.layout(
|
||||||
|
title = "Tournament calendar",
|
||||||
|
moreJs = moreJs,
|
||||||
|
moreCss = moreCss) {
|
||||||
|
<div class="content_box no_padding tournament_calendar">
|
||||||
|
<h1>Tournament calendar</h1>
|
||||||
|
<div id="tournament_calendar"></div>
|
||||||
|
</div>
|
||||||
|
}
|
|
@ -229,6 +229,7 @@ GET /tournament controllers.Tournament.home(page:
|
||||||
GET /tournament/featured controllers.Tournament.featured
|
GET /tournament/featured controllers.Tournament.featured
|
||||||
GET /tournament/new controllers.Tournament.form
|
GET /tournament/new controllers.Tournament.form
|
||||||
POST /tournament/new controllers.Tournament.create
|
POST /tournament/new controllers.Tournament.create
|
||||||
|
GET /tournament/calendar controllers.Tournament.calendar
|
||||||
GET /tournament/$id<\w{8}> controllers.Tournament.show(id: String)
|
GET /tournament/$id<\w{8}> controllers.Tournament.show(id: String)
|
||||||
GET /tournament/$id<\w{8}>/standing/:page controllers.Tournament.standing(id: String, page: Int)
|
GET /tournament/$id<\w{8}>/standing/:page controllers.Tournament.standing(id: String, page: Int)
|
||||||
GET /tournament/$id<\w{8}>/socket/v:apiVersion controllers.Tournament.websocket(id: String, apiVersion: Int)
|
GET /tournament/$id<\w{8}>/socket/v:apiVersion controllers.Tournament.websocket(id: String, apiVersion: Int)
|
||||||
|
|
|
@ -10,9 +10,9 @@ final class ScheduleJsonView(lightUser: LightUser.Getter) {
|
||||||
import JsonView._
|
import JsonView._
|
||||||
|
|
||||||
def apply(tournaments: VisibleTournaments): Fu[JsObject] = for {
|
def apply(tournaments: VisibleTournaments): Fu[JsObject] = for {
|
||||||
created <- tournaments.created.map(tournamentJson).sequenceFu
|
created <- tournaments.created.map(fullJson).sequenceFu
|
||||||
started <- tournaments.started.map(tournamentJson).sequenceFu
|
started <- tournaments.started.map(fullJson).sequenceFu
|
||||||
finished <- tournaments.finished.map(tournamentJson).sequenceFu
|
finished <- tournaments.finished.map(fullJson).sequenceFu
|
||||||
} yield Json.obj(
|
} yield Json.obj(
|
||||||
"created" -> created,
|
"created" -> created,
|
||||||
"started" -> started,
|
"started" -> started,
|
||||||
|
@ -20,14 +20,17 @@ final class ScheduleJsonView(lightUser: LightUser.Getter) {
|
||||||
)
|
)
|
||||||
|
|
||||||
def featured(tournaments: List[Tournament]): Fu[JsObject] =
|
def featured(tournaments: List[Tournament]): Fu[JsObject] =
|
||||||
tournaments.map(tournamentJson).sequenceFu map { objs =>
|
tournaments.map(fullJson).sequenceFu map { objs =>
|
||||||
Json.obj("featured" -> objs)
|
Json.obj("featured" -> objs)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def tournamentJson(tour: Tournament): Fu[JsObject] = for {
|
def calendar(tournaments: List[Tournament]): JsObject = Json.obj(
|
||||||
owner <- tour.nonLichessCreatedBy ?? lightUser
|
"since" -> tournaments.headOption.map(_.startsAt.withTimeAtStartOfDay),
|
||||||
winner <- tour.winnerId ?? lightUser
|
"to" -> tournaments.lastOption.map(_.finishesAt.withTimeAtStartOfDay plusDays 1),
|
||||||
} yield Json.obj(
|
"tournaments" -> JsArray(tournaments.map(baseJson))
|
||||||
|
)
|
||||||
|
|
||||||
|
private def baseJson(tour: Tournament): JsObject = Json.obj(
|
||||||
"id" -> tour.id,
|
"id" -> tour.id,
|
||||||
"createdBy" -> tour.createdBy,
|
"createdBy" -> tour.createdBy,
|
||||||
"system" -> tour.system.toString.toLowerCase,
|
"system" -> tour.system.toString.toLowerCase,
|
||||||
|
@ -45,14 +48,19 @@ final class ScheduleJsonView(lightUser: LightUser.Getter) {
|
||||||
"startsAt" -> tour.startsAt,
|
"startsAt" -> tour.startsAt,
|
||||||
"finishesAt" -> tour.finishesAt,
|
"finishesAt" -> tour.finishesAt,
|
||||||
"status" -> tour.status.id,
|
"status" -> tour.status.id,
|
||||||
"winner" -> winner.map(userJson),
|
|
||||||
"perf" -> tour.perfType.map(perfJson)
|
"perf" -> tour.perfType.map(perfJson)
|
||||||
).add("hasMaxRating", tour.conditions.maxRating.isDefined)
|
).add("hasMaxRating", tour.conditions.maxRating.isDefined)
|
||||||
.add("major", owner.exists(_.title.isDefined))
|
|
||||||
.add("private", tour.`private`)
|
.add("private", tour.`private`)
|
||||||
.add("position", tour.position.some.filterNot(_.initial) map positionJson)
|
.add("position", tour.position.some.filterNot(_.initial) map positionJson)
|
||||||
.add("schedule", tour.schedule map scheduleJson)
|
.add("schedule", tour.schedule map scheduleJson)
|
||||||
|
|
||||||
|
private def fullJson(tour: Tournament): Fu[JsObject] = for {
|
||||||
|
owner <- tour.nonLichessCreatedBy ?? lightUser
|
||||||
|
winner <- tour.winnerId ?? lightUser
|
||||||
|
} yield baseJson(tour) ++ Json.obj(
|
||||||
|
"winner" -> winner.map(userJson)
|
||||||
|
).add("major", owner.exists(_.title.isDefined))
|
||||||
|
|
||||||
private def userJson(u: LightUser) = Json.obj(
|
private def userJson(u: LightUser) = Json.obj(
|
||||||
"id" -> u.id,
|
"id" -> u.id,
|
||||||
"name" -> u.name,
|
"name" -> u.name,
|
||||||
|
|
|
@ -2,6 +2,7 @@ package lila.tournament
|
||||||
|
|
||||||
import akka.actor.{ Props, ActorRef, ActorSelection, ActorSystem }
|
import akka.actor.{ Props, ActorRef, ActorSelection, ActorSystem }
|
||||||
import akka.pattern.{ ask, pipe }
|
import akka.pattern.{ ask, pipe }
|
||||||
|
import org.joda.time.DateTime
|
||||||
import play.api.libs.json._
|
import play.api.libs.json._
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
|
@ -399,6 +400,11 @@ final class TournamentApi(
|
||||||
}.sequenceFu.map(_.toMap)
|
}.sequenceFu.map(_.toMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def calendar: Fu[List[Tournament]] = {
|
||||||
|
val from = DateTime.now.minusDays(1)
|
||||||
|
TournamentRepo.calendar(from = from, to = from plusYears 1)
|
||||||
|
}
|
||||||
|
|
||||||
private def fetchGames(tour: Tournament, ids: Seq[String]) =
|
private def fetchGames(tour: Tournament, ids: Seq[String]) =
|
||||||
if (tour.isFinished) GameRepo gamesFromSecondary ids
|
if (tour.isFinished) GameRepo gamesFromSecondary ids
|
||||||
else GameRepo gamesFromPrimary ids
|
else GameRepo gamesFromPrimary ids
|
||||||
|
|
|
@ -233,4 +233,10 @@ object TournamentRepo {
|
||||||
)
|
)
|
||||||
).list[Tournament](none, ReadPreference.secondaryPreferred)
|
).list[Tournament](none, ReadPreference.secondaryPreferred)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def calendar(from: DateTime, to: DateTime): Fu[List[Tournament]] =
|
||||||
|
coll.find($doc(
|
||||||
|
"startsAt" $gte from $lte to,
|
||||||
|
"schedule.freq" $in Schedule.Freq.all.filter(_.isWeeklyOrBetter)
|
||||||
|
)).sort($sort asc "startsAt").list[Tournament](none, ReadPreference.secondaryPreferred)
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
"ui/site",
|
"ui/site",
|
||||||
"ui/tournament",
|
"ui/tournament",
|
||||||
"ui/tournamentSchedule",
|
"ui/tournamentSchedule",
|
||||||
|
"ui/tournamentCalendar",
|
||||||
"ui/tree",
|
"ui/tree",
|
||||||
"ui/@types/lichess"
|
"ui/@types/lichess"
|
||||||
]
|
]
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
div.day {
|
||||||
|
height: 30px;
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
div.day:nth-child(even) {
|
||||||
|
background: rgba(128,128,128,0.05);
|
||||||
|
}
|
||||||
|
day {
|
||||||
|
flex: 0 1 auto;
|
||||||
|
padding: 0 5px;
|
||||||
|
}
|
||||||
|
tours {
|
||||||
|
flex: 1 5 auto;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
#tournament_calendar .tournament {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 4px 0;
|
||||||
|
background-color: #303E43;
|
||||||
|
box-shadow: 0 5px 15px rgba(0,0,0,0.5);
|
||||||
|
border-radius: 2px;
|
||||||
|
transition: filter 0.13s;
|
||||||
|
color: #fff;
|
||||||
|
white-space: nowrap;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
#tournament_calendar .tournament:hover {
|
||||||
|
filter: brightness(1.08);
|
||||||
|
}
|
||||||
|
#tournament_calendar .tournament.hourly {
|
||||||
|
background-color: #3D9333;
|
||||||
|
}
|
||||||
|
#tournament_calendar .tournament.daily,
|
||||||
|
#tournament_calendar .tournament.eastern {
|
||||||
|
background-color: #0072B2;
|
||||||
|
}
|
||||||
|
@keyframes animatedBackground {
|
||||||
|
from { background-position: 0 0; }
|
||||||
|
to { background-position: 0 1000%; }
|
||||||
|
}
|
||||||
|
#tournament_calendar .tournament.weekly,
|
||||||
|
#tournament_calendar .tournament.weekend,
|
||||||
|
#tournament_calendar .tournament.monthly,
|
||||||
|
#tournament_calendar .tournament.marathon,
|
||||||
|
#tournament_calendar .tournament.yearly {
|
||||||
|
text-shadow: 0 0 2px rgba(0,0,0,0.7);
|
||||||
|
letter-spacing: 1px;
|
||||||
|
background-image: url(../images/grain.png);
|
||||||
|
animation: animatedBackground 50s linear infinite;
|
||||||
|
}
|
||||||
|
#tournament_calendar .tournament.weekly {
|
||||||
|
background-color: #D55E00;
|
||||||
|
}
|
||||||
|
#tournament_calendar .tournament.monthly {
|
||||||
|
background-color: #C93D3D;
|
||||||
|
}
|
||||||
|
#tournament_calendar .tournament.yearly,
|
||||||
|
#tournament_calendar .tournament.weekend {
|
||||||
|
background-color: #d59120;
|
||||||
|
}
|
||||||
|
#tournament_calendar .tournament.marathon {
|
||||||
|
background-color: #66558C;
|
||||||
|
}
|
||||||
|
#tournament_calendar .tournament.unique {
|
||||||
|
background-color: #d59120;
|
||||||
|
}
|
||||||
|
#tournament_calendar .tournament.max-rating {
|
||||||
|
background-color: #8572ff;
|
||||||
|
}
|
||||||
|
#tournament_calendar .tournament {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
#tournament_calendar .tournament span {
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
#tournament_calendar .icon {
|
||||||
|
font-size: 1.3em;
|
||||||
|
margin: -4px 2px -1px 4px;
|
||||||
|
}
|
||||||
|
#tournament_calendar .tournament .body {
|
||||||
|
flex: 1 0;
|
||||||
|
margin-right: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
const gulp = require('gulp');
|
||||||
|
const gutil = require('gulp-util');
|
||||||
|
const watchify = require('watchify');
|
||||||
|
const browserify = require('browserify');
|
||||||
|
const uglify = require('gulp-uglify');
|
||||||
|
const source = require('vinyl-source-stream');
|
||||||
|
const buffer = require('vinyl-buffer');
|
||||||
|
const tsify = require('tsify');
|
||||||
|
|
||||||
|
const destination = '../../public/compiled/';
|
||||||
|
|
||||||
|
function onError(error) {
|
||||||
|
gutil.log(gutil.colors.red(error.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
function build() {
|
||||||
|
return browserify('src/main.ts', {
|
||||||
|
standalone: 'LichessTournamentCalendar',
|
||||||
|
debug: true
|
||||||
|
})
|
||||||
|
.plugin(tsify);
|
||||||
|
}
|
||||||
|
|
||||||
|
const watchedBrowserify = watchify(build());
|
||||||
|
|
||||||
|
function bundle() {
|
||||||
|
return watchedBrowserify
|
||||||
|
.bundle()
|
||||||
|
.on('error', onError)
|
||||||
|
.pipe(source('lichess.tournament-calendar.js'))
|
||||||
|
.pipe(buffer())
|
||||||
|
.pipe(gulp.dest(destination));
|
||||||
|
}
|
||||||
|
|
||||||
|
gulp.task('default', bundle);
|
||||||
|
watchedBrowserify.on('update', bundle);
|
||||||
|
watchedBrowserify.on('log', gutil.log);
|
||||||
|
|
||||||
|
gulp.task('dev', function() {
|
||||||
|
return build()
|
||||||
|
.bundle()
|
||||||
|
.pipe(source('lichess.tournament-calendar.js'))
|
||||||
|
.pipe(gulp.dest(destination));
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('prod', function() {
|
||||||
|
return build()
|
||||||
|
.bundle()
|
||||||
|
.pipe(source('lichess.tournament-calendar.min.js'))
|
||||||
|
.pipe(buffer())
|
||||||
|
.pipe(uglify())
|
||||||
|
.pipe(gulp.dest(destination));
|
||||||
|
});
|
|
@ -0,0 +1,39 @@
|
||||||
|
{
|
||||||
|
"name": "tournamentCalendar",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "lichess.org tournament calendar",
|
||||||
|
"main": "src/main.js",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/ornicar/lila"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"chess",
|
||||||
|
"lichess",
|
||||||
|
"tournament",
|
||||||
|
"calendar"
|
||||||
|
],
|
||||||
|
"author": "Thibault Duplessis",
|
||||||
|
"license": "AGPL-3.0",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/ornicar/lila/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/ornicar/lila",
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/jquery": "^2.0",
|
||||||
|
"browserify": "^14",
|
||||||
|
"gulp": "^3",
|
||||||
|
"gulp-uglify": "^3",
|
||||||
|
"gulp-util": "^3",
|
||||||
|
"tsify": "^3",
|
||||||
|
"@types/lichess": "1.0.0",
|
||||||
|
"typescript": "^2",
|
||||||
|
"vinyl-buffer": "^1",
|
||||||
|
"vinyl-source-stream": "^1",
|
||||||
|
"watchify": "^3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"snabbdom": "ornicar/snabbdom#lichess",
|
||||||
|
"date-fns": "^1"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
export interface Tournament {
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
export interface Ctrl {
|
||||||
|
trans: Trans;
|
||||||
|
data: {
|
||||||
|
since: number;
|
||||||
|
to: number;
|
||||||
|
tournaments: Tournament[];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
import view from './view';
|
||||||
|
|
||||||
|
import { init } from 'snabbdom';
|
||||||
|
import { VNode } from 'snabbdom/vnode'
|
||||||
|
import klass from 'snabbdom/modules/class';
|
||||||
|
import attributes from 'snabbdom/modules/attributes';
|
||||||
|
|
||||||
|
import { Tournament, Ctrl } from './interfaces'
|
||||||
|
|
||||||
|
const patch = init([klass, attributes]);
|
||||||
|
|
||||||
|
export function app(element: HTMLElement, env: any) {
|
||||||
|
|
||||||
|
let vnode: VNode, ctrl: Ctrl = {
|
||||||
|
data: env.data,
|
||||||
|
trans: window.lichess.trans(env.i18n)
|
||||||
|
};
|
||||||
|
|
||||||
|
function redraw() {
|
||||||
|
vnode = patch(vnode || element, view(ctrl));
|
||||||
|
}
|
||||||
|
|
||||||
|
redraw();
|
||||||
|
};
|
|
@ -0,0 +1,89 @@
|
||||||
|
import { h } from 'snabbdom'
|
||||||
|
import { VNode } from 'snabbdom/vnode'
|
||||||
|
import { eachDay, addYears, addDays, format, getHours, getMinutes } from 'date-fns'
|
||||||
|
import { Tournament, Ctrl } from './interfaces'
|
||||||
|
|
||||||
|
function displayClockLimit(limit) {
|
||||||
|
switch (limit) {
|
||||||
|
case 15:
|
||||||
|
return '¼';
|
||||||
|
case 30:
|
||||||
|
return '½';
|
||||||
|
case 45:
|
||||||
|
return '¾';
|
||||||
|
case 90:
|
||||||
|
return '1.5';
|
||||||
|
default:
|
||||||
|
return limit / 60;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayClock(clock) {
|
||||||
|
return displayClockLimit(clock.limit) + "+" + clock.increment;
|
||||||
|
}
|
||||||
|
|
||||||
|
function tournamentClass(tour: Tournament) {
|
||||||
|
const classes = {
|
||||||
|
rated: tour.rated,
|
||||||
|
casual: !tour.rated,
|
||||||
|
'max-rating': tour.hasMaxRating
|
||||||
|
};
|
||||||
|
if (tour.schedule) classes[tour.schedule.freq] = true;
|
||||||
|
return classes;
|
||||||
|
}
|
||||||
|
|
||||||
|
function iconOf(tour, perfIcon) {
|
||||||
|
return (tour.schedule && tour.schedule.freq === 'shield') ? '5' : perfIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderTournament(ctrl: Ctrl, tour: Tournament) {
|
||||||
|
// moves content into viewport, for long tourneys and marathons
|
||||||
|
// const paddingLeft = tour.minutes < 90 ? 0 : Math.max(0,
|
||||||
|
// Math.min(width - 250, // max padding, reserved text space
|
||||||
|
// leftPos(now) - left - 380)); // distance from Now
|
||||||
|
// // cut right overflow to fit viewport and not widen it, for marathons
|
||||||
|
// width = Math.min(width, leftPos(stopTime) - left);
|
||||||
|
const paddingLeft = 0;
|
||||||
|
const date = tour.startsAt;
|
||||||
|
const left = (getHours(date) + getMinutes(date) / 60) / 24 * 100;
|
||||||
|
const width = tour.minutes / 60 / 24 * 100;
|
||||||
|
|
||||||
|
return h('a.tournament', {
|
||||||
|
class: tournamentClass(tour),
|
||||||
|
attrs: {
|
||||||
|
href: '/tournament/' + tour.id,
|
||||||
|
style: 'width: ' + width + '%; left: ' + left + '%'
|
||||||
|
},
|
||||||
|
}, [
|
||||||
|
h('span.icon', tour.perf ? {
|
||||||
|
attrs: {
|
||||||
|
'data-icon': iconOf(tour, tour.perf.icon),
|
||||||
|
title: tour.perf.name
|
||||||
|
}
|
||||||
|
} : {}),
|
||||||
|
h('span.body', [ tour.fullName ])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function endsAt(tour: Tournament): Date {
|
||||||
|
return new Date(tour.startsAt + tour.minutes * 60 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderDay(ctrl: Ctrl) {
|
||||||
|
return function(day: Date): VNode | undefined {
|
||||||
|
const dayEnd = addDays(day, 1);
|
||||||
|
const tours = ctrl.data.tournaments.filter(t =>
|
||||||
|
t.startsAt < dayEnd.getTime() && endsAt(t) > day
|
||||||
|
);
|
||||||
|
return h('div.day', [
|
||||||
|
h('day', [format(day, 'DD/MM')]),
|
||||||
|
h('tours', tours.map(t => renderTournament(ctrl, t)))
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function(ctrl) {
|
||||||
|
return h('div#tournament_calendar',
|
||||||
|
eachDay(new Date(ctrl.data.since), new Date(ctrl.data.to)).map(renderDay(ctrl))
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"include": ["src/*.ts", "src/*.js"],
|
||||||
|
"exclude": [],
|
||||||
|
"compilerOptions": {
|
||||||
|
"allowJs": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"noUnusedLocals": false,
|
||||||
|
"noEmitOnError": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noImplicitThis": true,
|
||||||
|
"noUnusedParameters": false,
|
||||||
|
"target": "es5",
|
||||||
|
"lib": ["DOM", "ES5"]
|
||||||
|
}
|
||||||
|
}
|
|
@ -878,6 +878,10 @@ dashdash@^1.12.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
assert-plus "^1.0.0"
|
assert-plus "^1.0.0"
|
||||||
|
|
||||||
|
date-fns@^1:
|
||||||
|
version "1.29.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.29.0.tgz#12e609cdcb935127311d04d33334e2960a2a54e6"
|
||||||
|
|
||||||
date-now@^0.1.4:
|
date-now@^0.1.4:
|
||||||
version "0.1.4"
|
version "0.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
|
resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
|
||||||
|
|
Loading…
Reference in New Issue