front-end restructuring, chat shows message ownership
This commit is contained in:
parent
d44bcf6fda
commit
4e9e6dce2a
@ -2,6 +2,8 @@
|
||||
|
||||
@import 'tw-animate-css';
|
||||
|
||||
@import './components.css';
|
||||
|
||||
@source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php';
|
||||
@source '../../storage/framework/views/*.php';
|
||||
|
||||
|
||||
16
resources/css/components.css
Normal file
16
resources/css/components.css
Normal file
@ -0,0 +1,16 @@
|
||||
/* ==========================================================================
|
||||
BEM UI Components Index Manifest (Tailwind CSS v4)
|
||||
========================================================================== */
|
||||
|
||||
@import './components/heading.css';
|
||||
@import './components/input-error.css';
|
||||
@import './components/text-link.css';
|
||||
@import './components/app-logo.css';
|
||||
@import './components/user-info.css';
|
||||
@import './components/sidebar-header.css';
|
||||
@import './components/app-content.css';
|
||||
@import './components/appearance-tabs.css';
|
||||
@import './components/password-input.css';
|
||||
@import './components/auth-layout.css';
|
||||
@import './components/chat.css';
|
||||
@import './components/lightbox.css';
|
||||
5
resources/css/components/app-content.css
Normal file
5
resources/css/components/app-content.css
Normal file
@ -0,0 +1,5 @@
|
||||
/* 7. AppContent Layout Component */
|
||||
.app-content {
|
||||
@apply mx-auto flex h-full w-full max-w-7xl flex-1 flex-col gap-4;
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
20
resources/css/components/app-logo.css
Normal file
20
resources/css/components/app-logo.css
Normal file
@ -0,0 +1,20 @@
|
||||
/* 4. AppLogo Component */
|
||||
.app-logo__icon-container {
|
||||
@apply flex aspect-square size-8 items-center justify-center;
|
||||
border-radius: var(--radius);
|
||||
background-color: var(--sidebar-primary);
|
||||
color: var(--sidebar-primary-foreground);
|
||||
|
||||
.app-logo__icon {
|
||||
@apply size-5 fill-current;
|
||||
}
|
||||
}
|
||||
|
||||
.app-logo__text-container {
|
||||
@apply ml-1 grid flex-1 text-left text-sm;
|
||||
|
||||
.app-logo__text {
|
||||
@apply mb-0.5 truncate leading-tight font-semibold;
|
||||
color: var(--foreground);
|
||||
}
|
||||
}
|
||||
35
resources/css/components/appearance-tabs.css
Normal file
35
resources/css/components/appearance-tabs.css
Normal file
@ -0,0 +1,35 @@
|
||||
/* 8. AppearanceTabs Component */
|
||||
.appearance-tabs {
|
||||
@apply inline-flex gap-1 p-1;
|
||||
border-radius: var(--radius);
|
||||
background-color: var(--muted);
|
||||
|
||||
.appearance-tabs__tab {
|
||||
@apply flex cursor-pointer items-center px-3.5 py-1.5 transition-colors;
|
||||
border-radius: calc(var(--radius) - 2px);
|
||||
color: var(--muted-foreground);
|
||||
|
||||
&:hover {
|
||||
color: var(--foreground);
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
&.appearance-tabs__tab--active {
|
||||
background-color: var(--card);
|
||||
color: var(--card-foreground);
|
||||
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--card);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.appearance-tabs__icon {
|
||||
@apply -ml-1 h-4 w-4;
|
||||
}
|
||||
|
||||
.appearance-tabs__label {
|
||||
@apply ml-1.5 text-sm;
|
||||
}
|
||||
}
|
||||
46
resources/css/components/auth-layout.css
Normal file
46
resources/css/components/auth-layout.css
Normal file
@ -0,0 +1,46 @@
|
||||
/* 10. AuthSimpleLayout Component */
|
||||
.auth-layout {
|
||||
@apply flex min-h-svh flex-col items-center justify-center gap-6 p-6 md:p-10;
|
||||
background-color: var(--background);
|
||||
|
||||
.auth-layout__container {
|
||||
@apply w-full max-w-sm;
|
||||
|
||||
.auth-layout__inner {
|
||||
@apply flex flex-col gap-8;
|
||||
|
||||
.auth-layout__header {
|
||||
@apply flex flex-col items-center gap-4;
|
||||
|
||||
.auth-layout__logo-link {
|
||||
@apply flex flex-col items-center gap-2 font-medium;
|
||||
|
||||
.auth-layout__logo-box {
|
||||
@apply mb-1 flex h-9 w-9 items-center justify-center;
|
||||
border-radius: var(--radius);
|
||||
background-color: var(--sidebar-primary);
|
||||
|
||||
.auth-layout__logo {
|
||||
@apply size-9 fill-current;
|
||||
color: var(--sidebar-primary-foreground);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.auth-layout__title-box {
|
||||
@apply space-y-2 text-center;
|
||||
|
||||
.auth-layout__title {
|
||||
@apply text-xl font-medium;
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
.auth-layout__description {
|
||||
@apply text-center text-sm;
|
||||
color: var(--muted-foreground);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
210
resources/css/components/chat.css
Normal file
210
resources/css/components/chat.css
Normal file
@ -0,0 +1,210 @@
|
||||
/* 11. Chat Component */
|
||||
.c-chat {
|
||||
@apply mt-8;
|
||||
|
||||
.c-chat__title {
|
||||
@apply text-lg font-medium;
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
.c-chat__list {
|
||||
@apply mt-4 flex flex-col gap-3;
|
||||
|
||||
.c-chat__message {
|
||||
@apply overflow-hidden p-4 shadow-sm sm:rounded-lg;
|
||||
border: 1px solid var(--border);
|
||||
|
||||
&.c-chat__message--system {
|
||||
@apply w-full self-center border-0 bg-transparent p-0 shadow-none;
|
||||
}
|
||||
|
||||
&.c-chat__message--own {
|
||||
@apply self-end rounded-br-none text-right;
|
||||
max-width: 80%;
|
||||
background-color: var(--primary);
|
||||
border-color: var(--primary);
|
||||
|
||||
.c-chat__message-header {
|
||||
@apply flex-row-reverse;
|
||||
}
|
||||
.c-chat__message-author {
|
||||
color: var(--primary-foreground);
|
||||
}
|
||||
.c-chat__message-time {
|
||||
color: var(--primary-foreground);
|
||||
opacity: 0.7;
|
||||
}
|
||||
.c-chat__message-text {
|
||||
color: var(--primary-foreground);
|
||||
}
|
||||
}
|
||||
|
||||
&.c-chat__message--other {
|
||||
@apply self-start rounded-bl-none;
|
||||
max-width: 80%;
|
||||
background-color: var(--muted);
|
||||
border-color: var(--border);
|
||||
|
||||
.c-chat__message-author {
|
||||
color: var(--foreground);
|
||||
}
|
||||
.c-chat__message-time {
|
||||
color: var(--muted-foreground);
|
||||
}
|
||||
.c-chat__message-text {
|
||||
color: var(--foreground);
|
||||
}
|
||||
}
|
||||
|
||||
.c-chat__system-inner {
|
||||
@apply flex items-center gap-2 px-3 py-1.5 text-xs;
|
||||
background-color: var(--muted);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: calc(var(--radius) - 2px);
|
||||
color: var(--muted-foreground);
|
||||
|
||||
.c-chat__system-icon {
|
||||
@apply size-3.5 shrink-0;
|
||||
color: var(--muted-foreground);
|
||||
}
|
||||
|
||||
.c-chat__system-text {
|
||||
@apply flex-1 font-medium;
|
||||
}
|
||||
|
||||
.c-chat__system-time {
|
||||
@apply shrink-0 text-[10px];
|
||||
color: var(--muted-foreground);
|
||||
}
|
||||
}
|
||||
|
||||
.c-chat__message-header {
|
||||
@apply flex justify-between;
|
||||
|
||||
.c-chat__message-author {
|
||||
@apply font-semibold;
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
.c-chat__message-time {
|
||||
@apply text-xs;
|
||||
color: var(--muted-foreground);
|
||||
}
|
||||
}
|
||||
|
||||
.c-chat__message-text {
|
||||
@apply mt-2 text-sm;
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
.c-chat__message-media {
|
||||
@apply mt-3 flex flex-wrap gap-2;
|
||||
|
||||
.c-chat__media-item {
|
||||
@apply relative max-w-[240px] overflow-hidden bg-black;
|
||||
border-radius: calc(var(--radius) - 2px);
|
||||
border: 1px solid var(--border);
|
||||
|
||||
.c-chat__image {
|
||||
@apply h-auto max-h-[180px] w-full object-cover;
|
||||
}
|
||||
|
||||
.c-chat__video {
|
||||
@apply h-auto max-h-[180px] w-full;
|
||||
}
|
||||
|
||||
.c-chat__play-overlay {
|
||||
@apply absolute inset-0 flex items-center justify-center bg-black/40 text-2xl font-bold text-white;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.c-chat__empty {
|
||||
color: var(--muted-foreground);
|
||||
}
|
||||
|
||||
.c-chat__form {
|
||||
@apply mt-6 space-y-6;
|
||||
|
||||
.c-chat__form-group {
|
||||
@apply space-y-2;
|
||||
|
||||
.c-chat__label {
|
||||
@apply block text-sm font-medium;
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
.c-chat__textarea {
|
||||
@apply mt-1 block w-full shadow-sm;
|
||||
border-radius: var(--radius);
|
||||
border: 1px solid var(--border);
|
||||
background-color: var(--background);
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
.c-chat__error {
|
||||
@apply text-sm;
|
||||
color: var(--destructive);
|
||||
}
|
||||
|
||||
.c-chat__attachment-container {
|
||||
@apply mt-2 flex items-center;
|
||||
|
||||
.c-chat__attach-btn {
|
||||
@apply inline-flex cursor-pointer items-center gap-1.5 text-xs transition-colors;
|
||||
color: var(--muted-foreground);
|
||||
|
||||
&:hover {
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
.c-chat__attach-icon {
|
||||
@apply size-3.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.c-chat__preview-list {
|
||||
@apply mt-2 flex flex-wrap gap-2;
|
||||
|
||||
.c-chat__preview-item {
|
||||
@apply relative inline-flex items-center gap-2 p-1.5 pr-8 text-xs;
|
||||
border-radius: calc(var(--radius) - 2px);
|
||||
border: 1px solid var(--border);
|
||||
background-color: var(--muted);
|
||||
|
||||
.c-chat__preview-name {
|
||||
@apply max-w-[150px] truncate;
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
.c-chat__preview-remove {
|
||||
@apply absolute top-1.5 right-1.5 cursor-pointer text-[10px];
|
||||
color: var(--muted-foreground);
|
||||
|
||||
&:hover {
|
||||
color: var(--destructive);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.c-chat__submit-box {
|
||||
@apply flex items-center gap-4;
|
||||
|
||||
.c-chat__button {
|
||||
@apply inline-flex items-center border border-transparent px-4 py-2 text-xs font-semibold tracking-widest uppercase transition duration-150 ease-in-out focus:ring-2 focus:outline-none;
|
||||
border-radius: var(--radius);
|
||||
background-color: var(--primary);
|
||||
color: var(--primary-foreground);
|
||||
|
||||
&:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
22
resources/css/components/heading.css
Normal file
22
resources/css/components/heading.css
Normal file
@ -0,0 +1,22 @@
|
||||
/* 1. Heading Component */
|
||||
.c-heading {
|
||||
@apply mb-8 space-y-0.5;
|
||||
|
||||
&.c-heading--small {
|
||||
@apply mb-0 space-y-0;
|
||||
|
||||
.c-heading__title {
|
||||
@apply mb-0.5 text-base font-medium tracking-normal;
|
||||
}
|
||||
}
|
||||
|
||||
.c-heading__title {
|
||||
@apply text-xl font-semibold tracking-tight;
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
.c-heading__description {
|
||||
@apply text-sm;
|
||||
color: var(--muted-foreground);
|
||||
}
|
||||
}
|
||||
5
resources/css/components/input-error.css
Normal file
5
resources/css/components/input-error.css
Normal file
@ -0,0 +1,5 @@
|
||||
/* 2. InputError Component */
|
||||
.c-input-error__message {
|
||||
@apply text-sm;
|
||||
color: var(--destructive);
|
||||
}
|
||||
25
resources/css/components/lightbox.css
Normal file
25
resources/css/components/lightbox.css
Normal file
@ -0,0 +1,25 @@
|
||||
/* 12. Reusable Lightbox Component */
|
||||
.c-lightbox {
|
||||
@apply fixed inset-0 z-50 flex items-center justify-center p-4;
|
||||
background-color: rgba(0, 0, 0, 0.95);
|
||||
|
||||
.c-lightbox__close {
|
||||
@apply absolute top-6 right-6 cursor-pointer text-3xl text-white transition-colors duration-200;
|
||||
|
||||
&:hover {
|
||||
color: var(--destructive);
|
||||
}
|
||||
}
|
||||
|
||||
.c-lightbox__content {
|
||||
@apply max-h-full max-w-full;
|
||||
|
||||
.c-lightbox__image {
|
||||
@apply max-h-[90vh] max-w-full rounded object-contain shadow-lg;
|
||||
}
|
||||
|
||||
.c-lightbox__video {
|
||||
@apply max-h-[90vh] max-w-full rounded shadow-lg;
|
||||
}
|
||||
}
|
||||
}
|
||||
21
resources/css/components/password-input.css
Normal file
21
resources/css/components/password-input.css
Normal file
@ -0,0 +1,21 @@
|
||||
/* 9. PasswordInput Component */
|
||||
.password-input {
|
||||
@apply relative;
|
||||
|
||||
.password-input__field {
|
||||
@apply pr-10;
|
||||
}
|
||||
|
||||
.password-input__toggle {
|
||||
@apply absolute inset-y-0 right-0 flex items-center rounded-r-md px-3 focus-visible:outline-none;
|
||||
color: var(--muted-foreground);
|
||||
|
||||
&:hover {
|
||||
color: var(--foreground);
|
||||
}
|
||||
}
|
||||
|
||||
.password-input__icon {
|
||||
@apply size-4;
|
||||
}
|
||||
}
|
||||
14
resources/css/components/sidebar-header.css
Normal file
14
resources/css/components/sidebar-header.css
Normal file
@ -0,0 +1,14 @@
|
||||
/* 6. AppSidebarHeader Component */
|
||||
.sidebar-header {
|
||||
@apply flex h-16 shrink-0 items-center gap-2 transition-[width,height] ease-linear md:px-4;
|
||||
border-bottom: 1px solid var(--sidebar-border);
|
||||
background-color: var(--sidebar-background);
|
||||
}
|
||||
|
||||
.sidebar-header__inner {
|
||||
@apply flex items-center gap-2;
|
||||
}
|
||||
|
||||
.group-has-data-[collapsible='icon']/sidebar-wrapper:h-12 .sidebar-header {
|
||||
@apply h-12;
|
||||
}
|
||||
10
resources/css/components/text-link.css
Normal file
10
resources/css/components/text-link.css
Normal file
@ -0,0 +1,10 @@
|
||||
/* 3. TextLink Component */
|
||||
.c-text-link {
|
||||
@apply underline underline-offset-4 transition-colors duration-300 ease-out;
|
||||
color: var(--foreground);
|
||||
text-decoration-color: var(--border);
|
||||
|
||||
&:hover {
|
||||
text-decoration-color: var(--foreground);
|
||||
}
|
||||
}
|
||||
19
resources/css/components/user-info.css
Normal file
19
resources/css/components/user-info.css
Normal file
@ -0,0 +1,19 @@
|
||||
/* 5. UserInfo Component */
|
||||
.user-info__avatar {
|
||||
@apply h-8 w-8 overflow-hidden;
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
|
||||
.user-info__details {
|
||||
@apply grid flex-1 text-left text-sm leading-tight;
|
||||
|
||||
.user-info__name {
|
||||
@apply truncate font-medium;
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
.user-info__email {
|
||||
@apply truncate text-xs;
|
||||
color: var(--muted-foreground);
|
||||
}
|
||||
}
|
||||
@ -19,7 +19,7 @@ configureEcho({
|
||||
forceTLS: false,
|
||||
enabledTransports: ['ws', 'wss'],
|
||||
});
|
||||
if (window) {
|
||||
if (typeof window !== 'undefined') {
|
||||
(window as any).echoConfigured = true;
|
||||
}
|
||||
|
||||
|
||||
@ -22,11 +22,3 @@ const className = computed(() => props.class);
|
||||
<slot />
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@reference "../../css/app.css";
|
||||
|
||||
.app-content {
|
||||
@apply mx-auto flex h-full w-full max-w-7xl flex-1 flex-col gap-4 rounded-xl;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -10,23 +10,3 @@ import AppLogoIcon from '@/components/AppLogoIcon.vue';
|
||||
<span class="app-logo__text">Laravel Starter Kit</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@reference "../../css/app.css";
|
||||
|
||||
.app-logo__icon-container {
|
||||
@apply flex aspect-square size-8 items-center justify-center rounded-md bg-sidebar-primary text-sidebar-primary-foreground;
|
||||
}
|
||||
|
||||
.app-logo__icon {
|
||||
@apply size-5 fill-current text-white dark:text-black;
|
||||
}
|
||||
|
||||
.app-logo__text-container {
|
||||
@apply ml-1 grid flex-1 text-left text-sm;
|
||||
}
|
||||
|
||||
.app-logo__text {
|
||||
@apply mb-0.5 truncate leading-tight font-semibold;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -23,15 +23,3 @@ withDefaults(
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@reference "../../css/app.css";
|
||||
|
||||
.sidebar-header {
|
||||
@apply flex h-16 shrink-0 items-center gap-2 border-b border-sidebar-border/70 px-6 transition-[width,height] ease-linear group-has-data-[collapsible=icon]/sidebar-wrapper:h-12 md:px-4;
|
||||
}
|
||||
|
||||
.sidebar-header__inner {
|
||||
@apply flex items-center gap-2;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -27,27 +27,3 @@ const tabs = [
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@reference "../../css/app.css";
|
||||
|
||||
.appearance-tabs {
|
||||
@apply inline-flex gap-1 rounded-lg bg-neutral-100 p-1 dark:bg-neutral-800;
|
||||
}
|
||||
|
||||
.appearance-tabs__tab {
|
||||
@apply flex items-center rounded-md px-3.5 py-1.5 text-neutral-500 transition-colors hover:bg-neutral-200/60 hover:text-black dark:text-neutral-400 dark:hover:bg-neutral-700/60;
|
||||
}
|
||||
|
||||
.appearance-tabs__tab--active {
|
||||
@apply bg-white shadow-xs hover:bg-white dark:bg-neutral-700 dark:text-neutral-100 dark:hover:bg-neutral-700;
|
||||
}
|
||||
|
||||
.appearance-tabs__icon {
|
||||
@apply -ml-1 h-4 w-4;
|
||||
}
|
||||
|
||||
.appearance-tabs__label {
|
||||
@apply ml-1.5 text-sm;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { useForm } from '@inertiajs/vue3';
|
||||
import { ref, computed } from 'vue';
|
||||
import { useForm, usePage } from '@inertiajs/vue3';
|
||||
import { useEcho, echoIsConfigured, configureEcho } from '@laravel/echo-vue';
|
||||
import { route } from 'ziggy-js';
|
||||
import { Paperclip, Info } from '@lucide/vue';
|
||||
@ -10,7 +10,7 @@ const props = defineProps<{
|
||||
id: number;
|
||||
messages: Array<{
|
||||
id: number;
|
||||
user: { name: string };
|
||||
user: { id: number; name: string };
|
||||
content: string;
|
||||
created_at: string;
|
||||
media?: Array<{
|
||||
@ -63,6 +63,12 @@ function removeFile(index: number) {
|
||||
form.media.splice(index, 1);
|
||||
}
|
||||
|
||||
const currentUser = computed(() => usePage().props.auth?.user);
|
||||
|
||||
function isOwnMessage(messageUserId: number): boolean {
|
||||
return currentUser.value && currentUser.value.id === messageUserId;
|
||||
}
|
||||
|
||||
function submit() {
|
||||
form.post(route('chats.messages.store', props.chat.id), {
|
||||
onSuccess: () => {
|
||||
@ -103,6 +109,10 @@ function closeLightbox() {
|
||||
{
|
||||
'c-chat__message--system':
|
||||
message.content.startsWith('System:'),
|
||||
'c-chat__message--own': isOwnMessage(message.user.id),
|
||||
'c-chat__message--other': !isOwnMessage(
|
||||
message.user.id,
|
||||
),
|
||||
},
|
||||
]"
|
||||
>
|
||||
@ -240,185 +250,22 @@ function closeLightbox() {
|
||||
</form>
|
||||
|
||||
<!-- Gorgeous Dark Lightbox Modal -->
|
||||
<div
|
||||
v-if="activeLightboxUrl"
|
||||
class="c-chat__lightbox"
|
||||
@click="closeLightbox"
|
||||
>
|
||||
<button @click="closeLightbox" class="c-chat__lightbox-close">
|
||||
✕
|
||||
</button>
|
||||
<div class="c-chat__lightbox-content" @click.stop>
|
||||
<div v-if="activeLightboxUrl" class="c-lightbox" @click="closeLightbox">
|
||||
<button @click="closeLightbox" class="c-lightbox__close">✕</button>
|
||||
<div class="c-lightbox__content" @click.stop>
|
||||
<img
|
||||
v-if="activeLightboxType === 'image'"
|
||||
:src="activeLightboxUrl"
|
||||
class="c-chat__lightbox-image"
|
||||
class="c-lightbox__image"
|
||||
/>
|
||||
<video
|
||||
v-else-if="activeLightboxType === 'video'"
|
||||
:src="activeLightboxUrl"
|
||||
controls
|
||||
autoplay
|
||||
class="c-chat__lightbox-video"
|
||||
class="c-lightbox__video"
|
||||
></video>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@reference "../../css/app.css";
|
||||
|
||||
.c-chat {
|
||||
@apply mt-8;
|
||||
}
|
||||
|
||||
.c-chat__title {
|
||||
@apply text-lg font-medium text-gray-900 dark:text-gray-100;
|
||||
}
|
||||
|
||||
.c-chat__list {
|
||||
@apply mt-4 space-y-4;
|
||||
}
|
||||
|
||||
.c-chat__message {
|
||||
@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;
|
||||
}
|
||||
|
||||
.c-chat__message-author {
|
||||
@apply font-semibold;
|
||||
}
|
||||
|
||||
.c-chat__message-time {
|
||||
@apply text-xs text-gray-500;
|
||||
}
|
||||
|
||||
.c-chat__message-text {
|
||||
@apply mt-2 text-sm text-gray-600 dark:text-gray-400;
|
||||
}
|
||||
|
||||
.c-chat__message-media {
|
||||
@apply mt-3 flex flex-wrap gap-2;
|
||||
}
|
||||
|
||||
.c-chat__media-item {
|
||||
@apply relative max-w-[240px] overflow-hidden rounded-md border border-neutral-200 bg-black dark:border-neutral-700;
|
||||
}
|
||||
|
||||
.c-chat__image {
|
||||
@apply h-auto max-h-[180px] w-full object-cover;
|
||||
}
|
||||
|
||||
.c-chat__video {
|
||||
@apply h-auto max-h-[180px] w-full;
|
||||
}
|
||||
|
||||
.c-chat__play-overlay {
|
||||
@apply absolute inset-0 flex items-center justify-center bg-black/40 text-2xl font-bold text-white;
|
||||
}
|
||||
|
||||
.c-chat__empty {
|
||||
@apply text-gray-500;
|
||||
}
|
||||
|
||||
.c-chat__form {
|
||||
@apply mt-6 space-y-6;
|
||||
}
|
||||
|
||||
.c-chat__form-group {
|
||||
@apply space-y-2;
|
||||
}
|
||||
|
||||
.c-chat__label {
|
||||
@apply block text-sm font-medium text-gray-700 dark:text-gray-300;
|
||||
}
|
||||
|
||||
.c-chat__textarea {
|
||||
@apply mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 dark:focus:border-indigo-600 dark:focus:ring-indigo-600;
|
||||
}
|
||||
|
||||
.c-chat__error {
|
||||
@apply text-sm text-red-600;
|
||||
}
|
||||
|
||||
.c-chat__attachment-container {
|
||||
@apply mt-2 flex items-center;
|
||||
}
|
||||
|
||||
.c-chat__attach-btn {
|
||||
@apply inline-flex cursor-pointer items-center gap-1.5 text-xs text-neutral-500 transition-colors hover:text-foreground;
|
||||
}
|
||||
|
||||
.c-chat__attach-icon {
|
||||
@apply size-3.5;
|
||||
}
|
||||
|
||||
.c-chat__preview-list {
|
||||
@apply mt-2 flex flex-wrap gap-2;
|
||||
}
|
||||
|
||||
.c-chat__preview-item {
|
||||
@apply relative inline-flex items-center gap-2 rounded border border-neutral-200 bg-neutral-100 p-1.5 pr-8 text-xs dark:border-neutral-700 dark:bg-neutral-800;
|
||||
}
|
||||
|
||||
.c-chat__preview-name {
|
||||
@apply max-w-[150px] truncate;
|
||||
}
|
||||
|
||||
.c-chat__preview-remove {
|
||||
@apply absolute top-1.5 right-1.5 cursor-pointer text-[10px] text-neutral-400 hover:text-red-500;
|
||||
}
|
||||
|
||||
.c-chat__submit-box {
|
||||
@apply flex items-center gap-4;
|
||||
}
|
||||
|
||||
.c-chat__button {
|
||||
@apply inline-flex items-center rounded-md border border-transparent bg-gray-800 px-4 py-2 text-xs font-semibold tracking-widest text-white uppercase transition duration-150 ease-in-out hover:bg-gray-700 focus:bg-gray-700 focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 focus:outline-none active:bg-gray-900 dark:bg-gray-200 dark:text-gray-800 dark:hover:bg-white dark:focus:bg-white dark:focus:ring-offset-gray-800 dark:active:bg-gray-300;
|
||||
}
|
||||
|
||||
/* Lightbox Styling */
|
||||
.c-chat__lightbox {
|
||||
@apply fixed inset-0 z-50 flex items-center justify-center bg-black/95 p-4;
|
||||
}
|
||||
|
||||
.c-chat__lightbox-close {
|
||||
@apply absolute top-6 right-6 cursor-pointer text-3xl text-white transition-colors duration-200 hover:text-red-500;
|
||||
}
|
||||
|
||||
.c-chat__lightbox-content {
|
||||
@apply max-h-full max-w-full;
|
||||
}
|
||||
|
||||
.c-chat__lightbox-image {
|
||||
@apply max-h-[90vh] max-w-full rounded object-contain shadow-lg;
|
||||
}
|
||||
|
||||
.c-chat__lightbox-video {
|
||||
@apply max-h-[90vh] max-w-full rounded shadow-lg;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -168,11 +168,15 @@ function submit() {
|
||||
}
|
||||
|
||||
.c-create-ledger-form__card {
|
||||
@apply overflow-hidden bg-white shadow-sm sm:rounded-lg dark:bg-gray-800;
|
||||
@apply overflow-hidden;
|
||||
background-color: var(--card);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
|
||||
.c-create-ledger-form__body {
|
||||
@apply p-6 text-gray-900 dark:text-gray-100;
|
||||
@apply p-6;
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
.c-create-ledger-form__title {
|
||||
@ -188,19 +192,29 @@ function submit() {
|
||||
}
|
||||
|
||||
.c-create-ledger-form__label {
|
||||
@apply block text-sm font-medium text-gray-700 dark:text-gray-300;
|
||||
@apply block text-sm font-medium;
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
.c-create-ledger-form__input {
|
||||
@apply mt-1 block w-full rounded-md border border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 dark:focus:border-indigo-600 dark:focus:ring-indigo-600;
|
||||
@apply mt-1 block w-full rounded-md border shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:focus:border-indigo-600 dark:focus:ring-indigo-600;
|
||||
border-color: var(--border);
|
||||
background-color: var(--background);
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
.c-create-ledger-form__textarea {
|
||||
@apply mt-1 block w-full rounded-md border border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 dark:focus:border-indigo-600 dark:focus:ring-indigo-600;
|
||||
@apply mt-1 block w-full rounded-md border shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:focus:border-indigo-600 dark:focus:ring-indigo-600;
|
||||
border-color: var(--border);
|
||||
background-color: var(--background);
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
.c-create-ledger-form__select {
|
||||
@apply mt-1 block w-full rounded-md border border-gray-300 bg-white p-2 text-sm shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 dark:focus:border-indigo-600 dark:focus:ring-indigo-600;
|
||||
@apply mt-1 block w-full rounded-md border p-2 text-sm shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:focus:border-indigo-600 dark:focus:ring-indigo-600;
|
||||
border-color: var(--border);
|
||||
background-color: var(--background);
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
.c-create-ledger-form__file-input {
|
||||
|
||||
@ -20,27 +20,3 @@ withDefaults(defineProps<Props>(), {
|
||||
</p>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@reference "../../css/app.css";
|
||||
|
||||
.c-heading {
|
||||
@apply mb-8 space-y-0.5;
|
||||
}
|
||||
|
||||
.c-heading--small {
|
||||
@apply mb-0 space-y-0;
|
||||
}
|
||||
|
||||
.c-heading__title {
|
||||
@apply text-xl font-semibold tracking-tight;
|
||||
}
|
||||
|
||||
.c-heading--small .c-heading__title {
|
||||
@apply mb-0.5 text-base font-medium tracking-normal;
|
||||
}
|
||||
|
||||
.c-heading__description {
|
||||
@apply text-sm text-muted-foreground;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -11,11 +11,3 @@ defineProps<{
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@reference "../../css/app.css";
|
||||
|
||||
.c-input-error__message {
|
||||
@apply text-sm text-red-600 dark:text-red-500;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -105,7 +105,8 @@ defineProps<{
|
||||
}
|
||||
|
||||
.c-ledger-list__title {
|
||||
@apply text-lg font-medium text-gray-900 dark:text-gray-100;
|
||||
@apply text-lg font-medium;
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
.c-ledger-list__grid {
|
||||
@ -113,15 +114,20 @@ defineProps<{
|
||||
}
|
||||
|
||||
.c-ledger-list__item {
|
||||
@apply border-b border-gray-200 bg-white p-6 dark:border-gray-600 dark:bg-gray-700;
|
||||
@apply p-6;
|
||||
background-color: var(--card);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
|
||||
.c-ledger-list__item-name {
|
||||
@apply text-lg font-semibold;
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
.c-ledger-list__item-score {
|
||||
@apply mt-2 text-sm text-gray-600 dark:text-gray-400;
|
||||
@apply mt-2 text-sm;
|
||||
color: var(--muted-foreground);
|
||||
}
|
||||
|
||||
.c-ledger-list__alignment-wrapper {
|
||||
|
||||
@ -30,7 +30,8 @@ defineProps<{
|
||||
}
|
||||
|
||||
.c-participants-list__title {
|
||||
@apply text-lg font-medium text-gray-900 dark:text-gray-100;
|
||||
@apply text-lg font-medium;
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
.c-participants-list__grid {
|
||||
@ -38,6 +39,10 @@ defineProps<{
|
||||
}
|
||||
|
||||
.c-participants-list__item {
|
||||
@apply overflow-hidden bg-white p-4 shadow-sm sm:rounded-lg dark:bg-gray-800;
|
||||
@apply overflow-hidden p-4;
|
||||
background-color: var(--card);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
color: var(--foreground);
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -40,23 +40,3 @@ defineExpose({
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@reference "../../css/app.css";
|
||||
|
||||
.password-input {
|
||||
@apply relative;
|
||||
}
|
||||
|
||||
:deep(.password-input__field) {
|
||||
@apply pr-10;
|
||||
}
|
||||
|
||||
.password-input__toggle {
|
||||
@apply absolute inset-y-0 right-0 flex items-center rounded-r-md px-3 text-muted-foreground hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring focus-visible:outline-none;
|
||||
}
|
||||
|
||||
.password-input__icon {
|
||||
@apply size-4;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -23,11 +23,3 @@ defineProps<Props>();
|
||||
<slot />
|
||||
</Link>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@reference "../../css/app.css";
|
||||
|
||||
.c-text-link {
|
||||
@apply text-foreground underline decoration-neutral-300 underline-offset-4 transition-colors duration-300 ease-out hover:decoration-current! dark:decoration-neutral-500;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -34,23 +34,3 @@ const showAvatar = computed(
|
||||
<span v-if="showEmail" class="user-info__email">{{ user.email }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@reference "../../css/app.css";
|
||||
|
||||
.user-info__avatar {
|
||||
@apply h-8 w-8 overflow-hidden rounded-lg;
|
||||
}
|
||||
|
||||
.user-info__details {
|
||||
@apply grid flex-1 text-left text-sm leading-tight;
|
||||
}
|
||||
|
||||
.user-info__name {
|
||||
@apply truncate font-medium;
|
||||
}
|
||||
|
||||
.user-info__email {
|
||||
@apply truncate text-xs text-muted-foreground;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -32,47 +32,3 @@ defineProps<{
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@reference "../../../css/app.css";
|
||||
|
||||
.auth-layout {
|
||||
@apply flex min-h-svh flex-col items-center justify-center gap-6 bg-background p-6 md:p-10;
|
||||
}
|
||||
|
||||
.auth-layout__container {
|
||||
@apply w-full max-w-sm;
|
||||
}
|
||||
|
||||
.auth-layout__inner {
|
||||
@apply flex flex-col gap-8;
|
||||
}
|
||||
|
||||
.auth-layout__header {
|
||||
@apply flex flex-col items-center gap-4;
|
||||
}
|
||||
|
||||
.auth-layout__logo-link {
|
||||
@apply flex flex-col items-center gap-2 font-medium;
|
||||
}
|
||||
|
||||
.auth-layout__logo-box {
|
||||
@apply mb-1 flex h-9 w-9 items-center justify-center rounded-md;
|
||||
}
|
||||
|
||||
.auth-layout__logo {
|
||||
@apply size-9 fill-current text-[var(--foreground)] dark:text-white;
|
||||
}
|
||||
|
||||
.auth-layout__title-box {
|
||||
@apply space-y-2 text-center;
|
||||
}
|
||||
|
||||
.auth-layout__title {
|
||||
@apply text-xl font-medium;
|
||||
}
|
||||
|
||||
.auth-layout__description {
|
||||
@apply text-center text-sm text-muted-foreground;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -76,11 +76,15 @@ const breadcrumbs = [
|
||||
}
|
||||
|
||||
.c-dynamic-show__card {
|
||||
@apply overflow-hidden bg-white shadow-sm sm:rounded-lg dark:bg-gray-800;
|
||||
@apply overflow-hidden;
|
||||
background-color: var(--card);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
|
||||
.c-dynamic-show__body {
|
||||
@apply p-6 text-gray-900 dark:text-gray-100;
|
||||
@apply p-6;
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
.c-dynamic-show__title {
|
||||
|
||||
@ -250,26 +250,20 @@ function isOwnerUser(userId: number): boolean {
|
||||
</div>
|
||||
|
||||
<!-- Lightbox Modal -->
|
||||
<div
|
||||
v-if="activeLightboxUrl"
|
||||
class="c-ledger-show__lightbox"
|
||||
@click="closeLightbox"
|
||||
>
|
||||
<button @click="closeLightbox" class="c-ledger-show__lightbox-close">
|
||||
✕
|
||||
</button>
|
||||
<div class="c-ledger-show__lightbox-content" @click.stop>
|
||||
<div v-if="activeLightboxUrl" class="c-lightbox" @click="closeLightbox">
|
||||
<button @click="closeLightbox" class="c-lightbox__close">✕</button>
|
||||
<div class="c-lightbox__content" @click.stop>
|
||||
<img
|
||||
v-if="activeLightboxType === 'image'"
|
||||
:src="activeLightboxUrl"
|
||||
class="c-ledger-show__lightbox-img"
|
||||
class="c-lightbox__image"
|
||||
/>
|
||||
<video
|
||||
v-else-if="activeLightboxType === 'video'"
|
||||
:src="activeLightboxUrl"
|
||||
controls
|
||||
autoplay
|
||||
class="c-ledger-show__lightbox-video"
|
||||
class="c-lightbox__video"
|
||||
></video>
|
||||
</div>
|
||||
</div>
|
||||
@ -361,24 +355,4 @@ function isOwnerUser(userId: number): boolean {
|
||||
.c-ledger-show__media-video-overlay {
|
||||
@apply absolute inset-0 flex items-center justify-center bg-black/40 text-2xl font-bold text-white;
|
||||
}
|
||||
|
||||
.c-ledger-show__lightbox {
|
||||
@apply fixed inset-0 z-50 flex items-center justify-center bg-black/95 p-4;
|
||||
}
|
||||
|
||||
.c-ledger-show__lightbox-close {
|
||||
@apply absolute top-6 right-6 cursor-pointer text-3xl text-white transition-colors duration-200 hover:text-red-500;
|
||||
}
|
||||
|
||||
.c-ledger-show__lightbox-content {
|
||||
@apply max-h-full max-w-full;
|
||||
}
|
||||
|
||||
.c-ledger-show__lightbox-img {
|
||||
@apply max-h-[90vh] max-w-full rounded object-contain shadow-lg;
|
||||
}
|
||||
|
||||
.c-ledger-show__lightbox-video {
|
||||
@apply max-h-[90vh] max-w-full rounded shadow-lg;
|
||||
}
|
||||
</style>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user