init template
commit
c62d531e8d
|
@ -0,0 +1,3 @@
|
||||||
|
APP_ID=2984220425889259895
|
||||||
|
ZMP_TOKEN=
|
||||||
|
VITE_GAME_LINK=
|
|
@ -0,0 +1,40 @@
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variables file
|
||||||
|
.env
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Production build
|
||||||
|
www/
|
||||||
|
|
||||||
|
.idea/
|
|
@ -0,0 +1,126 @@
|
||||||
|
# Zalo Mini App
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
### Using Zalo Mini App Extension
|
||||||
|
|
||||||
|
1. Install [Visual Studio Code](https://code.visualstudio.com/download) and [Zalo Mini App Extension](https://mini.zalo.me/docs/dev-tools).
|
||||||
|
1. In the **Home** tab, process **Config App ID** and **Install Dependencies**.
|
||||||
|
1. Navigate to the **Run** tab, select the suitable launcher, and click **Start**.
|
||||||
|
|
||||||
|
### Using Zalo Mini App CLI
|
||||||
|
|
||||||
|
1. [Install Node JS](https://nodejs.org/en/download/).
|
||||||
|
1. [Install Zalo Mini App CLI](https://mini.zalo.me/docs/dev-tools/cli/intro/).
|
||||||
|
1. **Install dependencies**:
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
1. **Start** the dev server:
|
||||||
|
```bash
|
||||||
|
zmp start
|
||||||
|
```
|
||||||
|
1. **Open** `localhost:3000` in your browser.
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
|
||||||
|
1. **Create** a mini program. For instructions on how to create a mini program, please refer to the [Coffee Shop Tutorial](https://mini.zalo.me/tutorial/coffee-shop/step-1/)
|
||||||
|
|
||||||
|
1. **Deploy** your mini program to Zalo using the mini app ID created.
|
||||||
|
|
||||||
|
- **Using Zalo Mini App Extension**: navigate to the **Deploy** panel > **Login** > **Deploy**.
|
||||||
|
- **Using Zalo Mini App CLI**:
|
||||||
|
```bash
|
||||||
|
zmp login
|
||||||
|
zmp deploy
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Open the mini app in Zalo by scanning the QR code.
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
- [Zalo Mini App Official Website](https://mini.zalo.me/)
|
||||||
|
- [ZaUI Documentation](https://mini.zalo.me/documents/zaui/)
|
||||||
|
- [ZMP SDK Documentation](https://mini.zalo.me/documents/api/)
|
||||||
|
- [DevTools Documentation](https://mini.zalo.me/docs/dev-tools/)
|
||||||
|
- [Ready-made Mini App Templates](https://mini.zalo.me/zaui-templates)
|
||||||
|
- [Community Support](https://mini.zalo.me/community)
|
||||||
|
|
||||||
|
# Unity Game
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
1. **Install dependencies**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install react-unity-webgl
|
||||||
|
```
|
||||||
|
or
|
||||||
|
```bash
|
||||||
|
pnpm install react-unity-webgl
|
||||||
|
```
|
||||||
|
or
|
||||||
|
```bash
|
||||||
|
yarn install react-unity-webgl
|
||||||
|
```
|
||||||
|
|
||||||
|
1. **Create** the game component:
|
||||||
|
```tsx
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { Unity, useUnityContext } from 'react-unity-webgl';
|
||||||
|
import zmpSdk from 'zmp-sdk';
|
||||||
|
|
||||||
|
export const UnityGame = () => {
|
||||||
|
const gameLink = import.meta.env.VITE_GAME_LINK;
|
||||||
|
const { unityProvider, isLoaded, loadingProgression, UNSAFE__unityInstance } = useUnityContext({
|
||||||
|
loaderUrl: `${gameLink}/Build/Build.loader.js`,
|
||||||
|
dataUrl: `${gameLink}/Build/Build.data.unityweb`,
|
||||||
|
frameworkUrl: `${gameLink}/Build/Build.framework.js.unityweb`,
|
||||||
|
codeUrl: `${gameLink}/Build/Build.wasm.unityweb`,
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.ZaloMiniAppSDK = zmpSdk;
|
||||||
|
window.unityInstance = UNSAFE__unityInstance;
|
||||||
|
}, [UNSAFE__unityInstance]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{!isLoaded && (
|
||||||
|
<div className={'h-full w-full items-center justify-center text-center'}>
|
||||||
|
Loading {loadingProgression * 100 + 10}%
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<Unity
|
||||||
|
id='unity-canvas'
|
||||||
|
unityProvider={unityProvider}
|
||||||
|
className={clsx('h-full w-full', !isLoaded && 'hidden')}
|
||||||
|
devicePixelRatio={window.devicePixelRatio}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
1. **Add** game link to env:
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
APP_ID=
|
||||||
|
ZMP_TOKEN=
|
||||||
|
VITE_GAME_LINK=[your game link]
|
||||||
|
```
|
||||||
|
|
||||||
|
1. **Import** and use it anywhere:
|
||||||
|
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
export default function MainApp() {
|
||||||
|
return (
|
||||||
|
<div className={'flex h-dvh w-screen flex-col items-center justify-center'}>
|
||||||
|
<UnityGame />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"app": {
|
||||||
|
"title": "promogame-react-unity-template",
|
||||||
|
"textColor": {
|
||||||
|
"light": "black",
|
||||||
|
"dark": "white"
|
||||||
|
},
|
||||||
|
"statusBar": "transparent",
|
||||||
|
"actionBarHidden": true,
|
||||||
|
"hideIOSSafeAreaBottom": true,
|
||||||
|
"hideAndroidBottomNavigationBar": true
|
||||||
|
},
|
||||||
|
"listCSS": [],
|
||||||
|
"listSyncJS": [],
|
||||||
|
"listAsyncJS": []
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://biomejs.dev/schemas/1.9.3/schema.json",
|
||||||
|
"organizeImports": {
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
"files": {
|
||||||
|
"ignoreUnknown": false,
|
||||||
|
"ignore": ["src/main.tsx", "src/generated/*.ts"]
|
||||||
|
},
|
||||||
|
"linter": {
|
||||||
|
"enabled": true,
|
||||||
|
"rules": {
|
||||||
|
"recommended": true,
|
||||||
|
"complexity": {
|
||||||
|
"useSimplifiedLogicExpression": "warn"
|
||||||
|
},
|
||||||
|
"nursery": {
|
||||||
|
"useSortedClasses": "warn"
|
||||||
|
},
|
||||||
|
"correctness": {
|
||||||
|
"noUnusedImports": "error",
|
||||||
|
"noUnusedPrivateClassMembers": "error",
|
||||||
|
"noUnusedVariables": "error"
|
||||||
|
},
|
||||||
|
"suspicious": {
|
||||||
|
"noConsoleLog": "off",
|
||||||
|
"noArrayIndexKey": "off"
|
||||||
|
},
|
||||||
|
"style": {
|
||||||
|
"noNonNullAssertion": "off"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"formatter": {
|
||||||
|
"enabled": true,
|
||||||
|
"formatWithErrors": true,
|
||||||
|
"attributePosition": "auto",
|
||||||
|
"indentStyle": "space",
|
||||||
|
"indentWidth": 2,
|
||||||
|
"lineEnding": "lf",
|
||||||
|
"lineWidth": 120
|
||||||
|
},
|
||||||
|
"vcs": {
|
||||||
|
"enabled": true,
|
||||||
|
"clientKind": "git"
|
||||||
|
},
|
||||||
|
"javascript": {
|
||||||
|
"formatter": {
|
||||||
|
"arrowParentheses": "always",
|
||||||
|
"bracketSameLine": false,
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"quoteStyle": "single",
|
||||||
|
"jsxQuoteStyle": "single",
|
||||||
|
"quoteProperties": "asNeeded",
|
||||||
|
"semicolons": "always",
|
||||||
|
"trailingCommas": "all",
|
||||||
|
"indentStyle": "space",
|
||||||
|
"indentWidth": 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"json": {
|
||||||
|
"formatter": {
|
||||||
|
"enabled": true,
|
||||||
|
"trailingCommas": "none"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta
|
||||||
|
name="viewport"
|
||||||
|
content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, viewport-fit=cover"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<meta name="theme-color" content="#007aff" />
|
||||||
|
<meta name="format-detection" content="telephone=no" />
|
||||||
|
<meta name="msapplication-tap-highlight" content="no" />
|
||||||
|
<title>Zalo Mini App</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<!-- built script files will be auto injected -->
|
||||||
|
|
||||||
|
<script type="module" src="/src/app.ts"></script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,51 @@
|
||||||
|
{
|
||||||
|
"name": "promogame-unity-template",
|
||||||
|
"private": true,
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "zmp-blank-templates",
|
||||||
|
"repository": "",
|
||||||
|
"license": "UNLICENSED",
|
||||||
|
"browserslist": [
|
||||||
|
"Android >= 5",
|
||||||
|
"IOS >= 9.3",
|
||||||
|
"Edge >= 15",
|
||||||
|
"Safari >= 9.1",
|
||||||
|
"Chrome >= 49",
|
||||||
|
"Firefox >= 31",
|
||||||
|
"Samsung >= 5"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"login": "zmp login",
|
||||||
|
"start": "zmp start",
|
||||||
|
"start-device": "zmp start -D",
|
||||||
|
"deploy": "zmp deploy"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"clsx": "^2.1.1",
|
||||||
|
"parse-path": "^7.0.0",
|
||||||
|
"prop-types": "^15.8.1",
|
||||||
|
"react": "^18.3.1",
|
||||||
|
"react-dom": "^18.3.1",
|
||||||
|
"react-unity-webgl": "^9.6.0",
|
||||||
|
"usehooks-ts": "^3.1.0",
|
||||||
|
"zmp-sdk": "latest",
|
||||||
|
"zmp-ui": "latest",
|
||||||
|
"zustand": "^5.0.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@biomejs/biome": "^1.9.4",
|
||||||
|
"@types/react": "^18.3.1",
|
||||||
|
"@types/react-dom": "^18.3.0",
|
||||||
|
"@vitejs/plugin-react": "^4.3.1",
|
||||||
|
"autoprefixer": "^10.4.19",
|
||||||
|
"cross-env": "^7.0.3",
|
||||||
|
"postcss": "^8.4.38",
|
||||||
|
"postcss-cli": "^8.3.1",
|
||||||
|
"postcss-preset-env": "^6.7.0",
|
||||||
|
"sass": "^1.76.0",
|
||||||
|
"tailwindcss": "^3.4.3",
|
||||||
|
"vite": "^5.2.13",
|
||||||
|
"vite-tsconfig-paths": "^4.3.2",
|
||||||
|
"zmp-vite-plugin": "latest"
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,5 @@
|
||||||
|
const tailwindcss = require("tailwindcss");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
plugins: [tailwindcss("./tailwind.config.js"), require("autoprefixer")],
|
||||||
|
};
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { UnityGame } from './components/unity-game';
|
||||||
|
|
||||||
|
export default function MainApp() {
|
||||||
|
return (
|
||||||
|
<div className={'flex h-dvh w-screen flex-col items-center justify-center'}>
|
||||||
|
<UnityGame />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
// ZaUI stylesheet
|
||||||
|
import 'zmp-ui/zaui.css';
|
||||||
|
// Tailwind stylesheet
|
||||||
|
import 'css/tailwind.scss';
|
||||||
|
// Your stylesheet
|
||||||
|
import 'css/app.scss';
|
||||||
|
|
||||||
|
// React core
|
||||||
|
import React from 'react';
|
||||||
|
import { createRoot } from 'react-dom/client';
|
||||||
|
|
||||||
|
// Expose app configuration
|
||||||
|
import appConfig from '../app-config.json';
|
||||||
|
|
||||||
|
if (!window.APP_CONFIG) {
|
||||||
|
window.APP_CONFIG = appConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
import App from './MainApp';
|
||||||
|
const root = createRoot(document.getElementById('app')!);
|
||||||
|
root.render(React.createElement(App));
|
|
@ -0,0 +1,35 @@
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { Unity, useUnityContext } from 'react-unity-webgl';
|
||||||
|
import zmpSdk from 'zmp-sdk';
|
||||||
|
|
||||||
|
export const UnityGame = () => {
|
||||||
|
const gameLink = import.meta.env.VITE_GAME_LINK;
|
||||||
|
const { unityProvider, isLoaded, loadingProgression, UNSAFE__unityInstance } = useUnityContext({
|
||||||
|
loaderUrl: `${gameLink}/Build/Build.loader.js`,
|
||||||
|
dataUrl: `${gameLink}/Build/Build.data.unityweb`,
|
||||||
|
frameworkUrl: `${gameLink}/Build/Build.framework.js.unityweb`,
|
||||||
|
codeUrl: `${gameLink}/Build/Build.wasm.unityweb`,
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.ZaloMiniAppSDK = zmpSdk;
|
||||||
|
window.unityInstance = UNSAFE__unityInstance;
|
||||||
|
}, [UNSAFE__unityInstance]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{!isLoaded && (
|
||||||
|
<div className={'h-full w-full items-center justify-center text-center'}>
|
||||||
|
Loading {loadingProgression * 100 + 10}%
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<Unity
|
||||||
|
id='unity-canvas'
|
||||||
|
unityProvider={unityProvider}
|
||||||
|
className={clsx('h-full w-full', !isLoaded && 'hidden')}
|
||||||
|
devicePixelRatio={window.devicePixelRatio}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,38 @@
|
||||||
|
.page {
|
||||||
|
padding: 16px 16px 96px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-container {
|
||||||
|
padding: 16px;
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress {
|
||||||
|
display: inline-block;
|
||||||
|
height: 50px;
|
||||||
|
width: 80%;
|
||||||
|
margin-bottom: 200px;
|
||||||
|
border-radius: 99px;
|
||||||
|
background: #f9f9f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar {
|
||||||
|
border-radius: 99px;
|
||||||
|
width: 0%;
|
||||||
|
height: 100%;
|
||||||
|
transition: width;
|
||||||
|
transition-duration: 1s;
|
||||||
|
transition-timing-function: cubic-bezier(.36,.55,.63,.48);
|
||||||
|
box-shadow: 0px 45px 50px rgba(0, 0, 0, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pattern {
|
||||||
|
background-color: #DFDBE5;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.zaui-list-item {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
|
@ -0,0 +1,10 @@
|
||||||
|
export {};
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
APP_ID: string;
|
||||||
|
APP_CONFIG: unknown;
|
||||||
|
ZaloMiniAppSDK: unknown;
|
||||||
|
unityInstance: unknown;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
module.exports = {
|
||||||
|
darkMode: ["selector", '[zaui-theme="dark"]'],
|
||||||
|
purge: {
|
||||||
|
enabled: true,
|
||||||
|
content: ["./src/**/*.{js,jsx,ts,tsx,vue}"],
|
||||||
|
},
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
fontFamily: {
|
||||||
|
mono: ["Roboto Mono", "monospace"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
|
@ -0,0 +1,35 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"noEmit": true,
|
||||||
|
"target": "es6",
|
||||||
|
"module": "esnext",
|
||||||
|
"noImplicitAny": false,
|
||||||
|
"preserveConstEnums": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"lib": ["dom", "dom.iterable", "es5", "es6", "es7", "es2017", "es2020"],
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"allowJs": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"declaration": false,
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"noEmitOnError": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noImplicitThis": true,
|
||||||
|
"noUnusedLocals": false,
|
||||||
|
"strict": true,
|
||||||
|
"strictFunctionTypes": false,
|
||||||
|
"pretty": true,
|
||||||
|
"removeComments": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"types": ["vite/client"],
|
||||||
|
"baseUrl": "src"
|
||||||
|
},
|
||||||
|
"exclude": ["node_modules"],
|
||||||
|
"include": ["src"]
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import zaloMiniApp from 'zmp-vite-plugin';
|
||||||
|
import react from '@vitejs/plugin-react';
|
||||||
|
import tsconfigPaths from 'vite-tsconfig-paths';
|
||||||
|
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default () => {
|
||||||
|
return defineConfig({
|
||||||
|
root: './src',
|
||||||
|
base: '',
|
||||||
|
plugins: [zaloMiniApp(), react(), tsconfigPaths()],
|
||||||
|
build: {
|
||||||
|
assetsInlineLimit: 0,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"cwd": "/Users/lap15182-local/Documents/zmp-blank-templates",
|
||||||
|
"name": "zmp-blank-templates",
|
||||||
|
"framework": "react-typescript",
|
||||||
|
"cssPreProcessor": "scss",
|
||||||
|
"includeTailwind": true,
|
||||||
|
"package": "zmp-ui",
|
||||||
|
"stateManagement": "jotai",
|
||||||
|
"newProject": true,
|
||||||
|
"template": "single-view",
|
||||||
|
"theming": {
|
||||||
|
"customColor": false,
|
||||||
|
"color": "#007aff",
|
||||||
|
"darkTheme": false,
|
||||||
|
"iconFonts": true,
|
||||||
|
"fillBars": false,
|
||||||
|
"useUiKits": true
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue