From 84b0aba8ec810bd58ed980c9bb46b521c7fdd5bd Mon Sep 17 00:00:00 2001
From: 0xshora <112358132134.fibon@gmail.com>
Date: Sun, 7 Jul 2024 15:11:57 +0200
Subject: [PATCH 1/2] chore: fix some UI/UX
---
src/components/Loading/Loading.module.css | 20 +-------
src/components/Loading/Loading.tsx | 28 +++++++++--
src/components/MenuBar/PxCounter.tsx | 4 +-
src/dojo/createSystemCalls.ts | 9 +++-
src/dojo/generated.ts | 24 ++++-----
src/hooks/useGetPixelsToReset.ts | 42 +++++++---------
src/vite-env.d.ts | 50 +++++++++----------
src/webtools/components/Viewport/constants.ts | 4 +-
8 files changed, 89 insertions(+), 92 deletions(-)
diff --git a/src/components/Loading/Loading.module.css b/src/components/Loading/Loading.module.css
index 186e047..d9c0516 100644
--- a/src/components/Loading/Loading.module.css
+++ b/src/components/Loading/Loading.module.css
@@ -1,23 +1,7 @@
.loadingContainer {
- @apply fixed inset-0 z-50 flex items-center justify-center bg-primary/90;
+ @apply fixed inset-0 z-50 flex items-center justify-center bg-bg-primary/90;
}
.loadingText {
@apply text-3xl font-bold text-white;
- animation: loadingAnimation 1s steps(4, end) infinite;
-}
-
-@keyframes loadingAnimation {
- 0% {
- content: 'Loading.';
- }
- 25% {
- content: 'Loading..';
- }
- 50% {
- content: 'Loading...';
- }
- 75% {
- content: 'Loading...';
- }
-}
+}
\ No newline at end of file
diff --git a/src/components/Loading/Loading.tsx b/src/components/Loading/Loading.tsx
index 05adf56..a094c75 100644
--- a/src/components/Loading/Loading.tsx
+++ b/src/components/Loading/Loading.tsx
@@ -1,9 +1,27 @@
+import React, { useState, useEffect } from 'react';
import styles from './Loading.module.css';
-const Loading = () => (
-
- Loading...
-
-);
+const Loading: React.FC = () => {
+ const [loadingText, setLoadingText] = useState('Loading.');
+
+ useEffect(() => {
+ const interval = setInterval(() => {
+ setLoadingText(prev => {
+ if (prev === 'Loading...') {
+ return 'Loading.';
+ }
+ return prev + '.';
+ });
+ }, 500);
+
+ return () => clearInterval(interval);
+ }, []);
+
+ return (
+
+ {loadingText}
+
+ );
+};
export default Loading;
diff --git a/src/components/MenuBar/PxCounter.tsx b/src/components/MenuBar/PxCounter.tsx
index e86d382..cf73cfe 100644
--- a/src/components/MenuBar/PxCounter.tsx
+++ b/src/components/MenuBar/PxCounter.tsx
@@ -12,8 +12,8 @@ const PxCounter = () => {
const player = usePlayer(address);
const pixelRecoveryRate = usePixelRecoveryRate();
- const playerPx = player?.data?.current_px ?? 10;
- const maxPx = player?.data?.max_px ?? 10;
+ const playerPx = player?.data?.current_px ?? 10; // Default to 10 if player is not loaded
+ const maxPx = player?.data?.max_px ?? 10; // Default to 10 if player is not loaded
const recoveryRate = pixelRecoveryRate?.data?.rate ?? 0;
const playerLastDate = player?.data?.last_date ?? 0;
diff --git a/src/dojo/createSystemCalls.ts b/src/dojo/createSystemCalls.ts
index 5f111d4..6f50bbe 100644
--- a/src/dojo/createSystemCalls.ts
+++ b/src/dojo/createSystemCalls.ts
@@ -110,12 +110,17 @@ export function createSystemCalls({ client }: { client: IWorld }) {
await new Promise((resolve) => setTimeout(resolve, 1000));
};
- const activateProposal = async (account: AccountInterface, gameId: number, index: number, clearData?: {x: number, y: number}[]) => {
+ const activateProposal = async (
+ account: AccountInterface,
+ gameId: number,
+ index: number,
+ clearData?: { x: number; y: number }[],
+ ) => {
const { transaction_hash } = await client.actions.activateProposal({
account,
gameId,
index,
- clearData
+ clearData,
});
await account.waitForTransaction(transaction_hash, {
diff --git a/src/dojo/generated.ts b/src/dojo/generated.ts
index 18312ea..1532bfd 100644
--- a/src/dojo/generated.ts
+++ b/src/dojo/generated.ts
@@ -94,23 +94,22 @@ export async function setupWorld(provider: DojoProvider) {
account,
gameId,
index,
- clearData
+ clearData,
}: {
account: AccountInterface;
gameId: number;
index: number;
- clearData?: {x: number, y: number}[]
+ clearData?: { x: number; y: number }[];
}) => {
-
- const clearDataArgs: number[] = []
+ const clearDataArgs: number[] = [];
if (clearData) {
- clearData.forEach(({x, y}) => {
- clearDataArgs.push(x)
- clearDataArgs.push(y)
- })
+ clearData.forEach(({ x, y }) => {
+ clearDataArgs.push(x);
+ clearDataArgs.push(y);
+ });
}
- if (clearData) console.log(clearDataArgs)
+ if (clearData) console.log(clearDataArgs);
try {
return await provider.execute(
@@ -118,12 +117,7 @@ export async function setupWorld(provider: DojoProvider) {
{
contractAddress: PROPOSAL_CONTRACT_ADDRESS,
entrypoint: 'activate_proposal',
- calldata: [
- gameId,
- index,
- clearData?.length ?? 0,
- ...clearDataArgs
- ],
+ calldata: [gameId, index, clearData?.length ?? 0, ...clearDataArgs],
},
{
skipValidate: true,
diff --git a/src/hooks/useGetPixelsToReset.ts b/src/hooks/useGetPixelsToReset.ts
index 6705c00..e17eb87 100644
--- a/src/hooks/useGetPixelsToReset.ts
+++ b/src/hooks/useGetPixelsToReset.ts
@@ -1,16 +1,16 @@
-import {useMutation} from '@tanstack/react-query';
+import { useMutation } from '@tanstack/react-query';
import { GraphQLClient } from 'graphql-request';
import GetResetPixels from '@/../graphql/GetPixelsToReset.graphql';
import { useSettingsStore } from '@/stores/SettingsStore.ts';
-import useBoard from "@/hooks/useBoard.ts";
-import {GAME_ID} from "@/global/constants.ts";
+import useBoard from '@/hooks/useBoard.ts';
+import { GAME_ID } from '@/global/constants.ts';
type Data = {
pixelModels: {
edges: {
node: {
- x: number,
- y: number
+ x: number;
+ y: number;
};
}[];
};
@@ -21,27 +21,23 @@ const useGetPixelsToReset = () => {
const baseUrl = settings?.config?.toriiUrl ?? 'http://localhost:8080';
const gqlClient = new GraphQLClient(`${baseUrl}/graphql`);
- const board = useBoard(GAME_ID)
+ const board = useBoard(GAME_ID);
return useMutation({
mutationKey: ['usePixelRecoveryRate'],
- mutationFn: async ({color}: {color: number}) => {
- if (!board.data) throw new Error('board data not yet loaded')
- const result: Data = await gqlClient
- .request(
- GetResetPixels,
- {
- color,
- xGTE: board.data.origin.x,
- xLTE: board.data.origin.x + board.data.width - 1,
- yGTE: board.data.origin.y,
- yLTE: board.data.origin.y + board.data.height - 1,
- limit: board.data.height * board.data.width
- }
- );
- return result.pixelModels.edges.map(({ node: { x, y }}) => {
- return { x, y }
- })
+ mutationFn: async ({ color }: { color: number }) => {
+ if (!board.data) throw new Error('board data not yet loaded');
+ const result: Data = await gqlClient.request(GetResetPixels, {
+ color,
+ xGTE: board.data.origin.x,
+ xLTE: board.data.origin.x + board.data.width - 1,
+ yGTE: board.data.origin.y,
+ yLTE: board.data.origin.y + board.data.height - 1,
+ limit: board.data.height * board.data.width,
+ });
+ return result.pixelModels.edges.map(({ node: { x, y } }) => {
+ return { x, y };
+ });
},
retryDelay: (failureCount) => failureCount * 1_000,
});
diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts
index 4c1b5db..f71fc57 100644
--- a/src/vite-env.d.ts
+++ b/src/vite-env.d.ts
@@ -1,25 +1,25 @@
///
type ImportMetaEnv = {
- // Auto-generated by `npx vite-envs update-types` and hot-reloaded by the `vite-env` plugin
- // You probably want to add `/src/vite-env.d.ts` to your .prettierignore
- BASE_URL: string
- MODE: string
- DEV: boolean
- PROD: boolean
- PUBLIC_RPC_URL: string
- PUBLIC_TORII_URL: string
- PUBLIC_RELAY_URL: string
- PUBLIC_SERVER_URL: string
- MASTER_ADDRESS: string
- MASTER_PRIVATE_KEY: string
- WORLD_ADDRESS: string
- ACCOUNT_CLASS_HASH: string
- FEETOKEN_ADDRESS: string
- SERVER_PORT: string
- CORE_VERSION: string
- PUBLIC_MANIFEST_URL: string
- // @user-defined-start
+ // Auto-generated by `npx vite-envs update-types` and hot-reloaded by the `vite-env` plugin
+ // You probably want to add `/src/vite-env.d.ts` to your .prettierignore
+ BASE_URL: string;
+ MODE: string;
+ DEV: boolean;
+ PROD: boolean;
+ PUBLIC_RPC_URL: string;
+ PUBLIC_TORII_URL: string;
+ PUBLIC_RELAY_URL: string;
+ PUBLIC_SERVER_URL: string;
+ MASTER_ADDRESS: string;
+ MASTER_PRIVATE_KEY: string;
+ WORLD_ADDRESS: string;
+ ACCOUNT_CLASS_HASH: string;
+ FEETOKEN_ADDRESS: string;
+ SERVER_PORT: string;
+ CORE_VERSION: string;
+ PUBLIC_MANIFEST_URL: string;
+ // @user-defined-start
/*
* Here you can define your own special variables
* that would be available on `import.meta.env` but
@@ -29,16 +29,16 @@ type ImportMetaEnv = {
*/
SSR: boolean;
// @user-defined-end
-}
+};
interface ImportMeta {
- // Auto-generated by `npx vite-envs update-types`
+ // Auto-generated by `npx vite-envs update-types`
- url: string
+ url: string;
- readonly hot?: import('vite-envs/types/hot').ViteHotContext
+ readonly hot?: import('vite-envs/types/hot').ViteHotContext;
- readonly env: ImportMetaEnv
+ readonly env: ImportMetaEnv;
- glob: import('vite-envs/types/importGlob').ImportGlobFunction
+ glob: import('vite-envs/types/importGlob').ImportGlobFunction;
}
diff --git a/src/webtools/components/Viewport/constants.ts b/src/webtools/components/Viewport/constants.ts
index c1c1e53..ec2fc56 100644
--- a/src/webtools/components/Viewport/constants.ts
+++ b/src/webtools/components/Viewport/constants.ts
@@ -1,6 +1,6 @@
-export const ZOOM_TILEMODE = 2699;
+export const ZOOM_TILEMODE = 1799;
export const ZOOM_FACTOR = 100;
export const ZOOM_MAX = 10000; // 100 pixels per cell side
-export const ZOOM_MIN = 2700; // 0.5 pixels per cell side
+export const ZOOM_MIN = 1800; // 0.5 pixels per cell side
// export const ZOOM_MIN = 50 // 0.5 pixels per cell side
export const ZOOM_SCALEFACTOR = 1.1;
From c43c0b283e0a3327bcd532ec031e037cd6ed620f Mon Sep 17 00:00:00 2001
From: 0xshora <112358132134.fibon@gmail.com>
Date: Sun, 7 Jul 2024 16:06:36 +0200
Subject: [PATCH 2/2] feat: add emoji to each address
---
.../Avatar/emojiAvatarForAddress.ts | 80 +++++++++++++++++++
src/components/MenuBar/MenuBar.tsx | 4 +-
src/components/ProposalList/ProposalItem.tsx | 6 +-
src/global/utils.ts | 9 +++
4 files changed, 94 insertions(+), 5 deletions(-)
create mode 100644 src/components/Avatar/emojiAvatarForAddress.ts
diff --git a/src/components/Avatar/emojiAvatarForAddress.ts b/src/components/Avatar/emojiAvatarForAddress.ts
new file mode 100644
index 0000000..54ef9fc
--- /dev/null
+++ b/src/components/Avatar/emojiAvatarForAddress.ts
@@ -0,0 +1,80 @@
+const colors = [
+ '#FC5C54',
+ '#FFD95A',
+ '#E95D72',
+ '#6A87C8',
+ '#5FD0F3',
+ '#75C06B',
+ '#FFDD86',
+ '#5FC6D4',
+ '#FF949A',
+ '#FF8024',
+ '#9BA1A4',
+ '#EC66FF',
+ '#FF8CBC',
+ '#FF9A23',
+ '#C5DADB',
+ '#A8CE63',
+ '#71ABFF',
+ '#FFE279',
+ '#B6B1B6',
+ '#FF6780',
+ '#A575FF',
+ '#4D82FF',
+ '#FFB35A',
+] as const;
+
+const avatars = [
+ { color: colors[0], emoji: '🌶' },
+ { color: colors[1], emoji: '🤑' },
+ { color: colors[2], emoji: '🐙' },
+ { color: colors[3], emoji: '🫐' },
+ { color: colors[4], emoji: '🐳' },
+ { color: colors[0], emoji: '🤶' },
+ { color: colors[5], emoji: '🌲' },
+ { color: colors[6], emoji: '🌞' },
+ { color: colors[7], emoji: '🐒' },
+ { color: colors[8], emoji: '🐵' },
+ { color: colors[9], emoji: '🦊' },
+ { color: colors[10], emoji: '🐼' },
+ { color: colors[11], emoji: '🦄' },
+ { color: colors[12], emoji: '🐷' },
+ { color: colors[13], emoji: '🐧' },
+ { color: colors[8], emoji: '🦩' },
+ { color: colors[14], emoji: '👽' },
+ { color: colors[0], emoji: '🎈' },
+ { color: colors[8], emoji: '🍉' },
+ { color: colors[1], emoji: '🎉' },
+ { color: colors[15], emoji: '🐲' },
+ { color: colors[16], emoji: '🌎' },
+ { color: colors[17], emoji: '🍊' },
+ { color: colors[18], emoji: '🐭' },
+ { color: colors[19], emoji: '🍣' },
+ { color: colors[1], emoji: '🐥' },
+ { color: colors[20], emoji: '👾' },
+ { color: colors[15], emoji: '🥦' },
+ { color: colors[0], emoji: '👹' },
+ { color: colors[17], emoji: '🙀' },
+ { color: colors[4], emoji: '⛱' },
+ { color: colors[21], emoji: '⛵️' },
+ { color: colors[17], emoji: '🥳' },
+ { color: colors[8], emoji: '🤯' },
+ { color: colors[22], emoji: '🤠' },
+] as const;
+
+function hashCode(text: string) {
+ let hash = 0;
+ if (text.length === 0) return hash;
+ for (let i = 0; i < text.length; i++) {
+ const chr = text.charCodeAt(i);
+ hash = (hash << 5) - hash + chr;
+ hash |= 0;
+ }
+ return hash;
+}
+
+export function emojiAvatarForAddress(address: string) {
+ const resolvedAddress = typeof address === 'string' ? address : '';
+ const avatarIndex = Math.abs(hashCode(resolvedAddress.toLowerCase()) % avatars.length);
+ return avatars[avatarIndex ?? 0];
+}
diff --git a/src/components/MenuBar/MenuBar.tsx b/src/components/MenuBar/MenuBar.tsx
index b07d4b6..66d4378 100644
--- a/src/components/MenuBar/MenuBar.tsx
+++ b/src/components/MenuBar/MenuBar.tsx
@@ -1,7 +1,7 @@
import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import styles from './MenuBar.module.css';
-import { formatWalletAddress } from '@/global/utils.ts';
+import { formatWalletAddressWithEmoji } from '@/global/utils.ts';
import PxCounter from '@/components/MenuBar/PxCounter.tsx';
interface MenuBarProps {
@@ -45,7 +45,7 @@ const MenuBar: React.FC = ({ address, endTime }) => {
{timeLeft}
-
{formatWalletAddress(address || '')}
+
{formatWalletAddressWithEmoji(address || '')}
diff --git a/src/components/ProposalList/ProposalItem.tsx b/src/components/ProposalList/ProposalItem.tsx
index bacf84e..873bd06 100644
--- a/src/components/ProposalList/ProposalItem.tsx
+++ b/src/components/ProposalList/ProposalItem.tsx
@@ -3,7 +3,7 @@ import { usePixelawProvider } from '@/providers/PixelawProvider.tsx';
import { ProposalType } from '@/global/types.ts';
import { numRGBAToHex } from '@/webtools/utils.ts';
import { GAME_ID, NEEDED_YES_PX } from '@/global/constants.ts';
-import { formatWalletAddress, toastContractError, formatTimeRemaining, formatTimeRemainingFotTitle } from '@/global/utils.ts';
+import { formatWalletAddressWithEmoji, toastContractError, formatTimeRemaining, formatTimeRemainingFotTitle } from '@/global/utils.ts';
import { type ProposalDataType } from '@/hooks/useProposals.ts';
import useGetPixelsToReset from "@/hooks/useGetPixelsToReset.ts";
@@ -30,7 +30,7 @@ const createProposalTitle = (proposalType: ProposalType, target_args_1: number,
case ProposalType.AddNewColor:
return `Adding A New Color: ${numRGBAToHex(target_args_1).toUpperCase()}`;
case ProposalType.ResetToWhiteByColor:
- return `Make A Disaster: ${numRGBAToHex(target_args_1).toUpperCase()}`;
+ return `Reset To White: ${numRGBAToHex(target_args_1).toUpperCase()}`;
case ProposalType.ExtendGameEndTime:
return `Extend Game End Time: ${formatTimeRemainingFotTitle(target_args_1)}`;
case ProposalType.ExpandArea:
@@ -167,7 +167,7 @@ const ProposalItem: React.FC = ({ proposal, onStartVote, filter, sear
- proposed by {formatWalletAddress(proposal.author.toString())}
+ proposed by {formatWalletAddressWithEmoji(proposal.author.toString())}
{
return address;
};
+export const formatWalletAddressWithEmoji = (address: string) => {
+ const avatar = emojiAvatarForAddress(address);
+ if (address.length > 10) {
+ return avatar.emoji + `${address.slice(0, 4)}...${address.slice(-4)}`;
+ }
+ return avatar.emoji + address;
+};
+
// Takes a RGB hex nr and converts it to numeric rgba (0 alpha)
export const coordinateToPosition = (coord: Coordinate): Position => {
return { x: coord[0], y: coord[1] };