Skip to content

Commit

Permalink
Merge pull request #7 from krazkidd/emote
Browse files Browse the repository at this point in the history
  • Loading branch information
krazkidd authored Sep 29, 2023
2 parents 45c9874 + 6f09af5 commit 5fc0237
Show file tree
Hide file tree
Showing 130 changed files with 16,454 additions and 21 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ License: AGPLv3 (see LICENSE.md file)
* Lock the lineup
* Only field positions can be changed after locking
* Live (real time) scoreboard which can be accessed by friends through a URL
* React with emojis!
* Customizable team colors
* Dark mode

Expand Down Expand Up @@ -74,4 +75,6 @@ An app spec is available under `.do/` which will run the SSG command and publish

## Attributions

The softball favicon (`public/favicon/favicon.ico`) is used under the [CC-BY 4.0](https://creativecommons.org/licenses/by/4.0/) license from the [twemoji](https://github.com/twitter/twemoji) project.
The softball favicon (`public/favicon/favicon.ico`) is used under the [CC-BY 4.0](https://creativecommons.org/licenses/by/4.0/) license from the [twemoji](https://github.com/twitter/twemoji) project.

The emoji images (`assets/images/fluentui-emoji`) are used under the MIT license (`assets/images/fluentui-emoji/LICENSE`) from the [Fluent Emoji](https://github.com/microsoft/fluentui-emoji) project.
2 changes: 1 addition & 1 deletion app.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { navMenuItems, homeMenuItem } from '~~/nav'
import { navMenuItems, homeMenuItem } from '~~/data/nav'
const colorMode = useColorMode();
Expand Down
18 changes: 18 additions & 0 deletions components/scoreboard/ScoreboardEmojiBoard.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<script setup lang="ts">
import { emojis } from '~~/data/emoji';
const emit = defineEmits<{
(e: "emote", payload: string): void;
}>();
</script>

<template>
<div class="grid grid-cols-4 md:grid-cols-8 lg:grid-cols-10 justify-items-center md:w-128 gap-1">
<ScoreboardEmojiButton
v-for="emoji of emojis"
:key="emoji"
:id="emoji"
@emote="emit('emote', $event)"
/>
</div>
</template>
23 changes: 23 additions & 0 deletions components/scoreboard/ScoreboardEmojiButton.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<script setup lang="ts">
import { emojiTitles } from '~~/data/emoji';
const props = defineProps<{
id: string
}>();
const emit = defineEmits<{
(e: "emote", payload: string): void;
}>();
const emojiTitle = computed(() => emojiTitles[props.id]);
</script>

<template>
<button type="button" @click="emit('emote', props.id)" class="mb-2">
<img
:src="`/lineup/images/fluentui-emoji/${props.id}_color.svg`"
:alt="emojiTitle"
:title="emojiTitle"
/>
</button>
</template>
2 changes: 1 addition & 1 deletion components/scoreboard/ScoreboardShareButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import type { ButtonPassThroughOptions } from 'primevue/button';
import { useToast } from "primevue/usetoast";
import { scoreboardMenuItem } from '~~/nav';
import { scoreboardMenuItem } from '~~/data/nav';
import type { ID, Team } from '~~/types';
const toast = useToast();
Expand Down
131 changes: 131 additions & 0 deletions data/emoji.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
const titularizeRegex = new RegExp(/[_-]/g);

export const emojis = [
'angry_face',
'angry_face_with_horns',
'anguished_face',
'anxious_face_with_sweat',
'astonished_face',
'beaming_face_with_smiling_eyes',
'clown_face',
'cold_face',
'confounded_face',
'confused_face',
'cowboy_hat_face',
'crying_face',
'disappointed_face',
'disguised_face',
'dotted_line_face',
'downcast_face_with_sweat',
'drooling_face',
'exploding_head',
'expressionless_face',
'face_blowing_a_kiss',
'face_exhaling',
'face_holding_back_tears',
'face_savoring_food',
'face_screaming_in_fear',
'face_vomiting',
'face_with_diagonal_mouth',
'face_with_hand_over_mouth',
'face_with_head-bandage',
'face_with_monocle',
'face_with_open_eyes_and_hand_over_mouth',
'face_with_open_mouth',
'face_without_mouth',
'face_with_peeking_eye',
'face_with_raised_eyebrow',
'face_with_rolling_eyes',
'face_with_spiral_eyes',
'face_with_steam_from_nose',
'face_with_symbols_on_mouth',
'face_with_tears_of_joy',
'face_with_thermometer',
'face_with_tongue',
'fearful_face',
'flushed_face',
'frowning_face',
'frowning_face_with_open_mouth',
'grimacing_face',
'grinning_face',
'grinning_face_with_smiling_eyes',
'grinning_face_with_sweat',
'grinning_squinting_face',
'hot_face',
'hugging_face',
'hushed_face',
'kissing_face_with_closed_eyes',
'kissing_face_with_smiling_eyes',
'knocked-out_face',
'loudly_crying_face',
'melting_face',
'nerd_face',
'neutral_face',
'partying_face',
'pensive_face',
'pleading_face',
'relieved_face',
'sad_but_relieved_face',
'shushing_face',
'sleeping_face',
'sleepy_face',
'slightly_frowning_face',
'slightly_smiling_face',
'smiling_face',
'smiling_face_with_halo',
'smiling_face_with_heart-eyes',
'smiling_face_with_hearts',
'smiling_face_with_horns',
'smiling_face_with_smiling_eyes',
'smiling_face_with_sunglasses',
'smiling_face_with_tear',
'smirking_face',
'squinting_face_with_tongue',
'thinking_face',
'tired_face',
'unamused_face',
'upside-down_face',
'weary_face',
'winking_face',
'winking_face_with_tongue',
'worried_face',
'yawning_face',
'zany_face',
'zipper-mouth_face',
'rolling_on_the_floor_laughing',
'star-struck',

'sun_with_face',
'full_moon_face',
'new_moon_face',

'cat_face',
'cow_face',
'dog_face',
'fox',
'frog',
'monkey_face',
'panda',
'pig_face',
'tiger_face',

'alien',

'bat',
'ghost',
'jack-o-lantern',

'red_heart',
'sparkling_heart',

'party_popper',
'pile_of_poo',

'softball',
];

export const emojiTitles: any = {};

emojis.forEach(emoji => {
emojiTitles[emoji] = emoji.replace(titularizeRegex, ' ');
});
File renamed without changes.
54 changes: 54 additions & 0 deletions db/Emotes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import {
Firestore,
CollectionReference,
DocumentData,

query,
where,
orderBy,

collection,
onSnapshot,

addDoc,
} from 'firebase/firestore';

import type { ID, Emote } from '~~/types';

let _db: Firestore;
let _collRef: CollectionReference<Emote>;

export async function getEmotes(db: Firestore) {
_db = db;

_collRef = collection(_db, 'emotes').withConverter<Emote, DocumentData>({
fromFirestore: (snapshot) => {
// Here you could do validation with a library like zod
return snapshot.data(
// this avoids having `null` while the server timestamp is updating
{ serverTimestamps: 'estimate' }
) as any
},
toFirestore: (data) => data,
});

return _collRef;
}

export function addEmote(emote: Emote) {
return addDoc(_collRef, emote);
}

export function getRecentEmotes(teamId: ID) {
return query(_collRef, where("teamId", "==", teamId), where("ticks", ">", Date.now()), orderBy("ticks"));
}

export function subscribeToNewEmotes(teamId: ID, callbackFn: Function) {
return onSnapshot(getRecentEmotes(teamId), (snapshot) => {
snapshot.docChanges().forEach((change) => {
if (change.type === "added") {
callbackFn(change.doc.data());
}
});
});
}
5 changes: 2 additions & 3 deletions db/Lineup.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import {
Firestore,
DocumentReference,
DocumentData,

doc,
getDoc,
setDoc,
updateDoc,

DocumentData,
DocumentReference,
} from 'firebase/firestore';

import type { ID, Lineup, Spot } from '~~/types';
Expand Down
5 changes: 2 additions & 3 deletions db/Scoreboard.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import {
Firestore,
DocumentReference,
DocumentData,

doc,
getDoc,
setDoc,
updateDoc,

DocumentData,
DocumentReference,

increment,
} from 'firebase/firestore';

Expand Down
5 changes: 2 additions & 3 deletions db/Team.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import {
Firestore,
DocumentReference,
DocumentData,

doc,
getDoc,
setDoc,
updateDoc,

DocumentData,
DocumentReference,
} from 'firebase/firestore';

import type { ID, Team } from '~~/types';
Expand Down
10 changes: 10 additions & 0 deletions firestore.rules
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ service cloud.firestore {
&& request.resource.data.otherTeamScore is int;
}

match /emotes/{id} {
allow read;
// only allow writing Scoreboard type
allow write:
if request.resource.data.size() == 3
&& request.resource.data.teamId is string
&& request.resource.data.emote is string
&& request.resource.data.ticks is int;
}

// forbid everything else
match /{document=**} {
allow read, write: if false;
Expand Down
7 changes: 6 additions & 1 deletion pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@
<li>Only field positions can be changed after locking</li>
</ul>
</li>
<li>Live (real time) scoreboard which can be accessed by friends through a URL</li>
<li>
Live (real time) scoreboard which can be accessed by friends through a URL
<ul>
<li>React with emojis!</li>
</ul>
</li>
<li>Customizable team colors</li>
<li>Dark mode</li>
</ul>
Expand Down
Loading

0 comments on commit 5fc0237

Please sign in to comment.