Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 55 additions & 34 deletions resources/js/components/admin/BulkRenameModal.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { router } from '@inertiajs/vue3';
import { PencilLine, Loader2, AlertCircle } from 'lucide-vue-next';
import { PencilLine, Loader2, AlertCircle, ArrowRight } from 'lucide-vue-next';
import { ref, computed, watch } from 'vue';
import BaseModal from '@/components/BaseModal.vue';

Expand All @@ -10,7 +10,7 @@ const props = defineProps<{
id: number;
name: string;
};
resourcesCount: number;
resources: Array<any>;
}>();

const emit = defineEmits<{
Expand All @@ -26,19 +26,22 @@ const cleanPrefix = computed(() => {
return prefix.value.replace(/\s*-\s*$/, '').trim();
});

const previews = computed(() => {
const totalCount = computed(() => props.resources?.length ?? 0);

const previewItems = computed(() => {
const start = Number(startNumber.value) || 1;
const count = Math.min(props.resourcesCount || 3, 3);
const items = [];
const sample = props.resources.slice(0, 5);

for (let i = 0; i < count; i++) {
const num = String(start + i).padStart(2, '0');
const title =
return sample.map((item, index) => {
const num = String(start + index).padStart(2, '0');
const after =
cleanPrefix.value !== '' ? `${cleanPrefix.value} - ${num}` : num;
items.push(title);
}

return items;
return {
before: item.title || 'Untitled',
after,
};
});
});

const handleClose = () => {
Expand All @@ -61,7 +64,7 @@ watch(
);

const handleSubmit = () => {
if (isSaving.value || props.resourcesCount === 0) {
if (isSaving.value || totalCount.value === 0) {
return;
}

Expand Down Expand Up @@ -162,36 +165,56 @@ const handleSubmit = () => {
/>
</div>

<!-- Live Preview Card -->
<!-- Before & After Preview Card -->
<div
class="rounded-xl border border-slate-100 bg-slate-50/70 p-3 dark:border-gray-800 dark:bg-gray-800/40"
class="rounded-xl border border-slate-200 bg-slate-50/70 p-3.5 dark:border-gray-800 dark:bg-gray-800/40"
>
<span
class="mb-1.5 block text-[11px] font-bold tracking-wider text-slate-500 uppercase dark:text-gray-400"
>
Preview (First {{ previews.length }} items)
</span>
<div
class="space-y-1 font-mono text-xs text-slate-700 dark:text-gray-300"
class="mb-2.5 flex items-center justify-between text-[11px] font-bold tracking-wider text-slate-500 uppercase dark:text-gray-400"
>
<span>Before & After Preview</span>
<span
class="font-medium text-slate-400 dark:text-gray-500"
>
Showing {{ previewItems.length }} of
{{ totalCount }}
</span>
</div>

<div class="space-y-1.5 text-xs">
<div
v-for="(item, idx) in previews"
v-for="(item, idx) in previewItems"
:key="idx"
class="flex items-center gap-2"
class="flex items-center justify-between gap-2.5 rounded-lg border border-slate-200/70 bg-white px-3 py-2 shadow-2xs dark:border-gray-700/60 dark:bg-gray-900/60"
>
<span class="text-slate-400 dark:text-gray-500"
>{{ idx + 1 }}.</span
<!-- Before -->
<div
class="min-w-0 flex-1 truncate text-slate-500 line-through decoration-slate-300 dark:text-gray-400 dark:decoration-gray-600"
:title="item.before"
>
<span
class="font-semibold text-indigo-600 dark:text-indigo-400"
>{{ item }}</span
{{ item.before }}
</div>

<!-- Arrow -->
<ArrowRight
class="h-3.5 w-3.5 shrink-0 text-slate-400 dark:text-gray-500"
/>

<!-- After -->
<div
class="min-w-0 flex-1 truncate text-right font-semibold text-indigo-600 dark:text-indigo-400"
:title="item.after"
>
{{ item.after }}
</div>
</div>

<div
v-if="resourcesCount > 3"
class="text-[11px] text-slate-400 dark:text-gray-500"
v-if="totalCount > previewItems.length"
class="pt-1.5 text-center text-[11px] text-slate-400 dark:text-gray-500"
>
... and {{ resourcesCount - 3 }} more
... and {{ totalCount - previewItems.length }} more
files will be renamed
</div>
</div>
</div>
Expand All @@ -211,14 +234,12 @@ const handleSubmit = () => {

<button
type="submit"
:disabled="isSaving || resourcesCount === 0 || !cleanPrefix"
:disabled="isSaving || totalCount === 0 || !cleanPrefix"
class="inline-flex cursor-pointer items-center justify-center gap-1.5 rounded-lg bg-indigo-600 px-4 py-2 text-xs font-semibold text-white shadow-2xs transition hover:bg-indigo-700 disabled:cursor-not-allowed disabled:opacity-50"
>
<Loader2 v-if="isSaving" class="h-3.5 w-3.5 animate-spin" />
<span>{{
isSaving
? 'Renaming...'
: `Rename All (${resourcesCount})`
isSaving ? 'Renaming...' : `Rename All (${totalCount})`
}}</span>
</button>
</div>
Expand Down
2 changes: 1 addition & 1 deletion resources/js/pages/admin/Node.vue
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ onUnmounted(() => document.removeEventListener('click', closeDropdowns));
v-if="parent"
:is-open="isBulkRenameModalOpen"
:node="parent"
:resources-count="resources?.length ?? 0"
:resources="resources ?? []"
@close="isBulkRenameModalOpen = false"
/>

Expand Down