mirror of
https://github.com/MPCStats/zk-stats-demo.git
synced 2026-01-08 05:13:51 -05:00
feat: support verify and use next
This commit is contained in:
@@ -1,4 +1,29 @@
|
|||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {}
|
|
||||||
|
|
||||||
module.exports = nextConfig
|
|
||||||
|
// Ref: https://github.com/zkonduit/ezkljs-engine/tree/main?tab=readme-ov-file#cross-origin-isolation
|
||||||
|
const nextConfig = {
|
||||||
|
// webpack: (config) => {
|
||||||
|
// config.resolve.alias['@ezkljs/verify'] = '@ezkljs/verify/dist/esm/index.js';
|
||||||
|
// return config;
|
||||||
|
// },
|
||||||
|
async headers() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
source: '/(.*)',
|
||||||
|
headers: [
|
||||||
|
{
|
||||||
|
key: 'Cross-Origin-Embedder-Policy',
|
||||||
|
value: 'require-corp',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'Cross-Origin-Opener-Policy',
|
||||||
|
value: 'same-origin',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = nextConfig
|
||||||
58
package-lock.json
generated
58
package-lock.json
generated
@@ -8,6 +8,7 @@
|
|||||||
"name": "demo-next",
|
"name": "demo-next",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@ezkljs/engine": "5.0.8",
|
||||||
"next": "14.0.4",
|
"next": "14.0.4",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
"react-dom": "^18"
|
"react-dom": "^18"
|
||||||
@@ -113,6 +114,15 @@
|
|||||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@ezkljs/engine": {
|
||||||
|
"version": "5.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ezkljs/engine/-/engine-5.0.8.tgz",
|
||||||
|
"integrity": "sha512-HY7Qv0O/ZmMIqPIMnUZ+xKDFEdt4fWOPuUW/NWtDM5Q2oTe6FIU+KzHnZE/bfdnvGs09GDUkbExW2MyJ7lRcoA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/json-bigint": "^1.0.1",
|
||||||
|
"json-bigint": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@humanwhocodes/config-array": {
|
"node_modules/@humanwhocodes/config-array": {
|
||||||
"version": "0.11.13",
|
"version": "0.11.13",
|
||||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz",
|
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz",
|
||||||
@@ -392,6 +402,11 @@
|
|||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/json-bigint": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/json-bigint/-/json-bigint-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-ydHooXLbOmxBbubnA7Eh+RpBzuaIiQjh8WGJYQB50JFGFrdxW7JzVlyEV7fAXw0T2sqJ1ysTneJbiyNLqZRAag=="
|
||||||
|
},
|
||||||
"node_modules/@types/json5": {
|
"node_modules/@types/json5": {
|
||||||
"version": "0.0.29",
|
"version": "0.0.29",
|
||||||
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
|
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
|
||||||
@@ -866,6 +881,14 @@
|
|||||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/bignumber.js": {
|
||||||
|
"version": "9.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz",
|
||||||
|
"integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==",
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/binary-extensions": {
|
"node_modules/binary-extensions": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||||
@@ -2660,6 +2683,14 @@
|
|||||||
"js-yaml": "bin/js-yaml.js"
|
"js-yaml": "bin/js-yaml.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/json-bigint": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"bignumber.js": "^9.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/json-buffer": {
|
"node_modules/json-buffer": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
|
||||||
@@ -4442,6 +4473,15 @@
|
|||||||
"integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==",
|
"integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@ezkljs/engine": {
|
||||||
|
"version": "5.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ezkljs/engine/-/engine-5.0.8.tgz",
|
||||||
|
"integrity": "sha512-HY7Qv0O/ZmMIqPIMnUZ+xKDFEdt4fWOPuUW/NWtDM5Q2oTe6FIU+KzHnZE/bfdnvGs09GDUkbExW2MyJ7lRcoA==",
|
||||||
|
"requires": {
|
||||||
|
"@types/json-bigint": "^1.0.1",
|
||||||
|
"json-bigint": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@humanwhocodes/config-array": {
|
"@humanwhocodes/config-array": {
|
||||||
"version": "0.11.13",
|
"version": "0.11.13",
|
||||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz",
|
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz",
|
||||||
@@ -4612,6 +4652,11 @@
|
|||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/json-bigint": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/json-bigint/-/json-bigint-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-ydHooXLbOmxBbubnA7Eh+RpBzuaIiQjh8WGJYQB50JFGFrdxW7JzVlyEV7fAXw0T2sqJ1ysTneJbiyNLqZRAag=="
|
||||||
|
},
|
||||||
"@types/json5": {
|
"@types/json5": {
|
||||||
"version": "0.0.29",
|
"version": "0.0.29",
|
||||||
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
|
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
|
||||||
@@ -4946,6 +4991,11 @@
|
|||||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"bignumber.js": {
|
||||||
|
"version": "9.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz",
|
||||||
|
"integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug=="
|
||||||
|
},
|
||||||
"binary-extensions": {
|
"binary-extensions": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||||
@@ -6254,6 +6304,14 @@
|
|||||||
"argparse": "^2.0.1"
|
"argparse": "^2.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"json-bigint": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==",
|
||||||
|
"requires": {
|
||||||
|
"bignumber.js": "^9.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"json-buffer": {
|
"json-buffer": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
|
||||||
|
|||||||
11
package.json
11
package.json
@@ -9,19 +9,20 @@
|
|||||||
"lint": "next lint"
|
"lint": "next lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@ezkljs/engine": "5.0.8",
|
||||||
|
"next": "14.0.4",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
"react-dom": "^18",
|
"react-dom": "^18"
|
||||||
"next": "14.0.4"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typescript": "^5",
|
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^18",
|
"@types/react": "^18",
|
||||||
"@types/react-dom": "^18",
|
"@types/react-dom": "^18",
|
||||||
"autoprefixer": "^10.0.1",
|
"autoprefixer": "^10.0.1",
|
||||||
|
"eslint": "^8",
|
||||||
|
"eslint-config-next": "14.0.4",
|
||||||
"postcss": "^8",
|
"postcss": "^8",
|
||||||
"tailwindcss": "^3.3.0",
|
"tailwindcss": "^3.3.0",
|
||||||
"eslint": "^8",
|
"typescript": "^5"
|
||||||
"eslint-config-next": "14.0.4"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
public/assets/kzg.srs
Normal file
BIN
public/assets/kzg.srs
Normal file
Binary file not shown.
BIN
public/assets/model.onnx
Normal file
BIN
public/assets/model.onnx
Normal file
Binary file not shown.
1
public/assets/model.pf
Normal file
1
public/assets/model.pf
Normal file
File diff suppressed because one or more lines are too long
BIN
public/assets/model.vk
Normal file
BIN
public/assets/model.vk
Normal file
Binary file not shown.
1
public/assets/settings.json
Normal file
1
public/assets/settings.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"run_args":{"tolerance":{"val":0.0,"scale":1.0},"input_scale":5,"param_scale":5,"scale_rebase_multiplier":10,"lookup_range":[0,9594],"logrows":14,"num_inner_cols":1,"variables":[["batch_size",1]],"input_visibility":{"Hashed":{"hash_is_public":true,"outlets":[]}},"output_visibility":"Public","param_visibility":"Private"},"num_rows":14432,"total_assignments":606,"total_const_size":0,"model_instance_shapes":[[1],[1]],"model_output_scales":[0,5],"model_input_scales":[5],"module_sizes":{"kzg":[],"poseidon":[14432,[1]],"elgamal":[0,[0]]},"required_lookups":["Abs",{"GreaterThan":{"a":0.0}}],"check_mode":"UNSAFE","version":"5.0.8","num_blinding_factors":null}
|
||||||
37
src/app/ezkl.ts
Normal file
37
src/app/ezkl.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import init, { init_panic_hook, init_logger, verify } from '@ezkljs/engine/web'
|
||||||
|
|
||||||
|
async function loadFileToBuffer(path: string) {
|
||||||
|
return await fetch(path).then((res) => res.arrayBuffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function initialize() {
|
||||||
|
// Initialize the WASM module. Here we are overiding the default memory allocation with the recommend allocation for the best performance across all mobile browsers.
|
||||||
|
await init(
|
||||||
|
undefined,
|
||||||
|
new WebAssembly.Memory({ initial: 20, maximum: 4096, shared: true }),
|
||||||
|
)
|
||||||
|
// Initialize the panic hook and logger
|
||||||
|
init_panic_hook()
|
||||||
|
init_logger()
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function verifyProof(
|
||||||
|
proofPath: string,
|
||||||
|
settingsPath: string,
|
||||||
|
verificationKeyPath: string,
|
||||||
|
srsPath: string,
|
||||||
|
) {
|
||||||
|
const [proof, settings, verificationKey, srs] = await Promise.all([
|
||||||
|
loadFileToBuffer(proofPath),
|
||||||
|
loadFileToBuffer(settingsPath),
|
||||||
|
loadFileToBuffer(verificationKeyPath),
|
||||||
|
loadFileToBuffer(srsPath),
|
||||||
|
]);
|
||||||
|
const output = verify(
|
||||||
|
new Uint8ClampedArray(proof),
|
||||||
|
new Uint8ClampedArray(verificationKey),
|
||||||
|
new Uint8ClampedArray(settings),
|
||||||
|
new Uint8ClampedArray(srs),
|
||||||
|
);
|
||||||
|
return output
|
||||||
|
}
|
||||||
261
src/app/page.tsx
261
src/app/page.tsx
@@ -1,113 +1,162 @@
|
|||||||
import Image from 'next/image'
|
'use client';
|
||||||
|
import React, { useEffect } from 'react';
|
||||||
|
|
||||||
|
import { initialize, verifyProof } from "./ezkl";
|
||||||
|
|
||||||
|
const host = "http://localhost:3000";
|
||||||
|
const assetsURL = `${host}/assets`;
|
||||||
|
const proofPath = `${assetsURL}/model.pf`;
|
||||||
|
const settingsPath = `${assetsURL}/settings.json`;
|
||||||
|
const verificationKeyPath = `${assetsURL}/model.vk`;
|
||||||
|
const srsPath = `${assetsURL}/kzg.srs`;
|
||||||
|
|
||||||
|
const Page = () => {
|
||||||
|
useEffect(() => {
|
||||||
|
// Call verify function here
|
||||||
|
const v = async () => {
|
||||||
|
try {
|
||||||
|
|
||||||
|
await initialize();
|
||||||
|
console.log("!@# loading files")
|
||||||
|
console.log("!@# proofPath=", proofPath)
|
||||||
|
console.log("!@# settingsPath=", settingsPath)
|
||||||
|
console.log("!@# verificationKeyPath=", verificationKeyPath)
|
||||||
|
console.log("!@# srsPath=", srsPath)
|
||||||
|
const result = await verifyProof(
|
||||||
|
proofPath,
|
||||||
|
settingsPath,
|
||||||
|
verificationKeyPath,
|
||||||
|
srsPath,
|
||||||
|
);
|
||||||
|
console.log("Verification result:", result);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Verification failed:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
v();
|
||||||
|
}, []);
|
||||||
|
|
||||||
export default function Home() {
|
|
||||||
return (
|
return (
|
||||||
<main className="flex min-h-screen flex-col items-center justify-between p-24">
|
<div>
|
||||||
<div className="z-10 max-w-5xl w-full items-center justify-between font-mono text-sm lg:flex">
|
<h1>Verification Page</h1>
|
||||||
<p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30">
|
<p>This page will call the verify function when it loads.</p>
|
||||||
Get started by editing
|
</div>
|
||||||
<code className="font-mono font-bold">src/app/page.tsx</code>
|
);
|
||||||
</p>
|
};
|
||||||
<div className="fixed bottom-0 left-0 flex h-48 w-full items-end justify-center bg-gradient-to-t from-white via-white dark:from-black dark:via-black lg:static lg:h-auto lg:w-auto lg:bg-none">
|
|
||||||
<a
|
|
||||||
className="pointer-events-none flex place-items-center gap-2 p-8 lg:pointer-events-auto lg:p-0"
|
|
||||||
href="https://vercel.com?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
By{' '}
|
|
||||||
<Image
|
|
||||||
src="/vercel.svg"
|
|
||||||
alt="Vercel Logo"
|
|
||||||
className="dark:invert"
|
|
||||||
width={100}
|
|
||||||
height={24}
|
|
||||||
priority
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="relative flex place-items-center before:absolute before:h-[300px] before:w-[480px] before:-translate-x-1/2 before:rounded-full before:bg-gradient-radial before:from-white before:to-transparent before:blur-2xl before:content-[''] after:absolute after:-z-20 after:h-[180px] after:w-[240px] after:translate-x-1/3 after:bg-gradient-conic after:from-sky-200 after:via-blue-200 after:blur-2xl after:content-[''] before:dark:bg-gradient-to-br before:dark:from-transparent before:dark:to-blue-700 before:dark:opacity-10 after:dark:from-sky-900 after:dark:via-[#0141ff] after:dark:opacity-40 before:lg:h-[360px] z-[-1]">
|
export default Page;
|
||||||
<Image
|
|
||||||
className="relative dark:drop-shadow-[0_0_0.3rem_#ffffff70] dark:invert"
|
|
||||||
src="/next.svg"
|
|
||||||
alt="Next.js Logo"
|
|
||||||
width={180}
|
|
||||||
height={37}
|
|
||||||
priority
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mb-32 grid text-center lg:max-w-5xl lg:w-full lg:mb-0 lg:grid-cols-4 lg:text-left">
|
// export default function Home() {
|
||||||
<a
|
// return (
|
||||||
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
// <main className="flex min-h-screen flex-col items-center justify-between p-24">
|
||||||
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
// <div className="z-10 max-w-5xl w-full items-center justify-between font-mono text-sm lg:flex">
|
||||||
target="_blank"
|
// <p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30">
|
||||||
rel="noopener noreferrer"
|
// Get started by editing
|
||||||
>
|
// <code className="font-mono font-bold">src/app/page.tsx</code>
|
||||||
<h2 className={`mb-3 text-2xl font-semibold`}>
|
// </p>
|
||||||
Docs{' '}
|
// <div className="fixed bottom-0 left-0 flex h-48 w-full items-end justify-center bg-gradient-to-t from-white via-white dark:from-black dark:via-black lg:static lg:h-auto lg:w-auto lg:bg-none">
|
||||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
// <a
|
||||||
->
|
// className="pointer-events-none flex place-items-center gap-2 p-8 lg:pointer-events-auto lg:p-0"
|
||||||
</span>
|
// href="https://vercel.com?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||||
</h2>
|
// target="_blank"
|
||||||
<p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
|
// rel="noopener noreferrer"
|
||||||
Find in-depth information about Next.js features and API.
|
// >
|
||||||
</p>
|
// By{' '}
|
||||||
</a>
|
// <Image
|
||||||
|
// src="/vercel.svg"
|
||||||
|
// alt="Vercel Logo"
|
||||||
|
// className="dark:invert"
|
||||||
|
// width={100}
|
||||||
|
// height={24}
|
||||||
|
// priority
|
||||||
|
// />
|
||||||
|
// </a>
|
||||||
|
// </div>
|
||||||
|
// </div>
|
||||||
|
|
||||||
<a
|
// <div className="relative flex place-items-center before:absolute before:h-[300px] before:w-[480px] before:-translate-x-1/2 before:rounded-full before:bg-gradient-radial before:from-white before:to-transparent before:blur-2xl before:content-[''] after:absolute after:-z-20 after:h-[180px] after:w-[240px] after:translate-x-1/3 after:bg-gradient-conic after:from-sky-200 after:via-blue-200 after:blur-2xl after:content-[''] before:dark:bg-gradient-to-br before:dark:from-transparent before:dark:to-blue-700 before:dark:opacity-10 after:dark:from-sky-900 after:dark:via-[#0141ff] after:dark:opacity-40 before:lg:h-[360px] z-[-1]">
|
||||||
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
// <Image
|
||||||
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
// className="relative dark:drop-shadow-[0_0_0.3rem_#ffffff70] dark:invert"
|
||||||
target="_blank"
|
// src="/next.svg"
|
||||||
rel="noopener noreferrer"
|
// alt="Next.js Logo"
|
||||||
>
|
// width={180}
|
||||||
<h2 className={`mb-3 text-2xl font-semibold`}>
|
// height={37}
|
||||||
Learn{' '}
|
// priority
|
||||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
// />
|
||||||
->
|
// </div>
|
||||||
</span>
|
|
||||||
</h2>
|
|
||||||
<p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
|
|
||||||
Learn about Next.js in an interactive course with quizzes!
|
|
||||||
</p>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a
|
// <div className="mb-32 grid text-center lg:max-w-5xl lg:w-full lg:mb-0 lg:grid-cols-4 lg:text-left">
|
||||||
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
// <a
|
||||||
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
// href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||||
target="_blank"
|
// className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
||||||
rel="noopener noreferrer"
|
// target="_blank"
|
||||||
>
|
// rel="noopener noreferrer"
|
||||||
<h2 className={`mb-3 text-2xl font-semibold`}>
|
// >
|
||||||
Templates{' '}
|
// <h2 className={`mb-3 text-2xl font-semibold`}>
|
||||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
// Docs{' '}
|
||||||
->
|
// <span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
||||||
</span>
|
// ->
|
||||||
</h2>
|
// </span>
|
||||||
<p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
|
// </h2>
|
||||||
Explore starter templates for Next.js.
|
// <p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
|
||||||
</p>
|
// Find in-depth information about Next.js features and API.
|
||||||
</a>
|
// </p>
|
||||||
|
// </a>
|
||||||
|
|
||||||
<a
|
// <a
|
||||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
// href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||||
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
// className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
||||||
target="_blank"
|
// target="_blank"
|
||||||
rel="noopener noreferrer"
|
// rel="noopener noreferrer"
|
||||||
>
|
// >
|
||||||
<h2 className={`mb-3 text-2xl font-semibold`}>
|
// <h2 className={`mb-3 text-2xl font-semibold`}>
|
||||||
Deploy{' '}
|
// Learn{' '}
|
||||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
// <span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
||||||
->
|
// ->
|
||||||
</span>
|
// </span>
|
||||||
</h2>
|
// </h2>
|
||||||
<p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
|
// <p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
|
||||||
Instantly deploy your Next.js site to a shareable URL with Vercel.
|
// Learn about Next.js in an interactive course with quizzes!
|
||||||
</p>
|
// </p>
|
||||||
</a>
|
// </a>
|
||||||
</div>
|
|
||||||
</main>
|
// <a
|
||||||
)
|
// href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||||
}
|
// className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
||||||
|
// target="_blank"
|
||||||
|
// rel="noopener noreferrer"
|
||||||
|
// >
|
||||||
|
// <h2 className={`mb-3 text-2xl font-semibold`}>
|
||||||
|
// Templates{' '}
|
||||||
|
// <span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
||||||
|
// ->
|
||||||
|
// </span>
|
||||||
|
// </h2>
|
||||||
|
// <p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
|
||||||
|
// Explore starter templates for Next.js.
|
||||||
|
// </p>
|
||||||
|
// </a>
|
||||||
|
|
||||||
|
// <a
|
||||||
|
// href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||||
|
// className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
||||||
|
// target="_blank"
|
||||||
|
// rel="noopener noreferrer"
|
||||||
|
// >
|
||||||
|
// <h2 className={`mb-3 text-2xl font-semibold`}>
|
||||||
|
// Deploy{' '}
|
||||||
|
// <span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
||||||
|
// ->
|
||||||
|
// </span>
|
||||||
|
// </h2>
|
||||||
|
// <p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
|
||||||
|
// Instantly deploy your Next.js site to a shareable URL with Vercel.
|
||||||
|
// </p>
|
||||||
|
// </a>
|
||||||
|
// </div>
|
||||||
|
// {/* This will only be executed on the client side */}
|
||||||
|
// <ClientSideComponent />
|
||||||
|
// </main>
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
|||||||
Reference in New Issue
Block a user