Skip to content

Commit af2c743

Browse files
committed
Merge branch 'plainblack-main'
2 parents 6c459af + e48f399 commit af2c743

File tree

117 files changed

+532
-38485
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

117 files changed

+532
-38485
lines changed

README.md

+1-1

app/assets/css/tailwind.css

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
@layer tailwind-base, primevue, tailwind-utilities;
2+
3+
@layer tailwind-base {
4+
@tailwind base;
5+
}
6+
7+
@layer tailwind-utilities {
8+
@tailwind components;
9+
@tailwind utilities;
10+
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<template>
2+
<div class="card flex justify-center">
3+
<a class="flex p-3 cursor-pointer" @click="toggle">
4+
<Icon v-if="isDark" name="circum:dark" />
5+
<Icon v-else name="circum:light" />
6+
</a>
7+
8+
<Popover ref="op">
9+
<Menu :model="[
10+
{label : 'Dark Mode', icon: 'circum:dark', value : true},
11+
{label : 'Light Mode', icon: 'circum:light', value: false},
12+
]">
13+
<template #item="{ item, props, hasSubmenu, root }">
14+
<div @mousedown="isDark = item.value; toggle()" class="flex p-2 cursor-pointer">
15+
<Icon :name="item.icon" class="mr-2" />
16+
<span>{{ item.label }}</span>
17+
</div>
18+
</template>
19+
</Menu>
20+
</Popover>
21+
</div>
22+
</template>
23+
24+
25+
<script setup>
26+
const op = ref();
27+
const toggle = (event) => {
28+
op.value.toggle(event);
29+
}
30+
const isDark = useDark();
31+
</script>
File renamed without changes.
File renamed without changes.

components/ving/FieldsetNav.vue app/components/ving/FieldsetNav.vue

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
<template>
2-
<div class="grid">
3-
<div class="col-12 md:col-9 xl:col-10">
2+
<div class="flex">
3+
<div class="md:grow">
44
<slot></slot>
55
</div>
6-
<div class="hidden md:block md:col-3 xl:col-2">
6+
<div class="md:hidden lg:block ml-5">
77
<ul class="list-none sticky m-0 p-0 pt-4 top-0">
88
<li class="mb-2" v-for="child in sortedChildren()" :key="child.id">
99
<a :href="`#${child.id}`">
File renamed without changes.

components/ving/FormInput.vue app/components/ving/FormInput.vue

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
<template>
22
<div :class="class">
33
<FormLabel :label="label" :id="computedId" />
4-
<div :class="append || prepend || $slots.prepend || $slots.append ? 'p-inputgroup flex-1' : 'flex-1'">
5-
<span v-if="$slots.prepend || prepend" class="p-inputgroup-addon"><slot name="prepend">{{ prepend }}</slot></span>
4+
<InputGroup class="flex-1">
5+
<InputGroupAddon v-if="$slots.prepend || prepend"><slot name="prepend">{{ prepend }}</slot></InputGroupAddon>
66
<InputNumber v-if="type == 'number' && (isNumber(val) || isNull(val) || isUndefined(val))"
77
v-model="val" showButtons :placeholder="placeholder" :name="name" :id="computedId"
88
:autocomplete="autocomplete" :required="required" :inputClass="fieldClass" :step="step"
9-
:incrementButtonClass="append ? 'border-noround' : ''" @change="emit('change')"
10-
:decrementButtonClass="append ? 'border-noround' : ''" />
11-
<InputSwitch v-else-if="type == 'switch' && (isBoolean(val) || isUndefined(val))"
9+
:incrementButtonClass="append ? 'rounded-none' : ''" @change="emit('change')"
10+
:decrementButtonClass="append ? 'rounded-none' : ''" />
11+
<ToggleSwitch v-else-if="type == 'switch' && (isBoolean(val) || isUndefined(val))"
1212
v-model="val" :placeholder="placeholder" :name="name" :id="computedId"
1313
:inputClass="fieldClass" @change="emit('change')"
1414
/>
@@ -17,11 +17,11 @@
1717
:autocomplete="autocomplete" :required="required" :inputClass="fieldClass" class="w-full" />
1818
<Textarea v-else-if="type == 'textarea' && (isString(val) || isNull(val) || isUndefined(val))"
1919
v-model="val" :placeholder="placeholder" :name="name" :id="computedId" :autocomplete="autocomplete"
20-
:class="fieldClass + ' border-round'" :required="required" autoResize @change="emit('change')" />
20+
:class="fieldClass + ' rounded'" :required="required" autoResize @change="emit('change')" />
2121
<MarkdownInput v-else-if="type == 'markdown' && (isString(val) || isNull(val) || isUndefined(val))"
2222
v-model="val" :placeholder="placeholder" :id="computedId" @change="emit('change')"
2323
/>
24-
<Dropdown v-else-if="type == 'select'" :placeholder="placeholder"
24+
<Select v-else-if="type == 'select'" :placeholder="placeholder"
2525
v-model="val" :name="name" :id="computedId" :options="modifiedOptions" :class="fieldClass" :required="required"
2626
@change="emit('change')" optionLabel="label" optionValue="value" />
2727
<InputText
@@ -32,8 +32,8 @@
3232
Can't display {{ displayName }} Form Input
3333
{{ val }}
3434
</Message>
35-
<span v-if="$slots.append || append" class="p-inputgroup-addon"><slot name="append">{{ append }}</slot></span>
36-
</div>
35+
<InputGroupAddon v-if="$slots.append || append"><slot name="append">{{ append }}</slot></InputGroupAddon>
36+
</InputGroup>
3737
<small :class="invalid && !empty ? 'text-red-500' : ''" v-if="subtext">{{ subtext }}</small>
3838
</div>
3939
</template>

