Skip to content

Commit

Permalink
[FEAT] Stream Elements (#1)
Browse files Browse the repository at this point in the history
* [FEAT] Stream Elements

* WebSockets working

* Icon improvements

* Upgrade to vue 3 and make sure old stuff still works

* Add storybook for components

* More finished components

* Working dynamic component

* Better slug

* Set node versions to 20 everywhere and make sure all scripts run
  • Loading branch information
fdendorfer committed Jun 9, 2024
1 parent 273cd6f commit 5a2f694
Show file tree
Hide file tree
Showing 42 changed files with 10,302 additions and 4,943 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ jobs:
runs-on: self-hosted
steps:
- uses: actions/checkout@v4
- name: Use Node.js 22
- name: Use Node.js 20
uses: actions/setup-node@v4
with:
node-version: 22
node-version: 20
cache: 'pnpm'
- run: pnpm install
- run: pnpm install --frozen-lockfile
- run: pnpm build
- run: pm2 delete svbot-web || true
- run: pm2 start npm --name "svbot-web" -- start
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,6 @@ logs
.env
.env.*
!.env.example

*storybook.log
storybook-static
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v20.14.0
11 changes: 11 additions & 0 deletions .storybook/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { StorybookConfig } from '@storybook/vue3-vite'

const config: StorybookConfig = {
stories: ['../**/*.mdx', '../**/*.stories.ts'],
addons: ['@storybook/addon-links', '@storybook/addon-essentials', '@storybook/addon-interactions'],
framework: {
name: '@storybook/vue3-vite',
options: {},
},
}
export default config
19 changes: 19 additions & 0 deletions .storybook/preview.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { Preview } from '@storybook/vue3'

const preview: Preview = {
tags: ['autodocs'],
parameters: {
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
docs: {
autodocs: true,
},
layout: 'fullscreen',
},
}

export default preview
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:22 as base
FROM node:20 as base

LABEL description="SVBot-Web"
LABEL version="1.3"
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ Vue in Nuxt with TypeScript, MongoDB and Socket.io

## Links

- Figma: <https://www.figma.com/file/ZIaIC7sFGchAHS9T3FhH6e/SVBot-Web>n
- Figma: <https://www.figma.com/file/ZIaIC7sFGchAHS9T3FhH6e/SVBot-Web>
- Figma Demo:
<https://www.figma.com/file/ZIaIC7sFGchAHS9T3FhH6e/Untitled?node-id=5%3A3>
<https://www.figma.com/design/ZIaIC7sFGchAHS9T3FhH6e/SVBot-Web?node-id=5-3>

## Future Tasks

Expand Down
34 changes: 14 additions & 20 deletions api.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,14 @@ import dotenv from 'dotenv'
dotenv.config()
const corsOptions = { origin: process.env.HOME_URI }

let db
;(async () => {
const client = await new MongoClient(process.env.MONGO_URI, {}).connect()
db = client.db(process.env.DB_NAME || 'svbot')
})()
const client = await new MongoClient(process.env.MONGO_URI, {}).connect()
const db = client.db(process.env.DB_NAME || 'svbot')

const app = express()
const server = createServer(app)
const io = new Server(server, { cors: corsOptions })

console.log('corsOptions', corsOptions)
app.use(cors(corsOptions))
app.use(json())
app.use(urlencoded({ extended: true }))
Expand All @@ -30,20 +28,7 @@ const cache = {
teamName: '',
rank: 'bronze',
rank2: 'bronze',
handicaps: [
// {
// points: 40,
// img: 'no_sound.png',
// text: 'NO IN GAME AUDIO',
// selected: true,
// },
// {
// points: 40,
// img: 'no_ult.png',
// text: "CAN'T USE ULTIMATE",
// selected: true,
// },
],
handicaps: [],
bounty: {
points: 2,
img: 'emote_on_dead_body.png',
Expand Down Expand Up @@ -78,6 +63,8 @@ app.post('/api/contestants', async (req, res) => {
const collection = await db.collection('contestants')

const result = await collection.insertOne(req.body)
io.emit('contestants updated', await collection.find().toArray())

res.json(result)
} catch (e) {
console.error('e', e)
Expand All @@ -93,6 +80,7 @@ app.put('/api/contestants', async (req, res) => {
const id = new ObjectId(req.body._id)
delete req.body._id
const result = await collection.updateOne({ _id: id }, { $set: req.body })
io.emit('contestants updated', await collection.find().toArray())

res.json({ modifiedCount: result.modifiedCount })
} catch (e) {
Expand All @@ -107,6 +95,7 @@ app.delete('/api/contestants', async (req, res) => {
const collection = await db.collection('contestants')

const result = await collection.deleteOne(req.body)
io.emit('contestants updated', await collection.find().toArray())

res.json(result)
} catch (e) {
Expand All @@ -123,15 +112,20 @@ app.get('/api/currentGame', (_req, res) => {
// Store current game
app.post('/api/currentGame', (req, res) => {
Object.assign(cache, req.body)
io.emit('game updated', cache) // TODO: this can just send back req.body
io.emit('game updated', cache)
res.json(cache)
})

// WS
io.on('connection', socket => {
socket.on('game updated', game => {
console.log('received game updated', game.contestantName)
socket.emit('game updated', game)
})
socket.on('contestants updated', list => {
console.log('received contestants updated', list)
socket.emit('contestants updated', list)
})
})

server.listen(process.env.API_PORT, () => console.log(`API running on port ${process.env.API_PORT}`))
7 changes: 0 additions & 7 deletions components/README.md

This file was deleted.

16 changes: 16 additions & 0 deletions components/generic-icon/GenericIcon.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { Meta, StoryObj } from '@storybook/vue3'
import GenericIcon from './GenericIcon.vue'

const meta = {
title: 'Components/Generic Icon',
component: GenericIcon,
} satisfies Meta<typeof GenericIcon>

export default meta
type Story = StoryObj<typeof GenericIcon>

export const Default: Story = {
args: {
src: '/ranks/orange/grandmaster.png',
},
}
18 changes: 18 additions & 0 deletions components/generic-icon/GenericIcon.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<template>
<div class="icon"><img :src="src" /></div>
</template>

<script setup lang="ts">
defineProps({
src: {
type: String,
required: true,
},
})
</script>

<style scoped>
.icon {
object-fit: contain;
}
</style>
30 changes: 30 additions & 0 deletions components/the-handicaps-vertical/TheHandicapsVertical.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { Meta, StoryObj } from '@storybook/vue3'
import TheHandicapsVertical from './TheHandicapsVertical.vue'
import { Handicap } from '../../types'

const meta = {
title: 'Components/The Handicaps Vertical',
component: TheHandicapsVertical,
} satisfies Meta<typeof TheHandicapsVertical>

export default meta
type Story = StoryObj<typeof TheHandicapsVertical>

export const Default: Story = {
args: {
handicaps: [
new Handicap({
points: 40,
img: 'no_sound.png',
text: 'NO IN GAME AUDIO',
selected: true,
}),
new Handicap({
points: 40,
img: 'no_ult.png',
text: "CAN'T USE ULTIMATE",
selected: true,
}),
],
},
}
41 changes: 41 additions & 0 deletions components/the-handicaps-vertical/TheHandicapsVertical.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<template>
<div class="handicaps">
<link rel="preconnect" href="https://fonts.bunny.net" />
<link href="https://fonts.bunny.net/css2?family=Rubik&display=swap" rel="stylesheet" />

<template v-for="(handicap, i) in handicaps" :key="i">
<img :src="`/handicaps/orange/${handicap.img}`" />
<span>{{ handicap.text }}</span>
</template>
</div>
</template>

<script setup lang="ts">
import type { Handicap } from '@/types'
defineProps({
handicaps: {
type: Object as PropType<Handicap[]>,
required: true,
},
})
</script>

<style scoped>
* {
box-sizing: border-box;
font-family: Rubik, sans-serif;
font-size: 26px;
color: var(--main-color, #ff9d16);
}
.handicaps {
display: grid;
grid-template-columns: auto 1fr;
gap: 16px;
}
img {
width: 40px;
height: 40px;
}
</style>
30 changes: 30 additions & 0 deletions components/the-handicaps/TheHandicaps.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { Meta, StoryObj } from '@storybook/vue3'
import TheHandicaps from './TheHandicaps.vue'
import { Handicap } from '../../types'

const meta = {
title: 'Components/The Handicaps',
component: TheHandicaps,
} satisfies Meta<typeof TheHandicaps>

export default meta
type Story = StoryObj<typeof TheHandicaps>

export const Default: Story = {
args: {
handicaps: [
new Handicap({
points: 40,
img: 'no_sound.png',
text: 'NO IN GAME AUDIO',
selected: true,
}),
new Handicap({
points: 40,
img: 'no_ult.png',
text: "CAN'T USE ULTIMATE",
selected: true,
}),
],
},
}
30 changes: 30 additions & 0 deletions components/the-handicaps/TheHandicaps.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<template>
<div class="handicaps">
<img v-for="(handicap, i) in handicaps" :key="i" :src="`/handicaps/orange/${handicap.img}`" />
</div>
</template>

<script setup lang="ts">
import type { Handicap } from '@/types'
defineProps({
handicaps: {
type: Array as PropType<Handicap[]>,
required: true,
},
})
</script>

<style scoped>
.handicaps {
display: flex;
flex-direction: row;
align-items: center;
height: 52px;
}
img {
width: 40px;
height: 40px;
margin-right: 5px;
}
</style>
29 changes: 29 additions & 0 deletions components/the-leaderboard/TheLeaderboard.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { Meta, StoryObj } from '@storybook/vue3'
import TheLeaderboard from './TheLeaderboard.vue'

const meta = {
title: 'Components/The Leaderboard',
component: TheLeaderboard,
} satisfies Meta<typeof TheLeaderboard>

export default meta
type Story = StoryObj<typeof TheLeaderboard>

export const Default: Story = {
args: {
standalone: false,
contestants: Array(15).fill({
_id: '1',
name: 'test1',
teamName: 'team1',
personalBest: 20,
bronzePoints: 20,
silverPoints: 0,
goldPoints: 0,
platinumPoints: 0,
diamondPoints: 0,
masterPoints: 0,
grandmasterPoints: 0,
}),
},
}
Loading

0 comments on commit 5a2f694

Please sign in to comment.