Skip to content

ShadcnVue v2.0.1 #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Apr 14, 2025
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
112 changes: 83 additions & 29 deletions electron/app.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
<template>
<div class="h-screen flex flex-col">
<AppMenubar />
<div class="p-4 flex -center justify-between gap-4">
<Input></Input>
<Button>Search</Button>
</div>
<div class="flex-grow overflow-hidden">
<ResizablePanelGroup direction="horizontal" class="h-full">
<ResizablePanel
Expand All @@ -10,13 +14,13 @@
<ScrollArea class="h-full rounded-md border p-4">
<div class="p-4 h-full overflow-auto">
<div>
<Button @click="getImages">Get Images</Button>
<Button @click="getImages()">Get Images</Button>
</div>
<div>
<div v-if="loading">Loading...</div>
<div
v-else-if="image_data.length"
class="grid grid-cols-custom-3 gap-4">
class="grid grid-cols-(--custom-3) gap-4">
<div
v-for="image in image_data"
:key="image.url"
Expand All @@ -26,19 +30,26 @@
selected_image === image
}"
@click="selectImage(image)">
<template v-if="!image.is_square">
<img
:src="image.url"
:alt="image.url"
class="w-full h-full object-cover blur" />
<template v-if="image.isPlaceholder">
<Link2Off
class="w-full h-full object-contain"
color="#e22c3c" />
</template>
<template v-else>
<template v-if="!image.is_square">
<img
:src="image.url"
:alt="image.url"
class="w-full h-full object-cover blur" />
</template>
<div
class="absolute inset-0 flex justify-center items-center">
<img
:src="image.url"
:alt="image.url"
class="w-full h-full object-contain" />
</div>
</template>
<div
class="absolute inset-0 flex justify-center items-center">
<img
:src="image.url"
:alt="image.url"
class="w-full h-full object-contain" />
</div>
</div>
</div>
<div v-else>No images available</div>
Expand All @@ -54,7 +65,7 @@
<ResizablePanelGroup direction="vertical">
<ResizablePanel :min-size="40" :default-size="25">
<div
class="h-full p-4 flex items-center justify-center">
class="h-full rounded-md border p-4 flex items-center justify-center">
<template v-if="selected_image">
<img
:src="selected_image.url"
Expand Down Expand Up @@ -147,7 +158,7 @@
</template>

<script setup lang="ts">
import { Plus, X } from 'lucide-vue-next';
import { Plus, X, Link2Off } from 'lucide-vue-next';

const image_data = ref<TagStackImageData[]>([]);
const selected_image = ref<TagStackImageData | null>(null);
Expand Down Expand Up @@ -213,12 +224,23 @@
size: source.file_size
};
}
async function getImages() {
async function getImages(cache: boolean = false) {
loading.value = true;
let file_path: string | null;

try {
const file_path: string | null = await openDialog();
if (!cache) {
file_path = await openDialog();
if (!file_path) throw new Error('No file path selected.');
await window.ipcRenderer.invoke(
'update-recent-directories',
file_path
);
} else
file_path = await window.ipcRenderer.invoke(
'get-most-recent-directory'
);

try {
if (!file_path) throw new Error('No file path selected.');

const files: FileData[] = await fetchFiles(file_path);
Expand All @@ -233,8 +255,44 @@
else image.id = exists;
}

const db_entries: Entry[] = await fetchEntries();
console.log('DB Entries:', db_entries);
const entry_map = new Map<number, TagStackImageData>();
for (const entry of db_entries) {
const filename = entry.filename;
const directory = entry.path;
const extension = entry.filename.split('.').pop();
const image = new_image_data.find(
(file) =>
file.directory === directory &&
file.filename === filename &&
file.extension.toLowerCase() === extension
);
if (image) {
entry_map.set(entry.id, image);
} else if (file_path === directory) {
entry_map.set(entry.id, {
id: entry.id,
url: '',
width: 0,
height: 0,
is_square: false,
directory: entry.path,
filename: entry.filename,
extension: '',
size: '',
isPlaceholder: true
});
console.log(
`Entry not found in directory: ${directory}\\${filename}`
);
}
}
const ordered_image_data = db_entries
.map((entry) => entry_map.get(entry.id))
.filter((image): image is TagStackImageData => !!image);
entries.value = await fetchEntries();
image_data.value = new_image_data;
image_data.value = ordered_image_data;
} catch (error) {
console.error(
`An error occurred while trying to get images: ${error}`
Expand All @@ -252,14 +310,7 @@

if (!entry?.fields) return;

const tag_ids: number[] =
(entry.fields as { [key: string]: any })['tag_id'] ?? [];
const tag_map: Map<number, Tag> = new Map(
tags.value.map((tag) => [tag.id, tag])
);
applied_tags.value = tag_ids
.filter((tag) => tag_map.has(tag))
.map((tag) => tag_map.get(tag) as Tag);
applied_tags.value = await getTagsFromImage(image);
}
function getExtension(url: string): string {
return url.split('.').pop()!.toUpperCase();
Expand Down Expand Up @@ -300,7 +351,9 @@
[entry.id, 1]
);
} catch (error) {
console.error('Error during insertEntry:', error);
console.error(
`An error occurred while trying to insert an entry: ${error}`
);
throw new Error('Failed to insert entry.');
}
}
Expand Down Expand Up @@ -400,6 +453,7 @@
);
}
tags.value = await fetchTags();
await getImages(true);
});
});
</script>
196 changes: 122 additions & 74 deletions electron/assets/css/tailwind.css
Original file line number Diff line number Diff line change
@@ -1,78 +1,126 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
:root {
--background: 0 0% 100%;
--foreground: 240 10% 3.9%;

--muted: 240 4.8% 95.9%;
--muted-foreground: 240 3.8% 46.1%;

--popover: 0 0% 100%;
--popover-foreground: 240 10% 3.9%;

--card: 0 0% 100%;
--card-foreground: 240 10% 3.9%;

--border: 240 5.9% 90%;
--input: 240 5.9% 90%;

--primary: 240 5.9% 10%;
--primary-foreground: 0 0% 98%;

--secondary: 240 4.8% 95.9%;
--secondary-foreground: 240 5.9% 10%;

--accent: 240 4.8% 95.9%;
--accent-foreground: 240 5.9% 10%;

--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;

--ring: 240 10% 3.9%;

--radius: 0.5rem;
}