components/ving/FormLabel.vue app/components/ving/FormLabel.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template>
2-
<label v-if="label" :for="id" class="block font-medium text-900 mb-2">{{ label }}</label>
2+
<label v-if="label" :for="id" class="block font-medium mb-2">{{ label }}</label>
33
</template>
44

55
<script setup>

components/ving/ManageButton.vue app/components/ving/ManageButton.vue

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
<template>
2-
<Button v-if="items.length == 1" @mousedown="takeAction($event, firstItem)" :severity="severity" class="white-space-nowrap">
3-
<Icon :name="firstItem.icon" class="mr-1 vertical-align-middle" />
4-
<span class="vertical-align-middle">{{ firstItem.label }}</span>
2+
<Button v-if="items.length == 1" @mousedown="takeAction($event, firstItem)" :severity="severity" class="text-nowrap">
3+
<Icon :name="firstItem.icon" class="mr-1 align-middle" />
4+
<span class="align-middle">{{ firstItem.label }}</span>
55
</Button>
6-
<SplitButton v-else-if="items.length > 1" :severity="severity" :model="otherItems" @mousedown="takeAction($event, firstItem)" class="white-space-nowrap">
6+
<SplitButton v-else-if="items.length > 1" :severity="severity" :model="otherItems" @click="takeAction($event, firstItem)" class="text-nowrap">
77
<span>
8-
<Icon :name="firstItem.icon" :title="firstItem.label" class="mr-1 vertical-align-middle" />
9-
<span class="vertical-align-middle">{{ firstItem.label }}</span>
8+
<Icon :name="firstItem.icon" :title="firstItem.label" class="mr-1 align-middle" />
9+
<span class="align-middle">{{ firstItem.label }}</span>
1010
</span>
1111
<template #item="{ item }">
12-
<span @mousedown="takeAction($event, item)" class="flex p-2 align-items-center" :title="item.label">
12+
<span @mousedown="takeAction($event, item)" class="flex p-2 items-center" :title="item.label">
1313
<Icon :name="item.icon" class="mr-1" />
1414
{{ item.label }}
1515
</span>

components/ving/MarkdownInput.vue app/components/ving/MarkdownInput.vue

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template>
2-
<MdEditor v-model="val" @onChange="changed" :placeholder="placeholder" :showCodeRowNumber="true" :editorId="id" language="en-US" :toolbars="toolbars" noUploadImg previewTheme="github" />
2+
<MdEditor :theme="colorScheme" v-model="val" @onChange="changed" :placeholder="placeholder" :showCodeRowNumber="true" :editorId="id" language="en-US" :toolbars="toolbars" noUploadImg previewTheme="github" />
33
</template>
44

