diff --git a/package.json b/package.json
index b3dfa70..ae9cf80 100644
--- a/package.json
+++ b/package.json
@@ -10,19 +10,20 @@
"test:unit": "vitest",
"build-only": "vite build",
"type-check": "vue-tsc --build --force",
- "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
+ "lint": "yarn lint:eslint && yarn lint:oxlint",
+ "lint:eslint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
+ "lint:oxlint": "oxlint -D perf",
"format": "prettier --write src/"
},
"dependencies": {
"@fontsource/poppins": "^5.0.8",
"@fontsource/roboto": "^5.0.8",
"@vueuse/core": "^10.7.2",
- "@vueuse/rxjs": "^10.7.2",
"less": "^4.2.0",
"pinia": "^2.1.7",
"pocketbase": "^0.21.1",
"rxjs": "^7.8.1",
- "vue": "^3.4.18",
+ "vue": "^3.4.19",
"vue-router": "^4.2.5"
},
"devDependencies": {
@@ -39,6 +40,7 @@
"eslint-plugin-vue": "^9.21.1",
"jsdom": "^24.0.0",
"npm-run-all2": "^6.1.2",
+ "oxlint": "^0.2.8",
"prettier": "^3.2.5",
"typescript": "~5.3.3",
"vite": "^5.1.1",
diff --git a/src/assets/_mixins.less b/src/assets/_mixins.less
index cbf3ab3..687b484 100644
--- a/src/assets/_mixins.less
+++ b/src/assets/_mixins.less
@@ -12,6 +12,10 @@
flex-direction: row;
}
+.center {
+ margin: 0 auto;
+}
+
.flex-center {
align-items: center;
}
@@ -30,6 +34,22 @@
justify-content: space-between;
}
+.flex-even {
+ justify-content: space-around;
+}
+
+.flex-wrap {
+ .flex;
+ flex-wrap: wrap;
+}
+
+.flex-size-even {
+ * {
+ flex: 1;
+ flex-basis: 100%;
+ }
+}
+
.themed(@property, @light, @dark) {
@{property}: @light;
html.dark & {
@@ -67,3 +87,7 @@
.flex-row;
justify-content: end;
}
+
+.text-center {
+ text-align: center;
+}
diff --git a/src/assets/components/buttons.less b/src/assets/components/buttons.less
index d951c99..cff0756 100644
--- a/src/assets/components/buttons.less
+++ b/src/assets/components/buttons.less
@@ -51,15 +51,15 @@ button,
}
&.h2 {
- padding: (@h2-size / 2) (@h2-size * (2 / 3));
+ padding: (@h2-size / 2) @h2-size;
}
&.h3 {
- padding: (@h3-size / 2) (@h3-size * (2 / 3));
+ padding: (@h3-size / 2) @h3-size;
}
&.h4 {
- padding: (@h4-size / 2) (@h4-size * (2 / 3));
+ padding: (@h4-size / 2) @h4-size;
}
header & {
diff --git a/src/assets/main.less b/src/assets/main.less
index 47deb53..23c485b 100644
--- a/src/assets/main.less
+++ b/src/assets/main.less
@@ -23,7 +23,7 @@ body {
ul.no-style {
list-style: none;
list-style-type: none;
- padding-left: 0;
+ padding: 0;
margin-top: 0;
margin-bottom: 0;
}
diff --git a/src/components/AppHeader.vue b/src/components/AppHeader.vue
index fa5783a..481e0ef 100644
--- a/src/components/AppHeader.vue
+++ b/src/components/AppHeader.vue
@@ -2,9 +2,9 @@
diff --git a/src/components/LoggedInHome.vue b/src/components/LoggedInHome.vue
index 9ae10ed..da5b1fb 100644
--- a/src/components/LoggedInHome.vue
+++ b/src/components/LoggedInHome.vue
@@ -1,28 +1,21 @@
- Bonjour {{ pbStore.auth.username }} !
+ Bonjour {{ pbStore.auth.username }} !
-
Campagnes
-
Créer une campagne
-
-
Pas de campagnes pour l’instant
+
Actions
+
Mes campagnes
-
+
+
diff --git a/src/components/LoggedOutHome.vue b/src/components/LoggedOutHome.vue
index e258b41..4eb4412 100644
--- a/src/components/LoggedOutHome.vue
+++ b/src/components/LoggedOutHome.vue
@@ -6,12 +6,12 @@
L'application web pour vous accompagner pour votre JDR avec Gégé, le bot discord.
-
+
Pourquoi ?
- - Accéder à ses fiche personnage
- - Faire évoluer ses personnage
- - Créer ses personnages
+ - Créer ses personnages
+ - Gérer ses fiche personnage
+ - Faire évoluer ses personnage
diff --git a/src/components/SmallCampaignCard.vue b/src/components/SmallCampaignCard.vue
new file mode 100644
index 0000000..6935257
--- /dev/null
+++ b/src/components/SmallCampaignCard.vue
@@ -0,0 +1,30 @@
+
+
+
+ {{ props.campaign.name }}
+
+
+ {{ displayName(props.campaign.expand!.game_master!) }}
+
+
+ -
+ {{ displayName(player) }}
+
+
+
+
+
+
+
+
diff --git a/src/main.ts b/src/main.ts
index a935a7b..8241c25 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -14,9 +14,8 @@ router.beforeEach((to, from, next) => {
const pbStore = usePocketbaseStore();
if (!pbStore.auth.loggedIn && ['home', 'login'].every((path) => path != to.name)) {
next({ name: 'home' });
- } else {
- next();
}
+ next();
});
app.use(createPinia());
diff --git a/src/models/Campaign.ts b/src/models/Campaign.ts
new file mode 100644
index 0000000..49bca5d
--- /dev/null
+++ b/src/models/Campaign.ts
@@ -0,0 +1,20 @@
+import { type RecordModel } from 'pocketbase';
+import { type User } from './User';
+
+interface CampaignDetails {
+ game_master?: User;
+ players?: User[];
+}
+
+export interface Campaign extends RecordModel {
+ expand?: CampaignDetails;
+ game_master: string;
+ name: string;
+ players: string[];
+}
+
+export interface NewCampaign {
+ game_master: string | null;
+ name: string | null;
+ players: string[];
+}
diff --git a/src/models/Character.ts b/src/models/Character.ts
new file mode 100644
index 0000000..046e34b
--- /dev/null
+++ b/src/models/Character.ts
@@ -0,0 +1,48 @@
+import type { RecordModel } from "pocketbase"
+
+interface Effect {
+ name: string,
+ effect: string
+}
+
+interface BaseSkill {
+ name: string,
+ mastery: number,
+}
+
+interface FavourableSkill extends BaseSkill {
+ favourable: boolean
+}
+
+export interface PremadeCharacter extends RecordModel {
+ first_name: string
+ last_name: string
+ age: number
+ heroic_culture: string
+ particularities: string
+ description: string
+ stamina: number
+ hope: number
+ defense: number
+ valour: number
+ wisdom: number
+ rewards: Effect[],
+ virtues: Effect[],
+ travelling_equipment: Effect[],
+ image: string
+ body: number
+ heart: number
+ spirit: number
+ skills: FavourableSkill[]
+ combat_skills: BaseSkill[]
+}
+
+export interface Character extends PremadeCharacter {
+ campaign: string
+ current_stamina: number
+ current_load: number
+ current_fatigue: number
+ current_hope: number
+ status: string
+ user: string
+}
diff --git a/src/models/User.ts b/src/models/User.ts
new file mode 100644
index 0000000..dd46889
--- /dev/null
+++ b/src/models/User.ts
@@ -0,0 +1,20 @@
+import type { RecordModel } from 'pocketbase';
+
+export interface SimpleUser extends RecordModel {
+ username: string;
+ name?: string;
+}
+
+export interface User extends SimpleUser {
+ avatar?: string;
+ email?: string;
+ emailVisibility: boolean;
+ verified: boolean;
+}
+
+export function displayName(user: SimpleUser): string {
+ if (user.name && user.name.trim() !== '') {
+ return user.name;
+ }
+ return user.username;
+}
diff --git a/src/router/index.ts b/src/router/index.ts
index 4af8478..7c0dcdb 100644
--- a/src/router/index.ts
+++ b/src/router/index.ts
@@ -13,6 +13,11 @@ const router = createRouter({
name: 'account',
component: () => import('@/views/AccountView.vue'),
},
+ {
+ path: '/campaigns',
+ name: 'campaigns',
+ component: () => import('@/views/CampaignsView.vue'),
+ },
{
path: '/new-campaign',
name: 'new-campaign',
diff --git a/src/stores/pocketbase.ts b/src/stores/pocketbase.ts
index 6fa3e5c..f7ffa3e 100644
--- a/src/stores/pocketbase.ts
+++ b/src/stores/pocketbase.ts
@@ -3,11 +3,8 @@ import { defineStore } from 'pinia';
import { from, map, Observable, tap } from 'rxjs';
import { computed, ref } from 'vue';
-export interface NewCampaign {
- name: string | null;
- game_master: string | null;
- players: string[] | null;
-}
+import type { Campaign, NewCampaign } from '@/models/Campaign';
+import type { SimpleUser } from '@/models/User';
export const usePocketbaseStore = defineStore('pocketbase', () => {
const pb = new PocketBase(import.meta.env.VITE_PB_URL);
@@ -47,22 +44,15 @@ export const usePocketbaseStore = defineStore('pocketbase', () => {
);
}
- function simpleUserList(): Observable
{
- return from(
- pb.collection('public_users').getFullList({
- sort: 'username',
- })
- );
- }
-
/////////////////////////////////////////////////////////////////////////////
// Campaigns //
/////////////////////////////////////////////////////////////////////////////
- function listCampaigns(): Observable {
+ function listCampaigns(): Observable {
return from(
- pb.collection('campaign').getFullList({
+ pb.collection('campaigns_simple_view').getFullList({
sort: 'name',
+ expand: 'players,game_master',
})
);
}
@@ -71,9 +61,20 @@ export const usePocketbaseStore = defineStore('pocketbase', () => {
return from(pb.collection('campaign').create(campaign));
}
+ /////////////////////////////////////////////////////////////////////////////
+ // Users //
+ /////////////////////////////////////////////////////////////////////////////
+
+ function allUsersSimple(): Observable {
+ return from(
+ pb.collection('public_users').getFullList({
+ sort: 'username',
+ })
+ );
+ }
+
return {
auth: {
- authData,
authStore,
loggedIn,
username,
@@ -88,7 +89,7 @@ export const usePocketbaseStore = defineStore('pocketbase', () => {
createCampaign,
},
users: {
- simpleUserList,
+ allUsersSimple,
},
};
});
diff --git a/src/views/CampaignsView.vue b/src/views/CampaignsView.vue
new file mode 100644
index 0000000..d945496
--- /dev/null
+++ b/src/views/CampaignsView.vue
@@ -0,0 +1,61 @@
+
+ Campagnes
+
+
+ Créer une campagne
+
+
Campagnes que je gère
+
+
+
+
Pas de campagne pour l’instant
+
+
+
+
Campagnes où je joue
+
+
+
Pas de campagne pour l’instant
+
+
+
+
+
diff --git a/src/views/CreateCampaignView.vue b/src/views/CreateCampaignView.vue
index fd7663f..7b6b3f2 100644
--- a/src/views/CreateCampaignView.vue
+++ b/src/views/CreateCampaignView.vue
@@ -1,9 +1,6 @@
Création d’une campagne
-
- {{ campaign.name }}
-
-