.dark {
--background: 240 10% 3.9%;
--foreground: 0 0% 98%;

--muted: 240 3.7% 15.9%;
--muted-foreground: 240 5% 64.9%;

--popover: 240 10% 3.9%;
--popover-foreground: 0 0% 98%;

--card: 240 10% 3.9%;
--card-foreground: 0 0% 98%;

--border: 240 3.7% 15.9%;
--input: 240 3.7% 15.9%;

--primary: 0 0% 98%;
--primary-foreground: 240 5.9% 10%;

--secondary: 240 3.7% 15.9%;
--secondary-foreground: 0 0% 98%;

--accent: 240 3.7% 15.9%;
--accent-foreground: 0 0% 98%;

--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;
@import 'tailwindcss';
@import 'tw-animate-css';

@custom-variant dark (&:is(.dark *));

@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
--color-chart-1: var(--chart-1);
--color-chart-2: var(--chart-2);
--color-chart-3: var(--chart-3);
--color-chart-4: var(--chart-4);
--color-chart-5: var(--chart-5);
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
--color-sidebar: var(--sidebar);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
}

--ring: 240 4.9% 83.9%;
}
:root {
--background: oklch(1 0 0);
--foreground: oklch(0.141 0.005 285.823);
--card: oklch(1 0 0);
--card-foreground: oklch(0.141 0.005 285.823);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.141 0.005 285.823);
--primary: oklch(0.21 0.006 285.885);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.967 0.001 286.375);
--secondary-foreground: oklch(0.21 0.006 285.885);
--muted: oklch(0.967 0.001 286.375);
--muted-foreground: oklch(0.552 0.016 285.938);
--accent: oklch(0.967 0.001 286.375);
--accent-foreground: oklch(0.21 0.006 285.885);
--destructive: oklch(0.577 0.245 27.325);
--destructive-foreground: oklch(0.577 0.245 27.325);
--border: oklch(0.92 0.004 286.32);
--input: oklch(0.92 0.004 286.32);
--ring: oklch(0.705 0.015 286.067);
--chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704);
--chart-3: oklch(0.398 0.07 227.392);
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
--radius: 0.625rem;
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.141 0.005 285.823);
--sidebar-primary: oklch(0.21 0.006 285.885);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.967 0.001 286.375);
--sidebar-accent-foreground: oklch(0.21 0.006 285.885);
--sidebar-border: oklch(0.92 0.004 286.32);
--sidebar-ring: oklch(0.705 0.015 286.067);
}
.dark {
--background: oklch(0.141 0.005 285.823);
--foreground: oklch(0.985 0 0);
--card: oklch(0.141 0.005 285.823);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.141 0.005 285.823);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.985 0 0);
--primary-foreground: oklch(0.21 0.006 285.885);
--secondary: oklch(0.274 0.006 286.033);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.274 0.006 286.033);
--muted-foreground: oklch(0.705 0.015 286.067);
--accent: oklch(0.274 0.006 286.033);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.396 0.141 25.723);
--destructive-foreground: oklch(0.637 0.237 25.331);
--border: oklch(0.274 0.006 286.033);
--input: oklch(0.274 0.006 286.033);
--ring: oklch(0.442 0.017 285.786);
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--sidebar: oklch(0.21 0.006 285.885);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.274 0.006 286.033);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(0.274 0.006 286.033);
--sidebar-ring: oklch(0.442 0.017 285.786);
}

@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}
* {
@apply border-border outline-ring/50;
}
body {
@apply bg-background text-foreground;
}
}

@theme {
--custom-3: repeat(auto-fill, minmax(128px, 1fr));
}
Loading