Skip to content

Commit

Permalink
feat: first block of work on entry list editor complete
Browse files Browse the repository at this point in the history
  • Loading branch information
Stoolbend committed Feb 17, 2024
1 parent 10c1ee3 commit 511336d
Show file tree
Hide file tree
Showing 8 changed files with 401 additions and 52 deletions.
106 changes: 106 additions & 0 deletions src/components/DriverEntryInlineForm.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<script lang="ts" setup>
import { DriverCategories } from '@/lib/gameData'
import type { EntryListDriver } from '@/lib/gameFiles'
import { formatPlayerId, getPlatformClass, parsePlayerId } from '@/lib/utils'
import { useDriverStore } from '@/stores/drivers'
import { PlatformOptionsSmall } from '@/stores/settings'
import type { SelectOption } from 'bootstrap-vue-next'
import { cloneDeep } from 'lodash-es'
import { onMounted } from 'vue'
import { computed, reactive, watchEffect } from 'vue'
const driverStore = useDriverStore()
const driver = defineModel<EntryListDriver>()
// #region Category
const driverCategoryOptions = computed(() => {
const options = [
{
value: '',
text: 'No category',
},
] as SelectOption[]
for (const category of DriverCategories) {
options.push({ value: category.value, text: category.name })
}
return options
})
// #endregion
// #region Player ID formatting
const playerIdForm = reactive({
id: '',
platform: cloneDeep(driverStore.defaultPlatform),
})
function onPlayerIdUpdated() {
if (!driver.value) return
driver.value.playerID = formatPlayerId(playerIdForm.id, playerIdForm.platform)
}
// #endregion
watchEffect(() => {
if (driver.value) {
// Remove blank properties
if (driver.value.firstName == '') delete driver.value.firstName
if (driver.value.lastName == '') delete driver.value.lastName
if (driver.value.shortName == '') delete driver.value.shortName
if (driver.value.driverCategory?.toString() == '') delete driver.value.driverCategory
}
})
onMounted(() => {
if (driver.value) {
const parsedId = parsePlayerId(driver.value.playerID, playerIdForm.platform)
playerIdForm.id = parsedId.playerId
playerIdForm.platform = parsedId.platform
}
})
</script>

<template>
<div v-if="driver" class="driver-entry-inline row">
<div class="col-4">
<b-input-group>
<template #prepend>
<b-form-select
v-model="playerIdForm.platform"
id="platform-select"
:class="`platform-select ${getPlatformClass(playerIdForm.platform)}`"
:options="PlatformOptionsSmall"
size="sm"
@update:model-value="onPlayerIdUpdated"
/>
</template>
<b-form-input v-model="playerIdForm.id" type="text" id="id" required size="sm" placeholder="Player ID" @update:model-value="onPlayerIdUpdated" />
</b-input-group>
</div>
<div class="col-5">
<b-input-group>
<b-form-input v-model="driver.firstName" type="text" id="first-name" size="sm" placeholder="First name" />
<b-form-input v-model="driver.lastName" type="text" id="last-name" size="sm" placeholder="Last name" />
<b-form-input v-model="driver.shortName" type="text" id="short-name" size="sm" placeholder="LAS" />
</b-input-group>
</div>
<div class="col-3">
<b-input-group>
<b-form-select v-model="driver.driverCategory" :options="driverCategoryOptions" id="category" size="sm" />
</b-input-group>
</div>
</div>
</template>

<style scoped lang="scss">
.driver-entry-inline {
padding: 0;
margin: 0;
div {
padding: 0 0.05em;
}
select#platform-select {
max-width: 4.5em;
}
input#short-name {
max-width: 3em;
}
}
</style>
17 changes: 17 additions & 0 deletions src/components/EntryOptionToggle.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<script lang="ts" setup>
const value = defineModel<boolean | number>()
function toggle() {
if (typeof value.value === 'number') value.value = value.value === 0 ? 1 : 0
else value.value = !value.value
}
</script>

<template>
<b-button class="option-toggle" :variant="value ? 'info' : 'outline-info'" size="sm" @click="toggle">
<slot />
</b-button>
</template>

<style lang="scss" scoped>
</style>
61 changes: 29 additions & 32 deletions src/components/FilePicker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,48 +14,50 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import download from "downloadjs";
import { cloneDeep } from "lodash-es";
import { ref, watch } from "vue";
import download from 'downloadjs'
import { clone, cloneDeep } from 'lodash-es'
import { ref, watch } from 'vue'
const props = defineProps<{
fileName: string,
fileName: string
default?: T
}>();
}>()
const jsonError = ref<string>();
const jsonError = ref<string>()
//#region File parsing
const file = defineModel<T>();
const fileText = ref<string>();
const file = defineModel<T>()
const fileText = ref<string>()
watch(file, (value) => {
try {
if (value !== undefined && value !== null)
fileText.value = JSON.stringify(value, null, 2);
else
fileText.value = undefined;
} catch (e: any) {
jsonError.value = e.message;
}
}, { deep: true });
watch(
file,
(value) => {
try {
if (value != undefined) {
fileText.value = JSON.stringify(value, null, 2)
} else fileText.value = undefined
} catch (e: any) {
jsonError.value = e.message
}
},
{ deep: true },
)
watch(fileText, (newValue) => {
try {
if (newValue) file.value = JSON.parse(newValue)
else file.value = undefined;
else file.value = undefined
} catch (e: any) {
jsonError.value = e.message;
jsonError.value = e.message
}
})
//#endregion
function onNew() {
file.value = cloneDeep(props.default);
file.value = cloneDeep(props.default)
}
function downloadFile() {
if (fileText.value)
download(fileText.value, `${props.fileName}.json`, "application/json");
if (fileText.value) download(fileText.value, `${props.fileName}.json`, 'application/json')
}
</script>

