init commit
Some checks are pending
Lint Node.js / build (windows-latest) (push) Waiting to run
Lint Node.js / build (macos-latest) (push) Waiting to run
Lint Node.js / build (ubuntu-latest) (push) Waiting to run
Lint Rust / build (macos-latest) (push) Waiting to run
Lint Rust / build (ubuntu-latest) (push) Waiting to run
Lint Rust / build (windows-latest) (push) Waiting to run
Some checks are pending
Lint Node.js / build (windows-latest) (push) Waiting to run
Lint Node.js / build (macos-latest) (push) Waiting to run
Lint Node.js / build (ubuntu-latest) (push) Waiting to run
Lint Rust / build (macos-latest) (push) Waiting to run
Lint Rust / build (ubuntu-latest) (push) Waiting to run
Lint Rust / build (windows-latest) (push) Waiting to run
This commit is contained in:
21
src/components/Card.tsx
Normal file
21
src/components/Card.tsx
Normal file
@@ -0,0 +1,21 @@
|
||||
interface CardProps {
|
||||
url: string
|
||||
title: string
|
||||
description: string
|
||||
}
|
||||
|
||||
export const Card: React.FC<CardProps> = ({
|
||||
url,
|
||||
title,
|
||||
description,
|
||||
}: CardProps) => (
|
||||
<a
|
||||
href={url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="m-4 max-w-xs rounded-xl border border-gray-200 p-6 text-left text-inherit transition-colors hover:border-blue-600 hover:text-blue-600 focus:border-blue-600 focus:text-blue-600 active:border-blue-600 active:text-blue-600"
|
||||
>
|
||||
<h2 className="mb-4 text-2xl">{title} →</h2>
|
||||
<p className="m-0 text-xl">{description}</p>
|
||||
</a>
|
||||
)
|
||||
20
src/components/CardButton.tsx
Normal file
20
src/components/CardButton.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
interface CardButtonProps {
|
||||
onClick: () => void
|
||||
title: string
|
||||
description: string
|
||||
}
|
||||
|
||||
export const CardButton: React.FC<CardButtonProps> = ({
|
||||
onClick,
|
||||
title,
|
||||
description,
|
||||
}: CardButtonProps) => (
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClick}
|
||||
className="m-4 max-w-xs rounded-xl border border-gray-200 p-6 text-left text-inherit transition-colors hover:border-blue-600 hover:text-blue-600 focus:border-blue-600 focus:text-blue-600 active:border-blue-600 active:text-blue-600"
|
||||
>
|
||||
<h2 className="mb-4 text-2xl">{title} →</h2>
|
||||
<p className="m-0 text-xl">{description}</p>
|
||||
</button>
|
||||
)
|
||||
40
src/hooks/tauri/shortcuts.ts
Normal file
40
src/hooks/tauri/shortcuts.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import {
|
||||
type ShortcutHandler,
|
||||
isRegistered,
|
||||
register,
|
||||
unregister,
|
||||
} from "@tauri-apps/api/globalShortcut"
|
||||
import { useEffect } from "react"
|
||||
|
||||
/**
|
||||
* A React hook to register global shortcuts using Tauri's globalShortcut API.
|
||||
* Internally this uses a useEffect hook, but has proper support for React.StrictMode
|
||||
* via cleaning up the effect hook, so as to maintain idempotency.
|
||||
*
|
||||
* @param shortcut The key combination string for the shortcut
|
||||
* @param shortcutHandler The handler callback when the shortcut is triggered
|
||||
*/
|
||||
export const useGlobalShortcut = (
|
||||
shortcut: string,
|
||||
shortcutHandler: ShortcutHandler,
|
||||
) => {
|
||||
useEffect(() => {
|
||||
let ignore = false
|
||||
|
||||
async function registerShortcut() {
|
||||
const isShortcutRegistered = await isRegistered(shortcut)
|
||||
if (!ignore && !isShortcutRegistered) {
|
||||
await register(shortcut, shortcutHandler)
|
||||
}
|
||||
}
|
||||
|
||||
void registerShortcut().catch((err: unknown) => {
|
||||
console.error(`Failed to register global shortcut '${shortcut}'`, err)
|
||||
})
|
||||
|
||||
return () => {
|
||||
ignore = true
|
||||
void unregister(shortcut)
|
||||
}
|
||||
}, [shortcut, shortcutHandler])
|
||||
}
|
||||
8
src/pages/_app.tsx
Normal file
8
src/pages/_app.tsx
Normal file
@@ -0,0 +1,8 @@
|
||||
import "@/styles/globals.css"
|
||||
import type { AppProps } from "next/app"
|
||||
|
||||
function MyApp({ Component, pageProps }: AppProps) {
|
||||
return <Component {...pageProps} />
|
||||
}
|
||||
|
||||
export default MyApp
|
||||
108
src/pages/index.tsx
Normal file
108
src/pages/index.tsx
Normal file
@@ -0,0 +1,108 @@
|
||||
import { Card } from "@/components/Card"
|
||||
import { CardButton } from "@/components/CardButton"
|
||||
import { useGlobalShortcut } from "@/hooks/tauri/shortcuts"
|
||||
import { invoke } from "@tauri-apps/api/tauri"
|
||||
import type { NextPage } from "next"
|
||||
import Head from "next/head"
|
||||
import Image from "next/image"
|
||||
import { useCallback, useState } from "react"
|
||||
|
||||
const Home: NextPage = () => {
|
||||
const [buttonDesc, setButtonDesc] = useState<string>(
|
||||
"Waiting to be clicked. This calls 'on_button_clicked' from Rust.",
|
||||
)
|
||||
const onButtonClick = () => {
|
||||
invoke<string>("on_button_clicked")
|
||||
.then((value) => {
|
||||
setButtonDesc(value)
|
||||
})
|
||||
.catch(() => {
|
||||
setButtonDesc("Failed to invoke Rust command 'on_button_clicked'")
|
||||
})
|
||||
}
|
||||
|
||||
const shortcutHandler = useCallback(() => {
|
||||
console.log("Ctrl+P was pressed!")
|
||||
}, [])
|
||||
useGlobalShortcut("CommandOrControl+P", shortcutHandler)
|
||||
|
||||
return (
|
||||
<div className="flex min-h-screen flex-col bg-white">
|
||||
<Head>
|
||||
<title>Create Next App</title>
|
||||
<meta name="description" content="Generated by create next app" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</Head>
|
||||
|
||||
<main className="flex flex-1 flex-col items-center justify-center py-8">
|
||||
<h1 className="m-0 text-center text-6xl">
|
||||
Welcome to{" "}
|
||||
<a
|
||||
href="https://nextjs.org"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-blue-600 hover:underline focus:underline active:underline"
|
||||
>
|
||||
Next.js!
|
||||
</a>
|
||||
</h1>
|
||||
|
||||
<p className="my-12 text-center text-2xl leading-9">
|
||||
Get started by editing{" "}
|
||||
<code className="rounded-md bg-gray-200 p-2 font-mono text-xl">
|
||||
src/pages/index.tsx
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<div className="flex max-w-3xl flex-wrap items-center justify-center">
|
||||
<Card
|
||||
url="https://nextjs.org/docs"
|
||||
title="Documentation"
|
||||
description="Find in-depth information about Next.js features and API."
|
||||
/>
|
||||
|
||||
<Card
|
||||
url="https://nextjs.org/learn"
|
||||
title="Learn"
|
||||
description="Learn about Next.js in an interactive course with quizzes!"
|
||||
/>
|
||||
|
||||
<Card
|
||||
url="https://github.com/vercel/next.js/tree/canary/examples"
|
||||
title="Examples"
|
||||
description="Discover and deploy boilerplate example Next.js projects."
|
||||
/>
|
||||
|
||||
<CardButton
|
||||
onClick={onButtonClick}
|
||||
title="Tauri Invoke"
|
||||
description={buttonDesc}
|
||||
/>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer className="flex flex-1 flex-grow-0 items-center justify-center border-t border-gray-200 py-4">
|
||||
<div>
|
||||
<a
|
||||
href="https://tauri.app/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex flex-grow items-center justify-center p-4"
|
||||
>
|
||||
Powered by{" "}
|
||||
<span className="ml-2 h-6">
|
||||
<Image
|
||||
src="/tauri_logo_light.svg"
|
||||
alt="Vercel Logo"
|
||||
height={24}
|
||||
width={78}
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Home
|
||||
20
src/styles/globals.css
Normal file
20
src/styles/globals.css
Normal file
@@ -0,0 +1,20 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
html,
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu,
|
||||
Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
Reference in New Issue
Block a user