55
<script setup>
@@ -33,7 +33,8 @@ const val = computed({
3333
}
3434
});
3535
36-
36+
const isDark = useDark();
37+
const colorScheme = computed(() => isDark.value == true ? 'dark' : 'light');
3738
3839
3940
const toolbars = [
File renamed without changes.
File renamed without changes.
File renamed without changes.

components/ving/PanelFrame.vue app/components/ving/PanelFrame.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template>
2-
<div class="flex flex-column lg:flex-row">
2+
<div class="flex flex-col lg:flex-row">
33
<div v-if="$slots.left" class="lg:pr-5 mb-1 lg:mb-0">
44
<div v-if="title" class="lg:mb-3 text-2xl text-color-secondary ml-1">{{section}}<template v-if="!section">&nbsp;</template></div>
55
<slot name="left"></slot>

components/ving/PanelNav.vue app/components/ving/PanelNav.vue

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
<template>
2-
<ul class="list-none m-0 p-0 flex flex-wrap lg:flex-column justify-content-evenly md:justify-content-between">
2+
<ul class="list-none m-0 p-0 flex flex-wrap lg:flex-col justify-evenly md:justify-between">
33
<li v-for="item in links" :key="item.label" :title="item.label">
4-
<NuxtLink :to="item.to" v-ripple
5-
:class="[route.path == item.to ? 'text-primary hover:bg-primary-reverse hover:text-primary' : 'text-color-secondary hover:bg-primary-reverse hover:text-color', 'flex align-items-center cursor-pointer p-0 py-2 border-round text-800 hover:surface-hover transition-duration-150 transition-colors p-ripple']"
4+
<NuxtLink :to="item.to"
5+
:class="[route.path == item.to ? 'text-primary hover:bg-primary-reverse hover:text-primary' : 'text-color-secondary hover:bg-primary-reverse hover:text-color', 'flex items-center cursor-pointer p-0 py-2 rounded text-800 hover:surface-hover transition-duration-150 transition-colors p-ripple']"
66
:aria-current="route.path == item.to ? 'page' : undefined">
77
<Icon :name="item.icon" aria-hidden="true"
88
:class="[route.path == item.to ? 'text-primary group-hover:text-primary' : 'text-color-secondary group-hover:text-color', 'md:mr-2']" />
9-
<span class="font-medium hidden md:block white-space-nowrap">{{ item.label }}</span>
9+
<span class="font-medium hidden md:block text-nowrap">{{ item.label }}</span>
1010
</NuxtLink>
1111
</li>
1212
<li v-if="links.length && buttons.length"><hr class="mt-2 mb-3 border-50 hidden lg:block"></li>
1313
<li v-for="item in buttons" :key="item.label" class="lg:mb-2 p-fluid">
1414
<Button @mousedown="takeAction($event, item)" :severity="item.severity" :title="item.label">
15-
<Icon :name="item.icon" class="mr-1" /> <span class="hidden md:block white-space-nowrap">{{ item.label }}</span>
15+
<Icon :name="item.icon" class="mr-1" /> <span class="hidden md:block text-nowrap">{{ item.label }}</span>
1616
</Button>
1717
</li>
1818
</ul>

components/ving/PanelZone.vue app/components/ving/PanelZone.vue

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<slot name="header">
44
<div v-if="title || info || $slots.title" class="mb-4">
55
<h2 v-if="title || $slots.title" class="text-900 font-semibold text-lg m-0 p-0"><slot name="title">{{ title }}</slot></h2>
6-
<div v-if="info" class="mt-1 text-sm text-gray-500">{{ info }}</div>
6+
<div v-if="info" class="mt-1 text-sm">{{ info }}</div>
77
</div>
88
</slot>
99

@@ -23,7 +23,7 @@ const props = defineProps({
2323
},
2424
look: {
2525
type: String,
26-
default: 'surface-card border-1 surface-border border-round',
26+
default: 'border bg-surface-50 dark:bg-surface-900 border-surface rounded',
2727
},
2828
padding: {
2929
type: String,

components/ving/SystemWideAlert.vue app/components/ving/SystemWideAlert.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template>
2-
<Message v-if="swa.message" :closable="false" :severity="swa.severity" class="m-0 border-1 border-noround">{{ swa.message }}</Message>
2+
<Message v-if="swa.message" :closable="false" :severity="swa.severity" class="m-0 border rounded-none">{{ swa.message }}</Message>
33
</template>
44

55
<script setup>

components/ving/Throbber.vue app/components/ving/Throbber.vue

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
2-
<div id="vingthrobber" style="z-index: 10000; position: fixed; top: 0px; width: 100%;">
2+
<div id="vingthrobber" class="fixed z-[10000] top-0 w-full">
33
<template v-if="throbber.counter > 0">
4-
<ProgressBar id="throbberprogressbar" mode="indeterminate" style="height: 5px"></ProgressBar>
4+
<ProgressBar id="throbberprogressbar" mode="indeterminate" class="h-0.5"></ProgressBar>
55
</template>
66
</div>
77
</template>

components/ving/UserAvatar.vue app/components/ving/UserAvatar.vue

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
2-
<span v-if="user" class="flex-inline align-items-center">
3-
<Avatar :image="user.meta?.avatarUrl" alt="user avatar" shape="circle" class="vertical-align-middle" />
4-
<span class="ml-2 vertical-align-middle">
2+
<span v-if="user" class="flex-inline items-center">
3+
<Avatar :image="user.meta?.avatarUrl" alt="user avatar" shape="circle" />
4+
<span class="ml-2">
55
{{ user.meta?.displayName }}
66
</span>
77
</span>

components/ving/UserProfileLink.vue app/components/ving/UserProfileLink.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template>
2-
<NuxtLink v-if="user" :to="`/user/${user.props.id}/profile`" v-ripple>
2+
<NuxtLink v-if="user" :to="`/user/${user.props.id}/profile`">
33
<UserAvatar :user="user" />
44
</NuxtLink>
55
<Message v-else severity="error">You may need to <i>includeRelated:['user']</i> to view this.</Message>
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

composables/ving/useVingKind.mjs app/composables/ving/useVingKind.mjs

+13-8
Original file line numberDiff line numberDiff line change
@@ -381,21 +381,26 @@ class VingKind {
381381
}
382382

383383
/**
384-
* Turns the list of records into an array compatible with various components such as FormInput, Dropdown and Autocomplete
384+
* Turns the list of records into an array compatible with various components such as FormInput, Select, and Autocomplete
385385
*
386386
* @param {'props'|'meta'|'extra'} section One of the describe section names such as `props`, or `meta`, or `extra`.
387387
* @param {string} field The name of the field within the `section` that will serve as the labelf for this option list.
388+
* @param {Function} filter An optional function that will be passed to an array filter to filter out any unwanted records from the current list of records.
388389
* @returns {object[]} An array of objects with `label` and `value` attributes.
389390
* @example
390391
* users.recordsAsOptions('meta','displayName')
391392
*/
392-
recordsAsOptions(section, field) {
393-
return this.records.map(u => {
394-
return {
395-
value: u.props?.id,
396-
label: u[section][field]
397-
}
398-
})
393+
recordsAsOptions(section, field, filter = () => true) {
394+
let out = [];
395+
for (const record of this.records) {
396+
if (!(filter(record)))
397+
continue;
398+
out.push({
399+
value: record.props?.id,
400+
label: record[section][field]
401+
});
402+
}
403+
return out;
399404
}
400405

401406
/**
File renamed without changes.

app/layouts/default.vue

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<template>
2+
<div>
3+
<Menubar id="topnav" :model="topNav" class="py-0">
4+
<template #start>
5+
<img :src="config.public.site.logoUrl" :alt="`${config.public.site.name} logo`" :title="config.public.site.name" class="h-10 mr-0 lg:mr-3">
6+
</template>
7+
<template #item="{ item, props, hasSubmenu, root }">
8+
<a v-if="hasSubmenu" :target="item.target" v-bind="props.action"
9+
class="flex items-center px-6 p-3 lg:px-3 lg:py-2 rounded cursor-pointer">
10+
<Icon :name="item.icon" class="mr-2" />
11+
<span class="ml-2">{{ item.label }}</span>
12+
<Icon v-if="hasSubmenu" name="pepicons-pop:angle-down" class="ml-2"/>
13+
</a>
14+
<NuxtLink v-else :to="item.to"
15+
class="flex items-center px-6 p-3 lg:px-3 lg:py-2 rounded cursor-pointer">
16+
<Icon :name="item.icon" class="mr-2" />
17+
<span>{{ item.label }}</span>
18+
</NuxtLink>
19+
</template>
20+
21+
<template #end>
22+
<div class="flex items-center gap-2">
23+
<DarkModeSelector/>
24+
<InputGroup>
25+
<InputGroupAddon>
26+
<Icon name="ion:search"/>
27+
</InputGroupAddon>
28+
<InputText placeholder="Search (non-functional)" type="text" class="w-8rem sm:w-auto" />
29+
</InputGroup>
30+
<SplitButton v-if="currentUser.props?.id" :model="userMenu" text>
31+
<NuxtLink to="/user/settings" class="flex items-center">
32+
<Avatar :image="currentUser.meta?.avatarUrl" alt="user avatar" shape="circle" />
33+
<span class="ml-2">
34+
{{ currentUser.meta?.displayName }}
35+
</span>
36+
</NuxtLink>
37+
<template #item="{ item }">
38+
<NuxtLink :to="item.to" class="flex p-3 items-center">
39+
<Icon :name="item.icon" class="mr-2" />
40+
{{ item.label }}
41+
</NuxtLink>
42+
</template>
43+
</SplitButton>
44+
<NuxtLink v-else to="/user/login" class="flex p-3 items-center text-nowrap">
45+
<Icon name="fa6-solid:door-open" class="mr-2" />
46+
Sign In
47+
</NuxtLink>
48+
</div>
49+
</template>
50+
</Menubar>
51+
52+
<SystemWideAlert />
53+
<div class="px-0 py-1 md:px-4">
54+
<div style="min-height: 20rem">
55+
<slot />
56+
</div>
57+
</div>
58+
</div>
59+
<Notify />
60+
<Throbber />
61+
</template>
62+
63+
<script setup>
64+
const config = useRuntimeConfig();
65+
const currentUser = useCurrentUser();
66+
await currentUser.isAuthenticated();
67+
onMounted(async () => {
68+
// subscribe to message bus
69+
useMessageBus();
70+
})
71+
const topNav = [
72+
{ label: 'Home', to: '/', icon: 'prime:home' },
73+
{ label: 'Games', to: '/game', icon: "prime:star" },
74+
{ label: 'Ving Documentation', to: 'https://plainblack.github.io/ving/', icon: "prime:book" },
75+
{
76+
label: 'Sample Dropdown', icon: "prime:thumbs-down", items: [
77+
{ label: 'Sample 1', to: '#', icon: 'pixelarticons:avatar' },
78+
{ label: 'Sample 2', to: '#', icon: 'prime:sliders-h' },
79+
80+
]
81+
},
82+
]
83+
84+
const userMenu = computed(() => {
85+
const out = [
86+
{ label: 'Settings', to: '/user/settings', icon: 'fa6-solid:sliders' },
87+
{ label: 'Sign Out', to: '/user/logout', icon: 'fa6-solid:door-closed' },
88+
];
89+
if (currentUser.props.admin)
90+
out.unshift({ label: 'Admin', to: '/admin', icon: 'prime:user-plus' });
91+
return out;
92+
})
93+
94+
</script>
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

pages/user/[id]/profile.vue app/pages/user/[id]/profile.vue

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
<template>
22
<Title>User profile for {{ user.meta?.displayName }}</Title>
3-
<div v-if="user.props?.id" class="surface-card p-4 border-1 surface-border border-round flex-auto">
3+
<div v-if="user.props?.id" class="surface-card p-4 border border-surface rounded flex-auto">
44
<div class="text-900 font-semibold text-lg mt-3">User profile for {{ user.meta?.displayName }}</div>
55

66
Created on {{ formatDate(user.props?.createdAt) }}
7-
<div class="flex gap-5 flex-column-reverse md:flex-row">
7+
<div class="flex gap-5 flex-col-reverse md:flex-row">
88
<div class="flex-auto">
99
<div class="mb-4">
1010

@@ -16,8 +16,8 @@
1616
</div>
1717

1818
</div>
19-
<div class="flex flex-column align-items-center flex-or">
20-
<Avatar :image="user.meta?.avatarUrl" alt="user avatar" class="h-10rem w-10rem" shape="circle" />
19+
<div class="flex flex-col items-center flex-or">
20+
<Avatar :image="user.meta?.avatarUrl" alt="user avatar" size="xlarge" shape="circle" />
2121
</div>
2222
</div>
2323

0 commit comments

Comments
 (0)