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']
|
DashboardSidebar: typeof import('./src/components/dashboard/DashboardSidebar.vue')['default']
|
||||||
DashboardTopbar: typeof import('./src/components/dashboard/DashboardTopbar.vue')['default']
|
DashboardTopbar: typeof import('./src/components/dashboard/DashboardTopbar.vue')['default']
|
||||||
EmptyState: typeof import('./src/components/dashboard/EmptyState.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']
|
HardDriveUpload: typeof import('./src/components/icons/HardDriveUpload.vue')['default']
|
||||||
Home: typeof import('./src/components/icons/Home.vue')['default']
|
Home: typeof import('./src/components/icons/Home.vue')['default']
|
||||||
IconField: typeof import('primevue/iconfield')['default']
|
IconField: typeof import('primevue/iconfield')['default']
|
||||||
@@ -36,6 +37,7 @@ declare module 'vue' {
|
|||||||
RootLayout: typeof import('./src/components/RootLayout.vue')['default']
|
RootLayout: typeof import('./src/components/RootLayout.vue')['default']
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
|
Select: typeof import('primevue/select')['default']
|
||||||
StatsCard: typeof import('./src/components/dashboard/StatsCard.vue')['default']
|
StatsCard: typeof import('./src/components/dashboard/StatsCard.vue')['default']
|
||||||
TestIcon: typeof import('./src/components/icons/TestIcon.vue')['default']
|
TestIcon: typeof import('./src/components/icons/TestIcon.vue')['default']
|
||||||
Toast: typeof import('primevue/toast')['default']
|
Toast: typeof import('primevue/toast')['default']
|
||||||
@@ -57,6 +59,7 @@ declare global {
|
|||||||
const DashboardSidebar: typeof import('./src/components/dashboard/DashboardSidebar.vue')['default']
|
const DashboardSidebar: typeof import('./src/components/dashboard/DashboardSidebar.vue')['default']
|
||||||
const DashboardTopbar: typeof import('./src/components/dashboard/DashboardTopbar.vue')['default']
|
const DashboardTopbar: typeof import('./src/components/dashboard/DashboardTopbar.vue')['default']
|
||||||
const EmptyState: typeof import('./src/components/dashboard/EmptyState.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 HardDriveUpload: typeof import('./src/components/icons/HardDriveUpload.vue')['default']
|
||||||
const Home: typeof import('./src/components/icons/Home.vue')['default']
|
const Home: typeof import('./src/components/icons/Home.vue')['default']
|
||||||
const IconField: typeof import('primevue/iconfield')['default']
|
const IconField: typeof import('primevue/iconfield')['default']
|
||||||
@@ -71,6 +74,7 @@ declare global {
|
|||||||
const RootLayout: typeof import('./src/components/RootLayout.vue')['default']
|
const RootLayout: typeof import('./src/components/RootLayout.vue')['default']
|
||||||
const RouterLink: typeof import('vue-router')['RouterLink']
|
const RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
const RouterView: typeof import('vue-router')['RouterView']
|
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 StatsCard: typeof import('./src/components/dashboard/StatsCard.vue')['default']
|
||||||
const TestIcon: typeof import('./src/components/icons/TestIcon.vue')['default']
|
const TestIcon: typeof import('./src/components/icons/TestIcon.vue')['default']
|
||||||
const Toast: typeof import('primevue/toast')['default']
|
const Toast: typeof import('primevue/toast')['default']
|
||||||
|
|||||||
@@ -587,7 +587,14 @@ export class Api<
|
|||||||
},
|
},
|
||||||
params: RequestParams = {},
|
params: RequestParams = {},
|
||||||
) =>
|
) =>
|
||||||
this.request<ResponseResponse, ResponseResponse>({
|
this.request<ResponseResponse & {
|
||||||
|
data: {
|
||||||
|
limit: number;
|
||||||
|
page: number;
|
||||||
|
total: number;
|
||||||
|
videos: ModelVideo[];
|
||||||
|
}
|
||||||
|
}, ResponseResponse>({
|
||||||
path: `/videos`,
|
path: `/videos`,
|
||||||
method: "GET",
|
method: "GET",
|
||||||
query: query,
|
query: query,
|
||||||
@@ -674,6 +681,6 @@ export class Api<
|
|||||||
|
|
||||||
export const client = new Api({
|
export const client = new Api({
|
||||||
baseUrl: 'r',
|
baseUrl: 'r',
|
||||||
// baseUrl: 'https://carey-novelty-various-manufacturers.trycloudflare.com',
|
// baseUrl: 'https://interesting-atmosphere-encryption-value.trycloudflare.com',
|
||||||
customFetch
|
customFetch
|
||||||
});
|
});
|
||||||
@@ -10,7 +10,7 @@ export const customFetch = async (url: string, options: RequestInit) => {
|
|||||||
Object.assign(options, {
|
Object.assign(options, {
|
||||||
headers: c.req.header()
|
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);
|
console.log('Fetching URL:', res);
|
||||||
res.headers.forEach((value, key) => {
|
res.headers.forEach((value, key) => {
|
||||||
c.header(key, value);
|
c.header(key, value);
|
||||||
|
|||||||
@@ -35,9 +35,11 @@ const props = defineProps<Props>();
|
|||||||
<button
|
<button
|
||||||
v-if="actionLabel && onAction"
|
v-if="actionLabel && onAction"
|
||||||
@click="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 }}
|
{{ actionLabel }}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
import { VNode } from 'vue';
|
||||||
|
|
||||||
interface Breadcrumb {
|
interface Breadcrumb {
|
||||||
label: string;
|
label: string;
|
||||||
@@ -8,7 +9,7 @@ interface Breadcrumb {
|
|||||||
|
|
||||||
interface Action {
|
interface Action {
|
||||||
label: string;
|
label: string;
|
||||||
icon?: string;
|
icon?: string | VNode;
|
||||||
variant?: 'primary' | 'secondary' | 'danger';
|
variant?: 'primary' | 'secondary' | 'danger';
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
}
|
}
|
||||||
@@ -76,7 +77,11 @@ const getButtonClass = (variant?: string) => {
|
|||||||
@click="action.onClick"
|
@click="action.onClick"
|
||||||
:class="getButtonClass(action.variant)"
|
: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 }}
|
{{ action.label }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -15,5 +15,5 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
defineProps<{ class?: string, filled?: boolean }>();
|
defineProps<{ filled?: boolean }>();
|
||||||
</script>
|
</script>
|
||||||
@@ -14,5 +14,5 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
defineProps<{ class?: string, filled?: boolean }>();
|
defineProps<{ filled?: boolean }>();
|
||||||
</script>
|
</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>
|
<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>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
defineProps<{ class?: string, filled?: boolean }>();
|
defineProps<{ filled?: boolean }>();
|
||||||
</script>
|
</script>
|
||||||
@@ -13,5 +13,5 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
defineProps<{ class?: string, filled?: boolean }>();
|
defineProps<{ filled?: boolean }>();
|
||||||
</script>
|
</script>
|
||||||
@@ -15,5 +15,5 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
defineProps<{ class?: string, filled?: boolean }>();
|
defineProps<{ filled?: boolean }>();
|
||||||
</script>
|
</script>
|
||||||
@@ -12,5 +12,5 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
defineProps<{ class?: string, filled?: boolean }>();
|
defineProps<{ filled?: boolean }>();
|
||||||
</script>
|
</script>
|
||||||
@@ -32,7 +32,7 @@ app.use(cors(), async (c, next) => {
|
|||||||
return next()
|
return next()
|
||||||
}
|
}
|
||||||
const url = new URL(c.req.url)
|
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.protocol = 'https:'
|
||||||
url.pathname = path.replace(/^\/r/, '') || '/'
|
url.pathname = path.replace(/^\/r/, '') || '/'
|
||||||
url.port = ''
|
url.port = ''
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted } from 'vue';
|
import { ref, onMounted, createStaticVNode } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import PageHeader from '@/components/dashboard/PageHeader.vue';
|
import PageHeader from '@/components/dashboard/PageHeader.vue';
|
||||||
import EmptyState from '@/components/dashboard/EmptyState.vue';
|
import EmptyState from '@/components/dashboard/EmptyState.vue';
|
||||||
@@ -12,7 +12,7 @@ const error = ref<string | null>(null);
|
|||||||
const searchQuery = ref('');
|
const searchQuery = ref('');
|
||||||
const selectedStatus = ref<string>('all');
|
const selectedStatus = ref<string>('all');
|
||||||
const viewMode = ref<'grid' | 'table'>('table');
|
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
|
// Pagination
|
||||||
const page = ref(1);
|
const page = ref(1);
|
||||||
const limit = ref(20);
|
const limit = ref(20);
|
||||||
@@ -31,11 +31,11 @@ const fetchVideos = async () => {
|
|||||||
error.value = null;
|
error.value = null;
|
||||||
try {
|
try {
|
||||||
const response = await client.videos.videosList({ page: page.value, limit: limit.value });
|
const response = await client.videos.videosList({ page: page.value, limit: limit.value });
|
||||||
const body = response.data as any;
|
const body = response.data.data
|
||||||
|
// console.log('Fetched videos:', body);
|
||||||
if (body.data && Array.isArray(body.data)) {
|
if (body.videos && Array.isArray(body.videos)) {
|
||||||
videos.value = body.data;
|
videos.value = body.videos;
|
||||||
total.value = body.total || body.data.length;
|
total.value = body.total || body.videos.length;
|
||||||
} else if (Array.isArray(body)) {
|
} else if (Array.isArray(body)) {
|
||||||
videos.value = body;
|
videos.value = body;
|
||||||
total.value = body.length;
|
total.value = body.length;
|
||||||
@@ -148,7 +148,8 @@ onMounted(() => {
|
|||||||
:actions="[
|
:actions="[
|
||||||
{
|
{
|
||||||
label: 'Upload Video',
|
label: 'Upload Video',
|
||||||
icon: 'i-heroicons-cloud-arrow-up',
|
// icon: 'i-heroicons-cloud-arrow-up',
|
||||||
|
icon: iconHoist,
|
||||||
variant: 'primary',
|
variant: 'primary',
|
||||||
onClick: () => router.push('/upload')
|
onClick: () => router.push('/upload')
|
||||||
}
|
}
|
||||||
@@ -161,28 +162,22 @@ onMounted(() => {
|
|||||||
<!-- Search -->
|
<!-- Search -->
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<div class="relative">
|
<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
|
<input
|
||||||
v-model="searchQuery"
|
v-model="searchQuery"
|
||||||
@keyup.enter="handleSearch"
|
@keyup.enter="handleSearch"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Search videos by title or description..."
|
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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Status Filter -->
|
<!-- Status Filter -->
|
||||||
<select
|
<FloatLabel class="w-full md:w-56" variant="on">
|
||||||
v-model="selectedStatus"
|
<Select v-model="selectedStatus" inputId="on_label" :options="statusOptions" optionLabel="label" optionValue="value" class="w-full" />
|
||||||
@change="handleFilter"
|
<label for="on_label">Status</label>
|
||||||
class="px-4 py-2.5 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent"
|
</FloatLabel>
|
||||||
>
|
|
||||||
<option v-for="option in statusOptions" :key="option.value" :value="option.value">
|
|
||||||
{{ option.label }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<!-- View Mode Toggle -->
|
<!-- View Mode Toggle -->
|
||||||
<div class="flex items-center gap-2 bg-gray-100 rounded-lg p-1">
|
<div class="flex items-center gap-2 bg-gray-100 rounded-lg p-1">
|
||||||
<button
|
<button
|
||||||
@@ -193,7 +188,9 @@ onMounted(() => {
|
|||||||
]"
|
]"
|
||||||
title="Table view"
|
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>
|
||||||
<button
|
<button
|
||||||
@click="viewMode = 'grid'"
|
@click="viewMode = 'grid'"
|
||||||
@@ -203,7 +200,9 @@ onMounted(() => {
|
|||||||
]"
|
]"
|
||||||
title="Grid view"
|
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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -228,7 +227,7 @@ onMounted(() => {
|
|||||||
v-else-if="videos.length === 0"
|
v-else-if="videos.length === 0"
|
||||||
title="No videos found"
|
title="No videos found"
|
||||||
description="You haven't uploaded any videos yet. Start by uploading your first video!"
|
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"
|
actionLabel="Upload Video"
|
||||||
:onAction="() => router.push('/upload')"
|
:onAction="() => router.push('/upload')"
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user