trypost/resources/js/pages/labels/Index.vue
Paulo Castellano adfba2755e feat: Add Pinterest integration and user language preferences
Pinterest Integration:
- Add Pinterest OAuth controller and routes
- Add PinterestPublisher service with support for pins, video pins, and carousels
- Add PinterestPreview component with board selector and content type options
- Add Pinterest content types enum (Pin, VideoPin, Carousel)
- Add Pinterest to Platform enum with proper configuration
- Support sandbox mode via PINTEREST_SANDBOX env variable
- Pass platform-specific data (boards) through PlatformPreview

Language Feature:
- Add languages table with migration
- Add Language model and seeder (en-US, pt-BR)
- Add LanguageCombobox component for profile settings
- Set default language (en-US) on user registration
- Add language_id foreign key to users table

UI Improvements:
- Refactor PlatformPreview to support contentTypeOptions, meta, and platformData props
- Move content type and board selectors into platform-specific preview components

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 13:10:01 -03:00

133 lines
4.9 KiB
Vue

<script setup lang="ts">
import { Head } from '@inertiajs/vue3';
import { ref } from 'vue';
import { Plus, Tag, Pencil, Trash2 } from 'lucide-vue-next';
import AppLayout from '@/layouts/AppLayout.vue';
import ConfirmDeleteModal from '@/components/ConfirmDeleteModal.vue';
import CreateDialog from '@/components/labels/CreateDialog.vue';
import EditDialog from '@/components/labels/EditDialog.vue';
import { Button } from '@/components/ui/button';
import { Card, CardHeader, CardTitle } from '@/components/ui/card';
import { index as labelsIndex, destroy as labelsDestroy } from '@/routes/labels';
import { type BreadcrumbItemType } from '@/types';
interface Workspace {
id: string;
name: string;
}
interface Label {
id: string;
name: string;
color: string;
created_at: string;
}
interface Props {
workspace: Workspace;
labels: Label[];
}
defineProps<Props>();
const deleteModal = ref<InstanceType<typeof ConfirmDeleteModal> | null>(null);
const isCreateDialogOpen = ref(false);
const isEditDialogOpen = ref(false);
const editingLabel = ref<Label | null>(null);
const breadcrumbs: BreadcrumbItemType[] = [
{ title: 'Labels', href: labelsIndex.url() },
];
const openEditDialog = (label: Label) => {
editingLabel.value = label;
isEditDialogOpen.value = true;
};
const handleDelete = (labelId: string) => {
deleteModal.value?.open({
url: labelsDestroy.url(labelId),
});
};
</script>
<template>
<Head title="Labels" />
<AppLayout :breadcrumbs="breadcrumbs">
<div class="flex flex-col gap-6 p-6">
<div v-if="labels.length > 0" class="flex items-center justify-between">
<div>
<h1 class="text-2xl font-bold tracking-tight">Labels</h1>
<p class="text-muted-foreground">
Create labels to organize and categorize your posts
</p>
</div>
<Button @click="isCreateDialogOpen = true">
<Plus class="mr-2 h-4 w-4" />
New Label
</Button>
</div>
<div v-if="labels.length === 0" class="flex flex-col items-center justify-center py-16">
<div class="h-16 w-16 rounded-full bg-muted flex items-center justify-center mb-4">
<Tag class="h-8 w-8 text-muted-foreground" />
</div>
<h3 class="text-lg font-semibold mb-2">No labels yet</h3>
<p class="text-muted-foreground mb-4 text-center max-w-sm">
Create labels to organize and categorize your posts
</p>
<Button @click="isCreateDialogOpen = true">
<Plus class="mr-2 h-4 w-4" />
Create your first label
</Button>
</div>
<div v-else class="grid gap-4 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
<Card v-for="label in labels" :key="label.id">
<CardHeader class="pb-3">
<div class="flex items-center justify-between">
<div class="flex items-center gap-3">
<div
class="h-6 w-6 rounded-md"
:style="{ backgroundColor: label.color }"
/>
<CardTitle class="text-lg">{{ label.name }}</CardTitle>
</div>
<div class="flex items-center gap-1">
<Button
variant="ghost"
size="icon"
class="h-8 w-8"
@click="openEditDialog(label)"
>
<Pencil class="h-4 w-4" />
</Button>
<Button
variant="ghost"
size="icon"
class="h-8 w-8 text-destructive hover:text-destructive"
@click="handleDelete(label.id)"
>
<Trash2 class="h-4 w-4" />
</Button>
</div>
</div>
</CardHeader>
</Card>
</div>
</div>
</AppLayout>
<CreateDialog v-model:open="isCreateDialogOpen" />
<EditDialog v-model:open="isEditDialogOpen" :label="editingLabel" />
<ConfirmDeleteModal
ref="deleteModal"
title="Delete Label"
description="Are you sure you want to delete this label? This action cannot be undone."
action="Delete"
cancel="Cancel"
/>
</template>