init: impersonator functional
This commit is contained in:
BIN
.github/demo-address-connected.png
vendored
Normal file
BIN
.github/demo-address-connected.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 70 KiB |
24
.gitignore
vendored
Normal file
24
.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
.env
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
15
README.md
Normal file
15
README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# 🎭 Impersonator 🕵️♂️
|
||||
|
||||
### Login into DApps by impersonating any Ethereum address via WalletConnect! <br />
|
||||
|
||||
<hr />
|
||||
|
||||
## Website:
|
||||
|
||||
**[https://apoorvlathey.com/impersonator/](https://apoorvlathey.com/impersonator/)**
|
||||
|
||||
## Screenshots:
|
||||
|
||||

|
||||
|
||||
(PS: Users won't be able to transact (obviously) as no private keys are being used here)
|
||||
50
package.json
Normal file
50
package.json
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"name": "impersonator",
|
||||
"version": "0.1.0",
|
||||
"homepage": ".",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@chakra-ui/icons": "^1.0.14",
|
||||
"@chakra-ui/react": "^1.6.5",
|
||||
"@emotion/react": "^11",
|
||||
"@emotion/styled": "^11",
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.36",
|
||||
"@fortawesome/free-brands-svg-icons": "^5.15.4",
|
||||
"@fortawesome/react-fontawesome": "^0.1.15",
|
||||
"@testing-library/jest-dom": "^5.11.4",
|
||||
"@testing-library/react": "^11.1.0",
|
||||
"@testing-library/user-event": "^12.1.10",
|
||||
"@walletconnect/client": "^1.6.2",
|
||||
"ethereum-checksum-address": "^0.0.6",
|
||||
"framer-motion": "^4",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-scripts": "4.0.3",
|
||||
"react-simple-code-editor": "^0.11.0",
|
||||
"web-vitals": "^1.0.1"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app",
|
||||
"react-app/jest"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
}
|
||||
}
|
||||
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.4 KiB |
88
public/index.html
Normal file
88
public/index.html
Normal file
@@ -0,0 +1,88 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||
<script
|
||||
async
|
||||
src="https://www.googletagmanager.com/gtag/js?id=UA-69758040-5"
|
||||
></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag() {
|
||||
dataLayer.push(arguments);
|
||||
}
|
||||
gtag("js", new Date());
|
||||
gtag("config", "UA-69758040-5");
|
||||
</script>
|
||||
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<!-- Primary Meta Tags -->
|
||||
<title>Impersonator</title>
|
||||
<meta name="title" content="Impersonator" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Impersonate any Ethereum Account and Login into DApps via WalletConnect!"
|
||||
/>
|
||||
|
||||
<!-- Open Graph / Facebook -->
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="https://apoorvlathey.com/impersonator/" />
|
||||
<meta property="og:title" content="Impersonator" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="Impersonate any Ethereum Account and Login into DApps via WalletConnect!"
|
||||
/>
|
||||
<meta
|
||||
property="og:image"
|
||||
content="https://apoorvlathey.com/impersonator/metaIMG.PNG"
|
||||
/>
|
||||
|
||||
<!-- Twitter -->
|
||||
<meta property="twitter:card" content="summary_large_image" />
|
||||
<meta
|
||||
property="twitter:url"
|
||||
content="https://apoorvlathey.com/impersonator/"
|
||||
/>
|
||||
<meta property="twitter:title" content="Impersonator" />
|
||||
<meta
|
||||
property="twitter:description"
|
||||
content="Impersonate any Ethereum Account and Login into DApps via WalletConnect!"
|
||||
/>
|
||||
<meta
|
||||
property="twitter:image"
|
||||
content="https://apoorvlathey.com/impersonator/metaIMG.PNG"
|
||||
/>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
BIN
public/logo192.png
Normal file
BIN
public/logo192.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.0 KiB |
BIN
public/logo512.png
Normal file
BIN
public/logo512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
25
public/manifest.json
Normal file
25
public/manifest.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"short_name": "React App",
|
||||
"name": "Create React App Sample",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
},
|
||||
{
|
||||
"src": "logo192.png",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "logo512.png",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
||||
BIN
public/metaIMG.PNG
Normal file
BIN
public/metaIMG.PNG
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
3
public/robots.txt
Normal file
3
public/robots.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
Disallow:
|
||||
16
src/App.js
Normal file
16
src/App.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import React from "react";
|
||||
import Body from "./components/Body/index";
|
||||
import Navbar from "./components/Navbar";
|
||||
import Footer from "./components/Footer";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div>
|
||||
<Navbar />
|
||||
<Body />
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
250
src/components/Body/index.js
Normal file
250
src/components/Body/index.js
Normal file
@@ -0,0 +1,250 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import {
|
||||
Container,
|
||||
Input,
|
||||
FormControl,
|
||||
useColorMode,
|
||||
FormLabel,
|
||||
Button,
|
||||
Box,
|
||||
Avatar,
|
||||
Text,
|
||||
Link,
|
||||
VStack,
|
||||
Spacer,
|
||||
Select,
|
||||
} from "@chakra-ui/react";
|
||||
import WalletConnect from "@walletconnect/client";
|
||||
import networkInfo from "./networkInfo";
|
||||
|
||||
function Body() {
|
||||
const { colorMode } = useColorMode();
|
||||
const bgColor = { light: "white", dark: "gray.700" };
|
||||
|
||||
const [address, setAddress] = useState("");
|
||||
const [uri, setUri] = useState("");
|
||||
const [chainIdIndex, setChainIdIndex] = useState(0);
|
||||
const [connector, setConnector] = useState();
|
||||
const [peerMeta, setPeerMeta] = useState();
|
||||
const [isConnected, setIsConnected] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const session = getCachedSession();
|
||||
|
||||
if (session) {
|
||||
let _connector = new WalletConnect({ session });
|
||||
|
||||
setConnector(_connector);
|
||||
setAddress(_connector.accounts[0]);
|
||||
setUri(_connector.uri);
|
||||
setPeerMeta(_connector.peerMeta);
|
||||
setIsConnected(true);
|
||||
|
||||
const chainId = _connector.chainId.chainID;
|
||||
for (let i = 0; i < networkInfo.length; i++) {
|
||||
if (networkInfo[i].chainID == chainId) {
|
||||
setChainIdIndex(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (connector) {
|
||||
subscribeToEvents();
|
||||
}
|
||||
}, [connector]);
|
||||
|
||||
const getCachedSession = () => {
|
||||
const local = localStorage ? localStorage.getItem("walletconnect") : null;
|
||||
|
||||
let session = null;
|
||||
if (local) {
|
||||
try {
|
||||
session = JSON.parse(local);
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
return session;
|
||||
};
|
||||
|
||||
const initWalletConnect = async () => {
|
||||
try {
|
||||
let _connector = new WalletConnect({ uri });
|
||||
|
||||
if (!_connector.connected) {
|
||||
await _connector.createSession();
|
||||
}
|
||||
|
||||
setConnector(_connector);
|
||||
setUri(_connector.uri);
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
const subscribeToEvents = () => {
|
||||
console.log("ACTION", "subscribeToEvents");
|
||||
|
||||
if (connector) {
|
||||
connector.on("session_request", (error, payload) => {
|
||||
console.log("EVENT", "session_request");
|
||||
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
console.log("SESSION_REQUEST", payload.params);
|
||||
setPeerMeta(payload.params[0].peerMeta);
|
||||
});
|
||||
|
||||
connector.on("session_update", (error) => {
|
||||
console.log("EVENT", "session_update");
|
||||
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
|
||||
connector.on("call_request", async (error, payload) => {
|
||||
console.log("EVENT", "call_request", "method", payload.method);
|
||||
console.log("EVENT", "call_request", "params", payload.params);
|
||||
|
||||
// if (error) {
|
||||
// throw error;
|
||||
// }
|
||||
|
||||
// await getAppConfig().rpcEngine.router(payload, this.state, this.bindedSetState);
|
||||
});
|
||||
|
||||
connector.on("connect", (error, payload) => {
|
||||
console.log("EVENT", "connect");
|
||||
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
// this.setState({ connected: true });
|
||||
});
|
||||
|
||||
connector.on("disconnect", (error, payload) => {
|
||||
console.log("EVENT", "disconnect");
|
||||
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
// this.resetApp();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const approveSession = () => {
|
||||
console.log("ACTION", "approveSession");
|
||||
if (connector) {
|
||||
let chainId = networkInfo[chainIdIndex].chainID;
|
||||
if (!chainId) {
|
||||
chainId = 1; // default to ETH Mainnet if no network selected
|
||||
}
|
||||
connector.approveSession({ chainId, accounts: [address] });
|
||||
setIsConnected(true);
|
||||
}
|
||||
};
|
||||
|
||||
const rejectSession = () => {
|
||||
console.log("ACTION", "rejectSession");
|
||||
if (connector) {
|
||||
connector.rejectSession();
|
||||
setPeerMeta(null);
|
||||
}
|
||||
};
|
||||
|
||||
const killSession = () => {
|
||||
console.log("ACTION", "killSession");
|
||||
if (connector) {
|
||||
connector.killSession();
|
||||
|
||||
setPeerMeta(null);
|
||||
setIsConnected(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Container my="16" minW={["0", "0", "2xl", "2xl"]}>
|
||||
<FormControl>
|
||||
<FormLabel>Enter Address to Impersonate</FormLabel>
|
||||
<Input
|
||||
placeholder="Address"
|
||||
aria-label="address"
|
||||
value={address}
|
||||
onChange={(e) => setAddress(e.target.value)}
|
||||
bg={bgColor[colorMode]}
|
||||
isDisabled={isConnected}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl my={4}>
|
||||
<FormLabel>WalletConnect URI</FormLabel>
|
||||
<Input
|
||||
placeholder="wc:xyz123"
|
||||
aria-label="uri"
|
||||
value={uri}
|
||||
onChange={(e) => setUri(e.target.value)}
|
||||
bg={bgColor[colorMode]}
|
||||
isDisabled={isConnected}
|
||||
/>
|
||||
</FormControl>
|
||||
<Select
|
||||
mb={4}
|
||||
placeholder="Select Network"
|
||||
variant="filled"
|
||||
_hover={{ cursor: "pointer" }}
|
||||
value={chainIdIndex}
|
||||
onChange={(e) => {
|
||||
setChainIdIndex(e.target.value);
|
||||
}}
|
||||
isDisabled={isConnected}
|
||||
>
|
||||
{networkInfo.map((network, i) => (
|
||||
<option value={i} key={i}>
|
||||
{network.name}
|
||||
</option>
|
||||
))}
|
||||
</Select>
|
||||
<Button onClick={initWalletConnect} isDisabled={isConnected}>
|
||||
Connect
|
||||
</Button>
|
||||
{peerMeta && (
|
||||
<>
|
||||
<Box mt={4} fontSize={24} fontWeight="semibold">
|
||||
{isConnected ? "✅ Connected To:" : "⚠ Allow to Connect"}
|
||||
</Box>
|
||||
<VStack>
|
||||
<Avatar src={peerMeta.icons[0]} alt={peerMeta.name} />
|
||||
<Text fontWeight="bold">{peerMeta.name}</Text>
|
||||
<Text fontSize="sm">{peerMeta.description}</Text>
|
||||
<Link href={peerMeta.url} textDecor="underline">
|
||||
{peerMeta.url}
|
||||
</Link>
|
||||
{!isConnected && (
|
||||
<Box pt={6}>
|
||||
<Button onClick={approveSession} mr={10}>
|
||||
Approve ✔
|
||||
</Button>
|
||||
<Button onClick={rejectSession}>Reject ❌</Button>
|
||||
</Box>
|
||||
)}
|
||||
{isConnected && (
|
||||
<Box pt={6}>
|
||||
<Button onClick={killSession}>Disconnect ☠</Button>
|
||||
</Box>
|
||||
)}
|
||||
</VStack>
|
||||
</>
|
||||
)}
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
export default Body;
|
||||
48
src/components/Body/networkInfo.js
Normal file
48
src/components/Body/networkInfo.js
Normal file
@@ -0,0 +1,48 @@
|
||||
const networkInfo = [
|
||||
{
|
||||
chainID: 1,
|
||||
name: "Ethereum Mainnet",
|
||||
},
|
||||
{
|
||||
chainID: 137,
|
||||
name: "Polygon",
|
||||
},
|
||||
{
|
||||
chainID: 56,
|
||||
name: "Binance Smart Chain",
|
||||
},
|
||||
{
|
||||
chainID: 10,
|
||||
name: "Optimistic Ethereum",
|
||||
},
|
||||
{
|
||||
chainID: 250,
|
||||
name: "Fantom Opera",
|
||||
},
|
||||
{
|
||||
chainID: 43114,
|
||||
name: "Avalanche",
|
||||
},
|
||||
{
|
||||
chainID: 100,
|
||||
name: "xDAI",
|
||||
},
|
||||
{
|
||||
chainID: 42,
|
||||
name: "Kovan Testnet",
|
||||
},
|
||||
{
|
||||
chainID: 3,
|
||||
name: "Ropsten Testnet",
|
||||
},
|
||||
{
|
||||
chainID: 4,
|
||||
name: "Rinkeby Testnet",
|
||||
},
|
||||
{
|
||||
chainID: 5,
|
||||
name: "Goerli Testnet",
|
||||
},
|
||||
];
|
||||
|
||||
export default networkInfo;
|
||||
59
src/components/Footer.js
Normal file
59
src/components/Footer.js
Normal file
@@ -0,0 +1,59 @@
|
||||
import React from "react";
|
||||
import {
|
||||
useColorMode,
|
||||
Flex,
|
||||
HStack,
|
||||
VStack,
|
||||
Heading,
|
||||
Spacer,
|
||||
Link,
|
||||
Text,
|
||||
} from "@chakra-ui/react";
|
||||
import { ExternalLinkIcon } from "@chakra-ui/icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
faGithub,
|
||||
faLinkedin,
|
||||
faTwitter,
|
||||
} from "@fortawesome/free-brands-svg-icons";
|
||||
|
||||
const Social = ({ icon, link }) => {
|
||||
return (
|
||||
<Link href={link} isExternal>
|
||||
<FontAwesomeIcon icon={icon} size="lg" />
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
function Footer() {
|
||||
const { colorMode } = useColorMode();
|
||||
const underlineColor = { light: "gray.500", dark: "gray.400" };
|
||||
|
||||
return (
|
||||
<Flex py="4" borderTop="2px" borderTopColor={underlineColor[colorMode]}>
|
||||
<Spacer flex="1" />
|
||||
<VStack>
|
||||
<Heading size="md">
|
||||
Built by:{" "}
|
||||
<Link href="https://apoorvlathey.com/" isExternal>
|
||||
<Text decoration="underline" display="inline">
|
||||
Apoorv Lathey
|
||||
</Text>{" "}
|
||||
<ExternalLinkIcon />
|
||||
</Link>
|
||||
</Heading>
|
||||
<HStack spacing={8} mt={10}>
|
||||
<Social icon={faTwitter} link="https://twitter.com/apoorvlathey" />
|
||||
<Social icon={faGithub} link="https://github.com/CodinMaster" />
|
||||
<Social
|
||||
icon={faLinkedin}
|
||||
link="https://www.linkedin.com/in/apoorvlathey/"
|
||||
/>
|
||||
</HStack>
|
||||
</VStack>
|
||||
<Spacer flex="1" />
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
||||
export default Footer;
|
||||
29
src/components/Navbar.js
Normal file
29
src/components/Navbar.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import React from "react";
|
||||
import { Button, useColorMode, Flex, Heading, Spacer } from "@chakra-ui/react";
|
||||
import { SunIcon, MoonIcon } from "@chakra-ui/icons";
|
||||
|
||||
function Navbar() {
|
||||
const { colorMode, toggleColorMode } = useColorMode();
|
||||
const underlineColor = { light: "gray.500", dark: "gray.400" };
|
||||
|
||||
return (
|
||||
<Flex
|
||||
py="4"
|
||||
px={["2", "4", "10", "10"]}
|
||||
borderBottom="2px"
|
||||
borderBottomColor={underlineColor[colorMode]}
|
||||
>
|
||||
<Spacer flex="1" />
|
||||
<Heading maxW={["302px", "4xl", "4xl", "4xl"]}>
|
||||
🎭 Impersonator 🕵️
|
||||
</Heading>
|
||||
<Flex flex="1" justifyContent="flex-end">
|
||||
<Button onClick={toggleColorMode} rounded="full" h="40px" w="40px">
|
||||
{colorMode === "light" ? <MoonIcon /> : <SunIcon />}
|
||||
</Button>
|
||||
</Flex>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
||||
export default Navbar;
|
||||
12
src/index.js
Normal file
12
src/index.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import App from "./App";
|
||||
import { ChakraProvider } from "@chakra-ui/react";
|
||||
import theme from "./theme";
|
||||
|
||||
ReactDOM.render(
|
||||
<ChakraProvider theme={theme}>
|
||||
<App />
|
||||
</ChakraProvider>,
|
||||
document.getElementById("root")
|
||||
);
|
||||
18
src/styles/scroll.css
Normal file
18
src/styles/scroll.css
Normal file
@@ -0,0 +1,18 @@
|
||||
.scroll::-webkit-scrollbar-track {
|
||||
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
|
||||
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
|
||||
border-radius: 10px;
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.scroll::-webkit-scrollbar {
|
||||
width: 12px;
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.scroll::-webkit-scrollbar-thumb {
|
||||
border-radius: 10px;
|
||||
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
|
||||
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
|
||||
background-color: #2a8ed6;
|
||||
}
|
||||
10
src/theme.js
Normal file
10
src/theme.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import { extendTheme } from "@chakra-ui/react";
|
||||
|
||||
const config = {
|
||||
initialColorMode: "dark",
|
||||
useSystemColorMode: false,
|
||||
};
|
||||
|
||||
const theme = extendTheme({ config });
|
||||
|
||||
export default theme;
|
||||
Reference in New Issue
Block a user