Expand All @@ -64,19 +66,14 @@ function downloadFile() {
<b-alert variant="danger" :show="!!jsonError" class="mb-2">
{{ jsonError }}
</b-alert>
<BFormTextarea v-model="fileText" rows="10" class="mb-2"
:placeholder="`Drag & Drop your ${fileName}.json or paste its contents here...`" />
<BFormTextarea v-model="fileText" rows="10" class="mb-2" :placeholder="`Drag & Drop your ${fileName}.json or paste its contents here...`" />
<div class="d-flex flex-row justify-content-center mb-1">
<b-button variant="secondary" @click="onNew">
New {{ fileName }}.json
</b-button>
<b-button variant="secondary" @click="onNew"> New {{ fileName }}.json </b-button>
</div>
<div v-if="!!file" class="d-flex flex-row justify-content-center mb-1">
<b-button variant="secondary" @click="downloadFile">
Download {{ fileName }}.json
</b-button>
<b-button variant="secondary" @click="downloadFile"> Download {{ fileName }}.json </b-button>
</div>
</div>
</template>

<style scoped></style>
<style scoped></style>
25 changes: 20 additions & 5 deletions src/composables/gameData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

import { CupCategories, DriverCategories, SessionTypes } from '@/lib/gameData'
import { Cars, CupCategories, DriverCategories, SessionTypes } from '@/lib/gameData'

export function useGameData() {
//#region Session types
Expand All @@ -23,7 +23,7 @@ export function useGameData() {
for (const item of SessionTypes) {
result.push({
text: item.name,
value: item.value
value: item.value,
})
}
return result
Expand All @@ -36,7 +36,7 @@ export function useGameData() {
for (const item of CupCategories) {
result.push({
text: item.name,
value: item.value
value: item.value,
})
}
return result
Expand All @@ -49,18 +49,33 @@ export function useGameData() {
for (const item of DriverCategories) {
result.push({
text: item.name,
value: item.value
value: item.value,
})
}
return result
}
//#endregion Driver categories

//#region Cars
function carOptions() {
const result = [
{
text: 'Any car',
value: -1,
},
]
for (const item of Cars) {
result.push({
text: item.name,
value: item.value,
})
}
return result
}
//#endregion Cars

//#region Tracks
//#endregion Tracks

return { sessionTypeOptions, cupCategoryOptions, driverCategoryOptions }
return { sessionTypeOptions, cupCategoryOptions, driverCategoryOptions, carOptions }
}
21 changes: 9 additions & 12 deletions src/lib/gameFiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

import { DriverCategory, SettingsCarGroup, SettingsFormationLapType } from './gameData'
import { randomString } from './utils'

//#region eventRules.json
export class EventRules {
Expand Down Expand Up @@ -61,27 +62,23 @@ export class EntryList {
entries: EntryListEntry[] = []
forceEntryList: 0 | 1 = 0
}
export type EntryListEntry = {
drivers: EntryListDriver[]
raceNumber: number
forcedCarModel: number
overrideDriverInfo: number
isServerAdmin: number
export class EntryListEntry {
drivers: EntryListDriver[] = []
raceNumber: number = 0
forcedCarModel: number = -1
overrideDriverInfo: number = 0
isServerAdmin: number = 0
defaultGridPosition?: number
ballastKg?: number
restrictor?: number
customCar?: string
overrideCarModelForCustomCar?: number
}
export type EntryListDriver = {
playerID: string
export class EntryListDriver {
playerID: string = ''
firstName?: string
lastName?: string
shortName?: string
driverCategory?: DriverCategory
}
// Defaults
export const EntryListDriverDefault: EntryListDriver = {
playerID: '',
}
//#endregion
5 changes: 2 additions & 3 deletions src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

import { Platform } from '@/stores/settings'
import type { EntryListEntry } from './gameFiles'

export function isNullOrWhitespace(input: string | null | undefined) {
return !input || !input.trim()
Expand Down Expand Up @@ -52,8 +51,8 @@ export function randomString(length: number = 6) {
for (let i = length; i > 0; --i) result += chars[Math.floor(Math.random() * chars.length)]
return result
}
export function parsePlayerId(playerId: string) {
let platform = Platform.Steam
export function parsePlayerId(playerId: string, defaultPlatform: Platform = Platform.Steam) {
let platform = defaultPlatform
if (playerId.startsWith('S')) platform = Platform.Steam
else if (playerId.startsWith('M')) platform = Platform.Xbox
else if (playerId.startsWith('P')) platform = Platform.PlayStation
Expand Down
5 changes: 5 additions & 0 deletions src/stores/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ export const PlatformOptions = [
{ value: Platform.Xbox, text: 'Xbox' },
{ value: Platform.PlayStation, text: 'PlayStation' },
] as SelectOption[]
export const PlatformOptionsSmall = [
{ value: Platform.Steam, text: 'S' },
{ value: Platform.Xbox, text: 'X' },
{ value: Platform.PlayStation, text: 'PS' },
] as SelectOption[]

export const useSettingsStore = defineStore('settings', () => {
// #region Platform
Expand Down
Loading

0 comments on commit 511336d

Please sign in to comment.