formatting, browser tests
This commit is contained in:
@@ -42,17 +42,10 @@ function submit() {
|
||||
|
||||
<template>
|
||||
<div class="c-add-mutation-form">
|
||||
<h4 class="c-add-mutation-form__title">
|
||||
Add Mutation
|
||||
</h4>
|
||||
<form
|
||||
@submit.prevent="submit"
|
||||
class="c-add-mutation-form__form"
|
||||
>
|
||||
<h4 class="c-add-mutation-form__title">Add Mutation</h4>
|
||||
<form @submit.prevent="submit" class="c-add-mutation-form__form">
|
||||
<div class="c-add-mutation-form__field">
|
||||
<label
|
||||
for="amount"
|
||||
class="c-add-mutation-form__label"
|
||||
<label for="amount" class="c-add-mutation-form__label"
|
||||
>Amount</label
|
||||
>
|
||||
<input
|
||||
@@ -61,15 +54,16 @@ function submit() {
|
||||
type="number"
|
||||
class="c-add-mutation-form__input"
|
||||
/>
|
||||
<div v-if="form.errors.amount" class="c-add-mutation-form__error">
|
||||
<div
|
||||
v-if="form.errors.amount"
|
||||
class="c-add-mutation-form__error"
|
||||
>
|
||||
{{ form.errors.amount }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="c-add-mutation-form__field">
|
||||
<label
|
||||
for="description"
|
||||
class="c-add-mutation-form__label"
|
||||
<label for="description" class="c-add-mutation-form__label"
|
||||
>Description</label
|
||||
>
|
||||
<textarea
|
||||
@@ -88,8 +82,7 @@ function submit() {
|
||||
|
||||
<!-- Media Uploads for Mutations -->
|
||||
<div class="c-add-mutation-form__field">
|
||||
<label
|
||||
class="c-add-mutation-form__label"
|
||||
<label class="c-add-mutation-form__label"
|
||||
>Attach Proof Media (Photos/Videos)</label
|
||||
>
|
||||
<input
|
||||
|
||||
@@ -33,6 +33,7 @@ import {
|
||||
} from '@/components/ui/tooltip';
|
||||
import UserMenuContent from '@/components/UserMenuContent.vue';
|
||||
import { useCurrentUrl } from '@/composables/useCurrentUrl';
|
||||
import { route } from 'ziggy-js';
|
||||
import { getInitials } from '@/composables/useInitials';
|
||||
import { toUrl } from '@/lib/utils';
|
||||
import { dashboard } from '@/routes';
|
||||
@@ -239,7 +240,7 @@ const rightNavItems: NavItem[] = [
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="page.props.unreadNotificationsCount > 0"
|
||||
v-if="(page.props as any).unreadNotificationsCount > 0"
|
||||
class="relative"
|
||||
>
|
||||
<Link
|
||||
@@ -260,7 +261,9 @@ const rightNavItems: NavItem[] = [
|
||||
d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"
|
||||
/>
|
||||
</svg>
|
||||
<span class="absolute -top-1 -right-1 flex h-4 w-4 items-center justify-center rounded-full bg-red-600 text-[10px] font-bold text-white">
|
||||
<span
|
||||
class="absolute -top-1 -right-1 flex h-4 w-4 items-center justify-center rounded-full bg-red-600 text-[10px] font-bold text-white"
|
||||
>
|
||||
{{ page.props.unreadNotificationsCount }}
|
||||
</span>
|
||||
</Link>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { useForm } from '@inertiajs/vue3';
|
||||
import { useEcho, echoIsConfigured, configureEcho } from '@laravel/echo-vue';
|
||||
import { Paperclip } from '@lucide/vue';
|
||||
import { ref } from 'vue';
|
||||
import { route } from 'ziggy-js';
|
||||
import { Paperclip, Info } from '@lucide/vue';
|
||||
|
||||
const props = defineProps<{
|
||||
chat: {
|
||||
@@ -52,7 +52,6 @@ useEcho(`chats.${props.chat.id}`, 'MessageSent', (e: any) => {
|
||||
|
||||
function handleFileChange(event: Event) {
|
||||
const files = (event.target as HTMLInputElement).files;
|
||||
|
||||
if (files) {
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
form.media.push(files[i]);
|
||||
@@ -68,7 +67,6 @@ function submit() {
|
||||
form.post(route('chats.messages.store', props.chat.id), {
|
||||
onSuccess: () => {
|
||||
form.reset();
|
||||
|
||||
if (fileInput.value) {
|
||||
fileInput.value.value = '';
|
||||
}
|
||||
@@ -100,50 +98,77 @@ function closeLightbox() {
|
||||
<div
|
||||
v-for="message in chat.messages"
|
||||
:key="message.id"
|
||||
class="c-chat__message"
|
||||
:class="[
|
||||
'c-chat__message',
|
||||
{
|
||||
'c-chat__message--system':
|
||||
message.content.startsWith('System:'),
|
||||
},
|
||||
]"
|
||||
>
|
||||
<div class="c-chat__message-header">
|
||||
<span class="c-chat__message-author">{{
|
||||
message.user.name
|
||||
}}</span>
|
||||
<span class="c-chat__message-time">{{
|
||||
new Date(message.created_at).toLocaleString()
|
||||
}}</span>
|
||||
</div>
|
||||
<p class="c-chat__message-text">
|
||||
{{ message.content }}
|
||||
</p>
|
||||
<!-- Standard User Chat Message -->
|
||||
<template v-if="!message.content.startsWith('System:')">
|
||||
<div class="c-chat__message-header">
|
||||
<span class="c-chat__message-author">{{
|
||||
message.user.name
|
||||
}}</span>
|
||||
<span class="c-chat__message-time">{{
|
||||
new Date(message.created_at).toLocaleString()
|
||||
}}</span>
|
||||
</div>
|
||||
<p class="c-chat__message-text">
|
||||
{{ message.content }}
|
||||
</p>
|
||||
|
||||
<!-- Attached Media Display -->
|
||||
<div
|
||||
v-if="message.media && message.media.length > 0"
|
||||
class="c-chat__message-media"
|
||||
>
|
||||
<!-- Attached Media Display -->
|
||||
<div
|
||||
v-for="item in message.media"
|
||||
:key="item.id"
|
||||
class="c-chat__media-item"
|
||||
v-if="message.media && message.media.length > 0"
|
||||
class="c-chat__message-media"
|
||||
>
|
||||
<img
|
||||
v-if="item.mime_type.startsWith('image/')"
|
||||
:src="item.url"
|
||||
:alt="item.file_name"
|
||||
class="c-chat__image cursor-pointer transition-opacity hover:opacity-90"
|
||||
@click="openLightbox(item.url, item.mime_type)"
|
||||
/>
|
||||
<div
|
||||
v-else-if="item.mime_type.startsWith('video/')"
|
||||
class="relative cursor-pointer transition-opacity hover:opacity-90"
|
||||
@click="openLightbox(item.url, item.mime_type)"
|
||||
v-for="item in message.media"
|
||||
:key="item.id"
|
||||
class="c-chat__media-item"
|
||||
>
|
||||
<video
|
||||
<img
|
||||
v-if="item.mime_type.startsWith('image/')"
|
||||
:src="item.url"
|
||||
class="c-chat__video"
|
||||
></video>
|
||||
<div class="c-chat__play-overlay">▶</div>
|
||||
:alt="item.file_name"
|
||||
class="c-chat__image cursor-pointer transition-opacity hover:opacity-90"
|
||||
@click="openLightbox(item.url, item.mime_type)"
|
||||
/>
|
||||
<div
|
||||
v-else-if="item.mime_type.startsWith('video/')"
|
||||
class="relative cursor-pointer transition-opacity hover:opacity-90"
|
||||
@click="openLightbox(item.url, item.mime_type)"
|
||||
>
|
||||
<video
|
||||
:src="item.url"
|
||||
class="c-chat__video"
|
||||
></video>
|
||||
<div class="c-chat__play-overlay">▶</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Subtle Activity Log System Message -->
|
||||
<template v-else>
|
||||
<div class="c-chat__system-inner">
|
||||
<Info class="c-chat__system-icon" />
|
||||
<span class="c-chat__system-text">
|
||||
{{ message.content.replace(/^System:\s*/, '') }}
|
||||
</span>
|
||||
<span class="c-chat__system-time">
|
||||
{{
|
||||
new Date(message.created_at).toLocaleTimeString(
|
||||
[],
|
||||
{ hour: '2-digit', minute: '2-digit' },
|
||||
)
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div v-if="chat.messages.length === 0" class="c-chat__empty">
|
||||
No messages yet.
|
||||
@@ -260,6 +285,26 @@ function closeLightbox() {
|
||||
@apply overflow-hidden bg-white p-4 shadow-sm sm:rounded-lg dark:bg-gray-800;
|
||||
}
|
||||
|
||||
.c-chat__message--system {
|
||||
@apply border-0 bg-transparent p-0 shadow-none;
|
||||
}
|
||||
|
||||
.c-chat__system-inner {
|
||||
@apply flex items-center gap-2 rounded-md border border-neutral-200/60 bg-neutral-50 px-3 py-1.5 text-xs text-neutral-500 dark:border-neutral-800/40 dark:bg-neutral-900/10 dark:text-neutral-400;
|
||||
}
|
||||
|
||||
.c-chat__system-icon {
|
||||
@apply size-3.5 shrink-0 text-neutral-400;
|
||||
}
|
||||
|
||||
.c-chat__system-text {
|
||||
@apply flex-1 font-medium;
|
||||
}
|
||||
|
||||
.c-chat__system-time {
|
||||
@apply shrink-0 text-[10px] text-neutral-400;
|
||||
}
|
||||
|
||||
.c-chat__message-header {
|
||||
@apply flex justify-between;
|
||||
}
|
||||
|
||||
@@ -40,11 +40,12 @@ function submit() {
|
||||
<div class="c-create-ledger-form__body">
|
||||
<h3 class="c-create-ledger-form__title">Create a New Ledger</h3>
|
||||
|
||||
<form @submit.prevent="submit" class="c-create-ledger-form__form">
|
||||
<form
|
||||
@submit.prevent="submit"
|
||||
class="c-create-ledger-form__form"
|
||||
>
|
||||
<div class="c-create-ledger-form__field">
|
||||
<label
|
||||
for="name"
|
||||
class="c-create-ledger-form__label"
|
||||
<label for="name" class="c-create-ledger-form__label"
|
||||
>Name</label
|
||||
>
|
||||
<input
|
||||
@@ -62,9 +63,7 @@ function submit() {
|
||||
</div>
|
||||
|
||||
<div class="c-create-ledger-form__field">
|
||||
<label
|
||||
for="rules"
|
||||
class="c-create-ledger-form__label"
|
||||
<label for="rules" class="c-create-ledger-form__label"
|
||||
>Rules</label
|
||||
>
|
||||
<textarea
|
||||
@@ -92,9 +91,15 @@ function submit() {
|
||||
id="alignment"
|
||||
class="c-create-ledger-form__select"
|
||||
>
|
||||
<option value="positive">Positive (Higher Score is Better)</option>
|
||||
<option value="neutral">Neutral (Frictionless / Standard)</option>
|
||||
<option value="negative">Negative (Lower Score is Better / Demerits)</option>
|
||||
<option value="positive">
|
||||
Positive (Higher Score is Better)
|
||||
</option>
|
||||
<option value="neutral">
|
||||
Neutral (Frictionless / Standard)
|
||||
</option>
|
||||
<option value="negative">
|
||||
Negative (Lower Score is Better / Demerits)
|
||||
</option>
|
||||
</select>
|
||||
<div
|
||||
v-if="form.errors.alignment"
|
||||
@@ -106,8 +111,7 @@ function submit() {
|
||||
|
||||
<!-- Media Uploads for Ledgers -->
|
||||
<div class="c-create-ledger-form__field">
|
||||
<label
|
||||
class="c-create-ledger-form__label"
|
||||
<label class="c-create-ledger-form__label"
|
||||
>Attach Cover/Rules Media</label
|
||||
>
|
||||
<input
|
||||
@@ -126,9 +130,10 @@ function submit() {
|
||||
:key="index"
|
||||
class="c-create-ledger-form__media-preview-item"
|
||||
>
|
||||
<span class="c-create-ledger-form__media-preview-name">{{
|
||||
file.name
|
||||
}}</span>
|
||||
<span
|
||||
class="c-create-ledger-form__media-preview-name"
|
||||
>{{ file.name }}</span
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
@click="removeLedgerFile(index)"
|
||||
|
||||
@@ -17,9 +17,7 @@ defineProps<{
|
||||
<template>
|
||||
<div class="c-ledger-list">
|
||||
<div class="c-ledger-list__header">
|
||||
<h4 class="c-ledger-list__title">
|
||||
Ledgers
|
||||
</h4>
|
||||
<h4 class="c-ledger-list__title">Ledgers</h4>
|
||||
</div>
|
||||
<ul class="c-ledger-list__grid">
|
||||
<li
|
||||
@@ -131,19 +129,19 @@ defineProps<{
|
||||
}
|
||||
|
||||
.c-ledger-list__alignment-badge {
|
||||
@apply text-[10px] font-semibold uppercase tracking-wide px-1.5 py-0.5 rounded;
|
||||
@apply rounded px-1.5 py-0.5 text-[10px] font-semibold tracking-wide uppercase;
|
||||
}
|
||||
|
||||
.c-ledger-list__alignment-badge--positive {
|
||||
@apply text-green-600 bg-green-50/50 dark:text-green-400 dark:bg-green-950/20;
|
||||
@apply bg-green-50/50 text-green-600 dark:bg-green-950/20 dark:text-green-400;
|
||||
}
|
||||
|
||||
.c-ledger-list__alignment-badge--negative {
|
||||
@apply text-red-600 bg-red-50/50 dark:text-red-400 dark:bg-red-950/20;
|
||||
@apply bg-red-50/50 text-red-600 dark:bg-red-950/20 dark:text-red-400;
|
||||
}
|
||||
|
||||
.c-ledger-list__alignment-badge--neutral {
|
||||
@apply text-gray-500 bg-gray-50/50 dark:text-gray-400 dark:bg-neutral-800/20;
|
||||
@apply bg-gray-50/50 text-gray-500 dark:bg-neutral-800/20 dark:text-gray-400;
|
||||
}
|
||||
|
||||
.c-ledger-list__media-list {
|
||||
|
||||
@@ -50,12 +50,16 @@ function getAmountClass(amount: number): string {
|
||||
const alignment = props.ledgerAlignment || 'neutral';
|
||||
|
||||
if (alignment === 'positive') {
|
||||
return amount > 0 ? 'c-mutation-list__item-amount--positive' : 'c-mutation-list__item-amount--negative';
|
||||
return amount > 0
|
||||
? 'c-mutation-list__item-amount--positive'
|
||||
: 'c-mutation-list__item-amount--negative';
|
||||
}
|
||||
|
||||
if (alignment === 'negative') {
|
||||
// Lower is better: negative amount is positive/favorable, positive amount is negative/unfavorable
|
||||
return amount < 0 ? 'c-mutation-list__item-amount--positive' : 'c-mutation-list__item-amount--negative';
|
||||
return amount < 0
|
||||
? 'c-mutation-list__item-amount--positive'
|
||||
: 'c-mutation-list__item-amount--negative';
|
||||
}
|
||||
|
||||
// Neutral alignment
|
||||
@@ -65,9 +69,7 @@ function getAmountClass(amount: number): string {
|
||||
|
||||
<template>
|
||||
<div class="c-mutation-list">
|
||||
<h4 class="c-mutation-list__title">
|
||||
Mutations
|
||||
</h4>
|
||||
<h4 class="c-mutation-list__title">Mutations</h4>
|
||||
<ul class="c-mutation-list__list">
|
||||
<li
|
||||
v-for="mutation in mutations"
|
||||
|
||||
@@ -9,9 +9,7 @@ defineProps<{
|
||||
|
||||
<template>
|
||||
<div class="c-participants-list">
|
||||
<h4 class="c-participants-list__title">
|
||||
Participants
|
||||
</h4>
|
||||
<h4 class="c-participants-list__title">Participants</h4>
|
||||
<ul class="c-participants-list__grid">
|
||||
<li
|
||||
v-for="participant in participants"
|
||||
|
||||
Reference in New Issue
Block a user