Skip to content

Commit 7947d3f

Browse files
committed
edit diff refactor
1 parent a6f6904 commit 7947d3f

7 files changed

Lines changed: 386 additions & 314 deletions

File tree

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<script setup>
2+
import { Icon } from "@iconify/vue";
3+
import Upvotable from "@/Components/Upvote/Upvotable.vue";
4+
5+
defineProps({
6+
editedResource: {
7+
type: Object,
8+
required: true,
9+
},
10+
});
11+
</script>
12+
13+
<template>
14+
<div class="mt-8 border-t border-gray-200 dark:border-gray-800 pt-6">
15+
<div class="flex justify-center">
16+
<Upvotable
17+
:flexRow="true"
18+
:upvotable-key="'edit'"
19+
:upvotable-id="editedResource.id"
20+
:initial-votes="editedResource.vote_score"
21+
:user-vote="editedResource.user_vote"
22+
:refresh="true"
23+
class="flex items-center gap-6"
24+
>
25+
<!-- Downvote (Reject) Button -->
26+
<template #alreadyDownvotedIcon>
27+
<span
28+
class="inline-flex items-center px-4 py-2 bg-red-600 text-white rounded-lg font-medium"
29+
>
30+
<Icon
31+
icon="mdi:close-circle"
32+
class="w-4 h-4 mr-2"
33+
/>
34+
Rejected
35+
</span>
36+
</template>
37+
<template #downvoteIcon>
38+
<span
39+
class="inline-flex items-center px-4 py-2 bg-red-50 hover:bg-red-100 text-red-700 border border-red-200 rounded-lg font-medium transition-colors cursor-pointer"
40+
>
41+
<Icon
42+
icon="mdi:close-circle-outline"
43+
class="w-4 h-4 mr-2"
44+
/>
45+
Reject Changes
46+
</span>
47+
</template>
48+
49+
<!-- Vote Count -->
50+
<template #votes="{ votes }">
51+
<div class="flex flex-col items-center">
52+
<span
53+
class="text-2xl font-bold text-gray-900 dark:text-gray-100"
54+
>{{ votes }}</span
55+
>
56+
<span class="text-sm text-gray-600 dark:text-gray-300">
57+
Approval{{ votes === 1 ? "" : "s" }}
58+
</span>
59+
</div>
60+
</template>
61+
62+
<!-- Upvote (Approve) Button -->
63+
<template #alreadyUpvotedIcon>
64+
<span
65+
class="inline-flex items-center px-4 py-2 bg-green-500 text-white rounded-lg font-medium"
66+
>
67+
<Icon
68+
icon="mdi:check-circle"
69+
class="w-4 h-4 mr-2"
70+
/>
71+
Approved!
72+
</span>
73+
</template>
74+
<template #upvoteIcon>
75+
<span
76+
class="inline-flex items-center px-4 py-2 bg-green-200 hover:bg-green-300 text-green-800 border border-green-300 rounded-lg font-medium transition-colors cursor-pointer"
77+
>
78+
<Icon
79+
icon="mdi:check-circle-outline"
80+
class="w-4 h-4 mr-2"
81+
/>
82+
Approve Changes
83+
</span>
84+
</template>
85+
</Upvotable>
86+
</div>
87+
</div>
88+
</template>
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<script setup>
2+
import { Icon } from "@iconify/vue";
3+
4+
defineProps({
5+
changedFields: {
6+
type: Array,
7+
required: true,
8+
},
9+
hasChanges: {
10+
type: Boolean,
11+
required: true,
12+
},
13+
});
14+
</script>
15+
16+
<template>
17+
<div v-if="hasChanges" class="space-y-6">
18+
<div
19+
v-for="field in changedFields"
20+
:key="field.key"
21+
class="bg-gray-50 dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-lg overflow-hidden"
22+
>
23+
<div
24+
class="bg-gray-100 dark:bg-gray-800 px-4 py-2 border-b border-gray-200 dark:border-gray-800"
25+
>
26+
<h3
27+
class="font-semibold text-gray-900 dark:text-gray-100 flex items-center gap-2"
28+
>
29+
<Icon
30+
icon="mdi:file-edit"
31+
class="w-4 h-4 text-primary"
32+
/>
33+
{{ field.label }}
34+
</h3>
35+
</div>
36+
<div class="p-4">
37+
<component
38+
:is="field.component"
39+
:field="field"
40+
/>
41+
</div>
42+
</div>
43+
</div>
44+
<p v-else class="text-gray-500 dark:text-gray-400 italic p-4">
45+
No changes to display in diff.
46+
</p>
47+
</template>
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<script setup>
2+
import Tag from "primevue/tag";
3+
import ResourceThumbnail from "@/Components/Resources/ResourceThumbnail.vue";
4+
5+
defineProps({
6+
field: {
7+
type: Object,
8+
required: true,
9+
},
10+
value: {
11+
required: true,
12+
},
13+
altText: {
14+
type: String,
15+
default: 'Image',
16+
},
17+
});
18+
</script>
19+
20+
<template>
21+
<div>
22+
<h3 class="font-semibold text-gray-600 dark:text-gray-300 mb-2">
23+
{{ field.label }}:
24+
</h3>
25+
<div v-if="field.key === 'image_url'">
26+
<p v-if="!value" class="italic">Image Removed</p>
27+
<ResourceThumbnail
28+
v-else
29+
:src="value"
30+
:alt="altText"
31+
/>
32+
</div>
33+
<div
34+
v-else-if="Array.isArray(value)"
35+
class="flex flex-wrap gap-2"
36+
>
37+
<Tag
38+
v-for="item in value"
39+
:key="item"
40+
:value="field.formatter ? field.formatter(item) : item"
41+
/>
42+
</div>
43+
<div
44+
v-else
45+
class="text-gray-800 dark:text-gray-100 p-2 rounded"
46+
>
47+
{{
48+
field.formatter
49+
? field.formatter(value)
50+
: value
51+
}}
52+
</div>
53+
</div>
54+
</template>
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<script setup>
2+
import { Icon } from "@iconify/vue";
3+
import BackButton from "@/Components/Navigation/BackButton.vue";
4+
import UserProfile from "@/Components/Profile/UserProfile.vue";
5+
import PrimaryButton from "@/Components/PrimaryButton.vue";
6+
7+
defineProps({
8+
editedResource: {
9+
type: Object,
10+
required: true,
11+
},
12+
originalResource: {
13+
type: Object,
14+
required: true,
15+
},
16+
});
17+
18+
const emit = defineEmits(['merge']);
19+
</script>
20+
21+
<template>
22+
<div>
23+
<div class="my-2">
24+
<BackButton
25+
:route="
26+
route('resources.show', {
27+
slug: originalResource.slug,
28+
tab: 'edits',
29+
})
30+
"
31+
/>
32+
</div>
33+
<div class="border-b border-gray-200 dark:border-gray-800 pb-6 mb-6">
34+
<div class="flex items-start justify-between">
35+
<div class="flex-1">
36+
<div class="flex items-center gap-3 mb-3">
37+
<h1
38+
class="text-3xl font-bold text-gray-900 dark:text-gray-100"
39+
>
40+
{{ editedResource.edit_title }}
41+
</h1>
42+
</div>
43+
<p
44+
class="text-gray-700 dark:text-gray-300 text-lg leading-relaxed mb-4"
45+
>
46+
{{ editedResource.edit_description }}
47+
</p>
48+
49+
<UserProfile
50+
:user="editedResource.user"
51+
:date="editedResource.created_at"
52+
/>
53+
</div>
54+
<div
55+
v-if="editedResource.can_merge_edits"
56+
class="ml-6"
57+
>
58+
<PrimaryButton
59+
@click="emit('merge', editedResource.id)"
60+
>
61+
<Icon
62+
icon="mdi:source-merge"
63+
class="w-4 h-4 mr-2"
64+
/>
65+
Merge Changes
66+
</PrimaryButton>
67+
</div>
68+
</div>
69+
</div>
70+
</div>
71+
</template>
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
<script setup>
2+
import { Icon } from "@iconify/vue";
3+
import { Link } from "@inertiajs/vue3";
4+
import FieldDisplay from "./FieldDisplay.vue";
5+
6+
defineProps({
7+
changedFields: {
8+
type: Array,
9+
required: true,
10+
},
11+
originalResource: {
12+
type: Object,
13+
required: true,
14+
},
15+
hasChanges: {
16+
type: Boolean,
17+
required: true,
18+
},
19+
});
20+
</script>
21+
22+
<template>
23+
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
24+
<!-- Proposed Changes Column -->
25+
<div
26+
class="bg-gray-50 dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-lg"
27+
>
28+
<div
29+
class="bg-primary/5 dark:bg-primary/10 border-b border-gray-200 dark:border-gray-800 px-4 py-3"
30+
>
31+
<h2
32+
class="text-lg font-semibold text-gray-900 dark:text-gray-100 flex items-center gap-2"
33+
>
34+
<Icon
35+
icon="mdi:plus-circle"
36+
class="w-5 h-5 text-primary"
37+
/>
38+
Proposed Changes
39+
</h2>
40+
</div>
41+
<div class="p-4 space-y-4">
42+
<FieldDisplay
43+
v-for="field in changedFields"
44+
:key="field.key"
45+
:field="field"
46+
:value="field.proposedValue"
47+
altText="Proposed Image"
48+
/>
49+
<p
50+
v-if="!hasChanges"
51+
class="text-gray-500 dark:text-gray-400 italic"
52+
>
53+
No changes were proposed.
54+
</p>
55+
</div>
56+
</div>
57+
58+
<!-- Current Version Column -->
59+
<div
60+
class="bg-gray-50 dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-lg"
61+
>
62+
<div
63+
class="bg-gray-100 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-800 px-4 py-3"
64+
>
65+
<Link
66+
:href="
67+
route('resources.show', {
68+
slug: originalResource.slug,
69+
})
70+
"
71+
class="group"
72+
>
73+
<h2
74+
class="text-lg font-semibold text-gray-900 dark:text-gray-100 flex items-center gap-2 group-hover:text-primary duration-200"
75+
>
76+
<Icon
77+
icon="mdi:file-document"
78+
class="w-5 h-5 text-gray-600 dark:text-gray-300 group-hover:text-primary duration-200"
79+
/>
80+
Current Version
81+
</h2>
82+
</Link>
83+
</div>
84+
<div class="p-4 space-y-4">
85+
<FieldDisplay
86+
v-for="field in changedFields"
87+
:key="field.key"
88+
:field="field"
89+
:value="field.originalValue"
90+
altText="Current Image"
91+
/>
92+
<p
93+
v-if="!hasChanges"
94+
class="text-gray-500 dark:text-gray-400 italic"
95+
>
96+
No changes to compare.
97+
</p>
98+
</div>
99+
</div>
100+
</div>
101+
</template>

resources/js/Pages/ResourceEdits/Create.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ const props = defineProps({
3434
required: true,
3535
},
3636
});
37-
// TODO: MOVE TO AXIOS BECAUSE REDIRECT FROM SUCCESSES WILL NOT CLEAR STORAGE, CONFIRM WITH TEST
37+
38+
// TODO: MOVE TO AXIOS BECAUSE REDIRECT FROM SUCCESSES WILL NOT CLEAR STORAGE, CONFIRM WITH TEST IN FUTURE
3839
const formData = useForm({
3940
edit_title: "",
4041
edit_description: "",

0 commit comments

Comments
 (0)