diff --git a/basrc/main-window.ts b/basrc/main-window.ts index fb3964d..356c723 100644 --- a/basrc/main-window.ts +++ b/basrc/main-window.ts @@ -45,7 +45,7 @@ export class MainWindow { width: windowState.width, x: windowState.x, y: windowState.y, - minHeight: 400, + minHeight: 450, minWidth: 600, frame: false, title: "Compwerstats", diff --git a/frsrc/character/controller.ts b/frsrc/character/controller.ts index 0681b53..64015c6 100644 --- a/frsrc/character/controller.ts +++ b/frsrc/character/controller.ts @@ -17,16 +17,16 @@ export class CharacterController { return table.toArray(); } - static async getExternalContent(): Promise { + static async getExternalContent(characterId: number, force: boolean = false): Promise { const database = CompwerstatsDatabase.getInstance(); const table = database.character; + const character = await Character.load(characterId); const dataUrlPrefix = 'data:image/png;base64,'; const generateCharacterUrlByType = (char: Character, fileName: string): string => { return `https://blzgdapipro-a.akamaihd.net/hero/${ char.getUrlSafeName() }/${ fileName }` }; database.transaction('rw', table, async () => { - const iconlessCharacters = await table.where('iconPath').equals('').toArray(); const types = [{ name: 'icon-portrait.png', default: './static/img/temp-icon-portrait.png', @@ -37,13 +37,13 @@ export class CharacterController { column: 'imagePath' }]; - iconlessCharacters.forEach((character: Character) => { - types.forEach((icon) => { + types.forEach((icon) => { + if (force || !character[icon.column]) { fetch(generateCharacterUrlByType(character, icon.name)) .then((response) => response.blob()) .then((blob) => { const reader = new FileReader(); - + reader.readAsDataURL(blob); reader.onloadend = () => { const dataUrl = reader.result; @@ -56,11 +56,21 @@ export class CharacterController { character.save(); } }); - }) + } }); }); } + static async getAllExternalContent() { + const database = CompwerstatsDatabase.getInstance(); + const table = database.character; + const iconlessCharacters = await table.where('iconPath').equals('').toArray(); + + iconlessCharacters.forEach((character) => { + CharacterController.getExternalContent(character.id); + }); + } + static async getFormSchema(create: boolean = false, saveCallback: () => void): Promise { const characterTypes = await CharacterTypeController.getAll(); @@ -108,8 +118,8 @@ export class CharacterController { type: 'submit', buttonText: create ? 'Create' : 'Save', onSubmit: async (model) => { - await model.save(); - CharacterController.getExternalContent(); + const id = await model.save(); + CharacterController.getExternalContent(id); if (typeof saveCallback === 'function') { saveCallback(); } diff --git a/frsrc/database.ts b/frsrc/database.ts index 020ad3a..d751cbd 100644 --- a/frsrc/database.ts +++ b/frsrc/database.ts @@ -50,6 +50,11 @@ export class CompwerstatsDatabase extends Dexie { rank: '++id, &title, iconPath, ratingMin, ratingMax', season: '++id, name, placementRating' }); + + this.version(2).stores({ + season: '++id, name, placementRating, archived', + match: '++id, [seasonId+type], mapId, &time, *character, result, comment, rating, groupsize, redRating, blueRating, steak', + }); } private setupClassMap() { @@ -77,9 +82,6 @@ export class CompwerstatsDatabase extends Dexie { Rank.create('Master', 3500, 3999, './static/img/rank_master.png').save(); Rank.create('Grandmaster', 4000, 5000, './static/img/rank_grandmaster.png').save(); - Season.create('Season 6').save(); - Season.create('Season 7').save(); - CommentSuggestion.create('Good communication').save(); CommentSuggestion.create('Great teamwork').save(); CommentSuggestion.create('Filled').save(); @@ -122,6 +124,7 @@ export class CompwerstatsDatabase extends Dexie { Character.create(ctSupport, 'Ana', '', '').save(); Character.create(ctSupport, 'LĂșcio', '', '').save(); Character.create(ctSupport, 'Mercy', '', '').save(); + // Character.create(ctSupport, 'Moira', '', '').save(); Character.create(ctSupport, 'Symmetra', '', '').save(); Character.create(ctSupport, 'Zenyatta', '', '').save(); @@ -141,10 +144,11 @@ export class CompwerstatsDatabase extends Dexie { OverwatchMap.create(mtControl, 'Oasis', 'https://bnetcmsus-a.akamaihd.net/cms/page_media/mn/MNNHA2I8CTIG1497480960107.jpg').save(); OverwatchMap.create(mtEscort, 'Dorado', 'https://bnetcmsus-a.akamaihd.net/cms/page_media/fn/FNBIVXUVWF6X1497480004798.jpg').save(); + OverwatchMap.create(mtEscort, 'Junkertown', 'https://bnetcmsus-a.akamaihd.net/cms/page_media/3EDBV89EVDZG1504724220173.jpg').save(); OverwatchMap.create(mtEscort, 'Route 66', 'https://bnetcmsus-a.akamaihd.net/cms/page_media/hj/HJDM6SIEAIGO1497481024426.jpg').save(); OverwatchMap.create(mtEscort, 'Watchpoint: Gibraltar', 'https://bnetcmsus-a.akamaihd.net/cms/page_media/x0/X0WORICQ092M1497480184004.jpg').save(); }).then(() => { - CharacterController.getExternalContent(); + CharacterController.getAllExternalContent(); OverwatchMapController.getExternalContent(); }, (reason) => { console.error(reason); diff --git a/frsrc/index.ts b/frsrc/index.ts index 37f6aab..27fa9ae 100644 --- a/frsrc/index.ts +++ b/frsrc/index.ts @@ -1,33 +1,131 @@ import Vue from 'vue'; +import Vuex from 'vuex' import VueRouter from 'vue-router'; +import * as VueMoment from 'vue-moment'; import Chrome from './view/chrome/chrome'; -import RouterFront from './view/page-front/router'; import RouterStats from './view/page-stats/router'; import RouterSettings from './view/page-settings/router'; import RouterCompetitive from './view/page-competitive/router'; +import RouterCreateSeason from './view/page-create-season/router'; +import { SeasonMode } from './interface' + +import { mainBasedOnMode } from './router-helper'; import PercentFilter from './view/filters/percent'; -const VueMoment = require('vue-moment'); - -Vue.use(VueRouter); -Vue.use(VueMoment); - -Vue.filter(PercentFilter.name, PercentFilter); - -const router = new VueRouter({ - routes: [ - ...RouterFront, - ...RouterStats, - ...RouterSettings, - ...RouterCompetitive - ] -}); - -const vue = new Vue({ - el: '.app', - components: { - Chrome - }, - router: router -}); +import { SeasonController } from './season'; +import { MatchController } from './match'; +import { Rank, RankController } from './rank'; + +async function init() { + // Initing initial data + const {season, seasonMode, rating, rank} = await getInitialState(); + + // Initing Vue stuff + Vue.use(Vuex); + Vue.use(VueRouter); + Vue.use(VueMoment); + + Vue.filter(PercentFilter.name, PercentFilter); + + const store = new Vuex.Store({ + strict: true, + state: { + seasonId: (season ? season.id : null), + seasonMode: seasonMode, + rating: rating, + rank: rank + }, + getters: { + getSeasonId: (state) => () => state.seasonId, + getSeasonMode: (state) => () => state.seasonMode, + getRating: (state) => () => state.rating, + getRank: (state) => () => state.rank + }, + mutations: { + seasonId: (store, seasonId: number) => { + store.seasonId = seasonId; + }, + seasonMode: (store, mode: SeasonMode) => { + store.seasonMode = mode; + }, + rating: (store, rating: number) => { + store.rating = rating; + }, + rank: (store, rank: Rank) => { + store.rank = rank; + } + }, + actions: { + updateSeasonId: async (context, seasonId: number): Promise => { + const season = await SeasonController.getSeasonById(seasonId); + const seasonMode = await SeasonController.getMode(seasonId); + var rating = await MatchController.latestSeasonMatchRating(seasonId); + + if (!rating && season.placementRating) { + rating = season.placementRating; + } + else if (!rating) { + rating = -1; + } + + context.commit('seasonId', seasonId); + context.commit('seasonMode', seasonMode); + context.dispatch('updateRating', rating); + }, + updateRating: async (context, rating): Promise => { + const rank = await RankController.getByRating(rating); + + context.commit('rating', rating); + context.commit('rank', rank); + } + } + }); + + const router = new VueRouter({ + routes: [ + { + path: '/', + redirect: (to) => { + return mainBasedOnMode(store.state.seasonMode); + } + }, + ...RouterStats, + ...RouterSettings, + ...RouterCompetitive, + ...RouterCreateSeason + ] + }); + + const vue = new Vue({ + el: '.app', + store, + components: { + Chrome + }, + router: router + }); + + return vue; +} + +async function getInitialState() { + let seasonMode = null; + let rating = null; + let rank = null; + const season = await SeasonController.getCurrent(); + if (season) { + seasonMode = await SeasonController.getMode(season.id); + rating = await MatchController.latestSeasonMatchRating(season.id); + rank = await RankController.getByRating(rating); + } + + return { + season, + seasonMode, + rating, + rank + }; +} + +init(); diff --git a/frsrc/interface.ts b/frsrc/interface.ts index b28cd5b..9c96442 100644 --- a/frsrc/interface.ts +++ b/frsrc/interface.ts @@ -2,3 +2,26 @@ export interface HeadSelectItem { value: string | number, label: string } + +export enum SeasonMode { + Placements = 1, + PlacementsComplete = 2, + Matches = 3 +} + +export interface ButtonMode { + label: string, + shortLabel: string, + path: string +} + +export enum MatchType { + Placement = 'placement', + Match = 'match' +} + +export enum MatchResult { + Win = 'win', + Loss = 'loss', + Draw = 'draw' +} \ No newline at end of file diff --git a/frsrc/match/controller.ts b/frsrc/match/controller.ts index 358bf81..b498ded 100644 --- a/frsrc/match/controller.ts +++ b/frsrc/match/controller.ts @@ -1,9 +1,11 @@ import { validators } from 'vue-form-generator'; import { Dexie } from 'dexie'; -import { Match, MatchType, MatchResult } from './model'; +import { Match } from './model'; import { CompwerstatsDatabase } from '../database'; +import { MatchType, MatchResult } from '../interface'; + import * as moment from 'moment'; import { Character, CharacterController } from '../character'; @@ -41,12 +43,12 @@ export class MatchController { return placementMatches.length < 10; } - static async latestSeasonMatch(seasonId: number): Promise { + static async latestSeasonMatch(seasonId: number, type: MatchType = MatchType.Match): Promise { const database = CompwerstatsDatabase.getInstance(); const table = database.match; const lastMatch = await table - .where('[seasonId+type]').equals([seasonId, MatchType.Match]) + .where('[seasonId+type]').equals([seasonId, type]) .limit(1).reverse().sortBy('time'); return lastMatch[0]; @@ -77,40 +79,32 @@ export class MatchController { } } - static async recalculateResults(seasonId: number): Promise { - // Transaction and a cool loop I guess. + static async recalculateStreaks(seasonId: number, type: MatchType): Promise { + const matches = await MatchController.getBySeason(seasonId, type); + if (matches.length) { + let lastResult = matches[0].result; + let currentStreak = 0; + + matches.forEach((match) => { + if (lastResult === match.result) { + currentStreak = currentStreak + 1; + match.streak = currentStreak; + } + else { + lastResult = match.result; + currentStreak = 1; + match.streak = currentStreak; + } + + match.save(); + }); + } } /** * Statistics */ static async calculateStatistics(seasonId: number) { - const timeGroups = { - '0': '00-02', - '1': '00-02', - '2': '00-02', - '3': '03-05', - '4': '03-05', - '5': '03-05', - '6': '06-08', - '7': '06-08', - '8': '06-08', - '9': '09-11', - '10': '09-11', - '11': '09-11', - '12': '12-14', - '13': '12-14', - '14': '12-14', - '15': '15-17', - '16': '15-17', - '17': '15-17', - '18': '18-20', - '19': '18-20', - '20': '18-20', - '21': '21-23', - '22': '21-23', - '23': '21-23' - }; const idToKey = (result, item) => { result[item.id] = item; return result; @@ -120,6 +114,7 @@ export class MatchController { .map((key) => from[key]) .reduce((result, current) => { result[current.id] = { + total: 0, win: 0, draw: 0, loss: 0 @@ -141,12 +136,14 @@ export class MatchController { } if (!obj[id]) { obj[id] = { + total: 0, win: 0, draw: 0, loss: 0 }; } + obj[id].total += 1; obj[id][key] += 1; } const data = { @@ -169,31 +166,15 @@ export class MatchController { data: data }; - var lastResult, - currentStreak, - longestStreak = { - win: 0, - draw: 0, - loss: 0 - }; + var lastResult; - data.matches.forEach((match) => { - // Streak - if (lastResult === match.result) { - currentStreak += 1; + stats.totalNumberOfMatches = data.matches.length; - if (currentStreak > longestStreak[lastResult]) { - longestStreak[lastResult] = currentStreak; - } - } - else { - currentStreak = 1; - lastResult = match.result; - } + data.matches.forEach((match) => { + const characterTypes = new Set; // Totals add(stats.totals, match.result); - stats.totalNumberOfMatches += 1; if (match.character) { match.character.forEach((charId) => { @@ -203,10 +184,15 @@ export class MatchController { wld(stats.character, charId, match.result); // Character Types - wld(stats.characterType, char.typeId, match.result); + characterTypes.add(char.typeId); }); } + // Character Types + characterTypes.forEach((typeId) => { + wld(stats.characterType, typeId, match.result); + }); + // Maps wld(stats.map, match.overwatchMapId, match.result); @@ -218,7 +204,7 @@ export class MatchController { // Time const momentTime = moment(match.time); - wld(stats.timeRange, timeGroups[momentTime.hour()], match.result); + wld(stats.timeRange, momentTime.hour(), match.result); wld(stats.dayOfTheWeek, momentTime.isoWeekday(), match.result); // Groupsize @@ -379,6 +365,7 @@ export class MatchController { buttonText: create ? 'Create' : 'Save', onSubmit: async (model) => { await model.save(); + await MatchController.recalculateStreaks(model.seasonId, model.type); if (typeof saveCallback === 'function') { saveCallback(); } diff --git a/frsrc/match/index.ts b/frsrc/match/index.ts index 4c2b349..65ed2d3 100644 --- a/frsrc/match/index.ts +++ b/frsrc/match/index.ts @@ -1,9 +1,7 @@ -import { Match, MatchType, MatchResult } from './model'; +import { Match } from './model'; import { MatchController } from './controller'; export { Match, - MatchType, - MatchResult, MatchController }; \ No newline at end of file diff --git a/frsrc/match/model.ts b/frsrc/match/model.ts index 3a8b592..19416b0 100644 --- a/frsrc/match/model.ts +++ b/frsrc/match/model.ts @@ -1,5 +1,7 @@ import * as Moment from 'moment'; import { CompwerstatsDatabase } from '../database'; +import { MatchController } from './controller'; +import { MatchResult, MatchType } from '../interface'; export class Match { public id: number; @@ -16,8 +18,9 @@ export class Match { public type: MatchType; public redRating: number; public blueRating: number; + public streak: number; - static create(seasonId: number, overwatchMapId: number, time: number, character: number[], rating: number, type: MatchType, result: MatchResult, comment?: string, groupsize?: number, redRating?: number, blueRating?: number): Match { + static create(seasonId: number, overwatchMapId: number, time: number, character: number[], rating: number, type: MatchType, result: MatchResult, comment?: string, groupsize?: number, redRating?: number, blueRating?: number, streak?: number): Match { const match = new Match(); match.seasonId = seasonId; @@ -31,6 +34,7 @@ export class Match { match.type = type; match.redRating = redRating; match.blueRating = blueRating; + match.streak = streak; return match; } @@ -51,7 +55,7 @@ export class Match { delete this.timeTime; } - this.id = await db.match.put(this, this.id); + this.id = await db.match.put(this); return this.id; } @@ -79,14 +83,3 @@ export class Match { } } } - -export enum MatchType { - Placement = 'placement', - Match = 'match' -} - -export enum MatchResult { - Win = 'win', - Loss = 'loss', - Draw = 'draw' -} \ No newline at end of file diff --git a/frsrc/router-helper.js b/frsrc/router-helper.js new file mode 100644 index 0000000..f5a36e7 --- /dev/null +++ b/frsrc/router-helper.js @@ -0,0 +1,14 @@ +import { SeasonMode } from './interface'; + +export function mainBasedOnMode (mode) { + switch (mode) { + case SeasonMode.Matches: + return '/competitive'; + case SeasonMode.Placements: + return '/placement'; + case SeasonMode.PlacementsComplete: + return '/placement/placement-sr'; + default: + return '/create-season'; + } +} \ No newline at end of file diff --git a/frsrc/season/controller.ts b/frsrc/season/controller.ts index 8178753..5242fa3 100644 --- a/frsrc/season/controller.ts +++ b/frsrc/season/controller.ts @@ -4,6 +4,12 @@ import { Dexie } from 'dexie'; import { Season } from './model'; import { CompwerstatsDatabase } from '../database'; +import { MatchController } from '../match'; + +import { MatchType } from '../interface'; + +import { SeasonMode } from '../interface'; + export class SeasonController { static async getAll(): Promise { const database = CompwerstatsDatabase.getInstance(); @@ -12,18 +18,51 @@ export class SeasonController { return table.toArray(); } - static async getCurrent(): Promise { + static async getActive(): Promise { const database = CompwerstatsDatabase.getInstance(); const table = database.season; + const active = await table.toArray(); - return table.reverse().first(); + return active.filter(season => !season.archived); + } + + static async getCurrent(): Promise { + const activeSeasons = await SeasonController.getActive(); + + return activeSeasons.reverse()[0]; } static async getSeasonById(seasonId: number): Promise { const database = CompwerstatsDatabase.getInstance(); const table = database.season; + + if (seasonId) { + return table.where('id').equals(seasonId).first(); + } + else { + return null; + } + } - return table.where('id').equals(seasonId).first(); + static async getMode(seasonId: number): Promise { + const season = await SeasonController.getSeasonById(seasonId); + + if (!season) { + return null; + } + + const placements = await MatchController.getBySeason(seasonId, MatchType.Placement); + const matches = await MatchController.getBySeason(seasonId, MatchType.Match); + + if (season.placementRating > 0 || matches.length) { + return SeasonMode.Matches; + } + else if (placements.length >= 10) { + return SeasonMode.PlacementsComplete; + } + else { + return SeasonMode.Placements; + } } static async getFormSchema(create: boolean = false, saveCallback: () => void): Promise { @@ -31,12 +70,13 @@ export class SeasonController { fields: [ { type: 'input', - inputType: 'text', - label: 'Name', + inputType: 'number', + label: 'Season Number', model: 'name', - maxlength: 50, + max: 9999, + min: 0, required: true, - placeholder: 'Season name (etc. Season 12)', + placeholder: 'Season number (etc. 12)', validator: validators.required }, { @@ -48,6 +88,11 @@ export class SeasonController { min: 0, placeholder: 'Placement SR', }, + { + type: 'checkbox', + label: 'Archive (an archived season will not be selectable in the season selector)', + model: 'archive' + }, { type: 'submit', buttonText: create ? 'Create' : 'Save', diff --git a/frsrc/season/model.ts b/frsrc/season/model.ts index 0b0c6e6..cae1978 100644 --- a/frsrc/season/model.ts +++ b/frsrc/season/model.ts @@ -4,12 +4,14 @@ export class Season { public id: number; public name: string; public placementRating: number; + public archived: boolean; - static create(name: string, placementRating?: number): Season { + static create(name: string, placementRating?: number, archived: boolean = false): Season { const season = new Season(); season.name = name; season.placementRating = placementRating; + season.archived = archived; return season; } @@ -23,7 +25,7 @@ export class Season { async save(): Promise { const db = CompwerstatsDatabase.getInstance(); - this.id = await db.season.put(this, this.id); + this.id = await db.season.put(this); return this.id; } @@ -35,6 +37,7 @@ export class Season { } getName(): string { - return this.name; + const [name] = this.name.match(/[\d]+/); + return name; } } \ No newline at end of file diff --git a/frsrc/view/button/back/button-back.scss b/frsrc/view/button/back/button-back.scss index 34f959e..727e829 100644 --- a/frsrc/view/button/back/button-back.scss +++ b/frsrc/view/button/back/button-back.scss @@ -28,10 +28,4 @@ .buttonBack__iconPath { stroke: transparent; fill: #fff; -} -@media (min-height: 720px) and (min-width: 1000px) { - .buttonBack__icon { - height: 23px; - width: 23px; - } } \ No newline at end of file diff --git a/frsrc/view/button/base/button-base.scss b/frsrc/view/button/base/button-base.scss index 726e15a..bdec6b5 100644 --- a/frsrc/view/button/base/button-base.scss +++ b/frsrc/view/button/base/button-base.scss @@ -2,11 +2,11 @@ -webkit-appearance: none; text-decoration: none; text-transform: uppercase; - font-family: Futura, sans-serif; + font-family: Roboto, sans-serif; padding: 10px 20px; font-size: 12px; line-height: 1; - font-weight: bold; + font-weight: 900; display: inline-block; border-width: 0; background: var(--color-background-button); @@ -26,7 +26,6 @@ .button--quick { padding: 5px 10px; - font-weight: normal; font-size: 14px; line-height: 20px; } @@ -53,19 +52,4 @@ box-shadow: 0 0 0 3px rgba(255, 255, 255, .75); background-color: rgb(12, 64, 120); } -} - -@media (min-height: 720px) and (min-width: 1000px) { - .button--quick { - font-size: 20px; - padding: 10px 20px; - margin: 5px; - line-height: 20px; - } - .button--head { - font-size: 16px; - padding: 10px 20px; - margin: 7px; - line-height: 1; - } } \ No newline at end of file diff --git a/frsrc/view/chrome/button/chrome-button.scss b/frsrc/view/chrome/button/chrome-button.scss index dfc97b0..2e721b8 100644 --- a/frsrc/view/chrome/button/chrome-button.scss +++ b/frsrc/view/chrome/button/chrome-button.scss @@ -13,7 +13,11 @@ .buttonChrome:hover { text-shadow: 0 0 3px rgba(255, 255, 255, 0.4); - background-color: rgba(63, 65, 130, 1); + background-color: rgb(63, 65, 130); +} + +.buttonChrome:last-of-type:hover { + background-color: rgb(130, 63, 69); } .buttonChrome__icon { @@ -31,12 +35,3 @@ .buttonChrome:hover .buttonChrome__iconPath { stroke: rgba(255, 255, 255, .75); } - -@media (min-height: 720px) and (min-width: 1000px) { - .buttonChrome { - padding: 22px 10px 17px; - } - .buttonChrome:last-of-type { - padding-right: 20px; - } -} \ No newline at end of file diff --git a/frsrc/view/chrome/chrome/chrome.html b/frsrc/view/chrome/chrome/chrome.html index 55254b7..4af6859 100644 --- a/frsrc/view/chrome/chrome/chrome.html +++ b/frsrc/view/chrome/chrome/chrome.html @@ -1,15 +1,9 @@
Compwerstats
- -
- -
{{ currentRating }}
-
-
- +
+ +
{{ $store.state.rating }}
@@ -17,6 +11,33 @@
+
+ + + Update avalible + + + + {{ buttonInfo.shortLabel }} + + + + Settings + +
diff --git a/frsrc/view/chrome/chrome/chrome.scss b/frsrc/view/chrome/chrome/chrome.scss index d92deb5..e128bc7 100644 --- a/frsrc/view/chrome/chrome/chrome.scss +++ b/frsrc/view/chrome/chrome/chrome.scss @@ -1,24 +1,28 @@ .chrome { display: grid; grid-template-rows: 40px auto; + grid-template-columns: 60px auto; + grid-template-areas: "head head" "sidebar main"; height: 100vh; } +.chrome.chrome--sidebarOpen { + grid-template-columns: 200px auto; +} .chrome__head { -webkit-app-region: drag; - background: #3f407f url('../../../../static/img/chrome-head-bg.jpg') 0 0 no-repeat; - background-size: cover; + grid-area: head; + background-color: var(--color-background-chrome); display: flex; - color: #ffffff; - justify-content: space-between; + color: var(--color-foreground-chrome); + justify-content: flex-end; align-items: stretch; - border-bottom: 1px solid #797897; + line-height: 1; } .chrome__title { - padding: 5px; - padding-right: 0; + padding: 5px 0 5px 5px; font-size: 30px; - line-height: 1; font-family: BigNoodle; + flex-grow: 2; } .chrome__title:before { content: ""; @@ -31,13 +35,6 @@ margin-right: 10px; float: left; } -.chrome__update { - flex-grow: 10; - padding: 5px 10px; - display: flex; - justify-content: center; - align-items: stretch; -} .chrome__rating { line-height: 40px; padding-right: 20px; @@ -48,111 +45,80 @@ width: auto; } .chrome__ratingLabel { - color: #fff; + color: var(--color-foreground-chrome); font-size: 30px; font-family: kOverwatch; } -.chrome__quickAction { - padding: 5px; - padding-right: 20px; - font-family: Futura; - font-size: 14px; -} .chrome__windowAction { white-space: nowrap; } +.chrome__sidebar { + grid-area: sidebar; + display: flex; + flex-direction: column; + background-color: var(--color-background-chrome); +} +.chrome__body { + grid-area: main; +} -.updateButton { - cursor: pointer; - padding: 5px 10px; - font-weight: normal; - font-size: 14px; - line-height: 20px; - background-color: #e02200; - color: #fff; - text-transform: uppercase; +.sidebarLink { text-decoration: none; - pointer-events: none; - opacity: 0; - transition: opacity 200ms; - max-width: 350px; - border-radius: 1px; - -webkit-app-region: no-drag; - box-shadow: 0 0 0 0 white; - animation: updateButton 10s infinite ease-in-out; - transition: background-color 200ms, box-shadow 200ms; -} -.updateButton:hover { - animation: updateButtonHover 500ms infinite alternate ease-in-out; - animation-delay: 200ms; - box-shadow: 0 0 0 2px white; - background-color: #f25824; -} -.updateButton--avalible { - pointer-events: all; - -webkit-app-region: no-drag; - opacity: 1; + display: block; + padding: 10px 5px; + color: var(--color-foreground-chrome); } - -@keyframes updateButton { - 0% { - transform: scale(1); - } - 96% { - transform: scale(1); - } - 98% { - transform: scale(1.04); - } - 100% { - transform: scale(1); - } -} -@keyframes updateButtonHover { - from { - box-shadow: 0 0 0 1px rgba(255, 255, 255, 1); - } - to { - box-shadow: 0 0 0 3px rgba(255, 255, 255, .75); - } +.sidebarLink.router-link-active { + color: var(--color-foreground-chrome-active); } - -@media (max-width: 675px) { - .updateButton__more { - display: none; - } +.sidebarLink--update { + margin-top: auto; + display: none; + color: var(--color-foreground-update); + background-color: var(--color-background-update); +} +.sidebarLink--updateAvalible { + display: block; +} +.sidebarLink:hover { + background-color: var(--color-background-chrome-hover); +} +.sidebarLink--update:hover { + color: var(--color-foreground-update-hover); + background-color: var(--color-background-update-hover); +} +.sidebarLink--addMatch { + margin-top: auto; +} +.sidebarLink--updateAvalible + .sidebarLink--addMatch, +.sidebarInfo--season + .sidebarLink--updateAvalible { + margin-top: 0; +} +.sidebarLink__icon { + height: 30px; + width: 30px; + margin: 0 auto 5px; + display: block; +} +.sidebarLink__label { + text-transform: uppercase; + text-align: center; + display: block; + font-size: 10px; +} +.sidebarInfo { + display: block; + margin-top: auto; + margin-bottom: auto; + padding: 10px 5px; + text-align: center; + color: var(--color-foreground-chrome); +} +.sidebarInfo__label { + text-transform: uppercase; + font-size: 10px; +} +.sidebarInfo__value { + font-size: 30px; + font-family: kOverwatch; } - -@media (min-height: 720px) and (min-width: 1000px) { - .chrome { - display: grid; - grid-template-rows: 60px auto; - } - .chrome__title { - font-size: 50px; - } - .chrome__title:before { - height: 50px; - width: 50px; - } - .chrome__update { - flex-grow: 10; - padding: 5px 30px; - } - .chrome__rating { - line-height: 60px; - } - .chrome__ratingIcon { - height: 60px; - width: auto; - } - .chrome__ratingLabel { - font-size: 40px; - } - .updateButton { - font-size: 20px; - padding: 10px 20px; - margin: 5px; - line-height: 20px; - } -} \ No newline at end of file diff --git a/frsrc/view/chrome/chrome/chrome.ts b/frsrc/view/chrome/chrome/chrome.ts index baafc90..42c6179 100644 --- a/frsrc/view/chrome/chrome/chrome.ts +++ b/frsrc/view/chrome/chrome/chrome.ts @@ -3,16 +3,19 @@ import { Component, Prop } from 'vue-property-decorator'; import updateUrl from '../../../update-checker'; -import { CompwerstatsDatabase } from '../../../database'; -import { SeasonController } from '../../../season'; -import { MatchController } from '../../../match'; -import { Rank, RankController } from '../../../rank'; +import { Rank } from '../../../rank'; +import { Season, SeasonController } from '../../../season'; + +import { SeasonMode, ButtonMode } from '../../../interface'; + +import { mainBasedOnMode } from '../../../router-helper'; import './chrome.scss'; import ButtonBase from '../../button/base'; import ButtonChrome from '../button'; + @Component({ template: require('./chrome.html'), components: { @@ -22,74 +25,47 @@ import ButtonChrome from '../button'; }) export default class Chrome extends Vue { loaded: boolean = false; - seasonId: string; - quickAddLabel: string = ''; - quickAddPath: string = ''; - currentRank: Rank = null; - currentRating: number = -1; + mainLink: string = ''; + matchesLink: string = ''; updateUrl: string = ''; - updateClass: string = 'updateButton'; - - created() { - this.prepareDataBasedProperties(); + updateClass: string = 'sidebarLink sidebarLink--update'; + buttonInfo: ButtonMode = { + label: '', + shortLabel: '', + path: '' + }; + + modeWatcher: Function = null; + seasonWatcher: Function = null; + + rating: number; + seasonId: number; + seasonMode: SeasonMode; + rank: Rank; + season: Season = null; + + async created() { this.fetchUpdateInformation(); - this.setupListeners(); - } - - async prepareDataBasedProperties(): Promise { - const currentSeason = await SeasonController.getCurrent(); - const currentSeasonPlacementsLeft = await MatchController.hasPlacementsLeft(currentSeason.id); - this.currentRating = await MatchController.latestSeasonMatchRating(currentSeason.id); - this.currentRank = await RankController.getByRating(this.currentRating); - - this.loaded = true; - this.seasonId = currentSeason.id.toString(); - - if (currentSeason.placementRating) { - this.quickAddLabel = 'Add match'; - this.quickAddPath = 'competitive-add'; - } - else if (currentSeasonPlacementsLeft) { - this.quickAddLabel = 'Add placement'; - this.quickAddPath = 'placement-add'; - } - else { - this.quickAddLabel = 'Add starting SR'; - this.quickAddPath = 'placement-sr'; - } - - return this.quickAddPath; - } + this.buttonInfo = this.quickAddInfo(this.$store.state.seasonMode); + this.matchesLink = mainBasedOnMode(this.$store.state.seasonMode); + this.mainLink = this.$store.state.seasonMode === 'competetive' ? '/competitive' : '/placement'; + this.modeWatcher = this.$store.watch(this.$store.getters.getSeasonMode, (newMode) => { + this.buttonInfo = this.quickAddInfo(newMode); + this.matchesLink = mainBasedOnMode(newMode); + this.mainLink = newMode === SeasonMode.Matches ? '/competitive' : '/placement'; + }); - setupListeners() { - const _this = this; - const db = CompwerstatsDatabase.getInstance(); - const callback = function() { - this.onsuccess = () => { - /** - * This sexy setTimeout is to allow for the running - * transacrion to finnish before reading from the - * database. When time can be found we should solve - * this in a better way. - * - * When it is solved, please remove this comment. - */ - setTimeout(() => { - _this.prepareDataBasedProperties() - }, 0); - }; - }; - - db.match.hook('creating', callback); - db.season.hook('creating', callback); - db.season.hook('updating', callback); + this.season = await this.getSeason(this.$store.state.seasonId); + this.seasonWatcher = this.$store.watch(this.$store.getters.getSeasonId, async (newSeasonId) => { + this.season = await this.getSeason(newSeasonId); + }); } async fetchUpdateInformation() { - const updateInterval = 4 * 60 * 60 * 1000; + const updateInterval = 22 * 60 * 60 * 1000; this.updateUrl = await updateUrl(); - this.updateClass = this.updateUrl ? 'updateButton updateButton--avalible' : 'updateButton'; + this.updateClass = this.updateUrl ? 'sidebarLink sidebarLink--updateAvalible sidebarLink--update' : 'sidebarLink sidebarLink--update'; setTimeout(() => { this.fetchUpdateInformation(); @@ -103,12 +79,58 @@ export default class Chrome extends Vue { } } + quickAddInfo(mode): ButtonMode { + switch (mode) { + case SeasonMode.Matches: + return { + label: 'Add match', + shortLabel: '+ Match', + path: this.$router.resolve({ + name: 'competitive-add' + }).location.path + }; + case SeasonMode.Placements: + return { + label: 'Add placement', + shortLabel: '+ PLCMT', + path: this.$router.resolve({ + name: 'placement-add' + }).location.path + }; + case SeasonMode.PlacementsComplete: + return { + label: 'Add starting SR', + shortLabel: '+ SR', + path: this.$router.resolve({ + name: 'placement-sr' + }).location.path + }; + } + } + + getSeason(seasonId) { + return SeasonController.getSeasonById(seasonId); + } + quickAdd() { this.$router.push({ - name: this.quickAddPath, + name: this.quickAddInfo(this.$store.state.seasonMode).path, params: { - seasonId: this.seasonId + seasonId: this.$store.state.seasonId.toString() } }); } + + setSeason(seasonId) { + this.$store.dispatch('updateSeasonId', seasonId); + } + + destroyed() { + if (typeof this.modeWatcher === 'function') { + this.modeWatcher(); + } + if (typeof this.seasonWatcher === 'function') { + this.seasonWatcher(); + } + } } \ No newline at end of file diff --git a/frsrc/view/fragments/character-list/character-list.html b/frsrc/view/fragments/character-list/character-list.html index 7e31ca6..d22c61e 100644 --- a/frsrc/view/fragments/character-list/character-list.html +++ b/frsrc/view/fragments/character-list/character-list.html @@ -1,11 +1,9 @@
-
- -
{{ item.type.getName() }}
-
- -
+
\ No newline at end of file diff --git a/frsrc/view/fragments/character-list/character-list.scss b/frsrc/view/fragments/character-list/character-list.scss index 0179a45..4553c6d 100644 --- a/frsrc/view/fragments/character-list/character-list.scss +++ b/frsrc/view/fragments/character-list/character-list.scss @@ -1,126 +1,62 @@ .characterList { - display: flex; - flex-flow: wrap; - justify-content: space-around; + padding: 10px 10px 5px; } + .characterType { - position: relative; - padding: 5px; -} -.characterType__icon { - position: absolute; - top: 7px; - left: 7px; - height: 15px; - width: 15px; -} -.characterType__label { - font-size: 20px; - font-family: BigNoodle; - padding-left: 20px; - line-height: 1; -} -.characterType__characters { - display: flex; - flex-flow: wrap; - justify-content: center; - padding: 3px 0; + display: grid; + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + grid-gap: 4px; + padding-bottom: 10px; } + .character { - height: 50px; - width: 56px; - position: relative; - margin-right: 5px; - margin-bottom: 5px; - background-size: contain, 0 0; - background-position: 50%; - background-repeat: no-repeat; - background-color: rgba(0, 0, 0, 0.75); - border-radius: 2px; - border: 2px solid #fff; -webkit-appearance: none; - color: #000; - filter: drop-shadow(0 2px 3px rgba(10, 20, 30, 0.4)); + display: grid; + border-radius: 0; + text-decoration: none; cursor: pointer; - transition: transform 200ms, background-color 200ms, border-color 200ms; + background-color: var(--color-background-label); + border-width: 0; + transition: + background-color 200ms, + transform 200ms, + opacity 200ms; + + grid-template-rows: 1fr; + grid-template-columns: 1fr 32px 50px; + grid-template-areas: "label icon image"; } .character:hover, .character:focus { - transform: scale(1.05) translate(0, -1px); - z-index: 1; + background-color: var(--color-background-label-hover); } .character:active { - transform: scale(1.05) translate(0, 1px); + background-color: var(--color-background-form-button-active); } .character.is-selected { - background-color: rgb(250, 160, 0); - border-color: rgba(0, 0, 0, 0.4); + background-color: var(--color-background-form-button-selected); } -.character__label { - display: none; +.character__typeIcon { + grid-area: icon; + height: 16px; + width: 16px; + margin: 0 5px; + align-self: center; + opacity: 0.75; } - -@media (min-width: 1400px) { - .characterType__icon { - top: 10px; - height: 20px; - width: 20px; - } - .characterType__label { - font-size: 30px; - padding-left: 27px; - } - - .character { - height: 75px; - width: 84px; - } - - .character__label { - display: inline-block; - font-family: kOverwatch; - font-size: 17px; - padding: 2px 4px; - line-height: 1; - text-align: center; - white-space: nowrap; - min-width: 50px; - position: absolute; - bottom: -14px; - left: 50%; - background-color: rgb(250, 160, 0); - border-radius: 3px; - transform: translate(-50%, 0) scale(0); - transition: transform 100ms ease-in; - } - .character.is-selected .character__label { - transform: translate(-50%, 0) scale(1); - } -} -@media (min-width: 2500px) { - .character { - height: 310px; - width: 180px; - background-size: 0 0, cover; - } - - .character__label { - display: inline-block; - font-family: kOverwatch; - font-size: 30px; - padding: 2px 4px; - line-height: 1; - text-align: center; - white-space: nowrap; - min-width: 50px; - position: absolute; - bottom: 10px; - left: 50%; - background-color: rgb(250, 160, 0); - border-radius: 3px; - transform: translate(-50%, 0) scale(0); - transition: transform 100ms ease-in; - } - .character.is-selected .character__label { - transform: translate(-50%, 0) scale(1); - } +.character__label { + grid-area: label; + font-size: 14px; + line-height: 2; + font-family: Roboto, sans-serif; + padding-left: 7px; + color: var(--color-foreground-label); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.character__image { + background-size: cover; + background-position: 50%; + transition: filter 200ms; + filter: saturate(1); } \ No newline at end of file diff --git a/frsrc/view/fragments/character-list/character-list.ts b/frsrc/view/fragments/character-list/character-list.ts index 65ae951..f0a1bd7 100644 --- a/frsrc/view/fragments/character-list/character-list.ts +++ b/frsrc/view/fragments/character-list/character-list.ts @@ -44,7 +44,7 @@ export default class CharacterList extends Vue { return { character: character, selected: this.selectedIds.includes(character.id), - background: `background-image: url(${ character.iconPath }), url(${ character.imagePath })` + background: `background-image: url(${ character.iconPath })` } }); diff --git a/frsrc/view/fragments/group-size/group-size.html b/frsrc/view/fragments/group-size/group-size.html index 6d83407..5694df4 100644 --- a/frsrc/view/fragments/group-size/group-size.html +++ b/frsrc/view/fragments/group-size/group-size.html @@ -1,20 +1,26 @@
\ No newline at end of file diff --git a/frsrc/view/fragments/group-size/group-size.scss b/frsrc/view/fragments/group-size/group-size.scss index 5a948ae..4a60e33 100644 --- a/frsrc/view/fragments/group-size/group-size.scss +++ b/frsrc/view/fragments/group-size/group-size.scss @@ -1,6 +1,7 @@ .groupSize { - padding: 20px; + padding: 10px 0; display: flex; + justify-content: center; } .groupSizeButton { flex-grow: 1; @@ -9,42 +10,32 @@ -webkit-appearance: none; border-width: 0; margin: 0 2px; - background-color: rgb(28, 116, 187); - border: 2px solid rgb(28, 116, 187); - box-shadow: 0 2px 3px rgba(10, 20, 30, 0.4); - padding: 20px 0; - border-radius: 2px; - font-size: 30px; - color: #fff; + background-color: var(--color-background-form-button); + border: 2px solid var(--color-background-form-button); + padding: 10px 0; + max-width: 120px; + color: var(--color-foreground-form-button); text-align: center; - font-family: Futura; - transition: transform 200ms, background-color 200ms, border-color 200ms; + font-family: Roboto, sans-serif; } .groupSizeButton:hover, .groupSizeButton:focus { - transform: translate(0, -1px) + background-color: var(--color-background-form-button-hover); } .groupSizeButton:active { - transform: translate(0, 1px) + background-color: var(--color-background-form-button-active); } .groupSizeButton.is-selected { - background-color: rgb(16, 88, 145); - border-color: #fff; + background-color: var(--color-background-form-button-selected); + border-color: var(--color-background-form-button-selected); } - -@media (max-width: 900px) { - .groupSizeButton { - padding: 10px 0; - } +.groupSizeButton__label { + text-transform: uppercase; + font-size: 10px; + line-height: 1; + opacity: 0.75; } -@media (min-width: 1400px) { - .groupSizeButton { - padding: 30px 0; - } -} -@media (min-width: 2500px) { - .groupSizeButton { - padding: 40px 0; - font-size: 50px; - } +.groupSizeButton__value { + font-size: 20px; + line-height: 1; } \ No newline at end of file diff --git a/frsrc/view/fragments/head-select/head-select.scss b/frsrc/view/fragments/head-select/head-select.scss index a70a4fe..d5178cc 100644 --- a/frsrc/view/fragments/head-select/head-select.scss +++ b/frsrc/view/fragments/head-select/head-select.scss @@ -6,7 +6,7 @@ line-height: 1; color: #fff; overflow: hidden; - background: rgba(63, 65, 130, 0.8); + background-color: var(--color-background-form-button); } .headSelectItem { @@ -16,21 +16,10 @@ min-width: 25px; text-align: center; cursor: pointer; - text-shadow: 0 0 1px rgba(195, 196, 227, 0.53); - transition: text-shadow 200ms; } .headSelectItem:hover { - text-shadow: 0 1px 1px rgba(195, 196, 227, 0.53); + background-color: var(--color-background-form-button-hover); } .headSelectItem.is-selected { - background: rgba(63, 65, 130, 0.8); -} - -@media (min-height: 720px) and (min-width: 1000px) { - .headSelect { - font-size: 16px; - } - .headSelectItem { - padding: 10px 15px; - } + background-color: var(--color-background-form-button-active); } \ No newline at end of file diff --git a/frsrc/view/fragments/list-item-settings/list-item-settings.scss b/frsrc/view/fragments/list-item-settings/list-item-settings.scss index 99f3a32..eb0693f 100644 --- a/frsrc/view/fragments/list-item-settings/list-item-settings.scss +++ b/frsrc/view/fragments/list-item-settings/list-item-settings.scss @@ -1,10 +1,6 @@ .listItemSettings { - background-color: #fff; - background-size: 100px 100px; - background-repeat: no-repeat; - background-position: 100% 50%; + background-color: var(--color-background-label); color: var(--color-foreground-label); - position: relative; overflow: hidden; display: block; text-decoration: none; @@ -12,64 +8,42 @@ padding: 10px; line-height: 1; transition: all 250ms; - box-shadow: 0 3px 2px rgba(0, 10, 20, 0.5); -} - -@mixin listItemDistinction($color) { - &:after { - content: ""; - display: block; - position: absolute; - right: 0; - top: 50%; - transform: translate(0, -50%); - height: 60px; - min-width: 10px; - border-radius: 2px 0 0 2px; - background-color: var($color); - transition: border-radius 200ms, - min-width 200ms; - } + border-bottom: 2px solid var(--color-foreground-label); } .listItemSettings--map { - @include listItemDistinction(--color-type-map); + border-bottom-color: var(--color-type-map); } .listItemSettings--maptype { - @include listItemDistinction(--color-type-maptype); + border-bottom-color: var(--color-type-maptype); } .listItemSettings--rank { - @include listItemDistinction(--color-type-rank); + border-bottom-color: var(--color-type-rank); } .listItemSettings--commentsuggestion { - @include listItemDistinction(--color-type-commentsuggestion); + border-bottom-color: var(--color-type-commentsuggestion); } .listItemSettings--season { - @include listItemDistinction(--color-type-season); + border-bottom-color: var(--color-type-season); } .listItemSettings--character { - @include listItemDistinction(--color-type-character); + border-bottom-color: var(--color-type-character); } .listItemSettings--charactertype { - @include listItemDistinction(--color-type-charactertype); + border-bottom-color: var(--color-type-charactertype); } .listItemSettings--placement { - @include listItemDistinction(--color-type-placement); + border-bottom-color: var(--color-type-placement); } .listItemSettings--match { - @include listItemDistinction(--color-type-match); + border-bottom-color: var(--color-type-match); } .listItemSettings:hover { - transform: translate(0, -2px); -} -.listItemSettings:hover:after { - border-radius: 5px 0 0 5px; - min-width: 40px; - transform: translate(0, -50%); + background-color: var(--color-background-label-hover); } .listItemSettings:active { - transform: translate(0, 2px); + background-color: var(--color-background-label-active); } .listItemSettings__iconWrapper { display: inline-block; @@ -92,4 +66,6 @@ .listItemSettings__description { font-size: 14px; text-transform: uppercase; + font-weight: 300; + padding-top: 4px; } \ No newline at end of file diff --git a/frsrc/view/fragments/map-list/map-list.html b/frsrc/view/fragments/map-list/map-list.html index 8040d81..d727623 100644 --- a/frsrc/view/fragments/map-list/map-list.html +++ b/frsrc/view/fragments/map-list/map-list.html @@ -1,6 +1,7 @@ \ No newline at end of file diff --git a/frsrc/view/fragments/map-list/map-list.scss b/frsrc/view/fragments/map-list/map-list.scss index 9b49e0d..3a16cab 100644 --- a/frsrc/view/fragments/map-list/map-list.scss +++ b/frsrc/view/fragments/map-list/map-list.scss @@ -1,111 +1,52 @@ .mapList { - display: flex; - flex-wrap: wrap; - justify-content: center; - align-content: flex-start; + display: grid; + grid-template-columns: repeat(auto-fill, minmax(270px, 1fr)); + grid-gap: 4px; padding: 10px; } .map { -webkit-appearance: none; - height: 120px; - width: 160px; - display: block; - background-size: cover; - background-position: 50%; - position: relative; - margin: 2.5px; - border-radius: 2px; + display: grid; + border-radius: 0; text-decoration: none; - text-align: left; - border: 2px solid #fff; - box-shadow: 0 2px 3px rgba(10, 20, 30, 0.4); cursor: pointer; - transition: transform 200ms, filter 200ms; + background-color: var(--color-background-label); + border-width: 0; + + grid-template-rows: 1fr; + grid-template-columns: 1fr 40px 70px; + grid-template-areas: "label icon image"; } .map:hover, .map:focus { - transform: scale(1.05) translate(0, -1px); - z-index: 1; + background-color: var(--color-background-label-hover); } .map:active { - transform: scale(1.05) translate(0, 1px); + background-color: var(--color-background-form-button-active); } -.mapList.is-selected .map { - filter: saturate(0) brightness(0.7); -} -.mapList .map.is-selected { - filter: saturate(1); +.map.is-selected { + background-color: var(--color-background-form-button-selected); } .map__typeIcon { - position: absolute; - right: 5px; - top: 5px; - height: 32px; - width: 32px; - filter: contrast(0) brightness(10) drop-shadow(0 1px 3px rgba(10, 20, 30, 0.75)); + grid-area: icon; + height: 24px; + width: 24px; + margin: 0 5px; + align-self: center; + opacity: 0.75; } .map__label { - background: rgba(0, 0, 0, 0.75); - font-size: 20px; - line-height: 1; - font-family: BigNoodle; - padding: 5px; - color: #fff; - position: absolute; - bottom: 0; - right: 0; - left: 0; -} - -@media (max-width: 900px) { - .map { - height: auto; - width: auto; - min-width: 200px; - flex-shrink: 0; - background-position: 50%; - } - .map__typeIcon { - display: none; - } - .map__label { - position: static; - overflow: hidden; - text-align: center; - background: rgba(10, 20, 30, 0.2); - text-shadow: - 0 0 4px rgb(10, 20, 30), - 1px 1px 0 rgb(10, 20, 30), - -1px 1px 0 rgb(10, 20, 30), - 1px -1px 0 rgb(10, 20, 30), - -1px -1px 0 rgb(10, 20, 30); - padding: 5px; - } -} - -@media (min-width: 1400px) { - .map { - height: 150px; - width: 230px; - } - .map__typeIcon { - height: 48px; - width: 48px; - } - .map__label { - font-size: 30px; - } -} -@media (min-width: 2500px) { - .map { - height: 240px; - width: 400px; - } - .map__typeIcon { - height: 60px; - width: 60px; - } - .map__label { - font-size: 50px; - } + grid-area: label; + font-size: 14px; + line-height: 2; + font-family: Roboto, sans-serif; + padding-left: 7px; + color: var(--color-foreground-label); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.map__image { + background-size: cover; + background-position: 50%; } \ No newline at end of file diff --git a/frsrc/view/fragments/map-list/map-list.ts b/frsrc/view/fragments/map-list/map-list.ts index 577a6d5..91f9073 100644 --- a/frsrc/view/fragments/map-list/map-list.ts +++ b/frsrc/view/fragments/map-list/map-list.ts @@ -40,8 +40,7 @@ export default class MapList extends Vue { list.push({ map: map, type: mapType, - selected: this.selectedId === map.id, - background: `background-image: url(${ map.getIcon() })` + selected: this.selectedId === map.id }); }); diff --git a/frsrc/view/fragments/match-result/match-result.scss b/frsrc/view/fragments/match-result/match-result.scss index ea4d935..91e281e 100644 --- a/frsrc/view/fragments/match-result/match-result.scss +++ b/frsrc/view/fragments/match-result/match-result.scss @@ -1,76 +1,43 @@ .results { margin: 0 auto; - padding: 20px; + padding: 10px; display: flex; justify-content: center; } .resultsLabel { cursor: pointer; display: block; - padding: 20px 10px; + padding: 10px 0; margin: 0 5px; - min-width: 100px; - border-radius: 2px; + min-width: 120px; text-align: center; line-height: 1; - color: #eee; - border-width: 2px; - border-style: solid; + border: 0 solid red; -webkit-appearance: none; - background: url('../../../../static/img/button-hightlight.png') no-repeat 50%; - background-size: cover; - filter: saturate(0.25); - box-shadow: 0 2px 3px 0 rgba(10, 20, 30, 0.4); - transition: filter 200ms, transform 200ms; + background-color: var(--color-background-form-button); +} +.resultsLabel:hover { + background-color: var(--color-background-form-button-hover); } -.resultsLabel:hover, .resultsLabel:focus { - transform: translate(0, -1px); + background-color: var(--color-background-form-button-focus); } .resultsLabel:active { - transform: translate(0, 2px); + background-color: var(--color-background-form-button-active); } .resultsLabel.is-selected { - filter: saturate(1); - border-color: #fff; - color: #fff; + background-color: var(--color-background-form-button-selected); } .resultsLabel--win { - background-color: #88b60b; - border-color: #88b60b; + color: var(--color-result-win); } .resultsLabel--draw { - background-color: #cbc728; - border-color: #cbc728; + color: var(--color-result-draw); } .resultsLabel--loss { - background-color: #9d2b49; - border-color: #9d2b49; + color: var(--color-result-loss); } .resultsLabel__label { - font-family: kOverwatch; - text-align: center; + font-family: Roboto, sans-serif; font-size: 20px; - text-shadow: - 1px 1px 0 rgb(10, 20, 30), - -1px 1px 0 rgb(10, 20, 30), - 1px -1px 0 rgb(10, 20, 30), - -1px -1px 0 rgb(10, 20, 30); } - -@media (min-width: 2500px) { - .resultsLabel { - padding: 40px 20px; - width: 300px; - } - .resultsLabel:hover, - .resultsLabel:focus { - transform: translate(0, -5px); - } - .resultsLabel:active { - transform: translate(0, 2px); - } - .resultsLabel__label { - font-size: 50px; - } -} \ No newline at end of file diff --git a/frsrc/view/fragments/match-result/match-result.ts b/frsrc/view/fragments/match-result/match-result.ts index 4ed7116..88ad8aa 100644 --- a/frsrc/view/fragments/match-result/match-result.ts +++ b/frsrc/view/fragments/match-result/match-result.ts @@ -1,7 +1,7 @@ import Vue from 'vue'; import { Component, Prop } from 'vue-property-decorator'; -import { MatchResult } from '../../../match'; +import { MatchResult } from '../../../interface'; import './match-result.scss'; diff --git a/frsrc/view/fragments/match/match.html b/frsrc/view/fragments/match/match.html index 9f2760f..e9d1a57 100644 --- a/frsrc/view/fragments/match/match.html +++ b/frsrc/view/fragments/match/match.html @@ -1,24 +1,34 @@ -
- -
-
{{ currentMap.name }}
-
{{ match.time | moment('YYYY-MM-DD HH:mm') }}
+
+ +
\ No newline at end of file diff --git a/frsrc/view/fragments/match/match.scss b/frsrc/view/fragments/match/match.scss index ddb3af5..aeac56a 100644 --- a/frsrc/view/fragments/match/match.scss +++ b/frsrc/view/fragments/match/match.scss @@ -1,115 +1,168 @@ .matchItem { - position: relative; - overflow: hidden; - height: 200px; - max-width: 650px; - width: 100%; box-sizing: border-box; - border-radius: 3px; - margin: 0 0 5px 5px; + padding: 5px; + margin-bottom: 5px; + display: grid; + grid-template-columns: 64px 50px 100px 1fr 120px; + grid-template-rows: 30px 14px auto auto; + grid-template-areas: + "icon mapname mapname mapname result" + "icon time time heroes result" + "icon streak teamratings heroes result" + "details details details details details"; + background-color: var(--color-background-label); + border-bottom: 2px solid var(--color-result-unknown); + // cursor: pointer; +} +.matchItem:hover { + // background-color: var(--color-background-label-hover); } -.matchItem__map { - position: absolute; - top: 50%; - left: 50%; - width: 110%; +.matchItem--win { + border-color: var(--color-result-win); +} +.matchItem--draw { + border-color: var(--color-result-draw) +} +.matchItem--loss { + border-color: var(--color-result-loss) +} + +.matchItem__details { + grid-area: details; + height: 0; + overflow: hidden; + display: grid; +} +.matchItem--details .matchItem__details { height: auto; - filter: blur(3px) brightness(0.75); - transform: translate(-50%, -50%); } -.matchItem__content { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; + +.matchItem__map { + grid-area: icon; + width: 64px; + height: 64px; + border-radius: 50%; + background-position: 50% 50%; + background-size: cover; + background-repeat: no-repeat; } .matchItem__mapName { - font-size: 50px; - padding: 5px 0 0 10px; + grid-area: mapname; + font-size: 30px; color: #fff; - text-shadow: 0 2px 3px rgba(10, 20, 30, 0.5); font-family: BigNoodle; line-height: 1; + padding-left: 10px; } .matchItem__time { - padding: 2px 0 0 20px; + grid-area: time; color: #fff; - text-shadow: 0 2px 3px rgba(10, 20, 30, 0.5); font-size: 14px; + padding: 2px 10px 0; + line-height: 1; +} +.matchItem__streak { + grid-area: streak; + padding: 2px 2px 0 10px; + font-weight: bold; + font-size: 14px; + line-height: 17px; +} +.matchItem__streak:before { + padding-right: 5px; +} +.matchItem--win .matchItem__streak { + color: var(--color-result-win); +} +.matchItem--win .matchItem__streak:before { + content: "â–Č"; +} +.matchItem--draw .matchItem__streak { + color: var(--color-result-draw); +} +.matchItem--draw .matchItem__streak:before { + content: "â–ș"; +} +.matchItem--loss .matchItem__streak { + color: var(--color-result-loss); +} +.matchItem--loss .matchItem__streak:before { + content: "â–Œ"; +} + +.matchItemTeamRating { + grid-area: teamratings; + display: flex; + justify-content: flex-end; + text-align: center; + font-size: 14px; + padding: 2px 10px 0 2px; + line-height: 17px; +} +.matchItemTeamRating__label { + font-size: 10px; + text-transform: uppercase; + text-align: right; + padding: 2px 2px 0 0; +} +.matchItemTeamRating__value { + min-width: 2.5ex; + line-height: 17px; + font-weight: bold; + text-align: right; +} +.matchItemTeamRating__value--blueAdvantage { + color: var(--color-team-blue); +} +.matchItemTeamRating__value--redAdvantage { + color: var(--color-team-red); } .matchItem__rating { - position: absolute; - right: 10px; - top: 10px; + grid-area: result; + white-space: nowrap; + display: flex; + align-items: center; + justify-content: space-around; } .matchItem__ratingIcon { - position: absolute; - z-index: 1; - left: 0; - top: -5px; height: auto; width: auto; - max-width: 60px; - max-height: 70px + max-width: 50px; + max-height: 64px; + margin-left: 10px; } .matchItem__ratingLabel { - position: relative; - padding: 0 0 0 60px; - font-size: 50px; + font-size: 40px; font-family: kOverwatch; - color: #fff; - text-shadow: - 1px 1px 0 rgb(10, 20, 30), - -1px 1px 0 rgb(10, 20, 30), - 1px -1px 0 rgb(10, 20, 30), - -1px -1px 0 rgb(10, 20, 30); -} -.matchItem__ratingLabel:before { - content: ""; - position: absolute; - top: 12px; - right: 7px; - bottom: 12px; - left: 67px; - background-color: rgba(255, 255, 255, 0.6); - border-radius: 10px; - filter: blur(7px); -} -.matchItem__ratingLabelText { - position: relative; - z-index: 1; + color: var(--color-result-unkown); + display: inline; } -.matchItem--win .matchItem__ratingLabelText { - color: #88b60b; +.matchItem--win .matchItem__ratingLabel { + color: var(--color-result-win); } -.matchItem--draw .matchItem__ratingLabelText { - color: #cbc728; +.matchItem--draw .matchItem__ratingLabel { + color: var(--color-result-draw) } -.matchItem--loss .matchItem__ratingLabelText { - color: #9d2b49; +.matchItem--loss .matchItem__ratingLabel { + color: var(--color-result-loss) } .matchItem__characters { - position: absolute; - bottom: 10px; - right: 10px; - left: 5px; + grid-area: heroes; display: flex; - justify-content: flex-end; - height: 60px; + justify-content: center; + flex-wrap: wrap; } .matchItem__character { - border: 1px solid #fff; - width: 54px; - background-position: 50% 50%, 0 0; - background-size: cover, 0 0; + width: 32px; + height: 32px; + background-position: 50% 50%; + background-size: cover; background-repeat: no-repeat; - border-radius: 2px; - box-shadow: 0 2px 3px rgba(10, 20, 30, 0.4); - margin: 0 0 0 5px; - background-color: rgba(0, 0, 0, 0.75); + margin: 0 0 2px 2px; + border: 1px solid var(--color-foreground-label); + border-radius: 10px; } \ No newline at end of file diff --git a/frsrc/view/fragments/match/match.ts b/frsrc/view/fragments/match/match.ts index 7f21a6e..2c5209e 100644 --- a/frsrc/view/fragments/match/match.ts +++ b/frsrc/view/fragments/match/match.ts @@ -1,44 +1,49 @@ import Vue from 'vue'; import { Component, Prop } from 'vue-property-decorator'; -import { Match, MatchType } from '../../../match'; +import { Match } from '../../../match'; import { OverwatchMap, OverwatchMapController } from '../../../overwatchmap'; import { Character, CharacterController } from '../../../character'; import { Rank, RankController } from '../../../rank'; +import { MatchType } from '../../../interface'; + import './match.scss'; +import LoadingSpinner from '../../fragments/loading-spinner'; + @Component({ - template: require('./match.html') + template: require('./match.html'), + components: { + LoadingSpinner + } }) export default class MatchItem extends Vue { loading: boolean = true; - currentMap: OverwatchMap; - currentRank: Rank; - usedCharacters: Character[]; + showingDetails: boolean = false; + map: OverwatchMap; + rank: Rank; + characters: Character[]; @Prop() match: Match; - @Prop() - maps: OverwatchMap[]; - - @Prop() - characters: Character[]; + async created() { + this.map = await OverwatchMap.load(this.match.overwatchMapId); + this.rank = await RankController.getByRating(this.match.rating); + this.characters = await Promise.all(this.match.character.map(Character.load)); - @Prop() - ranks: Rank[]; + if (typeof this.map === 'undefined') { + // If we don't know what map it is, we create a temporary fake map + this.map = OverwatchMap.create(0, 'UNKNOWN MAP', './static/img/no-map-image.jpg'); + } - created() { - const fakeMap = OverwatchMap.create(0, 'REMOVED MAP', './static/img/no-map-image.jpg'); - this.currentMap = this.maps.reduce((prev, curr) => curr.id === this.match.overwatchMapId ? curr : prev, fakeMap); - this.currentRank = RankController.getByRatingFromRanks(this.ranks, this.match.rating); - this.usedCharacters = this.characters.filter((char) => this.match.character && this.match.character.includes(char.id)); + this.loading = false; } data() { return { - mapImageStyle: this.currentMap ? `background-image: url(${ this.currentMap.imagePath })` : '' + mapImageStyle: this.map ? `background-image: url(${ this.map.imagePath })` : '' } } diff --git a/frsrc/view/fragments/season-select/season-select.scss b/frsrc/view/fragments/season-select/season-select.scss index adca63f..0aa6ccf 100644 --- a/frsrc/view/fragments/season-select/season-select.scss +++ b/frsrc/view/fragments/season-select/season-select.scss @@ -5,7 +5,7 @@ width: 120px; margin: 7px 7px 7px 15px; line-height: 1; - font-family: Futura; + font-family: Roboto, sans-serif; color: #fff; background-color: rgba(63, 65, 130, 0.8); background-image: url('../../../../static/img/select.svg'); @@ -29,20 +29,4 @@ } .seasonSelect__item:hover { background: rgba(63, 65, 130, 0.8); -} - -@media (min-height: 720px) and (min-width: 1000px) { - .seasonSelect { - font-size: 16px; - width: 190px; - padding: 1px 30px 0 10px; - background-size: 12px; - background-position: calc(100% - 10px) 50%; - } - .seasonSelect:hover { - background-position: calc(100% - 10px) calc(50% - 2px); - } - .seasonSelect:active { - background-position: calc(100% - 10px) calc(50% + 2px); - } } \ No newline at end of file diff --git a/frsrc/view/fragments/subpage/subpage.html b/frsrc/view/fragments/subpage/subpage.html index c03641c..9bba2bb 100644 --- a/frsrc/view/fragments/subpage/subpage.html +++ b/frsrc/view/fragments/subpage/subpage.html @@ -1,5 +1,5 @@ -
-
+
+
diff --git a/frsrc/view/fragments/subpage/subpage.scss b/frsrc/view/fragments/subpage/subpage.scss index 51452fb..3da3ad7 100644 --- a/frsrc/view/fragments/subpage/subpage.scss +++ b/frsrc/view/fragments/subpage/subpage.scss @@ -7,6 +7,12 @@ "main main main"; height: calc(100vh - 41px); } +.subpage.subpage--noHead { + grid-template-rows: 0 auto; +} +.subpage.subpage--noBack { + grid-template-columns: 0 auto; +} .subpage__back { display: flex; grid-area: back; @@ -21,11 +27,4 @@ grid-area: main; max-height: 100%; padding: 5px; -} -@media (min-height: 720px) and (min-width: 1000px) { - .subpage { - height: calc(100vh - 60px); - grid-template-rows: 50px auto; - grid-template-columns: 90px auto; - } } \ No newline at end of file diff --git a/frsrc/view/fragments/subpage/subpage.ts b/frsrc/view/fragments/subpage/subpage.ts index 57af6a9..493eee2 100644 --- a/frsrc/view/fragments/subpage/subpage.ts +++ b/frsrc/view/fragments/subpage/subpage.ts @@ -10,6 +10,11 @@ import ButtonBack from '../../button/back'; template: require('./subpage.html'), components: { ButtonBack + }, + computed: { + noHead() { + return !this.$slots.head; + } } }) export default class Subpage extends Vue { diff --git a/frsrc/view/page-competitive/page-competitive/index.ts b/frsrc/view/page-competitive/page-competitive/index.ts deleted file mode 100644 index 70ffc91..0000000 --- a/frsrc/view/page-competitive/page-competitive/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './page-competitive'; \ No newline at end of file diff --git a/frsrc/view/page-competitive/page-competitive/page-competitive.html b/frsrc/view/page-competitive/page-competitive/page-competitive.html deleted file mode 100644 index 0ede0bf..0000000 --- a/frsrc/view/page-competitive/page-competitive/page-competitive.html +++ /dev/null @@ -1,20 +0,0 @@ -
- - - - -
-
-
No matches
-
- -
-
-
\ No newline at end of file diff --git a/frsrc/view/page-competitive/page-competitive/page-competitive.scss b/frsrc/view/page-competitive/page-competitive/page-competitive.scss deleted file mode 100644 index 3b0fde6..0000000 --- a/frsrc/view/page-competitive/page-competitive/page-competitive.scss +++ /dev/null @@ -1,24 +0,0 @@ -.matchList { - display: flex; - flex-wrap: wrap; - justify-content: center; - align-content: flex-start; - height: 100%; -} -.matchList-noMatches { - display: flex; - justify-content: center; - align-items: center; - text-align: center; - font-size: 50px; - font-family: BigNoodle; - color: #fff; - height: 100%; - max-height: 400px; - min-height: 100px; - text-shadow: - 1px 1px 0 rgb(10, 20, 30), - -1px 1px 0 rgb(10, 20, 30), - 1px -1px 0 rgb(10, 20, 30), - -1px -1px 0 rgb(10, 20, 30); -} \ No newline at end of file diff --git a/frsrc/view/page-competitive/page-match-add/page-match-add.html b/frsrc/view/page-competitive/page-match-add/page-match-add.html index 2f0affc..8a09822 100644 --- a/frsrc/view/page-competitive/page-match-add/page-match-add.html +++ b/frsrc/view/page-competitive/page-match-add/page-match-add.html @@ -1,33 +1,52 @@
- + Skip placements - -
-

New rating

-
- -
-

Match result

- -

Select map

- -

Select played characters

- -

Group size

- -

Team Skill Rating

-
- - -
-

Comment

- -
-
Suggestions:
- {{ comment.content }} -
- Save + +
+

New rating

+
+ +
+
+
+

Match result

+ +
+
+

Select map

+ +
+
+

Select played characters

+ +
+
+

Group size

+ +
+
+

Team Skill Rating

+
+ + +
+
+
+

Comment

+
+ +
+
+
Suggestions:
+ +
+
+
+ Save +
\ No newline at end of file diff --git a/frsrc/view/page-competitive/page-match-add/page-match-add.scss b/frsrc/view/page-competitive/page-match-add/page-match-add.scss index 00d142c..d3008ae 100644 --- a/frsrc/view/page-competitive/page-match-add/page-match-add.scss +++ b/frsrc/view/page-competitive/page-match-add/page-match-add.scss @@ -1,61 +1,59 @@ -.addMatchHeader { +.addMatch__header { font-size: 20px; font-weight: normal; - font-size: 25px; - margin: 10px 20px 0; + margin: 0 20px 0; font-family: BigNoodle; - color: #fff; - text-shadow: - 0 0 4px rgb(10, 20, 30), - 1px 1px 0 rgb(10, 20, 30), - -1px 1px 0 rgb(10, 20, 30), - 1px -1px 0 rgb(10, 20, 30), - -1px -1px 0 rgb(10, 20, 30); + color: var(--color-foreground-content); +} +.addMatch__rating { + padding: 10px 0; } .addMatchRating { - font-size: 50px; + font-size: 20px; max-width: 230px; width: 100%; text-align: center; padding: 10px; -moz-appearance: none; display: block; - margin: 10px auto; + margin: 0 auto; box-sizing: border-box; - font-family: Futura; - border-radius: 10px; - border: 2px solid #fff; - box-shadow: - 0 0 3px rgba(10, 20, 30, 0.4), - inset 0 20px 40px -10px rgba(99, 75, 236, 0.2); + font-family: Roboto, sans-serif; + border-radius: 2px; + border: 2px solid var(--color-border-form-input); + background-color: var(--color-background-form-input); + color: var(--color-foreground-form-input); } +.addMatch__comment { + padding: 10px; +} .addMatchComment { display: block; - margin: 0 auto; + margin: 0 auto 0; padding: 5px; - font-family: Futura; - font-size: 20px; + font-family: Roboto, sans-serif; + font-size: 16px; line-height: 1.46; resize: vertical; - border-radius: 6px; - border: 2px solid #fff; - box-shadow: - 0 2px 3px rgba(10, 20, 30, 0.4), - inset 0 20px 40px -10px rgba(99, 75, 236, 0.3); - height: 150px; + height: 100px; box-sizing: border-box; max-width: 950px; width: 100%; + border: 2px solid var(--color-border-form-input); + background-color: var(--color-background-form-input); + color: var(--color-foreground-form-input); } -.addMatchTeamRating { +.addMatch__teamRating { display: flex; justify-content: space-around; + max-width: 960px; + margin: 0 auto; } .addMatchTeamRatingField { - font-size: 40px; + font-size: 20px; max-width: 230px; width: 100%; text-align: center; @@ -64,18 +62,19 @@ display: block; margin: 10px auto; box-sizing: border-box; - font-family: Futura; - border-radius: 10px; - border: 2px solid #fff; - box-shadow: - 0 0 3px rgba(10, 20, 30, 0.4), - inset 0 20px 40px -10px rgba(99, 75, 236, 0.2); + font-family: Roboto, sans-serif; + border: 2px solid var(--color-border-form-input); + background-color: var(--color-background-form-input); + color: var(--color-foreground-form-input); +} +.addMatchTeamRatingField::placeholder { + color: var(--color-foreground-form-input-placeholder); } .addMatchTeamRatingField--red { - border-color: #EB9DA4; + border-color: var(--color-team-red); } .addMatchTeamRatingField--blue { - border-color: #9DBFEB; + border-color: var(--color-team-blue); } .addMatchCommentSuggestions { @@ -87,27 +86,52 @@ } .addMatchCommentSuggestions__label { font-size: 16px; - color: #fff; + color: var(--color-foreground-content); margin: 0 0 5px; - text-shadow: - 0 0 4px rgb(10, 20, 30), - 1px 1px 0 rgb(10, 20, 30), - -1px 1px 0 rgb(10, 20, 30), - 1px -1px 0 rgb(10, 20, 30), - -1px -1px 0 rgb(10, 20, 30); +} +.addMatchCommentSuggestions__values { + overflow: auto; } .addMatchCommentSuggestions__text { text-decoration: none; - color: #555; + color: var(--color-foreound-form-button); + background-color: var(--color-background-form-button); + margin-left: 4px; padding: 5px; float: left; } .addMatchCommentSuggestions__text:hover { - text-decoration: underline; + text-decoration: none; + background-color: var(--color-background-form-button-hover); +} +.addMatchCommentSuggestions__text:focus { + background-color: var(--color-background-form-button-focus); +} +.addMatchCommentSuggestions__text:active { + background-color: var(--color-background-form-button-active); } -@media (min-width: 1400px) { - .addMatchHeader { - font-size: 50px; - } +.addMatch { +} +.addMatchGroup { + padding-bottom: 10px; +} +.addMatchGroup--rating { +} +.addMatchGroup--result { +} +.addMatchGroup--map { +} +.addMatchGroup--character { +} +.addMatchGroup--groupSize { +} +.addMatchGroup--teamRating { +} +.addMatchGroup--comment { +} +.addMatchGroup--save { + position: absolute; + bottom: 0; + right: 20px; } \ No newline at end of file diff --git a/frsrc/view/page-competitive/page-match-add/page-match-add.ts b/frsrc/view/page-competitive/page-match-add/page-match-add.ts index 87cc326..8791ab8 100644 --- a/frsrc/view/page-competitive/page-match-add/page-match-add.ts +++ b/frsrc/view/page-competitive/page-match-add/page-match-add.ts @@ -1,10 +1,13 @@ import Vue from 'vue'; import { Component, Prop, Watch } from 'vue-property-decorator'; -import { Match, MatchController, MatchType } from '../../../match'; +import { SeasonMode, MatchType } from '../../../interface'; + +import { Match, MatchController } from '../../../match'; import { Character, CharacterController } from '../../../character'; import { CharacterType, CharacterTypeController } from '../../../charactertype'; import { CommentSuggestion, CommentSuggestionController } from '../../../commentsuggestion'; +import { SeasonController } from '../../../season'; import './page-match-add.scss'; @@ -36,44 +39,28 @@ export default class PageMatchAdd extends Vue { comments: CommentSuggestion[] seasonId: number; comment: string = ''; - - @Prop() - type: string; + type: MatchType; created() { this.fetchData(); } async fetchData() { - const type = this.type === 'competitive' ? MatchType.Match : MatchType.Placement; + this.type = (this.$store.state.seasonMode === SeasonMode.Placements ? MatchType.Placement : MatchType.Match); this.loading = true; - this.seasonId = parseInt(this.$route.params.seasonId, 10); + this.seasonId = this.$store.state.seasonId; this.comments = await CommentSuggestionController.getAll(); this.match = new Match(); this.match.seasonId = this.seasonId; - this.match.type = type; + this.match.type = this.type === MatchType.Placement ? MatchType.Placement : MatchType.Match; this.loading = false; } - @Watch('$route') - watchRoute(to, from) { - this.fetchData(); - } - - updateSeasonId(seasonId) { - this.$router.replace({ - name: this.$router.currentRoute.name, - params: { - seasonId: seasonId - } - }); - } - save(ev: Event) { ev.preventDefault(); const saveButtonWithFocus = document.querySelector('.button--save:focus'); @@ -87,16 +74,21 @@ export default class PageMatchAdd extends Vue { } } - savePlacement() { + async savePlacement() { if (this.validatePlacement()) { - this.match.time = +(new Date()); - this.match.save(); - this.$router.push({ - name: 'placement', - params: { - seasonId: this.seasonId.toString() - } - }); + if (!this.match.time) { + this.match.time = Date.now(); + } + await this.match.save(); + const seasonMode = await SeasonController.getMode(this.match.seasonId); + this.$store.commit('seasonMode', seasonMode); + this.$router.push('/'); + } + else { + const label = this.$el.querySelector('.resultsLabel'); + if (label) { + label.focus(); + } } } @@ -107,22 +99,33 @@ export default class PageMatchAdd extends Vue { async saveMatch() { if (this.validateMatch()) { - const lastMatch = await MatchController.latestSeasonMatchRating(this.seasonId); - this.match.time = +(new Date()); + const lastMatchRating = await MatchController.latestSeasonMatchRating(this.seasonId); + const lastMatch = await MatchController.latestSeasonMatch(this.seasonId, this.match.type); + if (!this.match.time) { + this.match.time = Date.now(); + } this.match.comment = this.comment; - if (this.match.rating <= 500) { - this.match.result = this.match.result || MatchController.ratingToResult(this.match.rating, lastMatch); + if (this.match.rating <= 500 && !this.match.result) { + this.match.result = this.match.result || MatchController.ratingToResult(this.match.rating, lastMatchRating); + } + else if (!this.match.result) { + this.match.result = MatchController.ratingToResult(this.match.rating, lastMatchRating); + } + if (lastMatch && this.match.result === lastMatch.result) { + this.match.streak = lastMatch.streak + 1; } else { - this.match.result = MatchController.ratingToResult(this.match.rating, lastMatch); + this.match.streak = 1; + } + await this.match.save(); + this.$store.dispatch('updateRating', this.match.rating); + this.$router.push('/'); + } + else { + const rating = this.$el.querySelector('.addMatchRating'); + if (rating) { + rating.focus(); } - this.match.save(); - this.$router.push({ - name: 'competitive', - params: { - seasonId: this.seasonId.toString() - } - }); } } diff --git a/frsrc/view/page-competitive/page-matchlist/index.ts b/frsrc/view/page-competitive/page-matchlist/index.ts new file mode 100644 index 0000000..dcec3ef --- /dev/null +++ b/frsrc/view/page-competitive/page-matchlist/index.ts @@ -0,0 +1 @@ +export * from './page-matchlist'; \ No newline at end of file diff --git a/frsrc/view/page-competitive/page-placements/page-placements.html b/frsrc/view/page-competitive/page-matchlist/page-matchlist.html similarity index 52% rename from frsrc/view/page-competitive/page-placements/page-placements.html rename to frsrc/view/page-competitive/page-matchlist/page-matchlist.html index 0ede0bf..090e9ff 100644 --- a/frsrc/view/page-competitive/page-placements/page-placements.html +++ b/frsrc/view/page-competitive/page-matchlist/page-matchlist.html @@ -1,20 +1,12 @@
- + -
No matches
- +
\ No newline at end of file diff --git a/frsrc/view/page-competitive/page-matchlist/page-matchlist.scss b/frsrc/view/page-competitive/page-matchlist/page-matchlist.scss new file mode 100644 index 0000000..fbcd951 --- /dev/null +++ b/frsrc/view/page-competitive/page-matchlist/page-matchlist.scss @@ -0,0 +1,15 @@ +.matchList { + height: 100%; +} +.matchList-noMatches { + display: flex; + justify-content: center; + align-items: center; + text-align: center; + font-size: 50px; + font-family: BigNoodle; + color: var(--color-foreground-chrome); + height: 100%; + max-height: 400px; + min-height: 100px; +} \ No newline at end of file diff --git a/frsrc/view/page-competitive/page-competitive/page-competitive.ts b/frsrc/view/page-competitive/page-matchlist/page-matchlist.ts similarity index 57% rename from frsrc/view/page-competitive/page-competitive/page-competitive.ts rename to frsrc/view/page-competitive/page-matchlist/page-matchlist.ts index dba61f7..9df0bff 100644 --- a/frsrc/view/page-competitive/page-competitive/page-competitive.ts +++ b/frsrc/view/page-competitive/page-matchlist/page-matchlist.ts @@ -1,39 +1,35 @@ import Vue from 'vue'; import { Component, Watch } from 'vue-property-decorator'; -import { HeadSelectItem } from '../../../interface'; +import { HeadSelectItem, SeasonMode, MatchType } from '../../../interface'; -import { Match, MatchController, MatchType } from '../../../match'; +import { Match, MatchController } from '../../../match'; import { OverwatchMap, OverwatchMapController } from '../../../overwatchmap'; import { Character, CharacterController } from '../../../character'; import { Rank, RankController } from '../../../rank'; -import './page-competitive.scss'; +import './page-matchlist.scss'; import Subpage from '../../fragments/subpage'; import LoadingSpinner from '../../fragments/loading-spinner'; -import SeasonSelect from '../../fragments/season-select'; import MatchItem from '../../fragments/match'; import FormHeadSelect from '../../fragments/head-select'; @Component({ - template: require('./page-competitive.html'), + template: require('./page-matchlist.html'), components: { Subpage, LoadingSpinner, - SeasonSelect, MatchItem, FormHeadSelect } }) -export default class PageCompetitive extends Vue { +export default class PageMatchList extends Vue { + seasonWatcher: Function; + loading: boolean = true; matches: Match[] = []; - maps: OverwatchMap[] = []; - characters: Character[] = []; - ranks: Rank[] = []; - seasonId: number; - order: string = 'time'; + order: string = 'time-reverse'; sortOrders: HeadSelectItem[] = [{ value: 'time-reverse', label: 'Newest first' @@ -47,41 +43,30 @@ export default class PageCompetitive extends Vue { created() { this.fetchMatches(); + + this.seasonWatcher = this.$store.watch(this.$store.getters.getSeasonId, () => { + this.fetchMatches() + }); } async fetchMatches() { this.loading = true; + var matchType = this.$store.state.seasonMode === SeasonMode.Matches ? MatchType.Match : MatchType.Placement; - this.seasonId = parseInt(this.$route.params.seasonId, 10); - this.matches = await MatchController.getBySeason(this.seasonId, MatchType.Match); - this.maps = await OverwatchMapController.getAll(); - this.characters = await CharacterController.getAll(); - this.ranks = await RankController.getAll(); + if (this.$store.state.seasonId) { + this.matches = this.sort(await MatchController.getBySeason(this.$store.state.seasonId, matchType)); + } this.loading = false; } - @Watch('$route') - watchRoute(to, from) { - this.fetchMatches(); - } - - updateSeasonId(seasonId) { - this.$router.replace({ - name: this.$router.currentRoute.name, - params: { - seasonId: seasonId - } - }); - } - @Watch('order') onOrderChange (to, from) { this.sort(this.matches); } sort(me) { - me.sort((a, b) => { + return me.sort((a, b) => { if (this.order === 'time-reverse') { return b.time - a.time; } @@ -93,4 +78,10 @@ export default class PageCompetitive extends Vue { } }); } + + destroyed() { + if (typeof this.seasonWatcher === 'function') { + this.seasonWatcher(); + } + } } \ No newline at end of file diff --git a/frsrc/view/page-competitive/page-placements-sr/page-placements-sr.html b/frsrc/view/page-competitive/page-placements-sr/page-placements-sr.html index 31a4416..569b3f2 100644 --- a/frsrc/view/page-competitive/page-placements-sr/page-placements-sr.html +++ b/frsrc/view/page-competitive/page-placements-sr/page-placements-sr.html @@ -1,12 +1,11 @@
- - +

Your initial season skill rating

- Save Rating + Save Rating
diff --git a/frsrc/view/page-competitive/page-placements-sr/page-placements-sr.scss b/frsrc/view/page-competitive/page-placements-sr/page-placements-sr.scss index 7fe4000..83d42f2 100644 --- a/frsrc/view/page-competitive/page-placements-sr/page-placements-sr.scss +++ b/frsrc/view/page-competitive/page-placements-sr/page-placements-sr.scss @@ -11,17 +11,11 @@ font-size: 25px; margin: 10px 20px 0; font-family: BigNoodle; - color: #fff; - text-shadow: - 0 0 4px rgb(10, 20, 30), - 1px 1px 0 rgb(10, 20, 30), - -1px 1px 0 rgb(10, 20, 30), - 1px -1px 0 rgb(10, 20, 30), - -1px -1px 0 rgb(10, 20, 30); + color: var(--color-foreground-chrome); } .placementSrRating { - font-size: 50px; + font-size: 20px; max-width: 230px; width: 100%; text-align: center; @@ -30,10 +24,8 @@ display: block; margin: 10px auto; box-sizing: border-box; - font-family: Futura; - border-radius: 10px; - border: 2px solid #fff; - box-shadow: - 0 0 3px rgba(10, 20, 30, 0.4), - inset 0 20px 40px -10px rgba(99, 75, 236, 0.2); + font-family: Roboto, sans-serif; + border: 2px solid var(--color-border-form-input); + background-color: var(--color-background-form-input); + color: var(--color-foreground-form-input); } diff --git a/frsrc/view/page-competitive/page-placements-sr/page-placements-sr.ts b/frsrc/view/page-competitive/page-placements-sr/page-placements-sr.ts index 4ad9266..ee48783 100644 --- a/frsrc/view/page-competitive/page-placements-sr/page-placements-sr.ts +++ b/frsrc/view/page-competitive/page-placements-sr/page-placements-sr.ts @@ -7,7 +7,6 @@ import './page-placements-sr.scss'; import Subpage from '../../fragments/subpage'; import LoadingSpinner from '../../fragments/loading-spinner'; -import SeasonSelect from '../../fragments/season-select'; import ButtonBase from '../../button/base'; @Component({ @@ -15,14 +14,12 @@ import ButtonBase from '../../button/base'; components: { Subpage, LoadingSpinner, - SeasonSelect, ButtonBase } }) export default class PagePlacementsSr extends Vue { loading: boolean = true; season: Season; - seasonId: number; created() { this.fetchMatches(); @@ -31,35 +28,17 @@ export default class PagePlacementsSr extends Vue { async fetchMatches() { this.loading = true; - this.seasonId = parseInt(this.$route.params.seasonId, 10); - this.season = await SeasonController.getSeasonById(this.seasonId); + this.season = await SeasonController.getSeasonById(this.$store.state.seasonId); this.loading = false; } - @Watch('$route') - watchRoute(to, from) { - this.fetchMatches(); - } - async save() { if (this.season.placementRating) { - await this.season.save(); + await this.$store.dispatch('updateSeasonId', await this.season.save()); this.$router.replace({ - name: 'competitive', - params: { - seasonId: this.seasonId.toString() - } + path: '/' }); } } - - updateSeasonId(seasonId) { - this.$router.replace({ - name: this.$router.currentRoute.name, - params: { - seasonId: seasonId - } - }); - } } \ No newline at end of file diff --git a/frsrc/view/page-competitive/page-placements/index.ts b/frsrc/view/page-competitive/page-placements/index.ts deleted file mode 100644 index c41e9e0..0000000 --- a/frsrc/view/page-competitive/page-placements/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './page-placements'; \ No newline at end of file diff --git a/frsrc/view/page-competitive/page-placements/page-placements.scss b/frsrc/view/page-competitive/page-placements/page-placements.scss deleted file mode 100644 index 3b0fde6..0000000 --- a/frsrc/view/page-competitive/page-placements/page-placements.scss +++ /dev/null @@ -1,24 +0,0 @@ -.matchList { - display: flex; - flex-wrap: wrap; - justify-content: center; - align-content: flex-start; - height: 100%; -} -.matchList-noMatches { - display: flex; - justify-content: center; - align-items: center; - text-align: center; - font-size: 50px; - font-family: BigNoodle; - color: #fff; - height: 100%; - max-height: 400px; - min-height: 100px; - text-shadow: - 1px 1px 0 rgb(10, 20, 30), - -1px 1px 0 rgb(10, 20, 30), - 1px -1px 0 rgb(10, 20, 30), - -1px -1px 0 rgb(10, 20, 30); -} \ No newline at end of file diff --git a/frsrc/view/page-competitive/page-placements/page-placements.ts b/frsrc/view/page-competitive/page-placements/page-placements.ts deleted file mode 100644 index eb0bb24..0000000 --- a/frsrc/view/page-competitive/page-placements/page-placements.ts +++ /dev/null @@ -1,94 +0,0 @@ -import Vue from 'vue'; -import { Component, Watch } from 'vue-property-decorator'; - -import { HeadSelectItem } from '../../../interface'; - -import { Match, MatchController, MatchType } from '../../../match'; -import { OverwatchMap, OverwatchMapController } from '../../../overwatchmap'; -import { Character, CharacterController } from '../../../character'; -import { Rank, RankController } from '../../../rank'; - -import './page-placements.scss'; - -import Subpage from '../../fragments/subpage'; -import LoadingSpinner from '../../fragments/loading-spinner'; -import SeasonSelect from '../../fragments/season-select'; -import MatchItem from '../../fragments/match'; -import FormHeadSelect from '../../fragments/head-select'; - -@Component({ - template: require('./page-placements.html'), - components: { - Subpage, - LoadingSpinner, - MatchItem, - SeasonSelect, - FormHeadSelect - } -}) -export default class PagePlacements extends Vue { - loading: boolean = true; - matches: Match[] = []; - maps: OverwatchMap[] = []; - characters: Character[] = []; - ranks: Rank[] = []; - seasonId: number; - order: string = 'time'; - sortOrders: HeadSelectItem[] = [{ - value: 'time', - label: 'Newest first' - }, { - value: 'time-reverse', - label: 'Oldest first' - }]; - - created() { - this.fetchMatches(); - } - - async fetchMatches() { - this.loading = true; - - this.seasonId = parseInt(this.$route.params.seasonId, 10); - const matches = await MatchController.getBySeason(this.seasonId, MatchType.Placement); - this.matches = this.sort(matches); - this.maps = await OverwatchMapController.getAll(); - this.characters = await CharacterController.getAll(); - this.ranks = await RankController.getAll(); - - this.loading = false; - } - - @Watch('$route') - watchRoute(to, from) { - this.fetchMatches(); - } - - updateSeasonId(seasonId) { - this.$router.replace({ - name: this.$router.currentRoute.name, - params: { - seasonId: seasonId - } - }); - } - - @Watch('order') - onOrderChange (to, from) { - this.sort(this.matches); - } - - sort(me) { - return me.sort((a, b) => { - if (this.order === 'time') { - return a.time - b.time; - } - else if (this.order === 'time-reverse') { - return b.time - b.time; - } - else { - return a.rating - b.rating; - } - }); - } -} \ No newline at end of file diff --git a/frsrc/view/page-competitive/router.ts b/frsrc/view/page-competitive/router.ts index 21257b6..506b1a1 100644 --- a/frsrc/view/page-competitive/router.ts +++ b/frsrc/view/page-competitive/router.ts @@ -1,48 +1,44 @@ import { RouteConfig } from 'vue-router'; -import PageCompetitive from './page-competitive'; -import PagePlacements from './page-placements'; + +import { SeasonMode } from '../../interface'; + +import PageMatchList from './page-matchlist'; import PageMatchAdd from './page-match-add'; import PagePlacementsSr from './page-placements-sr'; export default [ { - path: '/competitive/:seasonId', + path: '/competitive', name: 'competitive', - component: PageCompetitive + component: PageMatchList }, { - path: '/competitive/:seasonId/add', + path: '/competitive/add', name: 'competitive-add', - component: PageMatchAdd, - props: { - type: 'competitive' - } + component: PageMatchAdd }, { - path: '/competitive/:seasonId/:id/edit', + path: '/competitive/:id/edit', name: 'competitive-edit', - component: PageCompetitive + component: PageMatchAdd }, { - path: '/placement/:seasonId', + path: '/placement', name: 'placement', - component: PagePlacements + component: PageMatchList }, { - path: '/placement/:seasonId/add', + path: '/placement/add', name: 'placement-add', - component: PageMatchAdd, - props: { - type: 'placement' - } + component: PageMatchAdd }, { - path: '/placement/:seasonId/:id/edit', + path: '/placement/:id/edit', name: 'placement-edit', - component: PagePlacements + component: PageMatchAdd }, { - path: '/placement/:seasonId/placement-sr', + path: '/placement/placement-sr', name: 'placement-sr', component: PagePlacementsSr } diff --git a/frsrc/view/page-front/page-main/index.ts b/frsrc/view/page-create-season/page-main/index.ts similarity index 100% rename from frsrc/view/page-front/page-main/index.ts rename to frsrc/view/page-create-season/page-main/index.ts diff --git a/frsrc/view/page-create-season/page-main/page-main.html b/frsrc/view/page-create-season/page-main/page-main.html new file mode 100644 index 0000000..46a5e66 --- /dev/null +++ b/frsrc/view/page-create-season/page-main/page-main.html @@ -0,0 +1,18 @@ +
+

Welcome to Compwerstats!

+

Getting started requires that you create a season that you can add all your matches to. If you are in the middle of a season you can fill in your starting Skill Rating in the Starting SR-field.

+
+ + +
+ Save +
+
+
\ No newline at end of file diff --git a/frsrc/view/page-create-season/page-main/page-main.scss b/frsrc/view/page-create-season/page-main/page-main.scss new file mode 100644 index 0000000..e46295f --- /dev/null +++ b/frsrc/view/page-create-season/page-main/page-main.scss @@ -0,0 +1,62 @@ +.pageCreateSeason { + max-width: 700px; + padding: 0 25px; + margin: 0 auto; +} +.pageCreateSeason h1 { + font-size: 36px; + font-weight: normal; + margin: 0; + padding: 1em 0 .75em; + text-align: center; + font-family: BigNoodle; + color: var(--color-foreground-chrome); +} +.pageCreateSeason p { + font-size: 16px; + font-family: Roboto; + color: var(--color-foreground-chrome); +} +.createSeason { + display: grid; + grid-template-columns: 1fr 1fr; + grid-template-rows: auto auto; + grid-template-areas: + "number startsr" + "save save"; +} +.createSeason__formItem--number { + grid-area: number; +} +.createSeason__formItem--startsr { + grid-area: startsr; +} +.createSeason__fromItem--save { + grid-area: save; + align-self: flex-end; +} +.createSeason__label { + font-size: 20px; + font-family: kOverwatch; + color: var(--color-foreground-chrome); +} +.createSeason__field { + font-size: 20px; + max-width: 230px; + width: 100%; + text-align: center; + padding: 10px; + -moz-appearance: none; + display: block; + margin: 10px auto; + box-sizing: border-box; + font-family: Roboto, sans-serif; + border: 2px solid var(--color-border-form-input); + background-color: var(--color-background-form-input); + color: var(--color-foreground-form-input); +} +.createSeason__description { + font-size: 14px; + text-align: center; + color: var(--color-foreground-chrome); +} diff --git a/frsrc/view/page-create-season/page-main/page-main.ts b/frsrc/view/page-create-season/page-main/page-main.ts new file mode 100644 index 0000000..ff663b4 --- /dev/null +++ b/frsrc/view/page-create-season/page-main/page-main.ts @@ -0,0 +1,32 @@ +import Vue from 'vue'; +import { Component, Watch } from 'vue-property-decorator'; + +import { Season } from '../../../season'; + +import './page-main.scss'; + +import Subpage from '../../fragments/subpage'; +import ButtonBase from '../../button/base'; +import ListItemSettings from '../../fragments/list-item-settings'; + +@Component({ + template: require('./page-main.html'), + name: 'PageCreateSeason', + components: { + Subpage, + ButtonBase, + ListItemSettings + } +}) +export default class PageCreateSeason extends Vue { + season: Season = Season.create(''); + + async saveSeason(ev) { + if (/\d+/.test(this.season.name)) { + await this.$store.dispatch('updateSeasonId', await this.season.save()); + this.$router.push({ + path: '/' + }); + } + } +} \ No newline at end of file diff --git a/frsrc/view/page-create-season/router.ts b/frsrc/view/page-create-season/router.ts new file mode 100644 index 0000000..731c12b --- /dev/null +++ b/frsrc/view/page-create-season/router.ts @@ -0,0 +1,10 @@ +import { RouteConfig } from 'vue-router'; +import PageCreateSeason from './page-main'; + +export default [ + { + path: '/create-season', + name: 'create-season', + component: PageCreateSeason + } +]; \ No newline at end of file diff --git a/frsrc/view/page-front/button-front/button-front.html b/frsrc/view/page-front/button-front/button-front.html deleted file mode 100644 index d8468f0..0000000 --- a/frsrc/view/page-front/button-front/button-front.html +++ /dev/null @@ -1,4 +0,0 @@ - \ No newline at end of file diff --git a/frsrc/view/page-front/button-front/button-front.scss b/frsrc/view/page-front/button-front/button-front.scss deleted file mode 100644 index d546736..0000000 --- a/frsrc/view/page-front/button-front/button-front.scss +++ /dev/null @@ -1,75 +0,0 @@ -.buttonFront { - -webkit-appearance: none; - border-width: 0; - display: block; - cursor: pointer; - background-size: 100% auto; - background-repeat: no-repeat; - width: 320px; - padding: 340px 0 0; - box-shadow: 0 3px 2px rgba(0, 10, 20, 0.5); - transform: translate(0, 5px); - transition: all 200ms; - box-sizing: border-box; -} -.buttonFront:hover, -.buttonFront:focus { - transform: translate(0, -5px); -} -.buttonFront--stats { - background-image: url('../../../../static/img/mainpanel-stats.png') -} -.buttonFront--competitive { - background-image: url('../../../../static/img/mainpanel-competitive.png') -} -.buttonFront--settings { - background-image: url('../../../../static/img/mainpanel-settings.png') -} -.buttonFront__label { - text-align: center; - line-height: 1; - font-size: 45px; - font-family: BigNoodle; - color: var(--color-foreground-label); - text-transform: uppercase; - background: #fff; - height: 45px; - padding: 40px 0 0; -} -.buttonFront__description { - text-align: center; - line-height: 1.2; - font-size: 14px; - color: var(--color-foreground-label); - text-transform: uppercase; - background: #fff; - height: 35px; - padding: 10px 20px 40px; -} - -@media (max-width: 1080px), (max-height: 600px) { - .buttonFront { - display: block; - background-size: auto 100%; - padding: 10px 10px 10px 70px; - margin-bottom: 5px; - width: 100%; - background-color: #fff; - transform: translate(0, 1px); - } - .buttonFront:hover, - .buttonFront:focus { - transform: translate(0, -1px); - } - .buttonFront__label { - padding: 0; - text-align: left; - height: auto; - font-size: 32px; - } - .buttonFront__description { - padding: 0; - text-align: left; - height: auto; - } -} \ No newline at end of file diff --git a/frsrc/view/page-front/button-front/button-front.ts b/frsrc/view/page-front/button-front/button-front.ts deleted file mode 100644 index ff954d9..0000000 --- a/frsrc/view/page-front/button-front/button-front.ts +++ /dev/null @@ -1,49 +0,0 @@ -import Vue from 'vue'; -import { - Component, - Prop } from 'vue-property-decorator'; - -import './button-front.scss'; - -import { SeasonController } from '../../../season'; - -@Component({ - template: require('./button-front.html') -}) -export default class ButtonFront extends Vue { - @Prop() - type: string; - - @Prop() - link: string; - - @Prop() - label: string; - - @Prop() - description: string; - - @Prop() - seasonId: string; - - data() { - return { - classNames: this.generateClasses() - } - } - - clickHandler() {; - this.$router.push({ - name: this.link || this.type, - params: { - seasonId: this.seasonId - } - }) - } - - private generateClasses(): string { - let classes = ['buttonFront', `buttonFront--${this.type}`]; - - return classes.join(' '); - } -} \ No newline at end of file diff --git a/frsrc/view/page-front/button-front/index.ts b/frsrc/view/page-front/button-front/index.ts deleted file mode 100644 index cf5f555..0000000 --- a/frsrc/view/page-front/button-front/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './button-front'; \ No newline at end of file diff --git a/frsrc/view/page-front/page-main/page-main.html b/frsrc/view/page-front/page-main/page-main.html deleted file mode 100644 index 28abc53..0000000 --- a/frsrc/view/page-front/page-main/page-main.html +++ /dev/null @@ -1,5 +0,0 @@ -
- - - -
\ No newline at end of file diff --git a/frsrc/view/page-front/page-main/page-main.scss b/frsrc/view/page-front/page-main/page-main.scss deleted file mode 100644 index 970c6a2..0000000 --- a/frsrc/view/page-front/page-main/page-main.scss +++ /dev/null @@ -1,19 +0,0 @@ -.pageFront { - margin: 0 auto; - width: 1080px; - height: 100%; - box-sizing: border-box; - display: flex; - justify-content: space-around; - align-items: center; -} - -@media (max-width: 1080px), (max-height: 600px) { - .pageFront { - padding: 5px; - display: block; - width: auto; - height: auto; - max-width: 640px; - } -} \ No newline at end of file diff --git a/frsrc/view/page-front/page-main/page-main.ts b/frsrc/view/page-front/page-main/page-main.ts deleted file mode 100644 index c22b2c0..0000000 --- a/frsrc/view/page-front/page-main/page-main.ts +++ /dev/null @@ -1,40 +0,0 @@ -import Vue from 'vue'; -import { Component } from 'vue-property-decorator'; - -import { SeasonController } from '../../../season'; -import { MatchController, MatchType } from '../../../match'; - -import './page-main.scss'; - -import ButtonFront from '../button-front'; - -@Component({ - template: require('./page-main.html'), - components: { - ButtonFront - } -}) -export default class PageFront extends Vue { - loaded: boolean = false; - competitiveLink: string = 'competitive'; - seasonId: string = ''; - - async created() { - const currentSeason = await SeasonController.getCurrent(); - const currentSeasonPlacementsLeft = await MatchController.hasPlacementsLeft(currentSeason.id); - - this.loaded = true; - - this.seasonId = currentSeason.id.toString(); - - if (currentSeason.placementRating) { - this.competitiveLink = 'competitive'; - } - else if (currentSeasonPlacementsLeft) { - this.competitiveLink = 'placement'; - } - else { - this.competitiveLink = 'placement-sr'; - } - } -} \ No newline at end of file diff --git a/frsrc/view/page-front/router.ts b/frsrc/view/page-front/router.ts deleted file mode 100644 index 988c310..0000000 --- a/frsrc/view/page-front/router.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { RouteConfig } from 'vue-router'; -import PageFront from './page-main'; - -export default [ - { - path: '/', - name: 'front', - component: PageFront - } -]; \ No newline at end of file diff --git a/frsrc/view/page-settings/page-edit/page-edit.scss b/frsrc/view/page-settings/page-edit/page-edit.scss index 1ccc941..1228e41 100644 --- a/frsrc/view/page-settings/page-edit/page-edit.scss +++ b/frsrc/view/page-settings/page-edit/page-edit.scss @@ -2,14 +2,15 @@ // We should not use this feature in scss, but sometimes it is easier fieldset { - border: 0 solid red; - background-color: #fff; + border-width: 0; padding: 10px; - box-shadow: 0 3px 2px rgba(0, 10, 20, 0.5); } label[for] { font-family: BigNoodle; - font-size: 30px; + font-size: 20px; + } + .field-wrap { + padding: 10px; } .error .errors { color: firebrick; @@ -25,13 +26,12 @@ display: block; box-sizing: border-box; width: 100%; - padding: 4px; + padding: 5px; font-size: 20px; - font-family: Futura; - border: 2px solid #fff; - box-shadow: - 0 0 3px rgba(10, 20, 30, 0.4), - inset 0 20px 40px -10px rgba(99, 75, 236, 0.2); + font-family: Roboto, sans-serif; + border: 2px solid var(--color-border-form-button); + background-color: var(--color-background-form-input); + color: var(--color-foreground-form-input); } input.form-control[type="text"], input.form-control[type="number"], @@ -46,7 +46,7 @@ -webkit-appearance: none; text-decoration: none; text-transform: uppercase; - font-family: Futura, sans-serif; + font-family: Roboto, sans-serif; padding: 10px 20px; font-size: 12px; line-height: 1; @@ -57,15 +57,8 @@ background: var(--color-background-button); color: var(--color-foreground-button); cursor: pointer; - border-radius: 1px; - -webkit-app-region: no-drag; - box-shadow: 0 0 0 0 rgba(255, 255, 255, 1); - transition: background-color 200ms, box-shadow 200ms; } .field-submit [type="submit"]:hover { - animation: buttonHover 500ms infinite alternate ease-in-out; - animation-delay: 200ms; - box-shadow: 0 0 0 2px rgba(255, 255, 255, 1); background-color: rgb(16, 88, 145); } .radio-list { @@ -73,8 +66,18 @@ label { font-size: 14px; - text-transform: uppercase; display: block; + cursor: pointer; + + &:hover { + background-color: var(--color-background-form-button-hover); + } + &:focus { + background-color: var(--color-background-form-button-focus); + } + &:active { + background-color: var(--color-background-form-button-active); + } } } .field-checklist .field-wrap { @@ -84,7 +87,18 @@ label { font-size: 14px; - text-transform: uppercase; + display: block; + cursor: pointer; + + &:hover { + background-color: var(--color-background-form-button-hover); + } + &:focus { + background-color: var(--color-background-form-button-focus); + } + &:active { + background-color: var(--color-background-form-button-active); + } } } .form-group { @@ -100,9 +114,10 @@ background-position: 50% 50%; } .hint { - padding: 5px; + padding: 0 10px 10px; + margin-top: -7px; font-size: 14px; - font-family: Futura; + font-family: Roboto, sans-serif; color: #747474; } .required > label:after { diff --git a/frsrc/view/page-settings/page-edit/page-edit.ts b/frsrc/view/page-settings/page-edit/page-edit.ts index f67aad9..dd1e771 100644 --- a/frsrc/view/page-settings/page-edit/page-edit.ts +++ b/frsrc/view/page-settings/page-edit/page-edit.ts @@ -64,7 +64,7 @@ export default class PageSettingsEdit extends Vue { remove(model) { // TODO: Replace with a cooler confirm for cooler people - const yes = confirm('Permanently remove this item?'); + const yes = confirm('Permanently remove this item?\nThings can and probably will break if you remove things that are used in other places.'); if (yes) { model.delete(); diff --git a/frsrc/view/page-settings/page-main/page-main.html b/frsrc/view/page-settings/page-main/page-main.html index de6a05d..1c38e90 100644 --- a/frsrc/view/page-settings/page-main/page-main.html +++ b/frsrc/view/page-settings/page-main/page-main.html @@ -1,5 +1,5 @@
- + diff --git a/frsrc/view/page-settings/page-main/page-main.scss b/frsrc/view/page-settings/page-main/page-main.scss index 7177581..b330ce4 100644 --- a/frsrc/view/page-settings/page-main/page-main.scss +++ b/frsrc/view/page-settings/page-main/page-main.scss @@ -1,5 +1,3 @@ .pageSettings { - margin: 0 auto; - max-width: 1080px; height: 100%; } \ No newline at end of file diff --git a/frsrc/view/page-stats/page-main/page-main.html b/frsrc/view/page-stats/page-main/page-main.html index f726a30..ccfd7dd 100644 --- a/frsrc/view/page-stats/page-main/page-main.html +++ b/frsrc/view/page-stats/page-main/page-main.html @@ -1,5 +1,4 @@ - - +
@@ -17,25 +16,25 @@
{{ models.characters[charId].getName() }}
-
{{ (cStats.win + cStats.draw + cStats.loss), stats.totalNumberOfMatches | percent }} %
-
{{ cStats.win + cStats.draw + cStats.loss }}
+
{{ cStats.total, stats.totalNumberOfMatches | percent }} %
+
{{ cStats.total }}
{{ cStats.win }}
{{ cStats.loss }}
{{ cStats.draw }}
-
{{ cStats.win, cStats.win + cStats.draw + cStats.loss | percent }} %
-
{{ cStats.loss, cStats.win + cStats.draw + cStats.loss | percent }} %
-
{{ cStats.draw, cStats.win + cStats.draw + cStats.loss | percent }} %
+
{{ cStats.win, cStats.total | percent }} %
+
{{ cStats.loss, cStats.total | percent }} %
+
{{ cStats.draw, cStats.total | percent }} %
{{ models.characterTypes[charTypeId].getName() }}
-
{{ (stats.characterTypesStats[charTypeId].win + stats.characterTypesStats[charTypeId].draw + stats.characterTypesStats[charTypeId].loss), stats.totalNumberOfMatches | percent }} %
-
{{ stats.characterTypesStats[charTypeId].win + stats.characterTypesStats[charTypeId].draw + stats.characterTypesStats[charTypeId].loss }}
+
{{ stats.characterTypesStats[charTypeId].total, stats.totalNumberOfMatches | percent }} %
+
{{ stats.characterTypesStats[charTypeId].total }}
{{ stats.characterTypesStats[charTypeId].win }}
{{ stats.characterTypesStats[charTypeId].loss }}
{{ stats.characterTypesStats[charTypeId].draw }}
-
{{ stats.characterTypesStats[charTypeId].win, stats.characterTypesStats[charTypeId].win + stats.characterTypesStats[charTypeId].draw + stats.characterTypesStats[charTypeId].loss | percent }} %
-
{{ stats.characterTypesStats[charTypeId].loss, stats.characterTypesStats[charTypeId].win + stats.characterTypesStats[charTypeId].draw + stats.characterTypesStats[charTypeId].loss | percent }} %
-
{{ stats.characterTypesStats[charTypeId].draw, stats.characterTypesStats[charTypeId].win + stats.characterTypesStats[charTypeId].draw + stats.characterTypesStats[charTypeId].loss | percent }} %
+
{{ stats.characterTypesStats[charTypeId].win, stats.characterTypesStats[charTypeId].total | percent }} %
+
{{ stats.characterTypesStats[charTypeId].loss, stats.characterTypesStats[charTypeId].total | percent }} %
+
{{ stats.characterTypesStats[charTypeId].draw, stats.characterTypesStats[charTypeId].total | percent }} %
@@ -54,25 +53,25 @@
{{ models.maps[mapId].getName() }}
-
{{ (mapStats.win + mapStats.draw + mapStats.loss), stats.totalNumberOfMatches | percent }} %
-
{{ mapStats.win + mapStats.draw + mapStats.loss }}
+
{{ (mapStats.total), stats.totalNumberOfMatches | percent }} %
+
{{ mapStats.total }}
{{ mapStats.win }}
{{ mapStats.loss }}
{{ mapStats.draw }}
-
{{ mapStats.win, mapStats.win + mapStats.draw + mapStats.loss | percent }} %
-
{{ mapStats.loss, mapStats.win + mapStats.draw + mapStats.loss | percent }} %
-
{{ mapStats.draw, mapStats.win + mapStats.draw + mapStats.loss | percent }} %
+
{{ mapStats.win, mapStats.total | percent }} %
+
{{ mapStats.loss, mapStats.total | percent }} %
+
{{ mapStats.draw, mapStats.total | percent }} %
{{ models.mapTypes[mapTypeId].getName() }}
-
{{ (stats.mapTypesStats[mapTypeId].win + stats.mapTypesStats[mapTypeId].draw + stats.mapTypesStats[mapTypeId].loss), stats.totalNumberOfMatches | percent }} %
-
{{ stats.mapTypesStats[mapTypeId].win + stats.mapTypesStats[mapTypeId].draw + stats.mapTypesStats[mapTypeId].loss }}
+
{{ stats.mapTypesStats[mapTypeId].total, stats.totalNumberOfMatches | percent }} %
+
{{ stats.mapTypesStats[mapTypeId].total }}
{{ stats.mapTypesStats[mapTypeId].win }}
{{ stats.mapTypesStats[mapTypeId].loss }}
{{ stats.mapTypesStats[mapTypeId].draw }}
-
{{ stats.mapTypesStats[mapTypeId].win, stats.mapTypesStats[mapTypeId].win + stats.mapTypesStats[mapTypeId].draw + stats.mapTypesStats[mapTypeId].loss | percent }} %
-
{{ stats.mapTypesStats[mapTypeId].loss, stats.mapTypesStats[mapTypeId].win + stats.mapTypesStats[mapTypeId].draw + stats.mapTypesStats[mapTypeId].loss | percent }} %
-
{{ stats.mapTypesStats[mapTypeId].draw, stats.mapTypesStats[mapTypeId].win + stats.mapTypesStats[mapTypeId].draw + stats.mapTypesStats[mapTypeId].loss | percent }} %
+
{{ stats.mapTypesStats[mapTypeId].win, stats.mapTypesStats[mapTypeId].total | percent }} %
+
{{ stats.mapTypesStats[mapTypeId].loss, stats.mapTypesStats[mapTypeId].total | percent }} %
+
{{ stats.mapTypesStats[mapTypeId].draw, stats.mapTypesStats[mapTypeId].total | percent }} %
diff --git a/frsrc/view/page-stats/page-main/page-main.scss b/frsrc/view/page-stats/page-main/page-main.scss index 18d1ef0..61cb807 100644 --- a/frsrc/view/page-stats/page-main/page-main.scss +++ b/frsrc/view/page-stats/page-main/page-main.scss @@ -10,7 +10,6 @@ $color-bg-altRow: rgba(0, 0, 0, 0.05); * Styles */ .statsTable { - background: #fff; margin: 0 auto; width: 100%; max-width: 1200px; diff --git a/frsrc/view/page-stats/page-main/page-main.ts b/frsrc/view/page-stats/page-main/page-main.ts index 8ebdb2a..f3cdc6f 100644 --- a/frsrc/view/page-stats/page-main/page-main.ts +++ b/frsrc/view/page-stats/page-main/page-main.ts @@ -21,17 +21,22 @@ import LoadingSpinner from '../../fragments/loading-spinner'; export default class PageStats extends Vue { loading: boolean = true; stats: object; - seasonId: number; models: object; + seasonWatcher: Function; + created() { this.fetchStats(); + + + this.seasonWatcher = this.$store.watch(this.$store.getters.getSeasonId, () => { + this.fetchStats() + }); } async fetchStats() { - this.seasonId = parseInt(this.$route.params.seasonId, 10); this.loading = true; - const stats = await MatchController.calculateStatistics(this.seasonId); + const stats = await MatchController.calculateStatistics(this.$store.state.seasonId); const processedStats = { totalNumberOfMatches: stats.totalNumberOfMatches, characterTypes: {}, @@ -71,17 +76,9 @@ export default class PageStats extends Vue { this.loading = false; } - @Watch('$route') - watchRoute(to, from) { - this.fetchStats(); - } - - updateSeasonId(seasonId) { - this.$router.replace({ - name: this.$router.currentRoute.name, - params: { - seasonId: seasonId - } - }); + destroyed() { + if (typeof this.seasonWatcher === 'function') { + this.seasonWatcher(); + } } } \ No newline at end of file diff --git a/frsrc/view/page-stats/router.ts b/frsrc/view/page-stats/router.ts index a02f310..a50e0f2 100644 --- a/frsrc/view/page-stats/router.ts +++ b/frsrc/view/page-stats/router.ts @@ -2,7 +2,7 @@ import PageStats from './page-main'; export default [ { - path: '/stats/:seasonId', + path: '/stats', name: 'stats', component: PageStats } diff --git a/index.html b/index.html index 07b2d53..122b1be 100644 --- a/index.html +++ b/index.html @@ -11,7 +11,9 @@
- + + Initializing the app +
diff --git a/package-lock.json b/package-lock.json index db2c204..5b14ff9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "@types/node": { - "version": "7.0.49", - "resolved": "https://registry.npmjs.org/@types/node/-/node-7.0.49.tgz", - "integrity": "sha512-DC4/sITgy/TI6UQoT6Lfr7zEaU/5U4gj5rbyHKhyHhMLgKhdWoGCYMBApVE8EeeHxpdAMSjEhmY7wnnEYym9dg==", + "version": "7.0.51", + "resolved": "https://registry.npmjs.org/@types/node/-/node-7.0.51.tgz", + "integrity": "sha512-h5u7FnEnG+Fn44HfknTTvu199FzFWVSo97ToSRWvXl1F11UfN6wGnE7exUy23pFfDn+CeluvEoCoe4l2eCVC3g==", "dev": true }, "abbrev": { @@ -1419,12 +1419,12 @@ } }, "electron": { - "version": "1.7.9", - "resolved": "https://registry.npmjs.org/electron/-/electron-1.7.9.tgz", - "integrity": "sha1-rdVOn4+D7QL2UZ7BATX2mLGTNs8=", + "version": "1.7.10", + "resolved": "https://registry.npmjs.org/electron/-/electron-1.7.10.tgz", + "integrity": "sha1-Oj6D2WX9f6/kc76N349HJWG2JT0=", "dev": true, "requires": { - "@types/node": "7.0.49", + "@types/node": "7.0.51", "electron-download": "3.3.0", "extract-zip": "1.6.5" } @@ -1727,9 +1727,9 @@ } }, "es6-promise": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.1.1.tgz", - "integrity": "sha512-OaU1hHjgJf+b0NzsxCg7NdIYERD6Hy/PEmFLTjw+b65scuisG3Kt4QoTvJ66BBkPZ581gr0kpoVzKnxniM8nng==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.2.tgz", + "integrity": "sha512-LSas5vsuA6Q4nEdf9wokY5/AJYXry98i0IzXsv49rYsgDGDNDPbqAYR1Pe23iFxygfbGZNR/5VrHXBCh2BhvUQ==", "dev": true }, "es6-set": { @@ -2058,9 +2058,9 @@ } }, "file-loader": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-1.1.5.tgz", - "integrity": "sha512-RzGHDatcVNpGISTvCpfUfOGpYuSR7HSsSg87ki+wF6rw1Hm0RALPTiAdsxAq1UwLf0RRhbe22/eHK6nhXspiOQ==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-1.1.6.tgz", + "integrity": "sha512-873ztuL+/hfvXbLDJ262PGO6XjERnybJu2gW1/5j8HUfxSiFJI9Hj/DhZ50ZGRUxBvuNiazb/cM2rh9pqrxP6Q==", "dev": true, "requires": { "loader-utils": "1.1.0", @@ -4378,9 +4378,9 @@ } }, "moment": { - "version": "2.19.4", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.19.4.tgz", - "integrity": "sha512-1xFTAknSLfc47DIxHDUbnJWC+UwgWxATmymaxIPQpmMh7LBm7ZbwVEsuushqwL2GYZU0jie4xO+TK44hJPjNSQ==" + "version": "2.20.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.20.1.tgz", + "integrity": "sha512-Yh9y73JRljxW5QxN08Fner68eFLxM5ynNOAw2LbIB1YAGeQzZT8QFSUvkAz609Zf+IHhhaUxqZK8dG3W/+HEvg==" }, "ms": { "version": "2.0.0", @@ -6631,9 +6631,9 @@ "dev": true }, "style-loader": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.19.0.tgz", - "integrity": "sha512-9mx9sC9nX1dgP96MZOODpGC6l1RzQBITI2D5WJhu+wnbrSYVKLGuy14XJSLVQih/0GFrPpjelt+s//VcZQ2Evw==", + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.19.1.tgz", + "integrity": "sha512-IRE+ijgojrygQi3rsqT0U4dd+UcPCqcVvauZpCnQrGAlEe+FUIyrK93bUDScamesjP08JlQNsFJU+KmPedP5Og==", "dev": true, "requires": { "loader-utils": "1.1.0", @@ -6647,7 +6647,7 @@ "dev": true, "requires": { "debug": "2.6.9", - "es6-promise": "4.1.1" + "es6-promise": "4.2.2" } }, "supports-color": { @@ -7225,9 +7225,9 @@ } }, "vue": { - "version": "2.5.9", - "resolved": "https://registry.npmjs.org/vue/-/vue-2.5.9.tgz", - "integrity": "sha512-9B9XBpCtj8y5eJFrspIcKxIWt+lG9FMdF8qgyOlUeOIvcS4xSAvcARygbzHA6Pi0KWFj4BvxjtWbuPVWRx/wuA==" + "version": "2.5.13", + "resolved": "https://registry.npmjs.org/vue/-/vue-2.5.13.tgz", + "integrity": "sha512-3D+lY7HTkKbtswDM4BBHgqyq+qo8IAEE8lz8va1dz3LLmttjgo0FxairO4r1iN2OBqk8o1FyL4hvzzTFEdQSEw==" }, "vue-class-component": { "version": "6.1.1", @@ -7245,7 +7245,7 @@ "resolved": "https://registry.npmjs.org/vue-moment/-/vue-moment-3.1.0.tgz", "integrity": "sha512-3qAUKi0HQc+CkhS1tGI02cozuZB+D5TLnKUdJ5SE0+b5+SFGKhDE48BUf1qgfMHWrxc+8KquV0QCquyEtnGq0g==", "requires": { - "moment": "2.19.4" + "moment": "2.20.1" } }, "vue-property-decorator": { @@ -7263,6 +7263,11 @@ "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.0.1.tgz", "integrity": "sha512-vLLoY452L+JBpALMP5UHum9+7nzR9PeIBCghU9ZtJ1eWm6ieUI8Zb/DI3MYxH32bxkjzYV1LRjNv4qr8d+uX/w==" }, + "vuex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/vuex/-/vuex-3.0.1.tgz", + "integrity": "sha512-wLoqz0B7DSZtgbWL1ShIBBCjv22GV5U+vcBFox658g6V0s4wZV9P4YjCNyoHSyIBpj1f29JBoNQIqD82cR4O3w==" + }, "watchpack": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.4.0.tgz", diff --git a/package.json b/package.json index 162be0e..3e6cea2 100644 --- a/package.json +++ b/package.json @@ -19,13 +19,13 @@ "awesome-typescript-loader": "^3.4.1", "clean-webpack-plugin": "^0.1.17", "css-loader": "^0.28.7", - "electron": "1.7.9", + "electron": "1.7.10", "electron-packager": "^10.1.0", - "file-loader": "^1.1.5", + "file-loader": "^1.1.6", "node-sass": "^4.7.2", "raw-loader": "^0.5.1", "sass-loader": "^6.0.6", - "style-loader": "^0.19.0", + "style-loader": "^0.19.1", "typescript": "^2.6.2", "vue-property-decorator": "^6.0.0", "webpack": "^3.10.0" @@ -33,12 +33,13 @@ "dependencies": { "dexie": "^2.0.1", "electron-window-state-manager": "^0.3.2", - "moment": "^2.19.4", + "moment": "^2.20.1", "semver": "^5.4.1", - "vue": "^2.5.9", + "vue": "^2.5.13", "vue-form-generator": "^2.1.1", "vue-moment": "^3.1.0", - "vue-router": "^3.0.1" + "vue-router": "^3.0.1", + "vuex": "^3.0.1" }, "bugs": { "url": "https://github.com/Sertion/compwerstats/issues" diff --git a/static/css/base.css b/static/css/base.css index 2b1b4e6..d89f34b 100644 --- a/static/css/base.css +++ b/static/css/base.css @@ -1,16 +1,14 @@ body { margin: 0; - background: url('../img/chrome-bg.jpg') no-repeat 50% 0%; - background-size: 1280px 500px; - font-family: Futura, sans-serif; - - display: grid; - grid-template-rows: 40px auto; + background-color: var(--color-background-content); + color: var(--color-foreground-content); + font-family: Roboto, sans-serif; height: 100vh; } - -@media (min-width: 1280px) { - body { - background-size: 100% auto; - } +chrome { + text-align: center; + line-height: 100vh; + font-size: 40px; + display: block; + -webkit-app-region: drag; } \ No newline at end of file diff --git a/static/css/font-face.css b/static/css/font-face.css index f48c5a1..75933a8 100644 --- a/static/css/font-face.css +++ b/static/css/font-face.css @@ -8,7 +8,66 @@ src: url('../font/koverwatch.ttf'); font-weight: 400; } +/* + * Roboto + */ @font-face { - font-family: Futura; - src: url('../font/futura.ttf'); + font-family: Roboto; + src: url('../font/Roboto-Light.ttf'); + font-weight: 300; + font-style: normal; +} +@font-face { + font-family: Roboto; + src: url('../font/Roboto-LightItalic.ttf'); + font-weight: 300; + font-style: italic; +} +@font-face { + font-family: Roboto; + src: url('../font/Roboto-Regular.ttf'); + font-weight: 400; + font-style: normal; +} +@font-face { + font-family: Roboto; + src: url('../font/Roboto-Italic.ttf'); + font-weight: 400; + font-style: italic; +} +@font-face { + font-family: Roboto; + src: url('../font/Roboto-Medium.ttf'); + font-weight: 500; + font-style: normal; +} +@font-face { + font-family: Roboto; + src: url('../font/Roboto-MediumItalic.ttf'); + font-weight: 500; + font-style: italic; +} +@font-face { + font-family: Roboto; + src: url('../font/Roboto-Bold.ttf'); + font-weight: 700; + font-style: normal; +} +@font-face { + font-family: Roboto; + src: url('../font/Roboto-BoldItalic.ttf'); + font-weight: 700; + font-style: italic; +} +@font-face { + font-family: Roboto; + src: url('../font/Roboto-Black.ttf'); + font-weight: 900; + font-style: normal; +} +@font-face { + font-family: Roboto; + src: url('../font/Roboto-BlackItalic.ttf'); + font-weight: 900; + font-style: italic; } \ No newline at end of file diff --git a/static/css/scroll.css b/static/css/scroll.css index fb6f349..0766b69 100644 --- a/static/css/scroll.css +++ b/static/css/scroll.css @@ -1,6 +1,6 @@ ::-webkit-scrollbar { width: 17px; - background: transparent; + background: var(--color-background-label); } ::-webkit-scrollbar-button { height: 0; @@ -10,12 +10,9 @@ } ::-webkit-scrollbar-track-piece { background-color: transparent; - background-image: linear-gradient(90deg, transparent 6px, rgba(0, 0, 0, .2) 6px, rgba(0, 0, 0, .2) 11px, transparent 11px); } ::-webkit-scrollbar-thumb { - background: #fafafa; - border-radius: 9px; - border: 1px solid rgba(50, 50, 50, .5); + background: var(--color-background-label-hover); } ::-webkit-scrollbar-corner { background: transparent; diff --git a/static/css/variables.css b/static/css/variables.css index 0a39e5b..9ca0d11 100644 --- a/static/css/variables.css +++ b/static/css/variables.css @@ -1,10 +1,45 @@ :root { - --color-background-chrome: #1c74bb; - --color-foreground-chrome: #ffffff; - --color-background-button: #1c74bb; - --color-foreground-button: #ffffff; + --color-background-chrome: #01111d; + --color-foreground-chrome: #cbdde4; + --color-background-chrome-hover: #1c2e3e; + --color-foreground-update-hover: #eff6f8; + --color-foreground-chrome-active: #61e785; + --color-background-content: #1b242b; + --color-foreground-content: #f9fdff; + --color-background-update: #b12b13; + --color-foreground-update: #e0cfcc; + --color-background-update-active: #d43b20; + --color-background-update-hover: #be3e27; + --color-background-update-focus: var(--color-background-update-hover); - --color-foreground-label: #263451; + --color-background-form-button: var(--color-background-label); + --color-background-form-button-hover: var(--color-background-label-hover); + --color-background-form-button-active: var(--color-background-label-active); + --color-background-form-button-focus: var(--color-background-form-button-hover); + --color-background-form-button-selected: #26508b; + --color-border-form-button: #2d4e68; + --color-foreground-form-button: var(--color-foreground-label); + + --color-background-form-input: var(--color-background-label); + --color-border-form-input: var(--color-foreground-chrome); + --color-foreground-form-input: var(--color-foreground-label); + --color-foreground-form-input-placeholder: #4f687c; + + --color-background-button: #3e3e3e; + --color-foreground-button: #c2c2c2; + + --color-background-label: #1d2831; + --color-background-label-hover: #28353f; + --color-background-label-active: #2a4153; + --color-foreground-label: var(--color-foreground-chrome); + + --color-result-win: #94e04e; + --color-result-draw: #f5f062; + --color-result-loss: #e4586b; + --color-result-unknown: #acacac; + + --color-team-red: #eb9da4; + --color-team-blue: #9dbfeb; --color-type-map: hsl(10, 62%, 49%); --color-type-maptype: hsl(25, 62%, 49%); diff --git a/static/font/Roboto-Black.ttf b/static/font/Roboto-Black.ttf new file mode 100644 index 0000000..3ecbdef Binary files /dev/null and b/static/font/Roboto-Black.ttf differ diff --git a/static/font/Roboto-BlackItalic.ttf b/static/font/Roboto-BlackItalic.ttf new file mode 100644 index 0000000..44c086c Binary files /dev/null and b/static/font/Roboto-BlackItalic.ttf differ diff --git a/static/font/Roboto-Bold.ttf b/static/font/Roboto-Bold.ttf new file mode 100644 index 0000000..70def3f Binary files /dev/null and b/static/font/Roboto-Bold.ttf differ diff --git a/static/font/Roboto-BoldItalic.ttf b/static/font/Roboto-BoldItalic.ttf new file mode 100644 index 0000000..216f9ce Binary files /dev/null and b/static/font/Roboto-BoldItalic.ttf differ diff --git a/static/font/Roboto-Italic.ttf b/static/font/Roboto-Italic.ttf new file mode 100644 index 0000000..f0f33db Binary files /dev/null and b/static/font/Roboto-Italic.ttf differ diff --git a/static/font/Roboto-Light.ttf b/static/font/Roboto-Light.ttf new file mode 100644 index 0000000..3a03044 Binary files /dev/null and b/static/font/Roboto-Light.ttf differ diff --git a/static/font/Roboto-LightItalic.ttf b/static/font/Roboto-LightItalic.ttf new file mode 100644 index 0000000..983381b Binary files /dev/null and b/static/font/Roboto-LightItalic.ttf differ diff --git a/static/font/Roboto-Medium.ttf b/static/font/Roboto-Medium.ttf new file mode 100644 index 0000000..284b1ba Binary files /dev/null and b/static/font/Roboto-Medium.ttf differ diff --git a/static/font/Roboto-MediumItalic.ttf b/static/font/Roboto-MediumItalic.ttf new file mode 100644 index 0000000..a0b10d2 Binary files /dev/null and b/static/font/Roboto-MediumItalic.ttf differ diff --git a/static/font/Roboto-Regular.ttf b/static/font/Roboto-Regular.ttf new file mode 100644 index 0000000..500b104 Binary files /dev/null and b/static/font/Roboto-Regular.ttf differ diff --git a/static/font/futura.ttf b/static/font/futura.ttf deleted file mode 100644 index c457f1e..0000000 Binary files a/static/font/futura.ttf and /dev/null differ diff --git a/static/img/charactertype_icon_defence.svg b/static/img/charactertype_icon_defence.svg index cf5ea34..6e02007 100644 --- a/static/img/charactertype_icon_defence.svg +++ b/static/img/charactertype_icon_defence.svg @@ -4,9 +4,9 @@ C10,0,9.9,1.3,9.9,1.6c0,0.7,0,0.3,0,1c0,0.3,0.1,0.4,0.4,0.4c0.7,0,1.5,0,2.2,0c0.2,0,0.4-0.2,0.4-0.4c0-0.4,0-0.8,0-1.2 c0-0.8,0.7-1.4,1.4-1.4c1.4,0,2,0,3.4,0c1.1,0,1.4,1.2,1.3,1.5c0,0.7,0,0.4,0,1.1c0,0.3,0.1,0.5,0.5,0.5c0.7,0,1.4,0,2.1,0 c0.4,0,0.5-0.1,0.5-0.5c0-0.7,0-0.7,0-1.4c0-0.3,0.1-1.2,1.3-1.2c0.4,0-0.1,0,0.4,0c0.8,0,1.4,0.7,1.4,1.5c0,2.1,0,4.3,0,6.4 - c0,1.5-1.4,2.8-2.9,2.8C20.2,10.8,18.1,10.8,16,10.8z"> + c0,1.5-1.4,2.8-2.9,2.8C20.2,10.8,18.1,10.8,16,10.8z" fill="#fff"> + c1.1,0,1.7-0.6,1.7-1.7C28.2,29.3,28.3,28.4,28.2,27.4z" fill="#fff"> \ No newline at end of file diff --git a/static/img/charactertype_icon_offence.svg b/static/img/charactertype_icon_offence.svg index a8bc488..90063ef 100644 --- a/static/img/charactertype_icon_offence.svg +++ b/static/img/charactertype_icon_offence.svg @@ -1,15 +1,15 @@ Offense - - + + - - + + - - + + \ No newline at end of file diff --git a/static/img/charactertype_icon_support.svg b/static/img/charactertype_icon_support.svg index 87682a6..d0ac1ed 100644 --- a/static/img/charactertype_icon_support.svg +++ b/static/img/charactertype_icon_support.svg @@ -2,5 +2,5 @@ Support +c1.5,0,2.7-1.2,2.7-2.7v-6.3C32,11.4,30.8,10.2,29.3,10.2z" fill="#fff"> \ No newline at end of file diff --git a/static/img/charactertype_icon_tank.svg b/static/img/charactertype_icon_tank.svg index 9089516..eaaa502 100644 --- a/static/img/charactertype_icon_tank.svg +++ b/static/img/charactertype_icon_tank.svg @@ -2,5 +2,5 @@ Tank +c3.1,0,7.7,1.1,9.4,1.6c1.3,0.4,2.7,0.9,2.9,2.2C29,4.9,28.9,6,29,7.1C29,8.3,29,9.5,29,10.7C29,10.7,29,10.7,29,10.7z" fill="#fff"> \ No newline at end of file diff --git a/static/img/maptype-assult.svg b/static/img/maptype-assult.svg index b3eb15a..1322dcc 100644 --- a/static/img/maptype-assult.svg +++ b/static/img/maptype-assult.svg @@ -1,9 +1,7 @@ - - - - - - - + + + + + \ No newline at end of file diff --git a/static/img/maptype-control.svg b/static/img/maptype-control.svg index c9ca135..b8a9a83 100644 --- a/static/img/maptype-control.svg +++ b/static/img/maptype-control.svg @@ -1,6 +1,4 @@ - - - - + + \ No newline at end of file diff --git a/static/img/maptype-elimination.svg b/static/img/maptype-elimination.svg index 262c5ac..d49acb0 100644 --- a/static/img/maptype-elimination.svg +++ b/static/img/maptype-elimination.svg @@ -1,9 +1,9 @@ - - - - - + + + + + \ No newline at end of file diff --git a/static/img/maptype-escort.svg b/static/img/maptype-escort.svg index 486d55a..459a0e2 100644 --- a/static/img/maptype-escort.svg +++ b/static/img/maptype-escort.svg @@ -1,11 +1,11 @@ - - - - - - - + + + + + + + \ No newline at end of file diff --git a/static/img/maptype-hybrid.svg b/static/img/maptype-hybrid.svg index cf20cc0..bff92a1 100644 --- a/static/img/maptype-hybrid.svg +++ b/static/img/maptype-hybrid.svg @@ -1,13 +1,13 @@ - - - - - - - - - + + + + + + + + + \ No newline at end of file diff --git a/static/img/no-map-image.jpg b/static/img/no-map-image.jpg index d637e74..28361f8 100644 Binary files a/static/img/no-map-image.jpg and b/static/img/no-map-image.jpg differ diff --git a/static/img/sold.png b/static/img/sold.png new file mode 100644 index 0000000..60f8bcf Binary files /dev/null and b/static/img/sold.png differ