Initial commit (ugly/incomplete)
This commit is contained in:
parent
545f4aca7e
commit
be2cf17a9e
136
.gitignore
vendored
136
.gitignore
vendored
@ -4,127 +4,25 @@ logs
|
|||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
lerna-debug.log*
|
lerna-debug.log*
|
||||||
.pnpm-debug.log*
|
|
||||||
|
|
||||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
node_modules
|
||||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
.DS_Store
|
||||||
|
|
||||||
# Runtime data
|
|
||||||
pids
|
|
||||||
*.pid
|
|
||||||
*.seed
|
|
||||||
*.pid.lock
|
|
||||||
|
|
||||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
|
||||||
lib-cov
|
|
||||||
|
|
||||||
# Coverage directory used by tools like istanbul
|
|
||||||
coverage
|
|
||||||
*.lcov
|
|
||||||
|
|
||||||
# nyc test coverage
|
|
||||||
.nyc_output
|
|
||||||
|
|
||||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
|
||||||
.grunt
|
|
||||||
|
|
||||||
# Bower dependency directory (https://bower.io/)
|
|
||||||
bower_components
|
|
||||||
|
|
||||||
# node-waf configuration
|
|
||||||
.lock-wscript
|
|
||||||
|
|
||||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
|
||||||
build/Release
|
|
||||||
|
|
||||||
# Dependency directories
|
|
||||||
node_modules/
|
|
||||||
jspm_packages/
|
|
||||||
|
|
||||||
# Snowpack dependency directory (https://snowpack.dev/)
|
|
||||||
web_modules/
|
|
||||||
|
|
||||||
# TypeScript cache
|
|
||||||
*.tsbuildinfo
|
|
||||||
|
|
||||||
# Optional npm cache directory
|
|
||||||
.npm
|
|
||||||
|
|
||||||
# Optional eslint cache
|
|
||||||
.eslintcache
|
|
||||||
|
|
||||||
# Optional stylelint cache
|
|
||||||
.stylelintcache
|
|
||||||
|
|
||||||
# Microbundle cache
|
|
||||||
.rpt2_cache/
|
|
||||||
.rts2_cache_cjs/
|
|
||||||
.rts2_cache_es/
|
|
||||||
.rts2_cache_umd/
|
|
||||||
|
|
||||||
# Optional REPL history
|
|
||||||
.node_repl_history
|
|
||||||
|
|
||||||
# Output of 'npm pack'
|
|
||||||
*.tgz
|
|
||||||
|
|
||||||
# Yarn Integrity file
|
|
||||||
.yarn-integrity
|
|
||||||
|
|
||||||
# dotenv environment variable files
|
|
||||||
.env
|
|
||||||
.env.development.local
|
|
||||||
.env.test.local
|
|
||||||
.env.production.local
|
|
||||||
.env.local
|
|
||||||
|
|
||||||
# parcel-bundler cache (https://parceljs.org/)
|
|
||||||
.cache
|
|
||||||
.parcel-cache
|
|
||||||
|
|
||||||
# Next.js build output
|
|
||||||
.next
|
|
||||||
out
|
|
||||||
|
|
||||||
# Nuxt.js build / generate output
|
|
||||||
.nuxt
|
|
||||||
dist
|
dist
|
||||||
|
dist-ssr
|
||||||
|
coverage
|
||||||
|
*.local
|
||||||
|
|
||||||
# Gatsby files
|
/cypress/videos/
|
||||||
.cache/
|
/cypress/screenshots/
|
||||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
|
||||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
|
||||||
# public
|
|
||||||
|
|
||||||
# vuepress build output
|
# Editor directories and files
|
||||||
.vuepress/dist
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
# vuepress v2.x temp and cache directory
|
.idea
|
||||||
.temp
|
*.suo
|
||||||
.cache
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
# Docusaurus cache and generated files
|
*.sln
|
||||||
.docusaurus
|
*.sw?
|
||||||
|
|
||||||
# Serverless directories
|
|
||||||
.serverless/
|
|
||||||
|
|
||||||
# FuseBox cache
|
|
||||||
.fusebox/
|
|
||||||
|
|
||||||
# DynamoDB Local files
|
|
||||||
.dynamodb/
|
|
||||||
|
|
||||||
# TernJS port file
|
|
||||||
.tern-port
|
|
||||||
|
|
||||||
# Stores VSCode versions used for testing VSCode extensions
|
|
||||||
.vscode-test
|
|
||||||
|
|
||||||
# yarn v2
|
|
||||||
.yarn/cache
|
|
||||||
.yarn/unplugged
|
|
||||||
.yarn/build-state.yml
|
|
||||||
.yarn/install-state.gz
|
|
||||||
.pnp.*
|
|
||||||
|
|||||||
3
.vscode/extensions.json
vendored
Normal file
3
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"]
|
||||||
|
}
|
||||||
27
components.d.ts
vendored
Normal file
27
components.d.ts
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
/* prettier-ignore */
|
||||||
|
// @ts-nocheck
|
||||||
|
// Generated by unplugin-vue-components
|
||||||
|
// Read more: https://github.com/vuejs/core/pull/3399
|
||||||
|
import '@vue/runtime-core'
|
||||||
|
|
||||||
|
export {}
|
||||||
|
|
||||||
|
declare module '@vue/runtime-core' {
|
||||||
|
export interface GlobalComponents {
|
||||||
|
FrontPage: typeof import('./src/components/FrontPage.vue')['default']
|
||||||
|
IconCommunity: typeof import('./src/components/icons/IconCommunity.vue')['default']
|
||||||
|
IconDocumentation: typeof import('./src/components/icons/IconDocumentation.vue')['default']
|
||||||
|
IconEcosystem: typeof import('./src/components/icons/IconEcosystem.vue')['default']
|
||||||
|
IconSupport: typeof import('./src/components/icons/IconSupport.vue')['default']
|
||||||
|
IconTooling: typeof import('./src/components/icons/IconTooling.vue')['default']
|
||||||
|
NavBar: typeof import('./src/components/NavBar.vue')['default']
|
||||||
|
NButton: typeof import('naive-ui')['NButton']
|
||||||
|
NMenu: typeof import('naive-ui')['NMenu']
|
||||||
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
|
StandingsTable: typeof import('./src/components/StandingsTable.vue')['default']
|
||||||
|
TheWelcome: typeof import('./src/components/TheWelcome.vue')['default']
|
||||||
|
WelcomeItem: typeof import('./src/components/WelcomeItem.vue')['default']
|
||||||
|
}
|
||||||
|
}
|
||||||
22
index.html
Normal file
22
index.html
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" style="height: 100%">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<link rel="icon" href="/favicon.ico">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
||||||
|
<meta property="og:title" content="SBa: Season 7" />
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:url" content="https://sombaseball.ddns.net" />
|
||||||
|
<meta property="og:image" content="https://sombaseball.ddns.net/static/images/sba-network.png" />
|
||||||
|
<meta property="og:description" content="The home of the Strat-o-matic Baseball Association" />
|
||||||
|
<meta name="theme-color" content="#A6CE39">
|
||||||
|
<title>SBa TEST</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="module" src="/src/main.ts"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
2730
package-lock.json
generated
Normal file
2730
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
29
package.json
Normal file
29
package.json
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"name": "sba2",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "run-p type-check build-only",
|
||||||
|
"preview": "vite preview",
|
||||||
|
"build-only": "vite build",
|
||||||
|
"type-check": "vue-tsc --noEmit"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"vue": "^3.2.45",
|
||||||
|
"vue-router": "^4.1.6"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^18.11.12",
|
||||||
|
"@vicons/fluent": "0.12.0",
|
||||||
|
"@vitejs/plugin-vue": "^4.0.0",
|
||||||
|
"@vue/tsconfig": "^0.1.3",
|
||||||
|
"naive-ui": "2.34.3",
|
||||||
|
"npm-run-all": "^4.1.5",
|
||||||
|
"typescript": "~4.7.4",
|
||||||
|
"unplugin-vue-components": "0.24.1",
|
||||||
|
"vfonts": "0.0.3",
|
||||||
|
"vite": "^4.0.0",
|
||||||
|
"vue-tsc": "^1.0.12"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.7 KiB |
102
src/App.vue
Normal file
102
src/App.vue
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
<template>
|
||||||
|
<html lang="en" style="height: 100%">
|
||||||
|
<!-- <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
|
||||||
|
integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
|
||||||
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootswatch/4.5.2/yeti/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="/src/assets/oldSite.css"> -->
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
|
<meta property="og:title" content="SBa: Season 8" />
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:url" content="https://sombaseball.ddns.net" />
|
||||||
|
<meta property="og:image" content="https://sombaseball.ddns.net/static/images/sba-network.png" />
|
||||||
|
<meta property="og:description" content="The home of the Strat-o-matic Baseball Association" />
|
||||||
|
<meta name="theme-color" content="#A6CE39">
|
||||||
|
<title>SBa Season {{ seasonNumber }}</title>
|
||||||
|
</head>
|
||||||
|
<NavBar />
|
||||||
|
|
||||||
|
<RouterView />
|
||||||
|
|
||||||
|
</html>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { RouterView } from 'vue-router'
|
||||||
|
import NavBar from './components/NavBar.vue'
|
||||||
|
import { CURRENT_SEASON } from '@/services/utilities'
|
||||||
|
export default {
|
||||||
|
name: "App",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
seasonNumber: CURRENT_SEASON as number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
header {
|
||||||
|
line-height: 1.5;
|
||||||
|
max-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav {
|
||||||
|
width: 100%;
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav a.router-link-exact-active {
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
nav a.router-link-exact-active:hover {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav a {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0 1rem;
|
||||||
|
border-left: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
nav a:first-of-type {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1024px) {
|
||||||
|
header {
|
||||||
|
display: flex;
|
||||||
|
place-items: center;
|
||||||
|
padding-right: calc(var(--section-gap) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
margin: 0 2rem 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
header .wrapper {
|
||||||
|
display: flex;
|
||||||
|
place-items: flex-start;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav {
|
||||||
|
text-align: left;
|
||||||
|
margin-left: -1rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
|
||||||
|
padding: 1rem 0;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
74
src/assets/base.css
Normal file
74
src/assets/base.css
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/* color palette from <https://github.com/vuejs/theme> */
|
||||||
|
:root {
|
||||||
|
--vt-c-white: #ffffff;
|
||||||
|
--vt-c-white-soft: #f8f8f8;
|
||||||
|
--vt-c-white-mute: #f2f2f2;
|
||||||
|
|
||||||
|
--vt-c-black: #181818;
|
||||||
|
--vt-c-black-soft: #222222;
|
||||||
|
--vt-c-black-mute: #282828;
|
||||||
|
|
||||||
|
--vt-c-indigo: #2c3e50;
|
||||||
|
|
||||||
|
--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
|
||||||
|
--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
|
||||||
|
--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
|
||||||
|
--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
|
||||||
|
|
||||||
|
--vt-c-text-light-1: var(--vt-c-indigo);
|
||||||
|
--vt-c-text-light-2: rgba(60, 60, 60, 0.66);
|
||||||
|
--vt-c-text-dark-1: var(--vt-c-white);
|
||||||
|
--vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* semantic color variables for this project */
|
||||||
|
:root {
|
||||||
|
--color-background: var(--vt-c-white);
|
||||||
|
--color-background-soft: var(--vt-c-white-soft);
|
||||||
|
--color-background-mute: var(--vt-c-white-mute);
|
||||||
|
|
||||||
|
--color-border: var(--vt-c-divider-light-2);
|
||||||
|
--color-border-hover: var(--vt-c-divider-light-1);
|
||||||
|
|
||||||
|
--color-heading: var(--vt-c-text-light-1);
|
||||||
|
--color-text: var(--vt-c-text-light-1);
|
||||||
|
|
||||||
|
--section-gap: 160px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root {
|
||||||
|
--color-background: var(--vt-c-black);
|
||||||
|
--color-background-soft: var(--vt-c-black-soft);
|
||||||
|
--color-background-mute: var(--vt-c-black-mute);
|
||||||
|
|
||||||
|
--color-border: var(--vt-c-divider-dark-2);
|
||||||
|
--color-border-hover: var(--vt-c-divider-dark-1);
|
||||||
|
|
||||||
|
--color-heading: var(--vt-c-text-dark-1);
|
||||||
|
--color-text: var(--vt-c-text-dark-2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*,
|
||||||
|
*::before,
|
||||||
|
*::after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
position: relative;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
min-height: 100vh;
|
||||||
|
color: var(--color-text);
|
||||||
|
background: var(--color-background);
|
||||||
|
transition: color 0.5s, background-color 0.5s;
|
||||||
|
line-height: 1.6;
|
||||||
|
font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu,
|
||||||
|
Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
|
||||||
|
font-size: 15px;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
1
src/assets/logo.svg
Normal file
1
src/assets/logo.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69" xmlns:v="https://vecta.io/nano"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>
|
||||||
|
After Width: | Height: | Size: 308 B |
35
src/assets/main.css
Normal file
35
src/assets/main.css
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
@import './base.css';
|
||||||
|
|
||||||
|
#app {
|
||||||
|
max-width: 1280px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 2rem;
|
||||||
|
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
a,
|
||||||
|
.green {
|
||||||
|
text-decoration: none;
|
||||||
|
color: hsla(160, 100%, 37%, 1);
|
||||||
|
transition: 0.4s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (hover: hover) {
|
||||||
|
a:hover {
|
||||||
|
background-color: hsla(160, 100%, 37%, 0.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1024px) {
|
||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
place-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
padding: 0 2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
102
src/assets/oldSite.css
Normal file
102
src/assets/oldSite.css
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
.centerDiv {
|
||||||
|
width: 92%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sticky-dark {
|
||||||
|
position: sticky;
|
||||||
|
left: 0em;
|
||||||
|
background-color: #E5E5E5
|
||||||
|
}
|
||||||
|
|
||||||
|
.sticky-light {
|
||||||
|
position: sticky;
|
||||||
|
left: 0em;
|
||||||
|
background-color: #F4F4F4
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-small {
|
||||||
|
width: 1em
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-med {
|
||||||
|
width: 10em
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-large {
|
||||||
|
width: 20em
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
color: black
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-dark {
|
||||||
|
background-color: black;
|
||||||
|
color: black;
|
||||||
|
margin-bottom: -5px
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark-mode {
|
||||||
|
background-color: black;
|
||||||
|
color: #E5E5E5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-toggle.active-dropdown::after {
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] {
|
||||||
|
background-color: black !important;
|
||||||
|
color: #E5E5E5;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .bg-light {
|
||||||
|
background-color: #333 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .bg-white {
|
||||||
|
background-color: #000 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .bg-black {
|
||||||
|
background-color: #eee !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .table td {
|
||||||
|
color: #E5E5E5 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .table th {
|
||||||
|
color: #ffffff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-preview {
|
||||||
|
max-width: 950px;
|
||||||
|
padding-bottom: 75px;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-subtitle {
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 10px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-article {
|
||||||
|
max-width: 700px;
|
||||||
|
padding-bottom: 75px;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-subtitle-large {
|
||||||
|
/* font-size: 22px;
|
||||||
|
line-height: 20px; */
|
||||||
|
vertical-align: middle;
|
||||||
|
padding-top: 25px;
|
||||||
|
padding-bottom: 50px;
|
||||||
|
}
|
||||||
270
src/components/NavBar.vue
Normal file
270
src/components/NavBar.vue
Normal file
@ -0,0 +1,270 @@
|
|||||||
|
<template>
|
||||||
|
<div class="navbar navbar-expand-sm navbar-dark bg-primary ">
|
||||||
|
<div class="nav-bar navbar-brand mb-0 h1">
|
||||||
|
<RouterLink to="/">SBa Season {{ seasonNumber }}</RouterLink>
|
||||||
|
<n-menu mode="horizontal" :options="menuOptions" />
|
||||||
|
<li class="nav-item"> <a id="login" class="nav-link">Login with Discord</a></li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a id="team-login-link" href="/teams?abbrev=">
|
||||||
|
<img id="team-login" style="max-height:35px" hidden />
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<form class="form-inline" action="/players">
|
||||||
|
<input type="text" name="name" placeholder="Player Search" list="player-names" id="player-choice">
|
||||||
|
<datalist id="player-names">
|
||||||
|
<option v-for="name in playerNames" :value="name">{{ name }}</option>
|
||||||
|
</datalist>
|
||||||
|
</form>
|
||||||
|
<ul class="navbar-nav navbar-right">
|
||||||
|
<li class="nav-item">
|
||||||
|
<div class="custom-control custom-switch">
|
||||||
|
<input type="checkbox" class="custom-control-input" id="darkSwitch" />
|
||||||
|
<label class="custom-control-label" for="darkSwitch">Dark Mode</label>
|
||||||
|
</div>
|
||||||
|
<!-- <script src="/static/dark-mode-switch.js"></script> -->
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- <nav class="container">
|
||||||
|
<RouterLink to="/">SBa Season {{ seasonNumber }}</RouterLink>
|
||||||
|
<RouterLink to="/schedule">Schedule</RouterLink>
|
||||||
|
<RouterLink to="/standings">Standings</RouterLink>
|
||||||
|
<RouterLink to="/stats">Stats & Leaders</RouterLink>
|
||||||
|
<RouterLink to="/teams">Teams</RouterLink>
|
||||||
|
<RouterLink to="/transactions">Transactions</RouterLink>
|
||||||
|
<RouterLink to="/history">History</RouterLink>
|
||||||
|
<RouterLink to="/rules">Rules Ref</RouterLink>
|
||||||
|
<RouterLink to="/news">News</RouterLink>
|
||||||
|
</nav> -->
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { RouterLink } from 'vue-router'
|
||||||
|
import type { MenuOption } from 'naive-ui'
|
||||||
|
import { fetchPlayers, type Player } from '@/services/playersService'
|
||||||
|
import { CURRENT_SEASON } from '@/services/utilities'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'NavBar',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
playerNames: [] as string[],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.populatePlayerNames()
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
menuOptions(): MenuOption[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: 'Schedule',
|
||||||
|
key: 'Schedule'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Standings',
|
||||||
|
key: 'Standings',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Stats & Leaders',
|
||||||
|
key: 'Stats & Leaders',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: 'Season Leaders',
|
||||||
|
key: 'Season Leaders',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: 'Batting Leaders',
|
||||||
|
key: 'Batting Leaders'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Pitching Leaders',
|
||||||
|
key: 'Pitching Leaders'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Fielding Leaders',
|
||||||
|
key: 'Fielding Leaders'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Team Stats',
|
||||||
|
key: 'Team Stats',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: 'Team Batting',
|
||||||
|
key: 'Team Batting'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Team Pitching',
|
||||||
|
key: 'Team Pitching'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Team Fielding',
|
||||||
|
key: 'Team Fielding'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Single-Game Records',
|
||||||
|
key: 'Single-Game Records',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: 'Single-Game Batting',
|
||||||
|
key: 'Single-Game Batting'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Single-Game Pitching',
|
||||||
|
key: 'Single-Game Pitching'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Single-Game Fielding',
|
||||||
|
key: 'Single-Game Fielding'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Single-Season Stats',
|
||||||
|
key: 'Single-Season Stats',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: 'Single-Season Batting',
|
||||||
|
key: 'Single-Season Batting'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Single-Season Pitching',
|
||||||
|
key: 'Single-Season Pitching'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Single-Season Fielding',
|
||||||
|
key: 'Single-Season Fielding'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Career Leaders',
|
||||||
|
key: 'Career Leaders',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: 'Career Batting',
|
||||||
|
key: 'Career Batting'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Career Pitching',
|
||||||
|
key: 'Career Pitching'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Career Fielding',
|
||||||
|
key: 'Career Fielding'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Teams',
|
||||||
|
key: 'Teams',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: 'AL East',
|
||||||
|
key: 'AL East',
|
||||||
|
children: [
|
||||||
|
{ label: 'Gators', key: 'Gators' },
|
||||||
|
{ label: 'Honeybees', keys: 'Honeybees' },
|
||||||
|
{ label: 'Kaiju', key: 'Kaiju' },
|
||||||
|
{ label: 'Phantoms', key: 'Phantoms' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'AL West',
|
||||||
|
key: 'AL West',
|
||||||
|
children: [
|
||||||
|
{ label: 'Cyclones', key: 'Cyclones' },
|
||||||
|
{ label: 'Mussels', keys: 'Mussels' },
|
||||||
|
{ label: 'Whale Sharks', key: 'Whale Sharks' },
|
||||||
|
{ label: 'Wu Xia', key: 'Wu Xia' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'NL East',
|
||||||
|
key: 'NL East',
|
||||||
|
children: [
|
||||||
|
{ label: 'Drillers', key: 'Drillers' },
|
||||||
|
{ label: 'Macho Men', keys: 'Macho Men' },
|
||||||
|
{ label: 'Shoebills', key: 'Shoebills' },
|
||||||
|
{ label: 'Zephyr', key: 'Zephyr' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'NL West',
|
||||||
|
key: 'NL West',
|
||||||
|
children: [
|
||||||
|
{ label: 'Angels', key: 'Angels' },
|
||||||
|
{ label: 'Black Bears', keys: 'Black Bears' },
|
||||||
|
{ label: 'Bovines', key: 'Bovines' },
|
||||||
|
{ label: 'Snow Geese', key: 'Snow Geese' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Transactions',
|
||||||
|
key: 'Transactions',
|
||||||
|
children: [
|
||||||
|
{ label: 'Free Agents', key: 'Free Agents' },
|
||||||
|
{ label: 'Transactions', key: 'Transactions' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'History',
|
||||||
|
key: 'History',
|
||||||
|
children: [
|
||||||
|
{ label: 'Awards', key: 'Awards' },
|
||||||
|
{
|
||||||
|
label: 'Managers',
|
||||||
|
key: 'Managers',
|
||||||
|
// TODO figure out a way to pull active/retired into children here
|
||||||
|
children: [{ label: 'Active', key: 'Active' }, { label: 'Retired', key: 'Retired' }]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Season Recaps',
|
||||||
|
key: 'Season Recaps',
|
||||||
|
children: [
|
||||||
|
{ label: 'Season 4', key: 'Season 4' },
|
||||||
|
{ label: 'Season 3', key: 'Season 3' },
|
||||||
|
{ label: 'Season 2', key: 'Season 2' },
|
||||||
|
{ label: 'Season 1', key: 'Season 1' },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{ label: 'Rules Ref', key: 'Rules Ref' },
|
||||||
|
{ label: 'News', key: 'News' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
seasonNumber(): number {
|
||||||
|
// TODO pull this from DB?
|
||||||
|
return CURRENT_SEASON
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async getPlayers(): Promise<Player[]> {
|
||||||
|
return await fetchPlayers(this.seasonNumber)
|
||||||
|
},
|
||||||
|
async populatePlayerNames(): Promise<void> {
|
||||||
|
const players: Player[] = await this.getPlayers()
|
||||||
|
this.playerNames = players.sort(p => p.wara).map(p => p.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
nav {
|
||||||
|
margin: 0%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
66
src/components/StandingsTable.vue
Normal file
66
src/components/StandingsTable.vue
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<template>
|
||||||
|
<div class="standings-table">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Team</th>
|
||||||
|
<th>Record</th>
|
||||||
|
<th>Win %</th>
|
||||||
|
<th>GB</th>
|
||||||
|
<th>E#</th>
|
||||||
|
<th>Run Diff</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="(team, index) in teams" :key="index">
|
||||||
|
<td>
|
||||||
|
<RouterLink
|
||||||
|
:to="{ name: 'team', params: { seasonNumber: seasonNumber(), teamAbbreviation: team.teamAbbreviation } }">
|
||||||
|
{{
|
||||||
|
team.teamName }}
|
||||||
|
</RouterLink>
|
||||||
|
</td>
|
||||||
|
<td>{{ record(team) }}</td>
|
||||||
|
<td>{{ team.winPercentage }}</td>
|
||||||
|
<td>{{ gamesBack(team) }}</td>
|
||||||
|
<td>{{ eliminationNumber(team) }}</td>
|
||||||
|
<td>{{ team.runDifferential }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import type { TeamStanding } from '@/services/standingsService'
|
||||||
|
import { CURRENT_SEASON } from '@/services/utilities'
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "StandingsTable",
|
||||||
|
props: {
|
||||||
|
teams: {
|
||||||
|
type: Array<TeamStanding>,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
isDivisional: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
eliminationNumber(teamStanding: TeamStanding): string {
|
||||||
|
return this.isDivisional ? teamStanding.divisionEliminationNumber : teamStanding.wildcardEliminationNumber
|
||||||
|
},
|
||||||
|
gamesBack(teamStanding: TeamStanding): string {
|
||||||
|
return this.isDivisional ? teamStanding.divisionGamesBack : teamStanding.wildcardGamesBack
|
||||||
|
},
|
||||||
|
record(teamStanding: TeamStanding): string {
|
||||||
|
return `${teamStanding.wins}-${teamStanding.losses}`
|
||||||
|
},
|
||||||
|
seasonNumber(): number {
|
||||||
|
return CURRENT_SEASON
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
16
src/components/TheWelcome.vue
Normal file
16
src/components/TheWelcome.vue
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<template>
|
||||||
|
<button @click="players">Log Players</button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { fetchPlayers } from '@/services/playersService'
|
||||||
|
import { CURRENT_SEASON } from '@/services/utilities'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
methods: {
|
||||||
|
async players(): Promise<void> {
|
||||||
|
await fetchPlayers(CURRENT_SEASON)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
7
src/components/icons/IconCommunity.vue
Normal file
7
src/components/icons/IconCommunity.vue
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<template>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
|
||||||
|
<path
|
||||||
|
d="M15 4a1 1 0 1 0 0 2V4zm0 11v-1a1 1 0 0 0-1 1h1zm0 4l-.707.707A1 1 0 0 0 16 19h-1zm-4-4l.707-.707A1 1 0 0 0 11 14v1zm-4.707-1.293a1 1 0 0 0-1.414 1.414l1.414-1.414zm-.707.707l-.707-.707.707.707zM9 11v-1a1 1 0 0 0-.707.293L9 11zm-4 0h1a1 1 0 0 0-1-1v1zm0 4H4a1 1 0 0 0 1.707.707L5 15zm10-9h2V4h-2v2zm2 0a1 1 0 0 1 1 1h2a3 3 0 0 0-3-3v2zm1 1v6h2V7h-2zm0 6a1 1 0 0 1-1 1v2a3 3 0 0 0 3-3h-2zm-1 1h-2v2h2v-2zm-3 1v4h2v-4h-2zm1.707 3.293l-4-4-1.414 1.414 4 4 1.414-1.414zM11 14H7v2h4v-2zm-4 0c-.276 0-.525-.111-.707-.293l-1.414 1.414C5.42 15.663 6.172 16 7 16v-2zm-.707 1.121l3.414-3.414-1.414-1.414-3.414 3.414 1.414 1.414zM9 12h4v-2H9v2zm4 0a3 3 0 0 0 3-3h-2a1 1 0 0 1-1 1v2zm3-3V3h-2v6h2zm0-6a3 3 0 0 0-3-3v2a1 1 0 0 1 1 1h2zm-3-3H3v2h10V0zM3 0a3 3 0 0 0-3 3h2a1 1 0 0 1 1-1V0zM0 3v6h2V3H0zm0 6a3 3 0 0 0 3 3v-2a1 1 0 0 1-1-1H0zm3 3h2v-2H3v2zm1-1v4h2v-4H4zm1.707 4.707l.586-.586-1.414-1.414-.586.586 1.414 1.414z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
7
src/components/icons/IconDocumentation.vue
Normal file
7
src/components/icons/IconDocumentation.vue
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<template>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="17" fill="currentColor">
|
||||||
|
<path
|
||||||
|
d="M11 2.253a1 1 0 1 0-2 0h2zm-2 13a1 1 0 1 0 2 0H9zm.447-12.167a1 1 0 1 0 1.107-1.666L9.447 3.086zM1 2.253L.447 1.42A1 1 0 0 0 0 2.253h1zm0 13H0a1 1 0 0 0 1.553.833L1 15.253zm8.447.833a1 1 0 1 0 1.107-1.666l-1.107 1.666zm0-14.666a1 1 0 1 0 1.107 1.666L9.447 1.42zM19 2.253h1a1 1 0 0 0-.447-.833L19 2.253zm0 13l-.553.833A1 1 0 0 0 20 15.253h-1zm-9.553-.833a1 1 0 1 0 1.107 1.666L9.447 14.42zM9 2.253v13h2v-13H9zm1.553-.833C9.203.523 7.42 0 5.5 0v2c1.572 0 2.961.431 3.947 1.086l1.107-1.666zM5.5 0C3.58 0 1.797.523.447 1.42l1.107 1.666C2.539 2.431 3.928 2 5.5 2V0zM0 2.253v13h2v-13H0zm1.553 13.833C2.539 15.431 3.928 15 5.5 15v-2c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM5.5 15c1.572 0 2.961.431 3.947 1.086l1.107-1.666C9.203 13.523 7.42 13 5.5 13v2zm5.053-11.914C11.539 2.431 12.928 2 14.5 2V0c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM14.5 2c1.573 0 2.961.431 3.947 1.086l1.107-1.666C18.203.523 16.421 0 14.5 0v2zm3.5.253v13h2v-13h-2zm1.553 12.167C18.203 13.523 16.421 13 14.5 13v2c1.573 0 2.961.431 3.947 1.086l1.107-1.666zM14.5 13c-1.92 0-3.703.523-5.053 1.42l1.107 1.666C11.539 15.431 12.928 15 14.5 15v-2z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
7
src/components/icons/IconEcosystem.vue
Normal file
7
src/components/icons/IconEcosystem.vue
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<template>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="20" fill="currentColor">
|
||||||
|
<path
|
||||||
|
d="M11.447 8.894a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm0 1.789a1 1 0 1 0 .894-1.789l-.894 1.789zM7.447 7.106a1 1 0 1 0-.894 1.789l.894-1.789zM10 9a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0H8zm9.447-5.606a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm2 .789a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zM18 5a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0h-2zm-5.447-4.606a1 1 0 1 0 .894-1.789l-.894 1.789zM9 1l.447-.894a1 1 0 0 0-.894 0L9 1zm-2.447.106a1 1 0 1 0 .894 1.789l-.894-1.789zm-6 3a1 1 0 1 0 .894 1.789L.553 4.106zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zm-2-.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 2.789a1 1 0 1 0 .894-1.789l-.894 1.789zM2 5a1 1 0 1 0-2 0h2zM0 7.5a1 1 0 1 0 2 0H0zm8.553 12.394a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 1a1 1 0 1 0 .894 1.789l-.894-1.789zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zM8 19a1 1 0 1 0 2 0H8zm2-2.5a1 1 0 1 0-2 0h2zm-7.447.394a1 1 0 1 0 .894-1.789l-.894 1.789zM1 15H0a1 1 0 0 0 .553.894L1 15zm1-2.5a1 1 0 1 0-2 0h2zm12.553 2.606a1 1 0 1 0 .894 1.789l-.894-1.789zM17 15l.447.894A1 1 0 0 0 18 15h-1zm1-2.5a1 1 0 1 0-2 0h2zm-7.447-5.394l-2 1 .894 1.789 2-1-.894-1.789zm-1.106 1l-2-1-.894 1.789 2 1 .894-1.789zM8 9v2.5h2V9H8zm8.553-4.894l-2 1 .894 1.789 2-1-.894-1.789zm.894 0l-2-1-.894 1.789 2 1 .894-1.789zM16 5v2.5h2V5h-2zm-4.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zm-2.894-1l-2 1 .894 1.789 2-1L8.553.106zM1.447 5.894l2-1-.894-1.789-2 1 .894 1.789zm-.894 0l2 1 .894-1.789-2-1-.894 1.789zM0 5v2.5h2V5H0zm9.447 13.106l-2-1-.894 1.789 2 1 .894-1.789zm0 1.789l2-1-.894-1.789-2 1 .894 1.789zM10 19v-2.5H8V19h2zm-6.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zM2 15v-2.5H0V15h2zm13.447 1.894l2-1-.894-1.789-2 1 .894 1.789zM18 15v-2.5h-2V15h2z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
7
src/components/icons/IconSupport.vue
Normal file
7
src/components/icons/IconSupport.vue
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<template>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
|
||||||
|
<path
|
||||||
|
d="M10 3.22l-.61-.6a5.5 5.5 0 0 0-7.666.105 5.5 5.5 0 0 0-.114 7.665L10 18.78l8.39-8.4a5.5 5.5 0 0 0-.114-7.665 5.5 5.5 0 0 0-7.666-.105l-.61.61z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
19
src/components/icons/IconTooling.vue
Normal file
19
src/components/icons/IconTooling.vue
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<!-- This icon is from <https://github.com/Templarian/MaterialDesign>, distributed under Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0) license-->
|
||||||
|
<template>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
aria-hidden="true"
|
||||||
|
role="img"
|
||||||
|
class="iconify iconify--mdi"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
preserveAspectRatio="xMidYMid meet"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M20 18v-4h-3v1h-2v-1H9v1H7v-1H4v4h16M6.33 8l-1.74 4H7v-1h2v1h6v-1h2v1h2.41l-1.74-4H6.33M9 5v1h6V5H9m12.84 7.61c.1.22.16.48.16.8V18c0 .53-.21 1-.6 1.41c-.4.4-.85.59-1.4.59H4c-.55 0-1-.19-1.4-.59C2.21 19 2 18.53 2 18v-4.59c0-.32.06-.58.16-.8L4.5 7.22C4.84 6.41 5.45 6 6.33 6H7V5c0-.55.18-1 .57-1.41C7.96 3.2 8.44 3 9 3h6c.56 0 1.04.2 1.43.59c.39.41.57.86.57 1.41v1h.67c.88 0 1.49.41 1.83 1.22l2.34 5.39z"
|
||||||
|
fill="currentColor"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
11
src/main.ts
Normal file
11
src/main.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { createApp } from 'vue'
|
||||||
|
import App from './App.vue'
|
||||||
|
import router from './router'
|
||||||
|
|
||||||
|
import './assets/main.css'
|
||||||
|
|
||||||
|
const app = createApp(App)
|
||||||
|
|
||||||
|
app.use(router)
|
||||||
|
|
||||||
|
app.mount('#app')
|
||||||
59
src/router/index.ts
Normal file
59
src/router/index.ts
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router'
|
||||||
|
|
||||||
|
const HomeView = () => import('../views/HomeView.vue')
|
||||||
|
|
||||||
|
export const routes: RouteRecordRaw[] = [
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
name: 'home',
|
||||||
|
component: HomeView
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/teams/:seasonNumber/:teamAbbreviation',
|
||||||
|
name: 'team',
|
||||||
|
component: () => import('../views/TeamView.vue'),
|
||||||
|
props: castTeamsRouteParams
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/managers/:managerName',
|
||||||
|
name: 'manager',
|
||||||
|
component: () => import('../views/ManagerView.vue'),
|
||||||
|
props: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/players/:seasonNumber/:playerName',
|
||||||
|
name: 'player',
|
||||||
|
component: () => import('../views/PlayerView.vue'),
|
||||||
|
props: castPlayersRouteParams
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
function castTeamsRouteParams(route: any) {
|
||||||
|
return {
|
||||||
|
teamAbbreviation: route.params.teamAbbreviation,
|
||||||
|
seasonNumber: Number(route.params.seasonNumber)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function castPlayersRouteParams(route: any) {
|
||||||
|
return {
|
||||||
|
playerName: route.params.playerName,
|
||||||
|
seasonNumber: Number(route.params.seasonNumber)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const router = createRouter({
|
||||||
|
history: createWebHistory(import.meta.env.BASE_URL),
|
||||||
|
routes,
|
||||||
|
})
|
||||||
|
|
||||||
|
// export function routerPush (name: AppRouteNames, params?: RouteParams): ReturnType<typeof router.push> {
|
||||||
|
// return params !== undefined
|
||||||
|
// ? router.push({
|
||||||
|
// name,
|
||||||
|
// params,
|
||||||
|
// })
|
||||||
|
// : router.push({ name })
|
||||||
|
// }
|
||||||
|
|
||||||
|
export default router
|
||||||
38
src/services/apiResponseTypes.ts
Normal file
38
src/services/apiResponseTypes.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
export interface Team {
|
||||||
|
abbrev: string
|
||||||
|
auto_draft: any
|
||||||
|
color: string // hex code
|
||||||
|
dice_color: string // hex code
|
||||||
|
division: Division
|
||||||
|
division_legacy: any
|
||||||
|
gmid: number
|
||||||
|
gmid2: number
|
||||||
|
gsheet: any
|
||||||
|
id: number
|
||||||
|
lname: string
|
||||||
|
manager1: Manager
|
||||||
|
manager2: Manager
|
||||||
|
manager_legacy: any
|
||||||
|
mascot: any
|
||||||
|
season: number
|
||||||
|
sname: string
|
||||||
|
stadium: string
|
||||||
|
thumbnail: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Manager {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
image: string
|
||||||
|
headline: string
|
||||||
|
bio: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Division {
|
||||||
|
division_abbrev: 'W' | 'E'
|
||||||
|
division_name: 'West' | 'East'
|
||||||
|
id: number
|
||||||
|
league_abbrev: 'NL' | 'AL'
|
||||||
|
league_name: 'National League' | 'American League'
|
||||||
|
season: number
|
||||||
|
}
|
||||||
25
src/services/currentService.ts
Normal file
25
src/services/currentService.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { SITE_URL } from './utilities'
|
||||||
|
|
||||||
|
export interface LeagueInfo {
|
||||||
|
id: number,
|
||||||
|
week: number,
|
||||||
|
freeze: boolean,
|
||||||
|
season: number,
|
||||||
|
transcount: number,
|
||||||
|
bstatcount: number,
|
||||||
|
pstatcount: number,
|
||||||
|
bet_week: number,
|
||||||
|
trade_deadline: number,
|
||||||
|
pick_trade_start: number,
|
||||||
|
pick_trade_end: number,
|
||||||
|
playoffs_begin: number,
|
||||||
|
injury_count: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchCurrentLeagueInfo(): Promise<LeagueInfo> {
|
||||||
|
const response = await fetch(`${SITE_URL}/api/v3/current`)
|
||||||
|
|
||||||
|
const leagueInfoResponse: LeagueInfo = await response.json()
|
||||||
|
|
||||||
|
return leagueInfoResponse
|
||||||
|
}
|
||||||
9
src/services/newsService.ts
Normal file
9
src/services/newsService.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// const api = new GhostContentAPI({
|
||||||
|
// url: 'https://sombaseball.ddns.net/writers',
|
||||||
|
// key: 'cfc331bb02beaebc0c62211b10',
|
||||||
|
// version: "v3"
|
||||||
|
// });
|
||||||
|
|
||||||
|
export function getPosts() {
|
||||||
|
|
||||||
|
}
|
||||||
68
src/services/playersService.ts
Normal file
68
src/services/playersService.ts
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import type { Team } from './apiResponseTypes'
|
||||||
|
import { SITE_URL } from './utilities'
|
||||||
|
|
||||||
|
export interface Player {
|
||||||
|
bbref_id: string
|
||||||
|
demotion_week: number
|
||||||
|
headshot: any
|
||||||
|
id: number
|
||||||
|
il_return: any
|
||||||
|
image: string
|
||||||
|
image2: string
|
||||||
|
injury_rating: string //could strongly type as XpYY
|
||||||
|
last_game: string // could strongly type as XX.X IP wXXgX
|
||||||
|
last_game2: string
|
||||||
|
name: string
|
||||||
|
pitcher_injury: string
|
||||||
|
pos_1: string
|
||||||
|
pos_2: string
|
||||||
|
pos_3: string
|
||||||
|
pos_4: string
|
||||||
|
pos_5: string
|
||||||
|
pos_6: string
|
||||||
|
pos_7: string
|
||||||
|
pos_8: string
|
||||||
|
season: number
|
||||||
|
strat_code: string
|
||||||
|
team: Team,
|
||||||
|
vanity_card: string
|
||||||
|
wara: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchPlayers(seasonNumber: number): Promise<Player[]> {
|
||||||
|
const response = await fetch(`${SITE_URL}/api/v3/players?season=${seasonNumber}`)
|
||||||
|
|
||||||
|
const playersResponse: {
|
||||||
|
count: number
|
||||||
|
players: Player[]
|
||||||
|
} = await response.json()
|
||||||
|
|
||||||
|
return playersResponse.players
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO should/can this use team abbrev instead of id?
|
||||||
|
export async function fetchPlayersByTeam(seasonNumber: number, teamId: number): Promise<Player[]> {
|
||||||
|
const response = await fetch(`${SITE_URL}/api/v3/players?season=${seasonNumber}&team_id=${teamId}`)
|
||||||
|
|
||||||
|
const playersResponse: {
|
||||||
|
count: number
|
||||||
|
players: Player[]
|
||||||
|
} = await response.json()
|
||||||
|
|
||||||
|
return playersResponse.players
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchPlayerByName(seasonNumber: number, playerName: string): Promise<Player> {
|
||||||
|
const response = await fetch(`${SITE_URL}/api/v3/players?season=${seasonNumber}&name=${playerName}`)
|
||||||
|
|
||||||
|
const playersResponse: {
|
||||||
|
count: number
|
||||||
|
players: Player[]
|
||||||
|
} = await response.json()
|
||||||
|
|
||||||
|
if (playersResponse.count !== 1) {
|
||||||
|
throw new Error('playersServices.fetchPlayerByName - Expected one player, return contained none or many')
|
||||||
|
}
|
||||||
|
|
||||||
|
return playersResponse.players[0]
|
||||||
|
}
|
||||||
101
src/services/standingsService.ts
Normal file
101
src/services/standingsService.ts
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
import type { Team } from './apiResponseTypes'
|
||||||
|
import { SITE_URL } from './utilities'
|
||||||
|
|
||||||
|
interface TeamStandingRaw {
|
||||||
|
away_losses: number
|
||||||
|
away_wins: number
|
||||||
|
div1_losses: number
|
||||||
|
div1_wins: number
|
||||||
|
div2_losses: number
|
||||||
|
div2_wins: number
|
||||||
|
div3_losses: number
|
||||||
|
div3_wins: number
|
||||||
|
div4_losses: number
|
||||||
|
div4_wins: number
|
||||||
|
div_e_num: number
|
||||||
|
div_gb: number
|
||||||
|
home_losses: number
|
||||||
|
home_wins: number
|
||||||
|
id: number
|
||||||
|
last8_losses: number
|
||||||
|
last8_wins: number
|
||||||
|
losses: number
|
||||||
|
one_run_losses: number
|
||||||
|
one_run_wins: number
|
||||||
|
pythag_losses: number
|
||||||
|
pythag_wins: number
|
||||||
|
run_diff: number
|
||||||
|
streak_num: number
|
||||||
|
streak_wl: 'w' | 'l'
|
||||||
|
team: Team
|
||||||
|
wc_e_num: number | null
|
||||||
|
wc_gb: number
|
||||||
|
wins: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TeamStanding {
|
||||||
|
teamName: string
|
||||||
|
teamAbbreviation: string
|
||||||
|
divisionAbbreviation: 'W' | 'E'
|
||||||
|
leagueAbbreviation: 'NL' | 'AL'
|
||||||
|
wins: number
|
||||||
|
losses: number
|
||||||
|
winPercentage: string,
|
||||||
|
last8Record: string,
|
||||||
|
streak: string
|
||||||
|
divisionGamesBack: string
|
||||||
|
divisionEliminationNumber: string
|
||||||
|
wildcardGamesBack: string
|
||||||
|
wildcardEliminationNumber: string
|
||||||
|
runDifferential: string
|
||||||
|
isWildcardTeam: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchStandings(seasonNumber: number): Promise<TeamStanding[]> {
|
||||||
|
const response = await fetch(`${SITE_URL}/api/v3/standings?season=${seasonNumber}`)//?league_abbrev=AL&division_abbrev=W`)
|
||||||
|
|
||||||
|
const standingsResponse: {
|
||||||
|
count: number
|
||||||
|
standings: TeamStandingRaw[]
|
||||||
|
} = await response.json()
|
||||||
|
const standings: TeamStandingRaw[] = standingsResponse.standings
|
||||||
|
|
||||||
|
return standings.map(normalizeStanding)
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeStanding(standing: TeamStandingRaw): TeamStanding {
|
||||||
|
const totalGamesPlayed = standing.wins + standing.losses
|
||||||
|
// round win percentage to 3 decimal places
|
||||||
|
const winPercentage: string = totalGamesPlayed ? `${Math.round(standing.wins / totalGamesPlayed * 1000) / 1000}%` : '-'
|
||||||
|
|
||||||
|
const formattedRunDiff = `${standing.run_diff > 0 ? '+' : ''}${standing.run_diff}`
|
||||||
|
const isWildcardTeam = standing.wc_gb !== null || standing.wc_e_num !== null
|
||||||
|
|
||||||
|
return {
|
||||||
|
teamName: standing.team.sname,
|
||||||
|
teamAbbreviation: standing.team.abbrev,
|
||||||
|
divisionAbbreviation: standing.team.division.division_abbrev,
|
||||||
|
leagueAbbreviation: standing.team.division.league_abbrev,
|
||||||
|
wins: standing.wins,
|
||||||
|
losses: standing.losses,
|
||||||
|
winPercentage,
|
||||||
|
last8Record: `${standing.last8_wins}-${standing.last8_losses}`,
|
||||||
|
streak: `${standing.streak_wl.toUpperCase()}${standing.streak_num}`,
|
||||||
|
divisionGamesBack: parseGamesBack(standing.div_gb),
|
||||||
|
divisionEliminationNumber: parseEliminationNumber(standing.div_e_num),
|
||||||
|
wildcardGamesBack: parseGamesBack(standing.wc_gb),
|
||||||
|
wildcardEliminationNumber: parseEliminationNumber(standing.wc_e_num),
|
||||||
|
runDifferential: formattedRunDiff,
|
||||||
|
isWildcardTeam
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseGamesBack(gamesBack: number | null): string {
|
||||||
|
if (gamesBack == null) return '-'
|
||||||
|
return `${gamesBack < 0 ? '+' : ''}${Math.abs(gamesBack).toFixed(1)}`
|
||||||
|
}
|
||||||
|
function parseEliminationNumber(eliminationNumber: number | null): string {
|
||||||
|
if (eliminationNumber == null) return '-'
|
||||||
|
return eliminationNumber <= 0 ? 'E' : `${eliminationNumber}`
|
||||||
|
}
|
||||||
|
|
||||||
17
src/services/teamsService.ts
Normal file
17
src/services/teamsService.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import type { Team } from './apiResponseTypes'
|
||||||
|
import { SITE_URL } from './utilities'
|
||||||
|
|
||||||
|
export async function fetchTeam(seasonNumber: number, teamAbbreviation: string): Promise<Team> {
|
||||||
|
const response = await fetch(`${SITE_URL}/api/v3/teams/?season=${seasonNumber}&team_abbrev=${teamAbbreviation}`)
|
||||||
|
|
||||||
|
const teamResponse: {
|
||||||
|
count: number
|
||||||
|
teams: Team[]
|
||||||
|
} = await response.json()
|
||||||
|
|
||||||
|
if (teamResponse.count !== 1) {
|
||||||
|
throw new Error('teamServices.fetchTeam - Expected one team, return contained none or many')
|
||||||
|
}
|
||||||
|
|
||||||
|
return teamResponse.teams[0]
|
||||||
|
}
|
||||||
43
src/services/transactionsService.ts
Normal file
43
src/services/transactionsService.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import type { Team } from './apiResponseTypes'
|
||||||
|
import type { Player } from './playersService'
|
||||||
|
import { SITE_URL } from './utilities'
|
||||||
|
|
||||||
|
export interface Transaction {
|
||||||
|
id: number
|
||||||
|
week: number
|
||||||
|
player: Player
|
||||||
|
oldteam: Team
|
||||||
|
newteam: Team
|
||||||
|
season: number
|
||||||
|
moveid: number
|
||||||
|
cancelled: boolean
|
||||||
|
frozen: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchTransactionsByTeamAndWeek(seasonNumber: number, teamAbbreviation: string, weekNumber: number): Promise<Transaction[]> {
|
||||||
|
const response = await fetch(`${SITE_URL}/api/v3/transactions?season=${seasonNumber}&team_abbrev=${teamAbbreviation}&week_start=${weekNumber}`)
|
||||||
|
|
||||||
|
const transactionsResponse: {
|
||||||
|
count: number
|
||||||
|
transactions: Transaction[]
|
||||||
|
} = await response.json()
|
||||||
|
|
||||||
|
console.log('fetchTransactionsByTeam', seasonNumber, teamAbbreviation, transactionsResponse)
|
||||||
|
|
||||||
|
return transactionsResponse.transactions
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchPlayerByName(seasonNumber: number, playerName: string): Promise<Player> {
|
||||||
|
const response = await fetch(`${SITE_URL}/api/v3/players?season=${seasonNumber}&name=${playerName}`)
|
||||||
|
|
||||||
|
const playersResponse: {
|
||||||
|
count: number
|
||||||
|
players: Player[]
|
||||||
|
} = await response.json()
|
||||||
|
|
||||||
|
if (playersResponse.count !== 1) {
|
||||||
|
throw new Error('playersServices.fetchPlayerByName - Expected one player, return contained none or many')
|
||||||
|
}
|
||||||
|
|
||||||
|
return playersResponse.players[0]
|
||||||
|
}
|
||||||
3
src/services/utilities.ts
Normal file
3
src/services/utilities.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export const SITE_URL = 'https://sba.manticorum.com'
|
||||||
|
|
||||||
|
export const CURRENT_SEASON = 8
|
||||||
4
src/shims-vue.d.ts
vendored
Normal file
4
src/shims-vue.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
declare module "*.vue" {
|
||||||
|
import Vue from 'vue'
|
||||||
|
export default Vue
|
||||||
|
}
|
||||||
92
src/views/HomeView.vue
Normal file
92
src/views/HomeView.vue
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<template>
|
||||||
|
<main class="home-view">
|
||||||
|
<TheWelcome />
|
||||||
|
|
||||||
|
<h1>Season {{ seasonNumber }} Standings</h1>
|
||||||
|
<h2 id="week-num">{{ weekNumber ? `Week ${weekNumber}` : '' }}</h2>
|
||||||
|
|
||||||
|
<!-- Division Standings -->
|
||||||
|
<div class="row">
|
||||||
|
<div class="column">
|
||||||
|
<h2>American League</h2>
|
||||||
|
<h3>East</h3>
|
||||||
|
<StandingsTable :teams="alEastTeams" :is-divisional=true />
|
||||||
|
<h3>West</h3>
|
||||||
|
<StandingsTable :teams="alWestTeams" :is-divisional=true />
|
||||||
|
<h3>AL Wildcard</h3>
|
||||||
|
<StandingsTable :teams="alWildcardTeams" :is-divisional=false />
|
||||||
|
|
||||||
|
<h2>National League</h2>
|
||||||
|
<h3>East</h3>
|
||||||
|
<StandingsTable :teams="nlEastTeams" :is-divisional=true />
|
||||||
|
<h3>West</h3>
|
||||||
|
<StandingsTable :teams="nlWestTeams" :is-divisional=true />
|
||||||
|
<h3>NL Wildcard</h3>
|
||||||
|
<StandingsTable :teams="nlWildcardTeams" :is-divisional=false />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="column">
|
||||||
|
<h3>Latest News</h3>
|
||||||
|
<div id="news-posts"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import StandingsTable from '@/components/StandingsTable.vue'
|
||||||
|
import { fetchStandings, type TeamStanding } from '@/services/standingsService'
|
||||||
|
import { fetchCurrentLeagueInfo, type LeagueInfo } from '@/services/currentService'
|
||||||
|
import { CURRENT_SEASON } from '@/services/utilities'
|
||||||
|
import TheWelcome from '../components/TheWelcome.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "HomeView",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
seasonNumber: CURRENT_SEASON as number,
|
||||||
|
weekNumber: undefined as number | undefined,
|
||||||
|
teamStandings: [] as TeamStanding[],
|
||||||
|
alEastTeams: [] as TeamStanding[],
|
||||||
|
alWestTeams: [] as TeamStanding[],
|
||||||
|
alWildcardTeams: [] as TeamStanding[],
|
||||||
|
nlEastTeams: [] as TeamStanding[],
|
||||||
|
nlWestTeams: [] as TeamStanding[],
|
||||||
|
nlWildcardTeams: [] as TeamStanding[],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async fetchData(): Promise<void> {
|
||||||
|
const leagueInfo: LeagueInfo = await fetchCurrentLeagueInfo()
|
||||||
|
this.weekNumber = leagueInfo.week
|
||||||
|
|
||||||
|
// TODO CHANGE THIS
|
||||||
|
this.teamStandings = await fetchStandings(CURRENT_SEASON - 1)
|
||||||
|
this.alEastTeams = this.teamStandings.filter(ts => ts.divisionAbbreviation === 'E' && ts.leagueAbbreviation === 'AL')
|
||||||
|
this.alWestTeams = this.teamStandings.filter(ts => ts.divisionAbbreviation === 'W' && ts.leagueAbbreviation === 'AL')
|
||||||
|
this.nlEastTeams = this.teamStandings.filter(ts => ts.divisionAbbreviation === 'E' && ts.leagueAbbreviation === 'NL')
|
||||||
|
this.nlWestTeams = this.teamStandings.filter(ts => ts.divisionAbbreviation === 'W' && ts.leagueAbbreviation === 'NL')
|
||||||
|
this.alWildcardTeams = this.teamStandings.filter(ts => ts.leagueAbbreviation === 'AL' && ts.isWildcardTeam)
|
||||||
|
this.nlWildcardTeams = this.teamStandings.filter(ts => ts.leagueAbbreviation === 'NL' && ts.isWildcardTeam)
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column {
|
||||||
|
flex-basis: 50%;
|
||||||
|
/* Sets the initial width of each column to 50% */
|
||||||
|
padding: 10px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
/* Includes padding within the width of each column */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
118
src/views/ManagerView.vue
Normal file
118
src/views/ManagerView.vue
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
<template>
|
||||||
|
<div class="manager-view centerDiv">
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<h1 id="manager-name">{{ managerName }}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<h3 id="manager-record">Career Record: 294-218</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<p id="manager-headline"></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<h3 style="text-align: center">Teams Managed</h3>
|
||||||
|
<div class="table-responsive-xl">
|
||||||
|
<table style="text-align: center" class="table table-sm table-striped" id="manager-teams-table">
|
||||||
|
<thead class="thead-dark">
|
||||||
|
<tr>
|
||||||
|
<th>Season</th>
|
||||||
|
<th>Team</th>
|
||||||
|
<th>Record</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>7</td>
|
||||||
|
<td><a href="/teams?abbrev=TK&season=7">Tokyo Kaiju</a></td>
|
||||||
|
<td id="season-7-record">47-41</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>6</td>
|
||||||
|
<td><a href="/teams?abbrev=TK&season=6">Tokyo Kaiju</a></td>
|
||||||
|
<td id="season-6-record">51-37</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>5</td>
|
||||||
|
<td><a href="/teams?abbrev=TK&season=5">Tokyo Kaiju</a></td>
|
||||||
|
<td id="season-5-record">55-33</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>4</td>
|
||||||
|
<td><a href="/teams?abbrev=TK&season=4">Tokyo Kaiju</a></td>
|
||||||
|
<td id="season-4-record">55-33</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>3</td>
|
||||||
|
<td><a href="/teams?abbrev=TK&season=3">Tokyo Kaiju</a></td>
|
||||||
|
<td id="season-3-record">49-39</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>2</td>
|
||||||
|
<td><a href="/teams?abbrev=TK&season=2">Tokyo Kaiju</a></td>
|
||||||
|
<td id="season-2-record">37-35</td>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="manager-teams"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm-5">
|
||||||
|
<h3 style="text-align: center">Awards Received</h3>
|
||||||
|
<div class="table-responsive-xl">
|
||||||
|
<table style="text-align: center" class="table table-sm table-striped" id="manager-awards-table">
|
||||||
|
<thead class="thead-dark">
|
||||||
|
<tr>
|
||||||
|
<th>Season</th>
|
||||||
|
<th>Award</th>
|
||||||
|
<th>Extras</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>3</td>
|
||||||
|
<td>AL Wildcard</td>
|
||||||
|
<td><a href="/teams?abbrev=TK&season=3">Tokyo Kaiju</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>2</td>
|
||||||
|
<td>Most Hated Ballpark</td>
|
||||||
|
<td><a href="/teams?abbrev=TK&season=2">Tokyo Kaiju</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>2</td>
|
||||||
|
<td>American League Pennant</td>
|
||||||
|
<td><a href="/teams?abbrev=TK&season=2">Tokyo Kaiju</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>2</td>
|
||||||
|
<td>AL East Leader</td>
|
||||||
|
<td><a href="/teams?abbrev=TK&season=2">Tokyo Kaiju</a></td>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="manager-awards"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<h3 style="text-align: center" id="manager-bio-header"></h3>
|
||||||
|
<p id="manager-bio"></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "ManagerView",
|
||||||
|
props: {
|
||||||
|
managerName: { type: String, required: true },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
1231
src/views/PlayerView.vue
Normal file
1231
src/views/PlayerView.vue
Normal file
File diff suppressed because it is too large
Load Diff
263
src/views/TeamView.vue
Normal file
263
src/views/TeamView.vue
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
<template>
|
||||||
|
<div class="team-view centerDiv">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm">
|
||||||
|
<h1 id="team-record">{{ teamName }}</h1>
|
||||||
|
<h2 id="standings"></h2>
|
||||||
|
<h2 id="streak">Last 8: {{ lastEight }} / Streak: {{ streak }}</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm">
|
||||||
|
<h2 id="manager">
|
||||||
|
Manager{{ hasMultipleManagers ? 's' : '' }}:
|
||||||
|
<RouterLink v-if="manager1Name" :to="{ name: 'manager', params: { managerName: manager1Name } }">
|
||||||
|
{{ manager1Name }}
|
||||||
|
</RouterLink>
|
||||||
|
{{ hasMultipleManagers ? ' & ' : '' }}
|
||||||
|
<RouterLink v-if="hasMultipleManagers && manager2Name"
|
||||||
|
:to="{ name: 'manager', params: { managerName: manager2Name } }">
|
||||||
|
{{ manager2Name }}
|
||||||
|
</RouterLink>
|
||||||
|
</h2>
|
||||||
|
<h2 id="abbrev">Abbrev: {{ teamAbbreviation }}</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm-1">
|
||||||
|
<!-- TODO move thumbnail to computed and fallback on default pic? -->
|
||||||
|
<img id="thumbnail" height="125" style="float:right; vertical-align:middle" :src=team?.thumbnail>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Team Rosters -->
|
||||||
|
<div class="row">
|
||||||
|
<!-- Left Column -->
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<h3 id="active-roster-count">({{ rosterCount }}/26) Active Roster ({{ swarTotal(players).toFixed(2) }})</h3>
|
||||||
|
<div class="table-responsive-xl">
|
||||||
|
<table class="table table-sm table-striped" id="table-active-roster">
|
||||||
|
<thead class="thead-dark">
|
||||||
|
<tr>
|
||||||
|
<th>Pos</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>sWAR</th>
|
||||||
|
<th>Injury</th>
|
||||||
|
<th>Positions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="active-roster">
|
||||||
|
<tr v-for="player in sortedPlayers(players)">
|
||||||
|
<td>{{ player.pos_1 }}</td>
|
||||||
|
<td>
|
||||||
|
<RouterLink :to="{ name: 'player', params: { seasonNumber: seasonNumber, playerName: player.name } }">
|
||||||
|
{{ player.name }}
|
||||||
|
</RouterLink>
|
||||||
|
</td>
|
||||||
|
<td>{{ player.wara }}</td>
|
||||||
|
<td>{{ player.injury_rating }}</td>
|
||||||
|
<td>{{ allPositions(player) }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<th>Pos</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>sWAR</th>
|
||||||
|
<th>Injury</th>
|
||||||
|
<th>Positions</th>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Right Column -->
|
||||||
|
<div class="col-sm-6">
|
||||||
|
|
||||||
|
<h3 id="minors-header">{{ minorsTeamName }} ({{ swarTotal(playersMinors).toFixed(2) }})</h3>
|
||||||
|
<div class="table-responsive-xl">
|
||||||
|
<table class="table table-sm table-striped" id="table-minors-roster">
|
||||||
|
<thead class="thead-dark">
|
||||||
|
<tr>
|
||||||
|
<th>Pos</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>WARa</th>
|
||||||
|
<th>Inj Return</th>
|
||||||
|
<th>Positions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="minors-roster">
|
||||||
|
<tr v-for="player in sortedPlayers(playersMinors)">
|
||||||
|
<td>{{ player.pos_1 }}</td>
|
||||||
|
<td>
|
||||||
|
<RouterLink :to="{ name: 'player', params: { seasonNumber: seasonNumber, playerName: player.name } }">
|
||||||
|
{{ player.name }}
|
||||||
|
</RouterLink>
|
||||||
|
</td>
|
||||||
|
<td>{{ player.wara }}</td>
|
||||||
|
<td>{{ player.il_return }}</td>
|
||||||
|
<td>{{ allPositions(player) }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<h3 id="short-il-header">Injured List ({{ swarTotal(playersInjuredList).toFixed(2) }})</h3>
|
||||||
|
<div class="table-responsive-xl">
|
||||||
|
<table class="table table-sm table-striped" id="table-shortil-roster">
|
||||||
|
<thead class="thead-dark">
|
||||||
|
<tr>
|
||||||
|
<th>Pos</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>WARa</th>
|
||||||
|
<th>Inj Return</th>
|
||||||
|
<th>Positions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="short-il-roster">
|
||||||
|
<tr v-for="player in sortedPlayers(playersInjuredList)">
|
||||||
|
<td>{{ player.pos_1 }}</td>
|
||||||
|
<td>
|
||||||
|
<RouterLink :to="{ name: 'player', params: { seasonNumber: seasonNumber, playerName: player.name } }">
|
||||||
|
{{ player.name }}
|
||||||
|
</RouterLink>
|
||||||
|
</td>
|
||||||
|
<td>{{ player.wara }}</td>
|
||||||
|
<td>{{ player.il_return }}</td>
|
||||||
|
<td>{{ allPositions(player) }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3 id="transactions-header">Week {{ transactionsWeekNumber }} Transactions ({{ transactionsWar.toFixed(2) }})
|
||||||
|
</h3>
|
||||||
|
<div class="table-responsive-xl">
|
||||||
|
<table class="table table-sm table-striped" id="table-transactions">
|
||||||
|
<thead class="thead-dark">
|
||||||
|
<tr>
|
||||||
|
<th>Week</th>
|
||||||
|
<th>Player</th>
|
||||||
|
<th>Old Team</th>
|
||||||
|
<th>New Team</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="transactions-body"></tbody>
|
||||||
|
<tr v-for="row in transactionRows">
|
||||||
|
<td>{{ row.week }}</td>
|
||||||
|
<td>{{ row.playerName }}</td>
|
||||||
|
<td>{{ row.oldTeam }}</td>
|
||||||
|
<td>{{ row.newTeam }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import type { Team } from '@/services/apiResponseTypes'
|
||||||
|
import { fetchCurrentLeagueInfo } from '@/services/currentService'
|
||||||
|
import { fetchPlayersByTeam, type Player } from '@/services/playersService'
|
||||||
|
import { fetchStandings, type TeamStanding } from '@/services/standingsService'
|
||||||
|
import { fetchTeam } from '@/services/teamsService'
|
||||||
|
import { fetchTransactionsByTeamAndWeek, type Transaction } from '@/services/transactionsService'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "TeamView",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
team: undefined as Team | undefined,
|
||||||
|
teamMinors: undefined as Team | undefined,
|
||||||
|
teamInjuredList: undefined as Team | undefined,
|
||||||
|
teamStanding: undefined as TeamStanding | undefined,
|
||||||
|
players: [] as Player[],
|
||||||
|
playersMinors: [] as Player[],
|
||||||
|
playersInjuredList: [] as Player[],
|
||||||
|
transactions: [] as Transaction[],
|
||||||
|
weekNumber: undefined as number | undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
seasonNumber: { type: Number, required: true },
|
||||||
|
teamAbbreviation: { type: String, required: true },
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
manager1Name(): string | undefined {
|
||||||
|
return this.team?.manager1?.name
|
||||||
|
},
|
||||||
|
manager2Name(): string | undefined {
|
||||||
|
return this.team?.manager2?.name
|
||||||
|
},
|
||||||
|
hasMultipleManagers(): boolean {
|
||||||
|
return !!(this.manager1Name && this.manager2Name)
|
||||||
|
},
|
||||||
|
teamName(): string | undefined {
|
||||||
|
return this.team?.lname
|
||||||
|
},
|
||||||
|
minorsTeamName(): string | undefined {
|
||||||
|
return this.teamMinors?.sname
|
||||||
|
},
|
||||||
|
lastEight(): string | undefined {
|
||||||
|
return this.teamStanding?.last8Record
|
||||||
|
},
|
||||||
|
streak(): string | undefined {
|
||||||
|
return this.teamStanding?.streak
|
||||||
|
},
|
||||||
|
rosterCount(): number {
|
||||||
|
return this.players.length
|
||||||
|
},
|
||||||
|
transactionsWeekNumber(): number | undefined {
|
||||||
|
if (this.weekNumber === undefined) return undefined
|
||||||
|
return this.weekNumber + 1
|
||||||
|
},
|
||||||
|
transactionsWar(): number {
|
||||||
|
const teamsWar = this.swarTotal(this.players)
|
||||||
|
if (!this.transactions.length) return teamsWar
|
||||||
|
|
||||||
|
const playersOut = this.transactions.filter(t => t.oldteam.abbrev === this.teamAbbreviation).map(t => t.player)
|
||||||
|
const playersIn = this.transactions.filter(t => t.newteam.abbrev === this.teamAbbreviation).map(t => t.player)
|
||||||
|
|
||||||
|
const swarOut = this.swarTotal(playersOut)
|
||||||
|
const swarIn = this.swarTotal(playersIn)
|
||||||
|
|
||||||
|
return teamsWar - swarOut + swarIn
|
||||||
|
},
|
||||||
|
transactionRows(): { week: number, playerName: string, oldTeam: string, newTeam: string }[] {
|
||||||
|
return this.transactions.map(t => {
|
||||||
|
return { week: t.week, playerName: t.player.name, oldTeam: t.oldteam.sname, newTeam: t.newteam.sname }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async fetchData(): Promise<void> {
|
||||||
|
this.team = await fetchTeam(this.seasonNumber, this.teamAbbreviation)
|
||||||
|
this.teamMinors = await fetchTeam(this.seasonNumber, `${this.teamAbbreviation}MiL`)
|
||||||
|
this.teamInjuredList = await fetchTeam(this.seasonNumber, `${this.teamAbbreviation}IL`)
|
||||||
|
|
||||||
|
this.teamStanding = (await fetchStandings(this.seasonNumber - 1)).find(ts => ts.teamName === this.team?.sname)
|
||||||
|
this.weekNumber = (await fetchCurrentLeagueInfo()).week
|
||||||
|
|
||||||
|
this.players = await fetchPlayersByTeam(this.seasonNumber, this.team?.id)
|
||||||
|
this.playersMinors = await fetchPlayersByTeam(this.seasonNumber, this.teamMinors?.id)
|
||||||
|
this.playersInjuredList = await fetchPlayersByTeam(this.seasonNumber, this.teamInjuredList?.id)
|
||||||
|
|
||||||
|
this.transactions = (await fetchTransactionsByTeamAndWeek(this.seasonNumber, this.teamAbbreviation, this.transactionsWeekNumber!))
|
||||||
|
console.log(this.transactions)
|
||||||
|
},
|
||||||
|
allPositions(player: Player): string {
|
||||||
|
let positions = []
|
||||||
|
positions.push(player.pos_1, player.pos_2, player.pos_3, player.pos_4, player.pos_5, player.pos_6, player.pos_7)
|
||||||
|
return positions.join(" ")
|
||||||
|
},
|
||||||
|
swarTotal(players: Player[]): number {
|
||||||
|
return players.map(p => p.wara).reduce((prev, curr) => prev + curr, 0)
|
||||||
|
},
|
||||||
|
sortedPlayers(players: Player[]): Player[] {
|
||||||
|
return players.sort((a, b) => b.wara - a.wara)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
8
tsconfig.config.json
Normal file
8
tsconfig.config.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"extends": "@vue/tsconfig/tsconfig.node.json",
|
||||||
|
"include": ["vite.config.*", "vitest.config.*", "cypress.config.*", "playwright.config.*"],
|
||||||
|
"compilerOptions": {
|
||||||
|
"composite": true,
|
||||||
|
"types": ["node"]
|
||||||
|
}
|
||||||
|
}
|
||||||
16
tsconfig.json
Normal file
16
tsconfig.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"extends": "@vue/tsconfig/tsconfig.web.json",
|
||||||
|
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./src/*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.config.json"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
20
vite.config.ts
Normal file
20
vite.config.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { fileURLToPath, URL } from 'node:url'
|
||||||
|
|
||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
import Components from 'unplugin-vue-components/vite'
|
||||||
|
import { NaiveUiResolver } from 'unplugin-vue-components/resolvers'
|
||||||
|
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [
|
||||||
|
vue(),
|
||||||
|
Components({
|
||||||
|
resolvers: [NaiveUiResolver()]
|
||||||
|
})],
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'@': fileURLToPath(new URL('./src', import.meta.url))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
Loading…
Reference in New Issue
Block a user