wip: dialog to choose folder to watch
This commit is contained in:
Binary file not shown.
@ -115,7 +115,7 @@ pub fn run() {
|
|||||||
.setup(|app| {
|
.setup(|app| {
|
||||||
let win_builder = WebviewWindowBuilder::new(app, "main", WebviewUrl::default())
|
let win_builder = WebviewWindowBuilder::new(app, "main", WebviewUrl::default())
|
||||||
.inner_size(480.0, 360.0)
|
.inner_size(480.0, 360.0)
|
||||||
.resizable(false);
|
.resizable(true);
|
||||||
// set transparent title bar only when building for macOS
|
// set transparent title bar only when building for macOS
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
let win_builder = win_builder.title_bar_style(TitleBarStyle::Transparent);
|
let win_builder = win_builder.title_bar_style(TitleBarStyle::Transparent);
|
||||||
|
@ -2,107 +2,109 @@ import { createSignal } from "solid-js";
|
|||||||
import { Search } from "@kobalte/core/search";
|
import { Search } from "@kobalte/core/search";
|
||||||
import { IconSearch, IconRefresh } from "@tabler/icons-solidjs";
|
import { IconSearch, IconRefresh } from "@tabler/icons-solidjs";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
|
import { ImageViewer } from "./components/ImageViewer";
|
||||||
|
|
||||||
type Emoji = {
|
type Emoji = {
|
||||||
emoji: string;
|
emoji: string;
|
||||||
name: string;
|
name: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [options, setOptions] = createSignal<Emoji[]>([]);
|
const [options, setOptions] = createSignal<Emoji[]>([]);
|
||||||
const [emoji, setEmoji] = createSignal<Emoji | null>(null);
|
const [emoji, setEmoji] = createSignal<Emoji | null>(null);
|
||||||
|
|
||||||
const emojiData: Emoji[] = [
|
const emojiData: Emoji[] = [
|
||||||
{ emoji: "😀", name: "Grinning Face" },
|
{ emoji: "😀", name: "Grinning Face" },
|
||||||
{ emoji: "😃", name: "Grinning Face with Big Eyes" },
|
{ emoji: "😃", name: "Grinning Face with Big Eyes" },
|
||||||
{ emoji: "😄", name: "Grinning Face with Smiling Eyes" },
|
{ emoji: "😄", name: "Grinning Face with Smiling Eyes" },
|
||||||
{ emoji: "😁", name: "Beaming Face with Smiling Eyes" },
|
{ emoji: "😁", name: "Beaming Face with Smiling Eyes" },
|
||||||
{ emoji: "😆", name: "Grinning Squinting Face" },
|
{ emoji: "😆", name: "Grinning Squinting Face" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const queryEmojiData = (query: string) => {
|
const queryEmojiData = (query: string) => {
|
||||||
return emojiData.filter((emoji) =>
|
return emojiData.filter((emoji) =>
|
||||||
emoji.name.toLowerCase().includes(query.toLowerCase()),
|
emoji.name.toLowerCase().includes(query.toLowerCase()),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main class="container pt-2">
|
<main class="container pt-2">
|
||||||
<div class="px-4">
|
<div class="px-4">
|
||||||
<Search
|
<Search
|
||||||
triggerMode="focus"
|
triggerMode="focus"
|
||||||
options={options()}
|
options={options()}
|
||||||
onInputChange={(query) => setOptions(queryEmojiData(query))}
|
onInputChange={(query) => setOptions(queryEmojiData(query))}
|
||||||
onChange={(result) => setEmoji(result)}
|
onChange={(result) => setEmoji(result)}
|
||||||
optionValue="name"
|
optionValue="name"
|
||||||
optionLabel="name"
|
optionLabel="name"
|
||||||
placeholder="Search for stuff..."
|
placeholder="Search for stuff..."
|
||||||
itemComponent={(props) => (
|
itemComponent={(props) => (
|
||||||
<Search.Item
|
<Search.Item
|
||||||
item={props.item}
|
item={props.item}
|
||||||
class={clsx(
|
class={clsx(
|
||||||
"text-2xl leading-none text-gray-900 rounded-md p-2 select-none outline-none grid justify-items-center w-[calc(20%-5px)] box-border",
|
"text-2xl leading-none text-gray-900 rounded-md p-2 select-none outline-none grid justify-items-center w-[calc(20%-5px)] box-border",
|
||||||
"hover:bg-gray-100 ui-highlighted:bg-gray-100 ui-highlighted:shadow-[inset_0_0_0_2px_rgb(2,132,199)] ui-disabled:text-gray-400 ui-disabled:opacity-50 ui-disabled:pointer-events-none",
|
"hover:bg-gray-100 ui-highlighted:bg-gray-100 ui-highlighted:shadow-[inset_0_0_0_2px_rgb(2,132,199)] ui-disabled:text-gray-400 ui-disabled:opacity-50 ui-disabled:pointer-events-none",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Search.ItemLabel class="mx-[-100px]">
|
<Search.ItemLabel class="mx-[-100px]">
|
||||||
{props.item.rawValue.emoji}
|
{props.item.rawValue.emoji}
|
||||||
</Search.ItemLabel>
|
</Search.ItemLabel>
|
||||||
</Search.Item>
|
</Search.Item>
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Search.Control
|
<Search.Control
|
||||||
class="inline-flex justify-between w-full rounded-xl text-base leading-none outline-none bg-white border border-gray-200 text-gray-900 transition-colors duration-250 ui-invalid:border-red-500 ui-invalid:text-red-500"
|
class="inline-flex justify-between w-full rounded-xl text-base leading-none outline-none bg-white border border-gray-200 text-gray-900 transition-colors duration-250 ui-invalid:border-red-500 ui-invalid:text-red-500"
|
||||||
aria-label="Emoji"
|
aria-label="Emoji"
|
||||||
>
|
>
|
||||||
<Search.Indicator
|
<Search.Indicator
|
||||||
class="appearance-none inline-flex justify-center items-center w-auto outline-none rounded-l-md px-2.5 text-gray-900 text-base leading-none transition-colors duration-250"
|
class="appearance-none inline-flex justify-center items-center w-auto outline-none rounded-l-md px-2.5 text-gray-900 text-base leading-none transition-colors duration-250"
|
||||||
loadingComponent={
|
loadingComponent={
|
||||||
<Search.Icon class="h-5 w-5 grid justify-items-center flex-none">
|
<Search.Icon class="h-5 w-5 grid justify-items-center flex-none">
|
||||||
<IconRefresh size={20} class="m-auto animate-spin" />
|
<IconRefresh size={20} class="m-auto animate-spin" />
|
||||||
</Search.Icon>
|
</Search.Icon>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Search.Icon class="h-5 w-5 grid justify-items-center flex-none">
|
<Search.Icon class="h-5 w-5 grid justify-items-center flex-none">
|
||||||
<IconSearch class="m-auto size-5 text-gray-600" />
|
<IconSearch class="m-auto size-5 text-gray-600" />
|
||||||
</Search.Icon>
|
</Search.Icon>
|
||||||
</Search.Indicator>
|
</Search.Indicator>
|
||||||
<Search.Input class="appearance-none inline-flex w-full min-h-[40px] text-base bg-transparent rounded-l-md outline-none placeholder:text-gray-600" />
|
<Search.Input class="appearance-none inline-flex w-full min-h-[40px] text-base bg-transparent rounded-l-md outline-none placeholder:text-gray-600" />
|
||||||
</Search.Control>
|
</Search.Control>
|
||||||
<Search.Portal>
|
<Search.Portal>
|
||||||
<Search.Content
|
<Search.Content
|
||||||
class="bg-white rounded-md border border-gray-200 shadow-md origin-[var(--kb-search-content-transform-origin)] w-[var(--kb-popper-anchor-width)] data-[expanded]:animate-contentShow"
|
class="bg-white rounded-md border border-gray-200 shadow-md origin-[var(--kb-search-content-transform-origin)] w-[var(--kb-popper-anchor-width)] data-[expanded]:animate-contentShow"
|
||||||
onCloseAutoFocus={(e) => e.preventDefault()}
|
onCloseAutoFocus={(e) => e.preventDefault()}
|
||||||
>
|
>
|
||||||
<Search.Listbox class="overflow-y-auto max-h-[360px] p-2 flex flex-row justify-start flex-wrap gap-1.5 leading-none focus:outline-none" />
|
<Search.Listbox class="overflow-y-auto max-h-[360px] p-2 flex flex-row justify-start flex-wrap gap-1.5 leading-none focus:outline-none" />
|
||||||
<Search.NoResult class="text-center p-2 pb-6 m-auto text-gray-600">
|
<Search.NoResult class="text-center p-2 pb-6 m-auto text-gray-600">
|
||||||
😬 No emoji found
|
😬 No emoji found
|
||||||
</Search.NoResult>
|
</Search.NoResult>
|
||||||
</Search.Content>
|
</Search.Content>
|
||||||
</Search.Portal>
|
</Search.Portal>
|
||||||
</Search>
|
</Search>
|
||||||
</div>
|
</div>
|
||||||
{/* <div class="mt-4 text-base leading-none">
|
{/* <div class="mt-4 text-base leading-none">
|
||||||
Emoji selected: {emoji()?.emoji} {emoji()?.name}
|
Emoji selected: {emoji()?.emoji} {emoji()?.name}
|
||||||
</div> */}
|
</div> */}
|
||||||
<div class="px-4 mt-4 bg-white rounded-t-2xl">
|
<ImageViewer />
|
||||||
<div class="h-[254px] overflow-scroll scrollbar-hide">
|
<div class="px-4 mt-4 bg-white rounded-t-2xl">
|
||||||
<div class="w-full grid grid-cols-9 grid-rows-9 gap-2 h-[480px] grid-flow-row-dense py-4">
|
<div class="h-[254px] overflow-scroll scrollbar-hide">
|
||||||
<div class="col-span-3 row-span-3 bg-red-200 rounded-xl" />
|
<div class="w-full grid grid-cols-9 grid-rows-9 gap-2 h-[480px] grid-flow-row-dense py-4">
|
||||||
<div class="col-span-3 row-span-3 bg-green-200 rounded-xl" />
|
<div class="col-span-3 row-span-3 bg-red-200 rounded-xl" />
|
||||||
<div class="col-span-6 row-span-3 bg-yellow-200 rounded-xl" />
|
<div class="col-span-3 row-span-3 bg-green-200 rounded-xl" />
|
||||||
<div class="col-span-3 row-span-3 bg-green-200 rounded-xl" />
|
<div class="col-span-6 row-span-3 bg-yellow-200 rounded-xl" />
|
||||||
<div class="col-span-3 row-span-3 bg-blue-200 rounded-xl" />
|
<div class="col-span-3 row-span-3 bg-green-200 rounded-xl" />
|
||||||
<div class="col-span-3 row-span-3 bg-green-200 rounded-xl" />
|
<div class="col-span-3 row-span-3 bg-blue-200 rounded-xl" />
|
||||||
<div class="col-span-6 row-span-3 bg-yellow-200 rounded-xl" />
|
<div class="col-span-3 row-span-3 bg-green-200 rounded-xl" />
|
||||||
</div>
|
<div class="col-span-6 row-span-3 bg-yellow-200 rounded-xl" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full border-t h-10 bg-white px-4 border-neutral-100">
|
</div>
|
||||||
footer
|
<div class="w-full border-t h-10 bg-white px-4 border-neutral-100">
|
||||||
</div>
|
footer
|
||||||
</main>
|
</div>
|
||||||
);
|
</main>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
@ -1,37 +1,40 @@
|
|||||||
import { createEffect, createSignal } from "solid-js";
|
import { createEffect, createSignal } from "solid-js";
|
||||||
import { listen } from "@tauri-apps/api/event";
|
import { listen } from "@tauri-apps/api/event";
|
||||||
import { FolderPicker } from "./FolderPicker";
|
import { FolderPicker } from "./FolderPicker";
|
||||||
|
import { sendImage } from "../network";
|
||||||
|
|
||||||
export function ImageViewer() {
|
export function ImageViewer() {
|
||||||
const [latestImage, setLatestImage] = createSignal<string | null>(null);
|
const [latestImage, setLatestImage] = createSignal<string | null>(null);
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
// Listen for PNG processing events
|
// Listen for PNG processing events
|
||||||
const unlisten = listen("png-processed", (event) => {
|
const unlisten = listen("png-processed", (event) => {
|
||||||
console.log("Received processed PNG");
|
console.log("Received processed PNG");
|
||||||
const base64Data = event.payload as string;
|
const base64Data = event.payload as string;
|
||||||
setLatestImage(`data:image/png;base64,${base64Data}`);
|
setLatestImage(`data:image/png;base64,${base64Data}`);
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
sendImage("test-image.png", base64Data);
|
||||||
unlisten.then((fn) => fn()); // Cleanup listener
|
});
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return () => {
|
||||||
<div>
|
unlisten.then((fn) => fn()); // Cleanup listener
|
||||||
<FolderPicker />
|
};
|
||||||
|
});
|
||||||
|
|
||||||
{latestImage() && (
|
return (
|
||||||
<div class="mt-4">
|
<div>
|
||||||
<h3>Latest Processed Image:</h3>
|
<FolderPicker />
|
||||||
<img
|
|
||||||
src={latestImage() || undefined}
|
{latestImage() && (
|
||||||
alt="Latest processed"
|
<div class="mt-4">
|
||||||
class="max-w-md"
|
<h3>Latest Processed Image:</h3>
|
||||||
/>
|
<img
|
||||||
</div>
|
src={latestImage() || undefined}
|
||||||
)}
|
alt="Latest processed"
|
||||||
</div>
|
class="max-w-md"
|
||||||
);
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user