develop-updateui #1
4
components.d.ts
vendored
4
components.d.ts
vendored
@@ -22,6 +22,7 @@ declare module 'vue' {
|
||||
DashboardSidebar: typeof import('./src/components/dashboard/DashboardSidebar.vue')['default']
|
||||
DashboardTopbar: typeof import('./src/components/dashboard/DashboardTopbar.vue')['default']
|
||||
EmptyState: typeof import('./src/components/dashboard/EmptyState.vue')['default']
|
||||
FloatLabel: typeof import('primevue/floatlabel')['default']
|
||||
HardDriveUpload: typeof import('./src/components/icons/HardDriveUpload.vue')['default']
|
||||
Home: typeof import('./src/components/icons/Home.vue')['default']
|
||||
IconField: typeof import('primevue/iconfield')['default']
|
||||
@@ -36,6 +37,7 @@ declare module 'vue' {
|
||||
RootLayout: typeof import('./src/components/RootLayout.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
Select: typeof import('primevue/select')['default']
|
||||
StatsCard: typeof import('./src/components/dashboard/StatsCard.vue')['default']
|
||||
TestIcon: typeof import('./src/components/icons/TestIcon.vue')['default']
|
||||
Toast: typeof import('primevue/toast')['default']
|
||||
@@ -57,6 +59,7 @@ declare global {
|
||||
const DashboardSidebar: typeof import('./src/components/dashboard/DashboardSidebar.vue')['default']
|
||||
const DashboardTopbar: typeof import('./src/components/dashboard/DashboardTopbar.vue')['default']
|
||||
const EmptyState: typeof import('./src/components/dashboard/EmptyState.vue')['default']
|
||||
const FloatLabel: typeof import('primevue/floatlabel')['default']
|
||||
const HardDriveUpload: typeof import('./src/components/icons/HardDriveUpload.vue')['default']
|
||||
const Home: typeof import('./src/components/icons/Home.vue')['default']
|
||||
const IconField: typeof import('primevue/iconfield')['default']
|
||||
@@ -71,6 +74,7 @@ declare global {
|
||||
const RootLayout: typeof import('./src/components/RootLayout.vue')['default']
|
||||
const RouterLink: typeof import('vue-router')['RouterLink']
|
||||
const RouterView: typeof import('vue-router')['RouterView']
|
||||
const Select: typeof import('primevue/select')['default']
|
||||
const StatsCard: typeof import('./src/components/dashboard/StatsCard.vue')['default']
|
||||
const TestIcon: typeof import('./src/components/icons/TestIcon.vue')['default']
|
||||
const Toast: typeof import('primevue/toast')['default']
|
||||
|
||||
@@ -587,7 +587,14 @@ export class Api<
|
||||
},
|
||||
params: RequestParams = {},
|
||||
) =>
|
||||
this.request<ResponseResponse, ResponseResponse>({
|
||||
this.request<ResponseResponse & {
|
||||
data: {
|
||||
limit: number;
|
||||
page: number;
|
||||
total: number;
|
||||
videos: ModelVideo[];
|
||||
}
|
||||
}, ResponseResponse>({
|
||||
path: `/videos`,
|
||||
method: "GET",
|
||||
query: query,
|
||||
@@ -674,6 +681,6 @@ export class Api<
|
||||
|
||||
export const client = new Api({
|
||||
baseUrl: 'r',
|
||||
// baseUrl: 'https://carey-novelty-various-manufacturers.trycloudflare.com',
|
||||
// baseUrl: 'https://interesting-atmosphere-encryption-value.trycloudflare.com',
|
||||
customFetch
|
||||
});
|
||||
@@ -10,7 +10,7 @@ export const customFetch = async (url: string, options: RequestInit) => {
|
||||
Object.assign(options, {
|
||||
headers: c.req.header()
|
||||
});
|
||||
const res = await fetch(["https://carey-novelty-various-manufacturers.trycloudflare.com", url.replace(/r\//, '')].join('/'), options);
|
||||
const res = await fetch(["https://interesting-atmosphere-encryption-value.trycloudflare.com", url.replace(/r\//, '')].join('/'), options);
|
||||
console.log('Fetching URL:', res);
|
||||
res.headers.forEach((value, key) => {
|
||||
c.header(key, value);
|
||||
|
||||
@@ -35,9 +35,11 @@ const props = defineProps<Props>();
|
||||
<button
|
||||
v-if="actionLabel && onAction"
|
||||
@click="onAction"
|
||||
class="px-6 py-3 bg-primary hover:bg-primary-600 text-white rounded-lg font-medium transition-colors press-animated flex items-center gap-2"
|
||||
class="btn btn-outline-primary press-animated flex items-center gap-2"
|
||||
>
|
||||
<span class="i-heroicons-plus w-5 h-5" />
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
|
||||
</svg>
|
||||
{{ actionLabel }}
|
||||
</button>
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { cn } from '@/lib/utils';
|
||||
import { VNode } from 'vue';
|
||||
|
||||
interface Breadcrumb {
|
||||
label: string;
|
||||
@@ -8,7 +9,7 @@ interface Breadcrumb {
|
||||
|
||||
interface Action {
|
||||
label: string;
|
||||
icon?: string;
|
||||
icon?: string | VNode;
|
||||
variant?: 'primary' | 'secondary' | 'danger';
|
||||
onClick: () => void;
|
||||
}
|
||||
@@ -76,7 +77,11 @@ const getButtonClass = (variant?: string) => {
|
||||
@click="action.onClick"
|
||||
:class="getButtonClass(action.variant)"
|
||||
>
|
||||
<span v-if="action.icon" :class="[action.icon, 'w-5 h-5']" />
|
||||
<component
|
||||
v-if="action.icon"
|
||||
:is="action.icon"
|
||||
class="w-5 h-5"
|
||||
/>
|
||||
{{ action.label }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -15,5 +15,5 @@
|
||||
</svg>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
defineProps<{ class?: string, filled?: boolean }>();
|
||||
defineProps<{ filled?: boolean }>();
|
||||
</script>
|
||||
@@ -14,5 +14,5 @@
|
||||
</svg>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
defineProps<{ class?: string, filled?: boolean }>();
|
||||
defineProps<{ filled?: boolean }>();
|
||||
</script>
|
||||
@@ -3,5 +3,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" v-else viewBox="-10 -194 532 404"><path d="M448-136c9 0 16 7 16 16v32H48v-32c0-9 7-16 16-16h384zm16 112v160c0 9-7 16-16 16H64c-9 0-16-7-16-16V-24h416zM64-184c-35 0-64 29-64 64v256c0 35 29 64 64 64h384c35 0 64-29 64-64v-256c0-35-29-64-64-64H64zM80 96c0 13 11 24 24 24h48c13 0 24-11 24-24s-11-24-24-24h-48c-13 0-24 11-24 24zm144 0c0 13 11 24 24 24h64c13 0 24-11 24-24s-11-24-24-24h-64c-13 0-24 11-24 24z" fill="#1e3050"/></svg>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
defineProps<{ class?: string, filled?: boolean }>();
|
||||
defineProps<{ filled?: boolean }>();
|
||||
</script>
|
||||
@@ -13,5 +13,5 @@
|
||||
</svg>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
defineProps<{ class?: string, filled?: boolean }>();
|
||||
defineProps<{ filled?: boolean }>();
|
||||
</script>
|
||||
@@ -15,5 +15,5 @@
|
||||
</svg>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
defineProps<{ class?: string, filled?: boolean }>();
|
||||
defineProps<{ filled?: boolean }>();
|
||||
</script>
|
||||
@@ -12,5 +12,5 @@
|
||||
</svg>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
defineProps<{ class?: string, filled?: boolean }>();
|
||||
defineProps<{ filled?: boolean }>();
|
||||
</script>
|
||||
@@ -32,7 +32,7 @@ app.use(cors(), async (c, next) => {
|
||||
return next()
|
||||
}
|
||||
const url = new URL(c.req.url)
|
||||
url.host = 'carey-novelty-various-manufacturers.trycloudflare.com'
|
||||
url.host = 'interesting-atmosphere-encryption-value.trycloudflare.com'
|
||||
url.protocol = 'https:'
|
||||
url.pathname = path.replace(/^\/r/, '') || '/'
|
||||
url.port = ''
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { ref, onMounted, createStaticVNode } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import PageHeader from '@/components/dashboard/PageHeader.vue';
|
||||
import EmptyState from '@/components/dashboard/EmptyState.vue';
|
||||
@@ -12,7 +12,7 @@ const error = ref<string | null>(null);
|
||||
const searchQuery = ref('');
|
||||
const selectedStatus = ref<string>('all');
|
||||
const viewMode = ref<'grid' | 'table'>('table');
|
||||
|
||||
const iconHoist = createStaticVNode(`<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 15a4 4 0 004 4h10a4 4 0 004-4v-1a4 4 0 00-4-4H7a4 4 0 00-4 4v1zM16 7l-4-4m0 0L8 7m4-4v12" /></svg>`, 1)
|
||||
// Pagination
|
||||
const page = ref(1);
|
||||
const limit = ref(20);
|
||||
@@ -31,11 +31,11 @@ const fetchVideos = async () => {
|
||||
error.value = null;
|
||||
try {
|
||||
const response = await client.videos.videosList({ page: page.value, limit: limit.value });
|
||||
const body = response.data as any;
|
||||
|
||||
if (body.data && Array.isArray(body.data)) {
|
||||
videos.value = body.data;
|
||||
total.value = body.total || body.data.length;
|
||||
const body = response.data.data
|
||||
// console.log('Fetched videos:', body);
|
||||
if (body.videos && Array.isArray(body.videos)) {
|
||||
videos.value = body.videos;
|
||||
total.value = body.total || body.videos.length;
|
||||
} else if (Array.isArray(body)) {
|
||||
videos.value = body;
|
||||
total.value = body.length;
|
||||
@@ -148,7 +148,8 @@ onMounted(() => {
|
||||
:actions="[
|
||||
{
|
||||
label: 'Upload Video',
|
||||
icon: 'i-heroicons-cloud-arrow-up',
|
||||
// icon: 'i-heroicons-cloud-arrow-up',
|
||||
icon: iconHoist,
|
||||
variant: 'primary',
|
||||
onClick: () => router.push('/upload')
|
||||
}
|
||||
@@ -161,28 +162,22 @@ onMounted(() => {
|
||||
<!-- Search -->
|
||||
<div class="flex-1">
|
||||
<div class="relative">
|
||||
<span class="absolute left-3 top-1/2 -translate-y-1/2 i-heroicons-magnifying-glass w-5 h-5 text-gray-400" />
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400" viewBox="-10 -258 534 534"><path d="M384-40c0-97-79-176-176-176S32-137 32-40s79 176 176 176S384 57 384-40zm-41 158c-36 31-83 50-135 50C93 168 0 75 0-40s93-208 208-208 208 93 208 208c0 52-19 99-50 135l141 142c7 6 7 16 0 22-6 7-16 7-22 0L343 118z" fill="#1e3050"/></svg>
|
||||
<input
|
||||
v-model="searchQuery"
|
||||
@keyup.enter="handleSearch"
|
||||
type="text"
|
||||
placeholder="Search videos by title or description..."
|
||||
class="w-full pl-10 pr-4 py-2.5 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent"
|
||||
class="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Status Filter -->
|
||||
<select
|
||||
v-model="selectedStatus"
|
||||
@change="handleFilter"
|
||||
class="px-4 py-2.5 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent"
|
||||
>
|
||||
<option v-for="option in statusOptions" :key="option.value" :value="option.value">
|
||||
{{ option.label }}
|
||||
</option>
|
||||
</select>
|
||||
|
||||
<FloatLabel class="w-full md:w-56" variant="on">
|
||||
<Select v-model="selectedStatus" inputId="on_label" :options="statusOptions" optionLabel="label" optionValue="value" class="w-full" />
|
||||
<label for="on_label">Status</label>
|
||||
</FloatLabel>
|
||||
<!-- View Mode Toggle -->
|
||||
<div class="flex items-center gap-2 bg-gray-100 rounded-lg p-1">
|
||||
<button
|
||||
@@ -193,7 +188,9 @@ onMounted(() => {
|
||||
]"
|
||||
title="Table view"
|
||||
>
|
||||
<span class="i-heroicons-list-bullet w-5 h-5" :class="viewMode === 'table' ? 'text-primary' : 'text-gray-600'" />
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" :class="viewMode === 'table' ? 'text-primary' : 'text-gray-600'" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 10h16M4 14h16M4 18h16" />
|
||||
</svg>
|
||||
</button>
|
||||
<button
|
||||
@click="viewMode = 'grid'"
|
||||
@@ -203,7 +200,9 @@ onMounted(() => {
|
||||
]"
|
||||
title="Grid view"
|
||||
>
|
||||
<span class="i-heroicons-squares-2x2 w-5 h-5" :class="viewMode === 'grid' ? 'text-primary' : 'text-gray-600'" />
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" :class="viewMode === 'grid' ? 'text-primary' : 'text-gray-600'" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4h6v6H4V4zm0 10h6v6H4v-6zm10-10h6v6h-6V4zm0 10h6v6h-6v-6z" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -228,7 +227,7 @@ onMounted(() => {
|
||||
v-else-if="videos.length === 0"
|
||||
title="No videos found"
|
||||
description="You haven't uploaded any videos yet. Start by uploading your first video!"
|
||||
icon="i-heroicons-film"
|
||||
imageUrl="https://cdn-icons-png.flaticon.com/512/7486/7486747.png"
|
||||
actionLabel="Upload Video"
|
||||
:onAction="() => router.push('/upload')"
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user