diff --git a/README.md b/README.md
index 0e796d3..e69de29 100644
--- a/README.md
+++ b/README.md
@@ -1,214 +0,0 @@
-# Tauri + Next.js Template
-
-![Tauri window screenshot](public/tauri-nextjs-template_screenshot.png)
-
-This is a [Tauri](https://tauri.app/) project template using [Next.js](https://nextjs.org/),
-bootstrapped by combining [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app)
-and [`create tauri-app`](https://tauri.app/v1/guides/getting-started/setup).
-
-This template uses [`pnpm`](https://pnpm.io/) as the Node.js dependency
-manager.
-
-## Template Features
-
-- TypeScript frontend using Next.js React framework
-- [TailwindCSS](https://tailwindcss.com/) as a utility-first atomic CSS framework
- - The example page in this template app has been updated to use only TailwindCSS
- - While not included by default, consider using
- [Radix UI Primitives](https://www.radix-ui.com/) and/or
- [HeadlessUI components](https://headlessui.com/) for completely unstyled and fully
- accessible UI components, which integrate nicely with TailwindCSS
-- Opinionated formatting and linting already setup and enabled
- - [ESLint](https://eslint.org/) + [Prettier](https://prettier.io/) for frontend,
- [clippy](https://github.com/rust-lang/rust-clippy) and
- [rustfmt](https://github.com/rust-lang/rustfmt) for Rust code
-- GitHub Actions to check code formatting and linting for both TypeScript and Rust
-
-## Getting Started
-
-### Running development server and use Tauri window
-
-After cloning for the first time, set up git pre-commit hooks:
-
-```shell
-pnpm prepare
-```
-
-To develop and run the frontend in a Tauri window:
-
-```shell
-pnpm dev
-```
-
-This will load the Next.js frontend directly in a Tauri webview window, in addition to
-starting a development server on `localhost:3000`.
-
-### Building for release
-
-To export the Next.js frontend via SSG and build the Tauri application for release:
-
-```shell
-pnpm build
-```
-
-Please remember to change the bundle identifier in
-`tauri.conf.json > tauri > bundle > identifier`, as the default value will yield an
-error that prevents you from building the application for release.
-
-### Source structure
-
-Next.js frontend source files are located in `src/` and Tauri Rust application source
-files are located in `src-tauri/`. Please consult the Next.js and Tauri documentation
-respectively for questions pertaining to either technology.
-
-## Caveats
-
-### Static Site Generation / Pre-rendering
-
-Next.js is a great React frontend framework which supports server-side rendering (SSR)
-as well as static site generation (SSG or pre-rendering). For the purposes of creating a
-Tauri frontend, only SSG can be used since SSR requires an active Node.js server.
-
-Using Next.js and SSG helps to provide a quick and performant single-page-application
-(SPA) frontend experience. More information regarding this can be found here:
-https://nextjs.org/docs/basic-features/pages#pre-rendering
-
-### `next/image`
-
-The [`next/image` component](https://nextjs.org/docs/basic-features/image-optimization)
-is an enhancement over the regular `` HTML element with additional optimizations
-built in. However, because we are not deploying the frontend onto Vercel directly, some
-optimizations must be disabled to properly build and export the frontend via SSG.
-As such, the
-[`unoptimized` property](https://nextjs.org/docs/api-reference/next/image#unoptimized)
-is set to true for the `next/image` component in the `next.config.js` configuration.
-This will allow the image to be served as-is from source, without
-changes to its quality, size, or format.
-
-### error[E0554]: `#![feature]` may not be used on the stable release channel
-
-If you are getting this issue when trying to run `pnpm tauri dev`, it may be that you
-have a newer version of a Rust dependency that uses an unstable feature.
-`pnpm tauri build` should still work for production builds, but to get the dev command
-working, either downgrade the dependency or use Rust nightly via
-`rustup override set nightly`.
-
-### ReferenceError: navigator is not defined
-
-If you are using Tauri's `invoke` function or any OS related Tauri function from within
-JavaScript, you may encounter this error when importing the function in a global,
-non-browser context. This is due to the nature of Next.js' dev server effectively
-running a Node.js server for SSR and hot module replacement (HMR), and Node.js does not
-have a notion of `window` or `navigator`.
-
-#### Solution 1 - Dependency Injection (may not always work)
-
-Make sure that you are calling these functions within the browser context, e.g. within a
-React component inside a `useEffect` hook when the DOM actually exists by then. If you
-are trying to use a Tauri function in a generalized utility source file, a workaround is
-to use dependency injection for the function itself to delay the actual importing of the
-real function (see example below for more info).
-
-Example using Tauri's `invoke` function:
-
-`src/lib/some_tauri_functions.ts` (problematic)
-
-```typescript
-// Generalized file containing all the invoke functions we need to fetch data from Rust
-import { invoke } from "@tauri-apps/api/tauri"
-
-const loadFoo = (): Promise => {
- return invoke("invoke_handler_foo")
-}
-
-const loadBar = (): Promise => {
- return invoke("invoke_handler_bar")
-}
-
-const loadBaz = (): Promise => {
- return invoke("invoke_handler_baz")
-}
-
-// and so on ...
-```
-
-`src/lib/some_tauri_functions.ts` (fixed)
-
-```typescript
-// Generalized file containing all the invoke functions we need to fetch data from Rust
-//
-// We apply the idea of dependency injection to use a supplied invoke function as a
-// function argument, rather than directly referencing the Tauri invoke function.
-// Hence, don't import invoke globally in this file.
-//
-// import { invoke } from "@tauri-apps/api/tauri" <-- remove this!
-//
-
-import { InvokeArgs } from "@tauri-apps/api/tauri"
-type InvokeFunction = (cmd: string, args?: InvokeArgs | undefined) => Promise
-
-const loadFoo = (invoke: InvokeFunction): Promise => {
- return invoke("invoke_handler_foo")
-}
-
-const loadBar = (invoke: InvokeFunction): Promise => {
- return invoke("invoke_handler_bar")
-}
-
-const loadBaz = (invoke: InvokeFunction): Promise => {
- return invoke("invoke_handler_baz")
-}
-
-// and so on ...
-```
-
-Then, when using `loadFoo`/`loadBar`/`loadBaz` within your React components, import the
-invoke function from `@tauri-apps/api` and pass `invoke` into the loadXXX function as
-the `InvokeFunction` argument. This should allow the actual Tauri API to be bundled
-only within the context of a React component, so it should not be loaded by Next.js upon
-initial startup until the browser has finished loading the page.
-
-#### Solution 2: Wrap Tauri API behind dynamic `import()`
-
-Since the Tauri API needs to read from the browser's `window` and `navigator` object,
-this data does not exist in a Node.js and hence SSR environment. One can create an
-exported function that wraps the Tauri API behind a dynamic runtime `import()` call.
-
-Example: create a `src/lib/tauri.ts` to re-export `invoke`
-
-```typescript
-import type { InvokeArgs } from "@tauri-apps/api/tauri"
-
-const isNode = (): boolean =>
- Object.prototype.toString.call(typeof process !== "undefined" ? process : 0) ===
- "[object process]"
-
-export async function invoke(
- cmd: string,
- args?: InvokeArgs | undefined,
-): Promise {
- if (isNode()) {
- // This shouldn't ever happen when React fully loads
- return Promise.resolve(undefined as unknown as T)
- }
- const tauriAppsApi = await import("@tauri-apps/api")
- const tauriInvoke = tauriAppsApi.invoke
- return tauriInvoke(cmd, args)
-}
-```
-
-Then, instead of importing `import { invoke } from "@tauri-apps/api/tauri"`, use invoke
-from `import { invoke } from "@/lib/tauri"`.
-
-## Learn More
-
-To learn more about Next.js, take a look at the following resources:
-
-- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and
- API.
-- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
-
-And to learn more about Tauri, take a look at the following resources:
-
-- [Tauri Documentation - Guides](https://tauri.app/v1/guides/) - learn about the Tauri
- toolkit.
diff --git a/package.json b/package.json
index 0d603b4..feb1ee3 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,7 @@
"email": "your-email-here@example.com"
},
"scripts": {
- "next-start": "cross-env BROWSER=none next dev",
+ "next-start": "cross-env BROWSER=none NODE_OPTIONS='--inspect' next dev",
"next-build": "next build",
"tauri": "tauri",
"build": "tauri build",
@@ -21,7 +21,8 @@
"next": "^14.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
- "tauri-plugin-clipboard-api": "^0.6.0"
+ "tauri-plugin-clipboard-api": "^0.6.0",
+ "zustand": "^4.5.0"
},
"devDependencies": {
"@prettier/plugin-xml": "^3.2.2",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index bb00e77..a740587 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -23,6 +23,9 @@ dependencies:
tauri-plugin-clipboard-api:
specifier: ^0.6.0
version: 0.6.0
+ zustand:
+ specifier: ^4.5.0
+ version: 4.5.0(@types/react@18.2.53)(react@18.2.0)
devDependencies:
'@prettier/plugin-xml':
@@ -668,7 +671,6 @@ packages:
/@types/prop-types@15.7.11:
resolution: {integrity: sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==}
- dev: true
/@types/react-dom@18.2.18:
resolution: {integrity: sha512-TJxDm6OfAX2KJWJdMEVTwWke5Sc/E/RlnPGvGfS0W7+6ocy2xhDVQVh/KvC2Uf7kACs+gDytdusDSdWfWkaNzw==}
@@ -682,11 +684,9 @@ packages:
'@types/prop-types': 15.7.11
'@types/scheduler': 0.16.8
csstype: 3.1.3
- dev: true
/@types/scheduler@0.16.8:
resolution: {integrity: sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==}
- dev: true
/@types/semver@7.5.6:
resolution: {integrity: sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==}
@@ -1419,7 +1419,6 @@ packages:
/csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
- dev: true
/damerau-levenshtein@1.0.8:
resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==}
@@ -4317,6 +4316,14 @@ packages:
punycode: 2.3.1
dev: true
+ /use-sync-external-store@1.2.0(react@18.2.0):
+ resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ dependencies:
+ react: 18.2.0
+ dev: false
+
/util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
dev: true
@@ -4425,3 +4432,23 @@ packages:
/zod@3.22.4:
resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==}
dev: false
+
+ /zustand@4.5.0(@types/react@18.2.53)(react@18.2.0):
+ resolution: {integrity: sha512-zlVFqS5TQ21nwijjhJlx4f9iGrXSL0o/+Dpy4txAP22miJ8Ti6c1Ol1RLNN98BMib83lmDH/2KmLwaNXpjrO1A==}
+ engines: {node: '>=12.7.0'}
+ peerDependencies:
+ '@types/react': '>=16.8'
+ immer: '>=9.0.6'
+ react: '>=16.8'
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ immer:
+ optional: true
+ react:
+ optional: true
+ dependencies:
+ '@types/react': 18.2.53
+ react: 18.2.0
+ use-sync-external-store: 1.2.0(react@18.2.0)
+ dev: false
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index dc86e87..8db2718 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -1,4 +1,6 @@
+import { useClipStore } from "@/store/clips.store";
import { UnlistenFn } from "@tauri-apps/api/event";
+import _ from "lodash";
import type { NextPage } from "next"
import { useEffect, useState } from "react"
import {
@@ -11,33 +13,22 @@ import {
} from "tauri-plugin-clipboard-api";
const Home: NextPage = () => {
const [copiedText, setCopiedText] = useState("Copied text will be here");
+ const { updateClips, clips } = useClipStore()
let unlistenTextUpdate: UnlistenFn;
- let unlistenImageUpdate: UnlistenFn;
let unlistenClipboard: () => Promise;
- let unlistenFiles: UnlistenFn;
let monitorRunning = false;
useEffect(() => {
+ const debouncedUpdateClips = _.debounce((newText) => {
+ updateClips(newText);
+ }, 300);
const unlistenFunctions = async () => {
unlistenTextUpdate = await onTextUpdate((newText) => {
- console.log(newText);
- setCopiedText(newText);
-
- });
- unlistenImageUpdate = await onImageUpdate((_) => {
- console.log("Image updated");
- });
- unlistenFiles = await onFilesUpdate((_) => {
- console.log("Files updated");
+ console.log("new text::");
+ debouncedUpdateClips(newText);
});
unlistenClipboard = await startListening();
-
- onClipboardUpdate(() => {
- console.log(
- "plugin:clipboard://clipboard-monitor/update event received"
- );
- });
};
listenToMonitorStatusUpdate((running) => {
@@ -49,33 +40,23 @@ const Home: NextPage = () => {
if (unlistenTextUpdate) {
unlistenTextUpdate();
}
- if (unlistenImageUpdate) {
- unlistenImageUpdate();
- }
- if (unlistenClipboard) {
- unlistenClipboard();
- }
- if (unlistenFiles) {
- unlistenFiles();
- }
- console.log(monitorRunning);
};
}, []);
return (
-
-
- {/* {
- clips.map((clip, index) => {
+
+
+ {
+ clips.reverse().map((clip, index) => {
return (
-
-
{copiedText || 'N/A'}
+
)
}
- )} */}
-
{copiedText}
+ )
+ }
)
diff --git a/src/store/clips.store.ts b/src/store/clips.store.ts
new file mode 100644
index 0000000..56c2097
--- /dev/null
+++ b/src/store/clips.store.ts
@@ -0,0 +1,23 @@
+import { create } from 'zustand';
+
+export interface ClipsStore {
+ clips: string[];
+ updateClips: (clip: string) => void;
+}
+
+const initialState: ClipsStore = {
+ clips: [],
+ updateClips: () => { }
+}
+export const useClipStore = create((set) => ({
+ ...initialState,
+ updateClips: (clip) => {
+ set((state) => {
+ // Only add the clip if it's not already in the array
+ if (!state.clips.includes(clip)) {
+ return { clips: [...state.clips, clip] };
+ }
+ return state;
+ });
+ },
+}));