Compare commits
No commits in common. "master" and "logout-button" have entirely different histories.
master
...
logout-but
15 changed files with 364 additions and 264 deletions
|
|
@ -1,6 +1,5 @@
|
||||||
POSTGRES_PORT=5432
|
POSTGRES_PORT=5432
|
||||||
EXPRESS_PORT=3000
|
EXPRESS_PORT=3000
|
||||||
FRONTEND_PORT=8080
|
|
||||||
|
|
||||||
POSTGRES_USER=postgres
|
POSTGRES_USER=postgres
|
||||||
POSTGRES_PASSWORD=postgres
|
POSTGRES_PASSWORD=postgres
|
||||||
|
|
|
||||||
183
README.md
183
README.md
|
|
@ -1,30 +1,163 @@
|
||||||
# RaspberryRocketeer
|
# RaspberryRocketeer
|
||||||
|
|
||||||
## How to run
|
## Class Diagram of all classes
|
||||||
|
|
||||||
### Copy .env
|
```mermaid
|
||||||
First you need to copy the `.env.example`.
|
classDiagram
|
||||||
|
direction BT
|
||||||
|
class Collidable {
|
||||||
|
collides(o: Entity) boolean
|
||||||
|
}
|
||||||
|
class Database {
|
||||||
|
any _db
|
||||||
|
any db
|
||||||
|
}
|
||||||
|
class Entity {
|
||||||
|
constructor(position: Position, width: number, height: number, fill: number)
|
||||||
|
Position _position
|
||||||
|
number _width
|
||||||
|
number _height
|
||||||
|
number fill
|
||||||
|
boolean _showHitbox
|
||||||
|
update() void
|
||||||
|
draw() void
|
||||||
|
Position position
|
||||||
|
number width
|
||||||
|
number height
|
||||||
|
boolean showHitbox
|
||||||
|
}
|
||||||
|
class Game {
|
||||||
|
number id
|
||||||
|
number score
|
||||||
|
string playtime
|
||||||
|
Date date
|
||||||
|
number userId
|
||||||
|
}
|
||||||
|
class GamePgPromiseRepository {
|
||||||
|
insert(game: Game) Promise~Game~
|
||||||
|
serialize(raw: any) Game
|
||||||
|
}
|
||||||
|
class GameRepository {
|
||||||
|
insert(game: Game) Promise~Game~
|
||||||
|
}
|
||||||
|
class HighscoreLeaderboard
|
||||||
|
class HighscoreLeaderboardPgPromiseRepository {
|
||||||
|
getAll() Promise~HighscoreLeaderboard~
|
||||||
|
serialize(raw: any) HighscoreLeaderboard
|
||||||
|
}
|
||||||
|
class HighscoreLeaderboardRepository {
|
||||||
|
getAll() Promise~HighscoreLeaderboard~
|
||||||
|
}
|
||||||
|
class Leaderboard
|
||||||
|
class LeaderboardEntry {
|
||||||
|
number username
|
||||||
|
number rank
|
||||||
|
T score
|
||||||
|
}
|
||||||
|
class Obstacle {
|
||||||
|
constructor(position: Position, obstacleWidth: number, obstacleHeight: number, pipeImagePath: string)
|
||||||
|
Pipe pipeTop
|
||||||
|
Pipe pipeBottom
|
||||||
|
number padding
|
||||||
|
number speed
|
||||||
|
number _distanceBetweenPipes
|
||||||
|
number _startX
|
||||||
|
resetPosition() void
|
||||||
|
randomizeHeight() void
|
||||||
|
randomRange(min: number, max: number) number
|
||||||
|
update() void
|
||||||
|
draw() void
|
||||||
|
collides(o: Entity) boolean
|
||||||
|
any startX
|
||||||
|
any distanceBetweenPipes
|
||||||
|
}
|
||||||
|
class Pipe {
|
||||||
|
constructor(positionX: number, width: number, height: number)
|
||||||
|
any _image
|
||||||
|
update() void
|
||||||
|
draw() void
|
||||||
|
move(speed: number) void
|
||||||
|
collides(o: Entity) boolean
|
||||||
|
any image
|
||||||
|
}
|
||||||
|
class Position {
|
||||||
|
constructor(x: number, y: number)
|
||||||
|
number _x
|
||||||
|
number _y
|
||||||
|
number x
|
||||||
|
number y
|
||||||
|
}
|
||||||
|
class Raspberry {
|
||||||
|
constructor(image: string)
|
||||||
|
number lift
|
||||||
|
number gravity
|
||||||
|
number _velocity
|
||||||
|
any _image
|
||||||
|
Position position
|
||||||
|
number maxVelocity
|
||||||
|
number WIDTH
|
||||||
|
number HEIGHT
|
||||||
|
number FILL
|
||||||
|
update() void
|
||||||
|
applyGravity() void
|
||||||
|
forceBoundaries() void
|
||||||
|
boost() void
|
||||||
|
draw() void
|
||||||
|
number velocity
|
||||||
|
any image
|
||||||
|
}
|
||||||
|
class TimeLeaderboard
|
||||||
|
class TimeLeaderboardPgPromiseRepository {
|
||||||
|
getAll() Promise~TimeLeaderboard~
|
||||||
|
serialize(raw: any) TimeLeaderboard
|
||||||
|
}
|
||||||
|
class TimeLeaderboardRepository {
|
||||||
|
getAll() Promise~TimeLeaderboard~
|
||||||
|
}
|
||||||
|
class User {
|
||||||
|
number id
|
||||||
|
string name
|
||||||
|
}
|
||||||
|
class UserPgPromiseRepository {
|
||||||
|
getById(id: number) Promise~User~
|
||||||
|
getByName(name: string) Promise~User~
|
||||||
|
withIdExists(id: number) Promise~boolean~
|
||||||
|
withNameExists(name: string) Promise~boolean~
|
||||||
|
insert(user: Omit~User, "id"~) Promise~User~
|
||||||
|
serialize(raw: any) User
|
||||||
|
}
|
||||||
|
class UserRepository {
|
||||||
|
getById(id: number) Promise~User~
|
||||||
|
getByName(name: string) Promise~User~
|
||||||
|
withIdExists(userId: number) Promise~boolean~
|
||||||
|
withNameExists(username: string) Promise~boolean~
|
||||||
|
insert(user: Omit~User, "id"~) Promise~User~
|
||||||
|
}
|
||||||
|
class UserScores {
|
||||||
|
number userId
|
||||||
|
number highscore
|
||||||
|
number totalScore
|
||||||
|
string totalPlaytime
|
||||||
|
number averageScore
|
||||||
|
number gamesPlayed
|
||||||
|
}
|
||||||
|
class UserScoresPgPromiseRepository {
|
||||||
|
getById(id: number) Promise~UserScores~
|
||||||
|
serialize(raw: any) UserScores
|
||||||
|
}
|
||||||
|
class UserScoresRepository {
|
||||||
|
getById(userId: number) Promise~UserScores~
|
||||||
|
}
|
||||||
|
|
||||||
|
GamePgPromiseRepository --> GameRepository
|
||||||
|
HighscoreLeaderboardPgPromiseRepository --> HighscoreLeaderboardRepository
|
||||||
|
Obstacle ..> Collidable
|
||||||
|
Obstacle --> Entity
|
||||||
|
Pipe ..> Collidable
|
||||||
|
Pipe --> Entity
|
||||||
|
Raspberry --> Entity
|
||||||
|
TimeLeaderboardPgPromiseRepository --> TimeLeaderboardRepository
|
||||||
|
UserPgPromiseRepository --> UserRepository
|
||||||
|
UserScoresPgPromiseRepository --> UserScoresRepository
|
||||||
|
|
||||||
```shell
|
|
||||||
cp .env.example .env
|
|
||||||
```
|
```
|
||||||
|
|
||||||
<small>Note: It is recommended to change the values for the database user.</small>
|
|
||||||
|
|
||||||
### Install node packages
|
|
||||||
Go into the frontend folder using
|
|
||||||
```shell
|
|
||||||
cd frontend
|
|
||||||
```
|
|
||||||
and run:
|
|
||||||
```shell
|
|
||||||
npm install
|
|
||||||
```
|
|
||||||
|
|
||||||
### Start the container (in the project root)
|
|
||||||
|
|
||||||
```shell
|
|
||||||
docker compose up --build
|
|
||||||
```
|
|
||||||
|
|
||||||
You can then access the website on `localhost:8080`
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ export class HighscoreLeaderboardPgPromiseRepository extends HighscoreLeaderboar
|
||||||
|
|
||||||
async getPage(entriesPerPage, page): Promise<HighscoreLeaderboard> {
|
async getPage(entriesPerPage, page): Promise<HighscoreLeaderboard> {
|
||||||
const raw: any = await Database.db.manyOrNone(
|
const raw: any = await Database.db.manyOrNone(
|
||||||
'SELECT * FROM lb_highscore INNER JOIN "user" ON user_id = id ORDER BY rank LIMIT $1 OFFSET $2;',
|
'SELECT * FROM lb_highscore INNER JOIN "user" ON user_id = id ORDER BY rank LIMIT $1 OFFSET $2*$1;',
|
||||||
[entriesPerPage, page * entriesPerPage]
|
[entriesPerPage, page * entriesPerPage]
|
||||||
);
|
);
|
||||||
return this.serialize(raw);
|
return this.serialize(raw);
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ export class TimeLeaderboardPgPromiseRepository extends TimeLeaderboardRepositor
|
||||||
|
|
||||||
async getPage(entriesPerPage: number, page: number): Promise<TimeLeaderboard> {
|
async getPage(entriesPerPage: number, page: number): Promise<TimeLeaderboard> {
|
||||||
const raw: any = await Database.db.manyOrNone(
|
const raw: any = await Database.db.manyOrNone(
|
||||||
'SELECT * FROM lb_total_playtime INNER JOIN "user" ON user_id = id ORDER BY rank LIMIT $1 OFFSET $2;',
|
'SELECT * FROM lb_total_playtime INNER JOIN "user" ON user_id = id ORDER BY rank LIMIT $1 OFFSET $2*$1;',
|
||||||
[entriesPerPage, page * entriesPerPage]
|
[entriesPerPage, page * entriesPerPage]
|
||||||
);
|
);
|
||||||
return this.serialize(raw);
|
return this.serialize(raw);
|
||||||
|
|
|
||||||
40
backend/db/initScripts/loadMockData.sql
Normal file
40
backend/db/initScripts/loadMockData.sql
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
insert into "user" (name) values ('dpettus0');
|
||||||
|
insert into "user" (name) values ('egreetland1');
|
||||||
|
insert into "user" (name) values ('smontford2');
|
||||||
|
insert into "user" (name) values ('idagwell3');
|
||||||
|
insert into "user" (name) values ('lgagan4');
|
||||||
|
insert into "user" (name) values ('acarmont5');
|
||||||
|
insert into "user" (name) values ('kjermyn6');
|
||||||
|
insert into "user" (name) values ('dokieran7');
|
||||||
|
insert into "user" (name) values ('pdrinkel8');
|
||||||
|
|
||||||
|
insert into game (user_id, score, playtime, date) values ('1', 74, '19:59', '2022-07-19');
|
||||||
|
insert into game (user_id, score, playtime, date) values ('1', 86, '20:32', '2022-11-24');
|
||||||
|
insert into game (user_id, score, playtime, date) values ('1', 68, '10:41', '2022-03-24');
|
||||||
|
insert into game (user_id, score, playtime, date) values ('2', 39, '5:55', '2022-06-01');
|
||||||
|
insert into game (user_id, score, playtime, date) values ('2', 20, '9:23', '2022-03-12');
|
||||||
|
insert into game (user_id, score, playtime, date) values ('2', 28, '23:45', '2022-04-01');
|
||||||
|
insert into game (user_id, score, playtime, date) values ('2', 44, '18:43', '2022-06-24');
|
||||||
|
insert into game (user_id, score, playtime, date) values ('3', 92, '14:54', '2022-11-06');
|
||||||
|
insert into game (user_id, score, playtime, date) values ('3', 73, '0:45', '2022-07-26');
|
||||||
|
insert into game (user_id, score, playtime, date) values ('3', 27, '2:49', '2022-02-03');
|
||||||
|
insert into game (user_id, score, playtime, date) values ('4', 26, '2:32', '2022-07-19');
|
||||||
|
insert into game (user_id, score, playtime, date) values ('4', 12, '17:03', '2022-04-25');
|
||||||
|
insert into game (user_id, score, playtime, date) values ('4', 6, '8:49', '2021-12-03');
|
||||||
|
insert into game (user_id, score, playtime, date) values ('4', 22, '22:27', '2022-03-02');
|
||||||
|
insert into game (user_id, score, playtime, date) values ('5', 94, '1:04', '2022-10-19');
|
||||||
|
insert into game (user_id, score, playtime, date) values ('5', 2, '2:14', '2022-04-06');
|
||||||
|
insert into game (user_id, score, playtime, date) values ('5', 21, '17:18', '2022-06-03');
|
||||||
|
insert into game (user_id, score, playtime, date) values ('6', 33, '16:01', '2022-02-02');
|
||||||
|
insert into game (user_id, score, playtime, date) values ('6', 27, '7:03', '2022-02-06');
|
||||||
|
insert into game (user_id, score, playtime, date) values ('6', 62, '0:45', '2022-11-15');
|
||||||
|
insert into game (user_id, score, playtime, date) values ('7', 12, '8:54', '2022-06-29');
|
||||||
|
insert into game (user_id, score, playtime, date) values ('7', 63, '16:01', '2022-11-05');
|
||||||
|
insert into game (user_id, score, playtime, date) values ('7', 29, '0:46', '2022-10-01');
|
||||||
|
insert into game (user_id, score, playtime, date) values ('8', 67, '1:27', '2022-09-29');
|
||||||
|
insert into game (user_id, score, playtime, date) values ('8', 84, '10:37', '2021-12-18');
|
||||||
|
insert into game (user_id, score, playtime, date) values ('8', 14, '19:14', '2022-01-31');
|
||||||
|
insert into game (user_id, score, playtime, date) values ('9', 21, '19:04', '2022-03-08');
|
||||||
|
insert into game (user_id, score, playtime, date) values ('9', 46, '2:34', '2022-04-18');
|
||||||
|
insert into game (user_id, score, playtime, date) values ('9', 78, '9:33', '2022-09-10');
|
||||||
|
insert into game (user_id, score, playtime, date) values ('9', 82, '11:19', '2022-11-29');
|
||||||
|
|
@ -21,12 +21,3 @@ services:
|
||||||
ports:
|
ports:
|
||||||
- "${EXPRESS_PORT}:3000"
|
- "${EXPRESS_PORT}:3000"
|
||||||
|
|
||||||
vue:
|
|
||||||
build: frontend
|
|
||||||
container_name: frontend
|
|
||||||
ports:
|
|
||||||
- "${FRONTEND_PORT}:8080"
|
|
||||||
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
- ./frontend:/app
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
node_modules
|
|
||||||
.gitignore
|
|
||||||
README.md
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
FROM node:18
|
|
||||||
|
|
||||||
COPY . /app
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
RUN npm install
|
|
||||||
|
|
||||||
EXPOSE 8080
|
|
||||||
|
|
||||||
ENTRYPOINT ["npm", "run", "serve"]
|
|
||||||
|
|
||||||
|
|
@ -10,11 +10,11 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bootstrap": "^5.2.3",
|
"bootstrap": "^5.2.3",
|
||||||
"vue": "^3.2.13",
|
"vue": "^3.2.13"
|
||||||
"@vue/cli-service": "~5.0.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vue/cli-plugin-typescript": "~5.0.0",
|
"@vue/cli-plugin-typescript": "~5.0.0",
|
||||||
|
"@vue/cli-service": "~5.0.0",
|
||||||
"typescript": "~4.5.5"
|
"typescript": "~4.5.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -153,9 +153,6 @@ function collisionCheck(o){
|
||||||
}
|
}
|
||||||
|
|
||||||
function die() {
|
function die() {
|
||||||
if(localStorage.getItem("frontend-ready") == "false")
|
|
||||||
return;
|
|
||||||
|
|
||||||
ready = false;
|
ready = false;
|
||||||
hasDied = true;
|
hasDied = true;
|
||||||
playTime = Date.now() - startTime;
|
playTime = Date.now() - startTime;
|
||||||
|
|
@ -208,15 +205,14 @@ function checkRaspberryScore(){
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetScore() {
|
function resetScore() {
|
||||||
if(!hasDied || localStorage.getItem("frontend-ready") == "false")
|
if (hasDied) {
|
||||||
return;
|
|
||||||
|
|
||||||
hasDied = false;
|
hasDied = false;
|
||||||
score = 0;
|
score = 0;
|
||||||
hasAlreadyScored = false;
|
hasAlreadyScored = false;
|
||||||
startTime = Date.now();
|
startTime = Date.now();
|
||||||
exportToLocalStorage();
|
exportToLocalStorage();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function keyPressed() {
|
function keyPressed() {
|
||||||
if (!ready)
|
if (!ready)
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
<Login v-if="!user" @userChange="(event) => {this.updateUser(event);}">
|
<Login v-if="!user" @userChange="(event) => {this.updateUser(event);}">
|
||||||
</Login>
|
</Login>
|
||||||
<div v-if="user" class="logout-wrapper offset-10 col-2">
|
<div v-if="user" class="logout-wrapper offset-10 col-2">
|
||||||
<RRButton @click="logOut()" text="Logout"></RRButton>
|
<RRButton @click="this.user = null; this.userId = -1;" text="Logout"></RRButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
@ -59,9 +59,7 @@ export default defineComponent({
|
||||||
leaderboardEvent: new Event('reloadLeaderboard')
|
leaderboardEvent: new Event('reloadLeaderboard')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
|
||||||
localStorage.setItem("frontend-ready", "false");
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
async fetchFromApi(path: string, method: "GET" | "POST") {
|
async fetchFromApi(path: string, method: "GET" | "POST") {
|
||||||
|
|
@ -82,12 +80,6 @@ export default defineComponent({
|
||||||
await this.updateUserScores();
|
await this.updateUserScores();
|
||||||
}
|
}
|
||||||
window.dispatchEvent(this.leaderboardEvent);
|
window.dispatchEvent(this.leaderboardEvent);
|
||||||
},
|
|
||||||
logOut(){
|
|
||||||
this.user = null;
|
|
||||||
this.userId = -1;
|
|
||||||
this.userScores = {};
|
|
||||||
localStorage.setItem('frontend-ready', 'false');
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
@ -107,11 +99,9 @@ export default defineComponent({
|
||||||
.everything {
|
.everything {
|
||||||
margin-bottom: 4em;
|
margin-bottom: 4em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hidden {
|
.hidden {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logout-wrapper {
|
.logout-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: right;
|
justify-content: right;
|
||||||
|
|
|
||||||
|
|
@ -58,9 +58,3 @@ export default {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
|
||||||
#p5_loading {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -9,12 +9,9 @@
|
||||||
<RRButton @click="nextPage" text=">"></RRButton>
|
<RRButton @click="nextPage" text=">"></RRButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row" v-if="this.page.length > 0" v-for="entry in this.page" :key="entry.rank">
|
<div class="row" v-for="entry in this.page" :key="entry.rank">
|
||||||
<LeaderboardEntry :entry="entry"></LeaderboardEntry>
|
<LeaderboardEntry :entry="entry"></LeaderboardEntry>
|
||||||
</div>
|
</div>
|
||||||
<div class="row" v-else>
|
|
||||||
Loading...
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -42,7 +39,11 @@ export default {
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.updatePage();
|
this.updatePage();
|
||||||
window.addEventListener('itemInserted', event => this.onItemInserted(event), false);
|
window.addEventListener('itemInserted', (event) => {
|
||||||
|
if (event.key === 'game-isRunning' && event.value === 'false'){
|
||||||
|
this.updatePage();
|
||||||
|
}
|
||||||
|
}, false)
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async fetchPage() {
|
async fetchPage() {
|
||||||
|
|
@ -52,33 +53,21 @@ export default {
|
||||||
title() {
|
title() {
|
||||||
return this.type === "totalplaytime" ? "Total Playtime" : "Highscore";
|
return this.type === "totalplaytime" ? "Total Playtime" : "Highscore";
|
||||||
},
|
},
|
||||||
async nextPage() {
|
nextPage() {
|
||||||
if (this.page.length !== this.entriesPerPage) return;
|
|
||||||
|
|
||||||
this.pageNumber++;
|
this.pageNumber++;
|
||||||
await this.updatePage();
|
this.updatePage();
|
||||||
if (this.page.length === 0) {
|
|
||||||
this.prevPage();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
prevPage() {
|
prevPage() {
|
||||||
if (this.pageNumber <= 0) return;
|
if (this.pageNumber > 0) this.pageNumber--;
|
||||||
|
|
||||||
this.pageNumber--;
|
|
||||||
this.updatePage();
|
this.updatePage();
|
||||||
},
|
},
|
||||||
async updatePage() {
|
async updatePage() {
|
||||||
let tempPage = await this.fetchPage();
|
let tempPage = await this.fetchPage();
|
||||||
for (let i = 0; i < this.entriesPerPage; i++) {
|
for (let i = 0; i < this.entriesPerPage; i++) {
|
||||||
this.page.pop();
|
this.page.pop()
|
||||||
}
|
}
|
||||||
for (const entry of tempPage) {
|
for (const entry of tempPage) {
|
||||||
this.page.push(entry);
|
this.page.push(entry)
|
||||||
}
|
|
||||||
},
|
|
||||||
onItemInserted(event) {
|
|
||||||
if (event.key === 'game-isRunning' && event.value === 'false') {
|
|
||||||
this.updatePage();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,17 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="col-1 text-right">{{this.entry.rank}}</div>
|
<div class="col-1 text-left">{{this.entry.rank}}</div>
|
||||||
<span class="col offset-1 text-left username">{{this.entry.username}}</span>
|
<div class="col text-left">{{this.entry.username}}</div>
|
||||||
<div class="col-2 text-right">{{this.entry.score}}</div>
|
<div class="col text-right">{{this.entry.score}}</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {defineComponent, PropType} from 'vue';
|
import {defineComponent} from 'vue';
|
||||||
import {Leaderboard, LeaderboardEntry} from "@/model/Leaderboard";
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "LeaderboardEntry",
|
name: "LeaderboardEntry",
|
||||||
props: {
|
props: {
|
||||||
entry: {
|
entry: {
|
||||||
type: Object as PropType<LeaderboardEntry<string>>,
|
type: Object,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -23,9 +22,4 @@ export default defineComponent({
|
||||||
* {
|
* {
|
||||||
font-size: 1.5em;
|
font-size: 1.5em;
|
||||||
}
|
}
|
||||||
.username {
|
|
||||||
overflow: hidden;
|
|
||||||
white-space: nowrap;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<h2>Enter a username</h2>
|
<h2>Enter a username</h2>
|
||||||
<div class="form-floating mb-3">
|
<div class="form-floating mb-3">
|
||||||
<input class="form-control" id="floatingInput" placeholder="example name" v-model="username">
|
<input type="email" class="form-control" id="floatingInput" placeholder="example name" v-model="username">
|
||||||
<label for="floatingInput">Username</label>
|
<label for="floatingInput">Username</label>
|
||||||
<RRButton @click="setUser()" text="Confirm"></RRButton>
|
<RRButton @click="setUser()" text="Confirm"></RRButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -19,13 +19,12 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
username: '',
|
username: '',
|
||||||
|
user: null,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['userChange'],
|
emits: ['userChange'],
|
||||||
methods: {
|
methods: {
|
||||||
async setUser() {
|
async setUser() {
|
||||||
if (this.username === '') return;
|
|
||||||
|
|
||||||
let user;
|
let user;
|
||||||
user = await User.getByName(this.username);
|
user = await User.getByName(this.username);
|
||||||
if (user.errors) {
|
if (user.errors) {
|
||||||
|
|
@ -38,7 +37,8 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
this.$emit('userChange', user);
|
this.user = user;
|
||||||
|
this.$emit('userChange', this.user);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -48,18 +48,6 @@ export default {
|
||||||
<style scoped>
|
<style scoped>
|
||||||
input {
|
input {
|
||||||
border: 3px solid black;
|
border: 3px solid black;
|
||||||
border-radius: 0;
|
|
||||||
background-color: beige;
|
background-color: beige;
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
input:focus {
|
|
||||||
background: beige;
|
|
||||||
border-color: rgba(184,134,11, 0.8);
|
|
||||||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 8px rgba(184,134,11, 0.6);
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue