├── public ├── favicon.ico ├── logo192.png ├── logo512.png ├── robots.txt ├── manifest.json └── index.html ├── src ├── assets │ ├── 4927.eps │ ├── 4927.jpg │ ├── Sword.ai │ ├── bmo.png │ ├── close.png │ ├── cool.gif │ ├── goku.png │ ├── logos.zip │ ├── vector.ai │ ├── button.png │ ├── daymode.jpg │ ├── dsword.png │ ├── example.png │ ├── favicon.ico │ ├── favicon.png │ ├── feedbg.jpg │ ├── feedbg2.jpg │ ├── feedbg3.jpg │ ├── feedbg4.jpg │ ├── refresh.png │ ├── scroll.png │ ├── scroll2.png │ ├── sword2.png │ ├── unknown.png │ ├── vector.jpg │ ├── vector.png │ ├── wooden.png │ ├── favicon_io.zip │ ├── finnsword.png │ ├── finnsword2.png │ ├── light-bulb.png │ ├── lightbulb2.png │ ├── nightmode.jpg │ ├── untitled-1.png │ ├── Demon_Sword.webp │ ├── deletebutton.jpg │ ├── nftpalbanner.png │ ├── RetroComputer.woff │ ├── RetroComputer.woff2 │ ├── Watermelon Days.otf │ ├── Watermelon Days.ttf │ ├── favicon-32x32.png │ ├── question-mark.png │ ├── retro_computer.zip │ ├── watermelon_days.zip │ ├── lemonpie-webfont.woff │ ├── Adventure Time Logo.ttf │ ├── adventure-time-logo.zip │ ├── candy_beans-webfont.woff │ ├── lemon_days-webfont.woff │ ├── lemon_days-webfont.woff2 │ ├── lemonpie-webfont.woff2 │ ├── candy_beans-webfont.woff2 │ ├── watermelon_days-webfont.woff │ ├── watermelon_days-webfont.woff2 │ ├── retro_computer_personal_use.ttf │ ├── webfontkit-20220809-192019.zip │ ├── webfontkit-20220810-172416.zip │ ├── adventure_time_logo-webfont.woff │ ├── adventure_time_logo-webfont.woff2 │ ├── tumblr_mayy7wWuRf1qzrbk9o1_500.jpg │ ├── transfonter.org-20220805-032912.zip │ ├── nothung__billy_s_sword__by_dandoorlando_d6qwgex-pre.jpg │ ├── torn-leaf-parchment-magic-diploma-fairy-grunge-cartoon-vector-illustration_81894-5813.jpg │ ├── ethereum-gold.svg │ ├── nftnerd.svg │ ├── etherscan.svg │ ├── eth.svg │ ├── opensea.svg │ ├── ethereum.svg │ ├── Sword.svg │ └── vector.svg ├── setupTests.js ├── App.test.js ├── reportWebVitals.js ├── Styles │ ├── Menu.css │ ├── Banner.css │ ├── index.css │ ├── Stats.css │ ├── App.css │ └── ModuleHandler.css ├── App.css ├── index.js ├── Banner.js ├── logo.svg ├── App.js ├── Menu.js ├── Stats.js ├── BackupModuleHandler.js └── ModuleHandler.js ├── .gitignore ├── package.json └── README.md /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/public/logo512.png -------------------------------------------------------------------------------- /src/assets/4927.eps: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/4927.eps -------------------------------------------------------------------------------- /src/assets/4927.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/4927.jpg -------------------------------------------------------------------------------- /src/assets/Sword.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/Sword.ai -------------------------------------------------------------------------------- /src/assets/bmo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/bmo.png -------------------------------------------------------------------------------- /src/assets/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/close.png -------------------------------------------------------------------------------- /src/assets/cool.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/cool.gif -------------------------------------------------------------------------------- /src/assets/goku.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/goku.png -------------------------------------------------------------------------------- /src/assets/logos.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/logos.zip -------------------------------------------------------------------------------- /src/assets/vector.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/vector.ai -------------------------------------------------------------------------------- /src/assets/button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/button.png -------------------------------------------------------------------------------- /src/assets/daymode.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/daymode.jpg -------------------------------------------------------------------------------- /src/assets/dsword.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/dsword.png -------------------------------------------------------------------------------- /src/assets/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/example.png -------------------------------------------------------------------------------- /src/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/favicon.ico -------------------------------------------------------------------------------- /src/assets/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/favicon.png -------------------------------------------------------------------------------- /src/assets/feedbg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/feedbg.jpg -------------------------------------------------------------------------------- /src/assets/feedbg2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/feedbg2.jpg -------------------------------------------------------------------------------- /src/assets/feedbg3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/feedbg3.jpg -------------------------------------------------------------------------------- /src/assets/feedbg4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/feedbg4.jpg -------------------------------------------------------------------------------- /src/assets/refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/refresh.png -------------------------------------------------------------------------------- /src/assets/scroll.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/scroll.png -------------------------------------------------------------------------------- /src/assets/scroll2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/scroll2.png -------------------------------------------------------------------------------- /src/assets/sword2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/sword2.png -------------------------------------------------------------------------------- /src/assets/unknown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/unknown.png -------------------------------------------------------------------------------- /src/assets/vector.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/vector.jpg -------------------------------------------------------------------------------- /src/assets/vector.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/vector.png -------------------------------------------------------------------------------- /src/assets/wooden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/wooden.png -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /src/assets/favicon_io.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/favicon_io.zip -------------------------------------------------------------------------------- /src/assets/finnsword.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/finnsword.png -------------------------------------------------------------------------------- /src/assets/finnsword2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/finnsword2.png -------------------------------------------------------------------------------- /src/assets/light-bulb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/light-bulb.png -------------------------------------------------------------------------------- /src/assets/lightbulb2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/lightbulb2.png -------------------------------------------------------------------------------- /src/assets/nightmode.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/nightmode.jpg -------------------------------------------------------------------------------- /src/assets/untitled-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/untitled-1.png -------------------------------------------------------------------------------- /src/assets/Demon_Sword.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/Demon_Sword.webp -------------------------------------------------------------------------------- /src/assets/deletebutton.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/deletebutton.jpg -------------------------------------------------------------------------------- /src/assets/nftpalbanner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/nftpalbanner.png -------------------------------------------------------------------------------- /src/assets/RetroComputer.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/RetroComputer.woff -------------------------------------------------------------------------------- /src/assets/RetroComputer.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/RetroComputer.woff2 -------------------------------------------------------------------------------- /src/assets/Watermelon Days.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/Watermelon Days.otf -------------------------------------------------------------------------------- /src/assets/Watermelon Days.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/Watermelon Days.ttf -------------------------------------------------------------------------------- /src/assets/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/favicon-32x32.png -------------------------------------------------------------------------------- /src/assets/question-mark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/question-mark.png -------------------------------------------------------------------------------- /src/assets/retro_computer.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/retro_computer.zip -------------------------------------------------------------------------------- /src/assets/watermelon_days.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/watermelon_days.zip -------------------------------------------------------------------------------- /src/assets/lemonpie-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/lemonpie-webfont.woff -------------------------------------------------------------------------------- /src/assets/Adventure Time Logo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/Adventure Time Logo.ttf -------------------------------------------------------------------------------- /src/assets/adventure-time-logo.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/adventure-time-logo.zip -------------------------------------------------------------------------------- /src/assets/candy_beans-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/candy_beans-webfont.woff -------------------------------------------------------------------------------- /src/assets/lemon_days-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/lemon_days-webfont.woff -------------------------------------------------------------------------------- /src/assets/lemon_days-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/lemon_days-webfont.woff2 -------------------------------------------------------------------------------- /src/assets/lemonpie-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/lemonpie-webfont.woff2 -------------------------------------------------------------------------------- /src/assets/candy_beans-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/candy_beans-webfont.woff2 -------------------------------------------------------------------------------- /src/assets/watermelon_days-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/watermelon_days-webfont.woff -------------------------------------------------------------------------------- /src/assets/watermelon_days-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/watermelon_days-webfont.woff2 -------------------------------------------------------------------------------- /src/assets/retro_computer_personal_use.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/retro_computer_personal_use.ttf -------------------------------------------------------------------------------- /src/assets/webfontkit-20220809-192019.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/webfontkit-20220809-192019.zip -------------------------------------------------------------------------------- /src/assets/webfontkit-20220810-172416.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/webfontkit-20220810-172416.zip -------------------------------------------------------------------------------- /src/assets/adventure_time_logo-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/adventure_time_logo-webfont.woff -------------------------------------------------------------------------------- /src/assets/adventure_time_logo-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/adventure_time_logo-webfont.woff2 -------------------------------------------------------------------------------- /src/assets/tumblr_mayy7wWuRf1qzrbk9o1_500.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/tumblr_mayy7wWuRf1qzrbk9o1_500.jpg -------------------------------------------------------------------------------- /src/assets/transfonter.org-20220805-032912.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/transfonter.org-20220805-032912.zip -------------------------------------------------------------------------------- /src/assets/nothung__billy_s_sword__by_dandoorlando_d6qwgex-pre.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/nothung__billy_s_sword__by_dandoorlando_d6qwgex-pre.jpg -------------------------------------------------------------------------------- /src/assets/torn-leaf-parchment-magic-diploma-fairy-grunge-cartoon-vector-illustration_81894-5813.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jckhe/nftpal/HEAD/src/assets/torn-leaf-parchment-magic-diploma-fairy-grunge-cartoon-vector-illustration_81894-5813.jpg -------------------------------------------------------------------------------- /src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /src/Styles/Menu.css: -------------------------------------------------------------------------------- 1 | 2 | .buttonLabelDiv span { 3 | z-index: 7; 4 | user-select: none; 5 | position: relative; 6 | left: 29%; 7 | top: 40%; 8 | font-size: 1.3rem; 9 | font-family: 'watermelondays' 10 | } 11 | 12 | .buttonLabelDiv strong { 13 | font-weight: normal; 14 | } 15 | 16 | .buttonLabelDiv { 17 | position: absolute; 18 | cursor: pointer; 19 | height: 120px; 20 | width: 200px; 21 | overflow: visible; 22 | padding: 0; 23 | top: -30px; 24 | left: -3%; 25 | filter:drop-shadow(1px 2px 5px black); 26 | } 27 | 28 | -------------------------------------------------------------------------------- /src/assets/ethereum-gold.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import './Styles/index.css'; 4 | import {App} from './App'; 5 | import {Banner} from './Banner.js' 6 | import { CookiesProvider } from "react-cookie"; 7 | import reportWebVitals from './reportWebVitals'; 8 | 9 | const root = ReactDOM.createRoot(document.getElementById('root')); 10 | root.render( 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | ); 19 | 20 | // If you want to start measuring performance in your app, pass a function 21 | // to log results (for example: reportWebVitals(console.log)) 22 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 23 | reportWebVitals(); 24 | -------------------------------------------------------------------------------- /src/Banner.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import bannerPNG from './assets/nftpalbanner.png' 3 | import './Styles/Banner.css' 4 | 5 | 6 | 7 | export function Banner (props) { 8 | return ( 9 |
10 |
11 | NFTPal Banner 12 |
13 |
14 |
15 |
16 |
17 | 18 |
19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /src/assets/nftnerd.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 9 | 11 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/assets/etherscan.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.16.5", 7 | "@testing-library/react": "^13.3.0", 8 | "@testing-library/user-event": "^13.5.0", 9 | "react": "^18.2.0", 10 | "react-cookie": "^4.1.1", 11 | "react-dom": "^18.2.0", 12 | "react-favicon": "^1.0.1", 13 | "react-router-dom": "^6.3.0", 14 | "react-scripts": "5.0.1", 15 | "react-switch": "^7.0.0", 16 | "react-usestateref": "^1.0.8", 17 | "universal-cookie": "^4.0.4", 18 | "web-vitals": "^2.1.4" 19 | }, 20 | "scripts": { 21 | "start": "react-scripts start", 22 | "build": "react-scripts build", 23 | "test": "react-scripts test", 24 | "eject": "react-scripts eject" 25 | }, 26 | "eslintConfig": { 27 | "extends": [ 28 | "react-app", 29 | "react-app/jest" 30 | ] 31 | }, 32 | "browserslist": { 33 | "production": [ 34 | ">0.2%", 35 | "not dead", 36 | "not op_mini all" 37 | ], 38 | "development": [ 39 | "last 1 chrome version", 40 | "last 1 firefox version", 41 | "last 1 safari version" 42 | ] 43 | }, 44 | "devDependencies": { 45 | "@iconify/react": "^3.2.2" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/assets/eth.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/Styles/Banner.css: -------------------------------------------------------------------------------- 1 | .header { 2 | display: flex; 3 | justify-content: center; 4 | flex-direction: column; 5 | align-items: center; 6 | caret-color: transparent!important; 7 | z-index: 4; 8 | position: relative; 9 | } 10 | 11 | .banner { 12 | 13 | padding: 7px; 14 | } 15 | 16 | .menu { 17 | display: flex; 18 | justify-content: center; 19 | gap: 100px; 20 | margin-bottom: 15px; 21 | } 22 | 23 | .menu button { 24 | 25 | 26 | } 27 | 28 | .button-74 { 29 | height: 40px; 30 | width: 115px; 31 | text-transform: uppercase; 32 | color: #000; 33 | cursor: pointer; 34 | border: 3px solid; 35 | padding: 0.25em 0.5em; 36 | box-shadow: 1px 1px 0px 0px, 2px 2px 0px 0px, 3px 3px 0px 0px, 4px 4px 0px 0px, 5px 5px 0px 0px; 37 | position: relative; 38 | user-select: none; 39 | -webkit-user-select: none; 40 | touch-action: manipulation; 41 | } 42 | 43 | 44 | 45 | .button-74:active { 46 | box-shadow: 0px 0px 0px 0px; 47 | top: 5px; 48 | left: 5px; 49 | } 50 | 51 | 52 | 53 | .button-74 span { 54 | 55 | bottom: -15px; 56 | left: 45px; 57 | letter-spacing: 3px; 58 | font-family: 'watermelondays'; 59 | color: #000000; 60 | -webkit-text-stroke: 0.1px; 61 | -webkit-text-stroke-color: rgba(255, 255, 255, .5); 62 | } 63 | 64 | .buttonHolder { 65 | display: flex; 66 | align-items: center; 67 | flex-direction: row; 68 | } 69 | 70 | .buttonHolder2 { 71 | display: flex; 72 | align-items: center; 73 | flex-direction: row; 74 | } 75 | 76 | @media (min-width: 768px) { 77 | .button-74 { 78 | min-width: 120px; 79 | padding: 0 25px; 80 | } 81 | } -------------------------------------------------------------------------------- /src/Styles/index.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'lemonpieregular'; 3 | src: url('../assets/lemonpie-webfont.woff2') format('woff2'), 4 | url('../assets/lemonpie-webfont.woff') format('woff'); 5 | font-weight: normal; 6 | font-style: normal; 7 | 8 | } 9 | 10 | @font-face { 11 | font-family: 'watermelondays'; 12 | src: url('../assets/watermelon_days-webfont.woff2') format('woff2'), 13 | url('../assets/watermelon_days-webfont.woff') format('woff'); 14 | font-weight: normal; 15 | font-style: normal; 16 | 17 | } 18 | 19 | @font-face { 20 | font-family: 'Retro Computer'; 21 | src: url('../assets/RetroComputer.woff2') format('woff2'), 22 | url('../assets/RetroComputer.woff') format('woff'); 23 | font-weight: normal; 24 | font-style: normal; 25 | font-display: swap; 26 | } 27 | 28 | 29 | @font-face { 30 | font-family: 'candy_beansregular'; 31 | src: url('../assets/candy_beans-webfont.woff2') format('woff2'), 32 | url('../assets/candy_beans-webfont.woff') format('woff'); 33 | font-weight: normal; 34 | font-style: normal; 35 | 36 | } 37 | 38 | @font-face { 39 | font-family: 'atime'; 40 | src: url('../assets/adventure_time_logo-webfont.woff2') format('woff2'), 41 | url('../assets/adventure_time_logo-webfont.woff') format('woff'); 42 | font-weight: normal; 43 | font-style: normal; 44 | 45 | } 46 | 47 | body { 48 | margin: 0; 49 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'lemonpieregular', 'Roboto', 'Oxygen', 50 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'candy_beansregular' , 'Droid Sans', 'Helvetica Neue', 51 | sans-serif; 52 | -webkit-font-smoothing: antialiased; 53 | -moz-osx-font-smoothing: grayscale; 54 | 55 | } 56 | 57 | #root { 58 | 59 | } 60 | 61 | 62 | code { 63 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 64 | monospace; 65 | } 66 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/Styles/Stats.css: -------------------------------------------------------------------------------- 1 | 2 | .stats { 3 | display: flex; 4 | flex-direction: row; 5 | align-items: center; 6 | width: 90%; 7 | height: 20%; 8 | cursor: pointer; 9 | gap: 100px; 10 | justify-content: space-evenly; 11 | margin-left: 3px; 12 | margin-top: 5px; 13 | margin-bottom: 5px; 14 | padding: 0 10px 5px; 15 | 16 | border-bottom: 1px DOTTED rgba(0, 0, 0, .5); 17 | position: relative; 18 | } 19 | 20 | 21 | #bigVal { 22 | padding-left: 5px; 23 | white-space: nowrap; 24 | } 25 | 26 | .stats:hover { 27 | border-bottom: 2px DOTTED rgb(255, 255, 255); 28 | } 29 | 30 | 31 | .stats-val { 32 | z-index: 100; 33 | font-weight: bolder; 34 | font-size: 1rem; 35 | font-family: 'candy_beansregular'; 36 | letter-spacing: 2px; 37 | -webkit-text-stroke: 1px; 38 | -webkit-text-fill-color: rgb(7, 255, 255); 39 | } 40 | 41 | .bigPlayButtonTrue { 42 | width: 210px; 43 | height: 90px; 44 | padding-top: 2px; 45 | position: absolute; 46 | transition: height .2s linear; 47 | transition: width .1s linear; 48 | filter:drop-shadow(1px 2px 1px black) 49 | drop-shadow(-1px -1px 0 rgb(121,189,154)); 50 | } 51 | 52 | .bigPlayButtonFalse { 53 | width: 200px; 54 | height: 70px; 55 | padding-top: 2px; 56 | position: absolute; 57 | transition: height .05s linear; 58 | transition: width .05s linear; 59 | filter:drop-shadow(1px 2px 1px black) 60 | drop-shadow(-1px -1px 0 rgb(121,189,154)); 61 | } 62 | 63 | .playButtonHoverFalse { 64 | width: 120px; 65 | height: 70px; 66 | padding-top: 2px; 67 | position: absolute; 68 | transition: heigh width 2s; 69 | filter:drop-shadow(1px 2px 1px black) 70 | drop-shadow(-1px -1px 0 rgb(121,189,154)); 71 | 72 | } 73 | 74 | .playButtonHoverTrue { 75 | width: 150px; 76 | height: 90px; 77 | padding-top: 2px; 78 | position: absolute; 79 | transition: height .2s linear; 80 | transition: width .1s linear; 81 | filter:drop-shadow(1px 2px 1px black) 82 | drop-shadow(-1px -1px 0 rgb(121,189,154)); 83 | 84 | } 85 | 86 | .playButton { 87 | width: 120px; 88 | height: 70px; 89 | padding-top: 2px; 90 | position: absolute; 91 | transition: heigh width 2s; 92 | filter:drop-shadow(1px 2px 1px black) 93 | drop-shadow(-1px -1px 0 rgb(121,189,154)); 94 | 95 | } 96 | 97 | .playButtonLarge { 98 | padding-top: 2px; 99 | position: absolute; 100 | padding-left: 10px; 101 | margin-left: 1px; 102 | filter:drop-shadow(1px 2px 1px black) 103 | drop-shadow(-1px -1px 0 rgb(121,189,154)); 104 | } 105 | 106 | 107 | .bmo { 108 | border: 2px solid rgba(0, 0, 0, .3); 109 | border-radius: 2px; 110 | position: absolute; 111 | top: -3px; 112 | filter:drop-shadow(1px 2px 3px rgba(216, 211, 211,.3)) 113 | drop-shadow(-1px -1px 0 rgba(228, 228, 228, .3)); 114 | } 115 | 116 | #floorprice { 117 | display: flex; 118 | flex-direction: row; 119 | align-items: center; 120 | gap: 2px; 121 | } 122 | 123 | .eth { 124 | color: #1f1d1d; 125 | filter:drop-shadow(1px 1px 3px rgb(167, 170, 7)) ; 126 | } -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import { ModuleHandler } from './ModuleHandler'; 2 | import './Styles/App.css'; 3 | import React, { useEffect } from 'react'; 4 | import useState from 'react-usestateref' 5 | import feedBG from './assets/feedbg4.jpg' 6 | import nightBG from './assets/nightmode.jpg' 7 | import Favico from './assets/favicon.png' 8 | import Favicon from "react-favicon"; 9 | import { AutoRefreshButton, ETHPrice, ManualRefreshButton, NightModeToggle } from './Menu'; 10 | 11 | 12 | export function App() { 13 | 14 | const [nightMode, setNightMode] = useState(true); 15 | const [manuelRefresh, toggleRefresh] = useState(); 16 | const [autoRefresh, toggleAutoRefresh] = useState(false); 17 | const [autoRefreshTimer, setRefreshTimer] = useState(0); 18 | 19 | //props for auto-refresh intervals 20 | const IntervalTimerFunc = (num) => { 21 | setRefreshTimer(num) 22 | console.log(num) 23 | console.log(autoRefreshTimer) 24 | } 25 | 26 | //night mode stuff 27 | const nightModeFunc = (e) => { 28 | setNightMode(!nightMode) 29 | } 30 | 31 | const nightModeHandler = () => { 32 | if (nightMode === false) { 33 | return { 34 | backgroundColor: "#cdd7b6" 35 | } 36 | } else { 37 | return { 38 | backgroundColor: "#383B32" 39 | } 40 | } 41 | } 42 | 43 | const nightModeBG = () => { 44 | if (nightMode === true) { 45 | return { 46 | backgroundImage: `url(${nightBG})` 47 | } 48 | } else { 49 | return { 50 | backgroundImage: `url(${feedBG})` 51 | } 52 | } 53 | } 54 | //ETH Price 55 | 56 | const fetchETHPrice = () => { 57 | const options = {method: 'GET'}; 58 | fetch("https://api.etherscan.io/api?module=stats&action=ethprice&apikey=NU8841D6JKV8NY9HXD3F9DEVRD9Z6VG5W4", options) 59 | .then(response => response.json()) 60 | .then(response => { 61 | let eth = response.result.ethusd; 62 | console.log(eth) 63 | }) 64 | } 65 | 66 | //manual refresh stuff 67 | const refreshClick = () => { 68 | toggleRefresh(true) 69 | 70 | } 71 | 72 | 73 | 74 | //props function 75 | const autoRefreshHandle = () => { 76 | toggleAutoRefresh(!autoRefresh) 77 | setRefreshTimer(300000) 78 | } 79 | 80 | 81 | 82 | 83 | useEffect(() => { 84 | document.title = 'NFTPal' 85 | let sessionID = localStorage.getItem('session_id'); 86 | console.log(sessionID) 87 | console.log("hey") 88 | if (autoRefresh === true) { 89 | setTimeout(() => { 90 | setRefreshTimer(autoRefreshTimer + 1); 91 | console.log("yo: " + autoRefreshTimer) 92 | }, autoRefreshTimer); 93 | } else { 94 | setRefreshTimer(0) 95 | } 96 | toggleRefresh(); 97 | }, [autoRefresh, autoRefreshTimer]) 98 | 99 | return ( 100 |
101 |
102 |
103 | 104 | 105 | 106 | 107 |
108 |
109 | 110 | 111 |
112 | 113 | 114 |
115 |
116 | ); 117 | } 118 | 119 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Create React App 2 | 3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 4 | 5 | ## Available Scripts 6 | 7 | In the project directory, you can run: 8 | 9 | ### `npm start` 10 | 11 | Runs the app in the development mode.\ 12 | Open [http://localhost:3000](http://localhost:3000) to view it in your browser. 13 | 14 | The page will reload when you make changes.\ 15 | You may also see any lint errors in the console. 16 | 17 | ### `npm test` 18 | 19 | Launches the test runner in the interactive watch mode.\ 20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 21 | 22 | ### `npm run build` 23 | 24 | Builds the app for production to the `build` folder.\ 25 | It correctly bundles React in production mode and optimizes the build for the best performance. 26 | 27 | The build is minified and the filenames include the hashes.\ 28 | Your app is ready to be deployed! 29 | 30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 31 | 32 | ### `npm run eject` 33 | 34 | **Note: this is a one-way operation. Once you `eject`, you can't go back!** 35 | 36 | If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 37 | 38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own. 39 | 40 | You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it. 41 | 42 | ## Learn More 43 | 44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 45 | 46 | To learn React, check out the [React documentation](https://reactjs.org/). 47 | 48 | ### Code Splitting 49 | 50 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) 51 | 52 | ### Analyzing the Bundle Size 53 | 54 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) 55 | 56 | ### Making a Progressive Web App 57 | 58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) 59 | 60 | ### Advanced Configuration 61 | 62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) 63 | 64 | ### Deployment 65 | 66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) 67 | 68 | ### `npm run build` fails to minify 69 | 70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) 71 | -------------------------------------------------------------------------------- /src/assets/opensea.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/ethereum.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/Menu.js: -------------------------------------------------------------------------------- 1 | import "./Styles/Menu.css"; 2 | import React, { useEffect } from "react"; 3 | import playButton from './assets/button.png' 4 | import useState from 'react-usestateref' 5 | 6 | 7 | export const NightModeToggle = (props) => { 8 | 9 | const [nightModeStatus, toggleNightMode, nightModeRef] = useState(true); 10 | let propsFunc = props.func; 11 | 12 | 13 | const handleClick = () => { 14 | toggleNightMode(!nightModeStatus); 15 | propsFunc(); 16 | } 17 | 18 | const nightModeChecker = () => { 19 | if (nightModeStatus === false) { 20 | return 'OFF' 21 | } else { 22 | return 'ON' 23 | } 24 | } 25 | 26 | 27 | return ( 28 | <> 29 |
34 | 35 | Night mode: {nightModeChecker()} 36 |
37 | 38 | ) 39 | } 40 | 41 | export const ManualRefreshButton = (props) => { 42 | const [refreshStatus, toggleRefreshAnimation] = useState('Refresh All') 43 | 44 | 45 | const refreshAnimation = () => { 46 | setTimeout(() => { 47 | toggleRefreshAnimation('Refreshing') 48 | setTimeout(() => { 49 | toggleRefreshAnimation('Refreshing.') 50 | setTimeout(() => { 51 | toggleRefreshAnimation('Refreshing..') 52 | setTimeout(() => { 53 | toggleRefreshAnimation('Refreshing...') 54 | setTimeout(() => { 55 | toggleRefreshAnimation('Refresh All') 56 | }, 350); 57 | }, 400); 58 | }, 400); 59 | }, 400); 60 | }, 5); 61 | } 62 | 63 | return ( 64 | <> 65 | 66 |
{ 67 | refreshAnimation(); 68 | props.refresh(); 69 | }} className="buttonLabelDiv2" style={{ 70 | backgroundImage: `url(${playButton})`, 71 | backgroundSize: 'cover' 72 | }} 73 | > 74 | {refreshStatus} 75 |
76 | 77 | ) 78 | } 79 | 80 | export const AutoRefreshButton = (props) => { 81 | const [refreshStatus, toggleRefreshStatus] = useState(false); 82 | const [clickedTimer, setTimer] = useState(300000) 83 | const [defaultChecked, setDefaultChecked, defaultCheckRef] = useState(false) 84 | 85 | 86 | const clickedChecker = () => { 87 | if (defaultChecked === false) { 88 | return false; 89 | } else { 90 | return true; 91 | } 92 | } 93 | //style handling 94 | const autoRefreshStatusSpan = () => { 95 | if (refreshStatus === true) { 96 | return 'ON' 97 | } else { 98 | return 'OFF' 99 | } 100 | } 101 | //gets the input value for the timer 102 | const handleChange = (e) => { 103 | let inputTimer = e.target.value; 104 | console.log(e.target.value); 105 | setTimer(inputTimer); 106 | props.intervalFunc(clickedTimer) 107 | } 108 | 109 | useEffect(() => { 110 | 111 | }, []) 112 | 113 | 114 | 115 | return ( 116 | <> 117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
{ 126 | toggleRefreshStatus(!refreshStatus) 127 | setDefaultChecked(!defaultChecked) 128 | props.func(); 129 | }} className="buttonLabelDiv3" style={{ 130 | backgroundImage: `url(${playButton})`, 131 | backgroundSize: 'cover' 132 | }} 133 | > 134 | Auto-Refresh: {autoRefreshStatusSpan()} 135 |
136 | 137 | ) 138 | } 139 | 140 | 141 | export function ETHPrice(props) { 142 | //usestate for eth price 143 | const [ethPrice, setETHPrice] = useState(); 144 | const [spanText, setSpanText] = useState("") 145 | 146 | 147 | 148 | const fetchETHPrice = () => { 149 | const options = {method: 'GET'}; 150 | setTimeout(() => { 151 | setETHPrice("") 152 | setSpanText("Updating") 153 | setTimeout(() => { 154 | setSpanText("Updating.") 155 | setTimeout(() => { 156 | setSpanText("Updating..") 157 | setTimeout(() => { 158 | setSpanText("ETH:$ ") 159 | fetch("https://api.coinbase.com/v2/prices/ETH-USD/spot", options) 160 | .then(response => response.json()) 161 | .then(response => { 162 | let eth = response.data.amount; 163 | console.log(response) 164 | setETHPrice(eth); 165 | }) 166 | }, 777); 167 | }, 555); 168 | }, 555); 169 | }, 100); 170 | } 171 | 172 | useEffect(() => { 173 | fetchETHPrice(); 174 | }, []) 175 | 176 | 177 | return ( 178 | <> 179 |
{fetchETHPrice()}} 184 | > 185 | {spanText}{ethPrice} 186 |
187 | 188 | ) 189 | } -------------------------------------------------------------------------------- /src/Stats.js: -------------------------------------------------------------------------------- 1 | import {React, useEffect, useState} from 'react'; 2 | import playButton from './assets/button.png' 3 | import './Styles/ModuleHandler.css' 4 | import bmo from './assets/bmo.png' 5 | import { Icon } from '@iconify/react'; 6 | 7 | 8 | 9 | //Each "stat module" is a div/container in the module 10 | export function SalesModule(props) { 11 | const [statInfoStyle, setStatInfoStyle] = useState("playButtonHoverFalse") 12 | let sales = props.sales; 13 | 14 | 15 | return ( 16 |
setStatInfoStyle("playButtonHoverTrue")} 17 | onMouseLeave={() => setStatInfoStyle("playButtonHoverFalse")} 18 | className="stats"> 19 |
20 | 22 | Sales: 23 |
24 |
25 | 26 | {sales} 27 |
28 |
29 | ) 30 | } 31 | 32 | export function SupplyModule(props) { 33 | const [statInfoStyle, setStatInfoStyle] = useState("playButtonHoverFalse") 34 | let supply = props.supply; 35 | 36 | 37 | return ( 38 |
setStatInfoStyle("playButtonHoverTrue")} 39 | onMouseLeave={() => setStatInfoStyle("playButtonHoverFalse")} 40 | className="stats"> 41 |
42 | 43 | Supply: 44 |
45 |
46 | 47 | {supply} 48 |
49 |
50 | ) 51 | } 52 | 53 | export function VolumeModule(props) { 54 | const [statInfoStyle, setStatInfoStyle] = useState("bigPlayButtonFalse") 55 | let volume = props.volume; 56 | 57 | 58 | return ( 59 |
setStatInfoStyle("bigPlayButtonTrue")} 60 | onMouseLeave={() => setStatInfoStyle("bigPlayButtonFalse")} 61 | className="stats"> 62 |
63 | 65 | Total Volume: 66 |
67 |
68 | 69 | {volume} 70 |
71 |
72 | ) 73 | } 74 | 75 | export function HoldersModule(props) { 76 | const [statInfoStyle, setStatInfoStyle] = useState("bigPlayButtonFalse") 77 | let holders = props.holders; 78 | 79 | 80 | return ( 81 |
setStatInfoStyle("bigPlayButtonTrue")} 82 | onMouseLeave={() => setStatInfoStyle("bigPlayButtonFalse")} 83 | className="stats"> 84 |
85 | 87 | # of Holders: 88 |
89 |
90 | 91 | {holders} 92 |
93 |
94 | ) 95 | } 96 | 97 | 98 | export function HolderRatioModule(props) { 99 | const [statInfoStyle, setStatInfoStyle] = useState("bigPlayButtonFalse") 100 | let holderRatio = props.holderRatio; 101 | 102 | 103 | return ( 104 |
setStatInfoStyle("bigPlayButtonTrue")} 105 | onMouseLeave={() => setStatInfoStyle("bigPlayButtonFalse")} 106 | className="stats"> 107 |
108 | 110 | Holder Ratio: 111 |
112 |
113 | 114 | {holderRatio} 115 |
116 |
117 | ) 118 | } 119 | 120 | 121 | export function FeeModule(props) { 122 | const [statInfoStyle, setStatInfoStyle] = useState("bigPlayButtonFalse") 123 | let royaltyFee = props.royaltyFee; 124 | 125 | 126 | return ( 127 |
setStatInfoStyle("bigPlayButtonTrue")} 128 | onMouseLeave={() => setStatInfoStyle("bigPlayButtonFalse")} className="stats"> 129 |
130 | 133 | Royalty Fee: 134 |
135 |
136 | 137 | {royaltyFee} 138 |
139 |
140 | ) 141 | } 142 | 143 | 144 | export function FloorPriceModule(props) { 145 | const [statInfoStyle, setStatInfoStyle] = useState("bigPlayButtonFalse") 146 | let floorPrice = props.floorPrice; 147 | 148 | 149 | return ( 150 |
setStatInfoStyle("bigPlayButtonTrue")} 151 | onMouseLeave={() => setStatInfoStyle("bigPlayButtonFalse")} 152 | className="stats"> 153 |
154 | 155 | Floor Price: 156 |
157 |
158 | 159 | {floorPrice} 160 |
161 |
162 | ) 163 | } -------------------------------------------------------------------------------- /src/Styles/App.css: -------------------------------------------------------------------------------- 1 | .feed { 2 | width: 66.7%; 3 | height: fit-content; 4 | display: flex; 5 | border: 5px solid rgba(0, 0, 0, 1); 6 | padding: 20px 5px 5px; 7 | margin-top: 50px; 8 | padding-bottom: 15px; 9 | flex-direction: column; 10 | flex-wrap: wrap; 11 | background-size: cover; 12 | justify-content: center; 13 | box-shadow: 0px 8px 32px 8px rgba(0,0,0,0.35); 14 | border-radius: 15px; 15 | margin-bottom: 10px; 16 | overflow: hidden; 17 | align-items: center; 18 | align-self: center; 19 | z-index: 2; 20 | } 21 | 22 | .nbuttonContainer { 23 | display: flex; 24 | position: relative; 25 | top: 14%; 26 | left: -1%; 27 | padding-left: 0; 28 | margin-left: 0; 29 | 30 | 31 | } 32 | 33 | @media only screen and (min-width: 1280px) { 34 | .feed { 35 | width: 80%; 36 | } 37 | } 38 | 39 | 40 | .body { 41 | display: flex; 42 | min-width: 100%; 43 | min-height: 100%; 44 | padding-top: 350px; 45 | position: absolute; 46 | top: 0; 47 | z-index: 0; 48 | 49 | flex-direction: column; 50 | align-items: center; 51 | justify-content: center; 52 | } 53 | 54 | .switch { 55 | width: 75%; 56 | height: 200px; 57 | z-index: -1; 58 | position: absolute; 59 | top: 15.5%; 60 | caret-color: transparent!important; 61 | 62 | } 63 | 64 | .buttonLabelDiv2 { 65 | position: absolute; 66 | cursor: pointer; 67 | height: 120px; 68 | width: 200px; 69 | overflow: visible; 70 | padding: 0; 71 | top: -30px; 72 | left: 16%; 73 | filter:drop-shadow(1px 2px 5px black); 74 | } 75 | 76 | .buttonLabelDiv2 span { 77 | z-index: 7; 78 | user-select: none; 79 | position: relative; 80 | left: 32.5%; 81 | top: 40%; 82 | letter-spacing: 1px; 83 | font-size: 1.35em; 84 | font-family: 'watermelondays' 85 | } 86 | 87 | .buttonLabelDiv:hover span { 88 | -webkit-text-fill-color: rgb(0, 0, 0); /* Will override color (regardless of order) */ 89 | -webkit-text-stroke-width: 0.5px; 90 | -webkit-text-stroke-color: rgba(255, 248, 248, .5); 91 | } 92 | 93 | .buttonLabelDiv:active { 94 | filter:drop-shadow(1px 2px 5px rgb(150, 148, 148)); 95 | } 96 | 97 | .buttonLabelDiv2:hover span { 98 | -webkit-text-fill-color: rgb(0, 0, 0); /* Will override color (regardless of order) */ 99 | -webkit-text-stroke-width: 0.5px; 100 | -webkit-text-stroke-color: rgba(255, 248, 248, .5); 101 | } 102 | 103 | .buttonLabelDiv2:active { 104 | filter:drop-shadow(1px 2px 5px rgb(150, 148, 148)); 105 | } 106 | 107 | .buttonLabelDiv3 { 108 | position: absolute; 109 | cursor: pointer; 110 | height: 120px; 111 | width: 200px; 112 | overflow: visible; 113 | padding: 0; 114 | top: -30px; 115 | left: 6.5%; 116 | z-index: 10; 117 | filter:drop-shadow(1px 2px 5px black); 118 | } 119 | 120 | .buttonLabelDiv3 span { 121 | z-index: 7; 122 | user-select: none; 123 | position: relative; 124 | left: 26.5%; 125 | top: 40%; 126 | font-size: 1.3em; 127 | font-family: 'watermelondays' 128 | } 129 | 130 | .buttonLabelDiv3:hover span { 131 | -webkit-text-fill-color: rgb(0, 0, 0); /* Will override color (regardless of order) */ 132 | -webkit-text-stroke-width: 0.5px; 133 | -webkit-text-stroke-color: rgba(255, 248, 248, .5); 134 | } 135 | 136 | .buttonLabelDiv3:active { 137 | filter:drop-shadow(1px 2px 5px rgb(150, 148, 148)); 138 | } 139 | 140 | div.autorefreshoptions { 141 | position: relative; 142 | cursor: pointer; 143 | top: -40px; 144 | left: 9.3%; 145 | display: flex; 146 | flex-direction: row; 147 | border: 3px solid black; 148 | border-radius: 15px; 149 | width: 105px; 150 | justify-content: space-evenly; 151 | overflow: hidden; 152 | padding: 0px 5px; 153 | background-color: #d7d4ce; 154 | height: 35px; 155 | filter:drop-shadow(1px 2px 5px black); 156 | z-index: 99; 157 | } 158 | 159 | div.autorefreshoptions:hover { 160 | filter:drop-shadow(1px 1px 5px rgb(255, 208, 0)) 161 | } 162 | 163 | .autorefreshoptions div { 164 | border: 1px solid black; 165 | cursor: pointer; 166 | z-index: 10; 167 | cursor: pointer; 168 | } 169 | 170 | .autorefreshoptions label { 171 | cursor: pointer; 172 | } 173 | 174 | 175 | .autorefreshoptions span { 176 | font-family: 'watermelondays'; 177 | font-size: 1.3rem; 178 | } 179 | 180 | div.auto1 { 181 | display: flex; 182 | } 183 | 184 | div.auto2 { 185 | display: flex; 186 | } 187 | 188 | 189 | div.auto3 { 190 | display: flex; 191 | } 192 | 193 | input#demo { 194 | display: none; 195 | } 196 | 197 | input#demo2 { 198 | display: none; 199 | } 200 | 201 | 202 | input#demo3 { 203 | display: none; 204 | } 205 | 206 | #demo:checked ~ label { 207 | background-color: rgba(191,77,40,.9); 208 | border: 2px solid rgba(191,77,40,.9); 209 | } 210 | 211 | #demo2:checked + label { 212 | background-color: rgba(191,77,40,.9); 213 | border: 2px solid rgba(191,77,40,.9); 214 | } 215 | 216 | #demo3:checked + label { 217 | background-color: rgba(191,77,40,.9); 218 | border: 2px solid rgba(191,77,40,.9); 219 | } 220 | 221 | .auto1 span { 222 | white-space: nowrap; 223 | } 224 | 225 | 226 | .auto2 span { 227 | white-space: nowrap; 228 | } 229 | 230 | 231 | 232 | .auto3 span { 233 | white-space: nowrap; 234 | } 235 | 236 | label.a1label { 237 | border: 1px solid rgb(255, 255, 255); 238 | z-index: 88888; 239 | position: relative; 240 | bottom: 0; 241 | width: 100%; 242 | white-space: nowrap; 243 | padding: 8px; 244 | } 245 | 246 | label.a2label { 247 | border: 1px solid rgb(255, 255, 255); 248 | z-index: 88888; 249 | position: relative; 250 | bottom: 0; 251 | width: 100%; 252 | white-space: nowrap; 253 | padding: 8px; 254 | } 255 | 256 | label.a3label { 257 | border: 1px solid rgb(255, 255, 255); 258 | z-index: 88888; 259 | position: relative; 260 | bottom: 0; 261 | width: 100%; 262 | white-space: nowrap; 263 | padding: 8px 6px 8px; 264 | } 265 | 266 | .buttonLabelDiv4 { 267 | position: absolute; 268 | cursor: pointer!important; 269 | height: 120px; 270 | width: 200px; 271 | overflow: visible; 272 | padding: 0; 273 | top: -30px; 274 | right: 6.5%; 275 | z-index: 10; 276 | filter:drop-shadow(1px 2px 5px black); 277 | } 278 | 279 | .buttonLabelDiv4 span { 280 | z-index: 7; 281 | cursor: pointer!important; 282 | user-select: none; 283 | position: relative; 284 | left: 30.5%; 285 | top: 37.5%; 286 | font-size: 1.5rem; 287 | font-family: 'watermelondays' 288 | } 289 | 290 | .buttonLabelDiv4 strong { 291 | 292 | position: relative; 293 | right: 4px; 294 | z-index: 9999; 295 | font-size: 1.55rem; 296 | font-weight: normal; 297 | color: rgb(122,179,23); 298 | text-shadow: 299 | 0.08em 0 #000000, 300 | 0 0.1em #000000, 301 | -0.07em 0 #000000, 302 | 0 -0.07em #000000; 303 | filter:drop-shadow(1px 1px 2px rgb(0, 0, 0)); 304 | } 305 | 306 | .buttonLabelDiv4 strong:hover { 307 | font-size: 1.6rem; 308 | transition: all 0.1s linear; 309 | } -------------------------------------------------------------------------------- /src/assets/Sword.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/BackupModuleHandler.js: -------------------------------------------------------------------------------- 1 | import React, {useEffect, useState} from 'react'; 2 | import './Styles/ModuleHandler.css' 3 | import scrollbg from './assets/vector.png' 4 | import sword from './assets/finnsword.png' 5 | import sword2 from './assets/finnsword2.png' 6 | import delButton from './assets/deletebutton.jpg' 7 | import delButton2 from './assets/close.png' 8 | import lightBulb2 from './assets/lightbulb2.png' 9 | import exampleSlug from './assets/example.png' 10 | import refButton from './assets/refresh.png' 11 | import questionMark from './assets/question-mark.png' 12 | import loadingScreen from './assets/cool.gif' 13 | import osicon from './assets/opensea.svg' 14 | import esicon from './assets/etherscan.svg' 15 | import nerdicon from './assets/nftnerd.svg' 16 | import playButton from './assets/button.png' 17 | import { SupplyModule, SalesModule, VolumeModule, HoldersModule, HolderRatioModule, FeeModule, FloorPriceModule } from './Stats'; 18 | 19 | 20 | 21 | //this component handles the modules and their orientation within the feed. 22 | //Essentially this component is the main parent of all the modules. 23 | export function ModuleHandler ({...props}) { 24 | //usestate props that will be toggled whenever these props are passed in. Refresh/Nightmode. If props aren't passed in, then 25 | //they won't trigger anything. 26 | const [manualRefresher, toggleRefresh] = useState(props.refresh); 27 | let nightMode = props.nightMode; 28 | 29 | useEffect(() => { 30 | //handles persist 31 | const sessionSlug = localStorage.getItem("slug") 32 | //Refreshes all modules 33 | if (props.autoRefresh !== 0) { 34 | toggleRefresh(true) 35 | } 36 | toggleRefresh() 37 | if (sessionSlug) { 38 | console.log(sessionSlug) 39 | } 40 | }, [props.refresh, props.autoRefresh]) 41 | 42 | return ( 43 | <> 44 |
45 | 46 | 47 | 48 |
49 |
50 | 51 | 52 | 53 |
54 | 55 | ) 56 | } 57 | 58 | 59 | //this Module handles the process between the search and the intialization (passing the slug over) 60 | function Module (props) { 61 | const [init, setInit] = useState(false); 62 | const [slug, setSlug] = useState(''); 63 | const [defaultModule, setDefault] = useState(props.default) 64 | const [savedSession, toggleSaved] = useState(); 65 | let defaultModule2 = props.default2; 66 | let defaultModule3 = props.default3; 67 | 68 | 69 | let nightMode = props.nightMode; 70 | 71 | 72 | const initHandler = (e) => { 73 | setSlug(e); 74 | setInit(true) 75 | } 76 | 77 | const delHandler = (e) => { 78 | setSlug('') 79 | setDefault() 80 | setInit(false) 81 | } 82 | 83 | const savedChecker = (data) => { 84 | toggleSaved(true) 85 | setSlug(data) 86 | } 87 | 88 | useEffect(() => { 89 | if (savedSession) { 90 | setInit(true) 91 | } 92 | if (defaultModule === true || defaultModule2 === true || defaultModule3 === true) { 93 | setInit(true) 94 | } 95 | 96 | }, [savedSession]) 97 | 98 | if (init === false) { 99 | return ( 100 | <> 101 | 102 | 103 | ) 104 | } else { 105 | return ( 106 | <> 107 | 108 | 109 | ) 110 | } 111 | } 112 | 113 | 114 | 115 | //this component handles the loading screen animation in between the search module and the initialized module. 116 | //the loading screen is purely for entertainment, stylistic purposes since it makes the module look more robust. 117 | function LoadingScreenComp (props) { 118 | // animation/style handling here for the loading screen 119 | const [animationClass, setClass] = useState("loadingScreen1") 120 | const [loading, setLoading] = useState(true); 121 | //default Modules - these are only here to be passed into ModuleInit 122 | let defaultModule = props.default; 123 | let defaultModule2 = props.default2; 124 | let defaultModule3 = props.default3; 125 | let slug = props.slug; 126 | let delHandler = props.func; 127 | let nightMode = props.nightMode; 128 | let saved = props.saved; 129 | 130 | 131 | //set the slug for default modules here 132 | if (defaultModule === true) { 133 | slug = "proof-moonbirds" 134 | } 135 | 136 | if (defaultModule2 === true) { 137 | slug = "boredapeyachtclub" 138 | } 139 | 140 | if (defaultModule3 === true) { 141 | slug = "azuki" 142 | } 143 | 144 | 145 | 146 | //nightMode style handler 147 | const nightModeHandler = () => { 148 | if (nightMode === true) { 149 | return { 150 | backgroundColor: '#6B8074' 151 | } 152 | } else { 153 | return { 154 | backgroundColor: '#A8DBA8' 155 | } 156 | } 157 | } 158 | 159 | 160 | useEffect(() => { 161 | if (props.refresh || props.autoRefresh !== 0) { 162 | console.log("hey") 163 | setLoading(true) 164 | } 165 | 166 | setTimeout(() => { 167 | setClass("loadingScreen2") 168 | setTimeout(() => { 169 | setClass("loadingScreen3") 170 | setTimeout(() => { 171 | setClass("loadingScreen2") 172 | setTimeout(() => { 173 | setClass("loadingScreen3") 174 | setTimeout(() => { 175 | setLoading(false) 176 | }, 100); 177 | }, 200); 178 | }, 200); 179 | }, 300); 180 | }, 50); 181 | }, [props.refresh, props.autoRefresh]) 182 | 183 | 184 | // this clause will always run first before the ModuleInit is rendered because the useState of loading is set to true by default 185 | // -> Because this runs first, the useEffect will be activated afterwards to set Loading to false thus returning ModuleInit next. 186 | 187 | if (loading === true) { 188 | return ( 189 |
190 |
191 | loading screen 192 |
193 |
194 | ) 195 | } else { 196 | return ( 197 | <> 198 | 199 | 200 | ) 201 | } 202 | } 203 | 204 | 205 | 206 | 207 | 208 | //This is the search component of the module. Basically this is the pre-initialized state. 209 | function ModuleSearch (props) { 210 | const [slugInput, slugInputter] = useState(''); 211 | const [swordAnimation, setSwordAnimation] = useState(0); 212 | const [swordAnimation2, setSwordAnimation2] = useState(0); 213 | const [slugHelpStatus, toggleHelp] = useState(false); 214 | 215 | 216 | let nightMode = props.nightMode; 217 | 218 | const handleChange = (e) => { 219 | slugInputter(e.target.value) 220 | } 221 | 222 | //nightMode style handler 223 | const nightModeHandler = () => { 224 | if (nightMode === true) { 225 | return { 226 | backgroundColor: '#6B8074' 227 | } 228 | } else { 229 | return { 230 | backgroundColor: '#A8DBA8' 231 | } 232 | } 233 | } 234 | 235 | 236 | //Helper Div Stuff 237 | const slugHelperClick = () => { 238 | toggleHelp(true) 239 | } 240 | 241 | const delslugHelperClicker = () => { 242 | toggleHelp(false) 243 | } 244 | 245 | const slugHelper = () => { 246 | if (slugHelpStatus === true) { 247 | return ( 248 |
249 |
250 | 251 |

What is a slug?

252 |

The slug of an NFT project can be found at the end of their opensea collection's URL.

253 |

{"For example, in the image above, the slug for Moonbirds is: "} 'proof-moonbirds' {"(with the dash)"}

254 | {delslugHelperClicker()}} src={delButton2} className="delButton3" alt="" height="18px" width="18px" /> 255 |
256 |
257 | ) 258 | } 259 | } 260 | 261 | //style functions 262 | const rotateonClick = () => { 263 | let rotation = swordAnimation + 90; 264 | setSwordAnimation(rotation) 265 | } 266 | const rotateonClick2 = () => { 267 | let rotation = swordAnimation2 + 90; 268 | setSwordAnimation2(rotation) 269 | } 270 | 271 | const lightBulbStyleHandling = () => { 272 | if (slugHelpStatus === true) { 273 | return { 274 | bottom: "55px", 275 | opacity: '0', 276 | position: 'absolute' 277 | } 278 | } 279 | } 280 | 281 | const HelperDivStyling = () => { 282 | if (slugHelpStatus === true) { 283 | return { 284 | opacity: '0.8', 285 | transition: 'opacity 1s linear' 286 | } 287 | } 288 | } 289 | 290 | 291 | return ( 292 |
293 |
294 |
sword
298 | 299 |
300 | {slugHelper()} 301 |
302 | {slugHelperClick()}}src={lightBulb2} alt="" height="50px" width="50px" /> 303 |
304 |
305 |
306 | 307 |
308 | 309 |
310 |
311 |
312 | submit 313 | SUBMIT 314 |
315 |
316 | {props.func(slugInput)}} className="searchSubmit" type="submit" value=" " /> 317 |
318 | 319 |
320 |
321 |
dsword
325 |
326 |
327 | ) 328 | } 329 | 330 | 331 | 332 | //This is the intialized component of the module. 333 | export function ModuleInit (props) { 334 | //info variables 335 | const [slug, setSlug] = useState(props.slug) 336 | const [name, setName] = useState(); 337 | const [collectionImage, setImage] = useState(); 338 | //stats 339 | const [sales, setSales] = useState(); 340 | const [floorPrice, setFloorPrice] = useState(); 341 | const [supply, setSupply] = useState(); 342 | const [volume, setVol] = useState(); 343 | const [holders, setHolders] = useState(); 344 | const [holderRatio, setRatio] = useState(); 345 | const [royaltyFee, setFee] = useState(); 346 | //links/control variables 347 | const [opensea, setOS] = useState(); 348 | const [nftnerd, setNerd] = useState(); 349 | const [etherscan, setES] = useState(); 350 | const [refreshHelp, toggleRefHelp] = useState(false); 351 | const [savePrompt, setSavePrompt] = useState(); 352 | //style 353 | const [cnamelength, setcname] = useState('cname'); 354 | //important usestate here: basically will check if this module has been initialized 355 | const [init, toggleInit] = useState(false); 356 | 357 | 358 | //props and etc 359 | let nightMode = props.nightMode; 360 | let url = `https://api.opensea.io/api/v1/collection/${slug}` 361 | let delHandler = props.func; 362 | 363 | const nightModeHandler = () => { 364 | if (nightMode === true) { 365 | return { 366 | backgroundColor: '#6B8074' 367 | } 368 | } else { 369 | return { 370 | backgroundColor: '#A8DBA8' 371 | } 372 | } 373 | } 374 | 375 | //Manual Refresh Function 376 | 377 | const refHandler = () => { 378 | fetchCollection(url) 379 | } 380 | 381 | //Helper Div Stuff 382 | const refHelpClick = () => { 383 | toggleRefHelp(true) 384 | } 385 | 386 | const delRefHelp = () => { 387 | toggleRefHelp(false) 388 | } 389 | 390 | const refreshDiv = () => { 391 | if (refreshHelp === true) { 392 | return ( 393 |
394 | {delRefHelp()}} id="rhelpdelbutton" className="delButton2" src={delButton2} height="18px" width="18px" alt="delete button 2" /> 395 |

If nothing changes after refreshing, it usually just means that there's nothing to update or refresh regarding the stats of the collection. Try again later when you think thing's might've changed!

396 |
397 | ) 398 | } 399 | } 400 | 401 | 402 | 403 | //save stuff 404 | 405 | const handleSaver = () => { 406 | localStorage.setItem("slug", slug) 407 | setSavePrompt(); 408 | } 409 | const SavePrompt = ( 410 |
411 | Save ? 412 |
413 | ) 414 | 415 | 416 | 417 | const handleSaveClick = () => { 418 | setTimeout(() => { 419 | setSavePrompt(true) 420 | }, 1000); 421 | } 422 | 423 | 424 | 425 | //main function to fetch the data from the Opensea API, then sets the useState variables accordingly. 426 | const fetchCollection = (collectionUrl) => { 427 | const options = {method: 'GET'}; 428 | fetch(collectionUrl, options) 429 | .then(response => response.json()) 430 | .then(response => { 431 | let stats = response.collection.stats; 432 | let contract = response.collection.primary_asset_contracts[0].address; 433 | let floorPrice = stats.floor_price; 434 | let collectionName = response.collection.primary_asset_contracts[0].name; 435 | 436 | const fee = () => { 437 | const jsonFee = response.collection.primary_asset_contracts[0].seller_fee_basis_points / 100 438 | const percentageFee = jsonFee.toString() + "%" 439 | return percentageFee; 440 | } 441 | 442 | const floorPriceParser = (floorPrice) => { 443 | if (floorPrice < 1) { 444 | return Number.parseFloat(floorPrice).toFixed(3) 445 | } else { 446 | return Number.parseFloat(floorPrice).toFixed(2) 447 | } 448 | } 449 | 450 | setFloorPrice(floorPriceParser(floorPrice)) 451 | setName(response.collection.primary_asset_contracts[0].name) 452 | setImage(response.collection.image_url) 453 | setSales(stats.total_sales) 454 | setSupply(stats.total_supply) 455 | setVol(Math.round(stats.total_volume)) 456 | setHolders(stats.num_owners) 457 | setRatio((stats.total_supply/stats.num_owners).toFixed(2)) 458 | setFee(fee()) 459 | setOS(`https://opensea.io/collection/${slug}`) 460 | setNerd(`https://nftnerds.ai/collection/${contract}/liveview`) 461 | setES(`https://etherscan.io/address/${contract}`) 462 | if (collectionName.length > 18) { 463 | setcname('cname2') 464 | } else if (collectionName.length > 12) { 465 | setcname('cname1') 466 | } 467 | 468 | }) 469 | 470 | } 471 | 472 | const ModuleImg = ( 473 | 474 | ) 475 | 476 | 477 | useEffect(() => { 478 | const session = localStorage.getItem("slug") 479 | if (session) { 480 | props.saved(slug) 481 | } 482 | fetchCollection(url); 483 | }, [SavePrompt]) 484 | 485 | 486 | return ( 487 |
488 |
489 |
490 | delete button {delHandler()}} src={delButton} height="40px" width="40px" /> 491 |
492 |
493 | refresh button {refHandler()}} src={refButton} height="40px" width="40px" /> 494 |
495 |
496 | {refHelpClick()}}alt="questionMark" src={questionMark} className="question-mark" height="16px" width="16px" /> 497 |
498 | {refreshDiv()} 499 | {!savePrompt && ModuleImg} 500 | {savePrompt && SavePrompt} 501 |
502 |
503 | 504 |
505 |
506 |

{name}

507 |
508 |
509 |
510 |
511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 | ) 526 | } 527 | -------------------------------------------------------------------------------- /src/ModuleHandler.js: -------------------------------------------------------------------------------- 1 | import React, {useEffect, useState} from 'react'; 2 | import './Styles/ModuleHandler.css' 3 | import scrollbg from './assets/vector.png' 4 | import sword from './assets/finnsword.png' 5 | import sword2 from './assets/finnsword2.png' 6 | import delButton from './assets/deletebutton.jpg' 7 | import delButton2 from './assets/close.png' 8 | import lightBulb2 from './assets/lightbulb2.png' 9 | import exampleSlug from './assets/example.png' 10 | import refButton from './assets/refresh.png' 11 | import questionMark from './assets/question-mark.png' 12 | import loadingScreen from './assets/cool.gif' 13 | import osicon from './assets/opensea.svg' 14 | import esicon from './assets/etherscan.svg' 15 | import nerdicon from './assets/nftnerd.svg' 16 | import playButton from './assets/button.png' 17 | import { SupplyModule, SalesModule, VolumeModule, HoldersModule, HolderRatioModule, FeeModule, FloorPriceModule } from './Stats'; 18 | 19 | 20 | 21 | //this component handles the modules and their orientation within the feed. 22 | //Essentially this component is the main parent of all the modules. 23 | export function ModuleHandler ({...props}) { 24 | //usestate props that will be toggled whenever these props are passed in. Refresh/Nightmode. If props aren't passed in, then 25 | //they won't trigger anything. 26 | const [manualRefresher, toggleRefresh] = useState(props.refresh); 27 | let nightMode = props.nightMode; 28 | 29 | 30 | //we can make an object here that will store all the saved slugs/session 31 | //this object will store the key (the order of the module) and their saved slug 32 | let savedSlugs = {} 33 | 34 | 35 | //function here will be passed down as a prop. 36 | //this function will help save the key value pair into savedSlugs object IF saved 37 | const saveSession = (data) => { 38 | let toSave = data; 39 | savedSlugs[data[0]] = data[1]; 40 | localStorage.setItem("savedSlugs", JSON.stringify(savedSlugs)); 41 | } 42 | 43 | const savePersist = (data) => { 44 | let toSave = data; 45 | savedSlugs[data[0]] = data[1]; 46 | localStorage.setItem("savedSlugs", JSON.stringify(savedSlugs)); 47 | } 48 | 49 | const delPersist = (data) => { 50 | delete savedSlugs[data[0]]; 51 | localStorage.setItem("savedSlugs", JSON.stringify(savedSlugs)); 52 | } 53 | 54 | useEffect(() => { 55 | //Refreshes all modules 56 | if (props.autoRefresh !== 0) { 57 | toggleRefresh(true) 58 | } 59 | toggleRefresh() 60 | 61 | //checks if saved sessions exist 62 | 63 | }, [props.refresh, props.autoRefresh]) 64 | 65 | 66 | if (localStorage.getItem("savedSlugs")) { 67 | console.log(JSON.parse(localStorage.getItem("savedSlugs"))) 68 | savedSlugs = JSON.parse(localStorage.getItem("savedSlugs")) 69 | } 70 | 71 | return ( 72 | <> 73 |
74 | 75 | 76 | 77 |
78 |
79 | 80 | 81 | 82 |
83 | 84 | ) 85 | } 86 | 87 | 88 | //THIS DETERMINES WHETHER THE MODULE IS INIT OR NOT 89 | function Module (props) { 90 | const [init, setInit] = useState(false); 91 | const [slug, setSlug] = useState(''); 92 | const [slugStore, setSlugStore] = useState(props.slugStore) 93 | let nightMode = props.nightMode; 94 | let key = props.mKey; 95 | let savedSlug = [key, slug] 96 | 97 | const initHandler = (e) => { 98 | setSlug(e); 99 | setInit(true) 100 | } 101 | 102 | const delHandler = (e) => { 103 | props.delPersist(savedSlug) 104 | setSlug('') 105 | setInit(false) 106 | } 107 | 108 | 109 | 110 | 111 | 112 | useEffect(() => { 113 | if (props.slug) { 114 | setSlug(props.slug) 115 | setInit(true) 116 | } 117 | 118 | }, []) 119 | 120 | useEffect(() => { 121 | if (key in slugStore) { 122 | setSlug(slugStore[key]) 123 | setInit(true) 124 | } 125 | }, []) 126 | 127 | 128 | if (init === false) { 129 | return ( 130 | <> 131 | 132 | 133 | ) 134 | } else { 135 | return ( 136 | <> 137 | 138 | 139 | ) 140 | } 141 | } 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | //This is the search component of the module. Basically this is the pre-initialized state. 152 | function ModuleSearch (props) { 153 | const [slugInput, slugInputter] = useState(''); 154 | const [swordAnimation, setSwordAnimation] = useState(0); 155 | const [swordAnimation2, setSwordAnimation2] = useState(0); 156 | const [slugHelpStatus, toggleHelp] = useState(false); 157 | let key = props.mKey; 158 | let savedSlug = [key, slugInput]; 159 | 160 | 161 | let nightMode = props.nightMode; 162 | 163 | const handleChange = (e) => { 164 | slugInputter(e.target.value) 165 | } 166 | 167 | //nightMode style handler 168 | const nightModeHandler = () => { 169 | if (nightMode === true) { 170 | return { 171 | backgroundColor: '#6B8074' 172 | } 173 | } else { 174 | return { 175 | backgroundColor: '#A8DBA8' 176 | } 177 | } 178 | } 179 | 180 | 181 | //Helper Div Stuff 182 | const slugHelperClick = () => { 183 | toggleHelp(true) 184 | } 185 | 186 | const delslugHelperClicker = () => { 187 | toggleHelp(false) 188 | } 189 | 190 | const slugHelper = () => { 191 | if (slugHelpStatus === true) { 192 | return ( 193 |
194 |
195 | 196 |

What is a slug?

197 |

The slug of an NFT project can be found at the end of their opensea collection's URL.

198 |

{"For example, in the image above, the slug for Moonbirds is: "} 'proof-moonbirds' {"(with the dash)"}

199 | {delslugHelperClicker()}} src={delButton2} className="delButton3" alt="" height="18px" width="18px" /> 200 |
201 |
202 | ) 203 | } 204 | } 205 | 206 | //style functions 207 | const rotateonClick = () => { 208 | let rotation = swordAnimation + 90; 209 | setSwordAnimation(rotation) 210 | } 211 | const rotateonClick2 = () => { 212 | let rotation = swordAnimation2 + 90; 213 | setSwordAnimation2(rotation) 214 | } 215 | 216 | const lightBulbStyleHandling = () => { 217 | if (slugHelpStatus === true) { 218 | return { 219 | bottom: "55px", 220 | opacity: '0', 221 | position: 'absolute' 222 | } 223 | } 224 | } 225 | 226 | const HelperDivStyling = () => { 227 | if (slugHelpStatus === true) { 228 | return { 229 | opacity: '0.8', 230 | transition: 'opacity 1s linear' 231 | } 232 | } 233 | } 234 | 235 | 236 | return ( 237 |
238 |
239 |
sword
243 | 244 |
245 | {slugHelper()} 246 |
247 | {slugHelperClick()}}src={lightBulb2} alt="" height="50px" width="50px" /> 248 |
249 |
250 |
251 | 252 |
253 | 254 |
255 |
256 |
257 | submit 258 | SUBMIT 259 |
260 |
261 | {props.func(slugInput); 262 | props.savePersist(savedSlug)}} className="searchSubmit" type="submit" value=" " /> 263 |
264 | 265 |
266 |
267 |
dsword
271 |
272 |
273 | ) 274 | } 275 | 276 | 277 | 278 | //This is the intialized component of the module. 279 | export function ModuleInit (props) { 280 | //info variables 281 | const [slug, setSlug] = useState(props.slug) 282 | const [name, setName] = useState(); 283 | const [collectionImage, setImage] = useState(); 284 | //stats 285 | const [sales, setSales] = useState(); 286 | const [floorPrice, setFloorPrice] = useState(); 287 | const [supply, setSupply] = useState(); 288 | const [volume, setVol] = useState(); 289 | const [holders, setHolders] = useState(); 290 | const [holderRatio, setRatio] = useState(); 291 | const [royaltyFee, setFee] = useState(); 292 | //links/control variables 293 | const [opensea, setOS] = useState(); 294 | const [nftnerd, setNerd] = useState(); 295 | const [etherscan, setES] = useState(); 296 | const [refreshHelp, toggleRefHelp] = useState(false); 297 | const [savePrompt, setSavePrompt] = useState(); 298 | //style 299 | const [cnamelength, setcname] = useState('cname'); 300 | //important usestate here: basically will check if this module has been initialized 301 | const [init, toggleInit] = useState(false); 302 | let saveslug; 303 | 304 | //props and etc 305 | let nightMode = props.nightMode; 306 | let url = `https://api.opensea.io/api/v1/collection/${slug}` 307 | let delHandler = props.func; 308 | 309 | const nightModeHandler = () => { 310 | if (nightMode === true) { 311 | return { 312 | backgroundColor: '#6B8074' 313 | } 314 | } else { 315 | return { 316 | backgroundColor: '#A8DBA8' 317 | } 318 | } 319 | } 320 | 321 | //Manual Refresh Function 322 | 323 | const refHandler = () => { 324 | fetchCollection(url) 325 | } 326 | 327 | //Helper Div Stuff 328 | const refHelpClick = () => { 329 | toggleRefHelp(true) 330 | } 331 | 332 | const delRefHelp = () => { 333 | toggleRefHelp(false) 334 | } 335 | 336 | const refreshDiv = () => { 337 | if (refreshHelp === true) { 338 | return ( 339 |
340 | {delRefHelp()}} id="rhelpdelbutton" className="delButton2" src={delButton2} height="18px" width="18px" alt="delete button 2" /> 341 |

If nothing changes after refreshing, it usually just means that there's nothing to update or refresh regarding the stats of the collection. Try again later when you think thing's might've changed!

342 |
343 | ) 344 | } 345 | } 346 | 347 | 348 | 349 | //save stuff 350 | 351 | //this is the function for the onClick event of the button (to save) 352 | function saveSession () { 353 | saveslug = [props.mKey, slug] 354 | props.saveFunc(saveslug) 355 | setSavePrompt() 356 | } 357 | 358 | 359 | 360 | //this handles clicking on the collection image -> which then prompts the savePrompt button 361 | const handleSaveClick = () => { 362 | setTimeout(() => { 363 | setSavePrompt(true) 364 | }, 1000); 365 | } 366 | 367 | 368 | //this the button that pops up to prompt a save session 369 | const SavePrompt = ( 370 |
371 | Save ? 372 |
373 | ) 374 | 375 | 376 | //main function to fetch the data from the Opensea API, then sets the useState variables accordingly. 377 | const fetchCollection = (collectionUrl) => { 378 | const options = {method: 'GET'}; 379 | fetch(collectionUrl, options) 380 | .then(response => response.json()) 381 | .then(response => { 382 | let stats = response.collection.stats; 383 | let contract = response.collection.primary_asset_contracts[0].address; 384 | let floorPrice = stats.floor_price; 385 | let collectionName = response.collection.primary_asset_contracts[0].name; 386 | 387 | const fee = () => { 388 | const jsonFee = response.collection.primary_asset_contracts[0].seller_fee_basis_points / 100 389 | const percentageFee = jsonFee.toString() + "%" 390 | return percentageFee; 391 | } 392 | 393 | const floorPriceParser = (floorPrice) => { 394 | if (floorPrice < 1) { 395 | return Number.parseFloat(floorPrice).toFixed(3) 396 | } else { 397 | return Number.parseFloat(floorPrice).toFixed(2) 398 | } 399 | } 400 | 401 | setFloorPrice(floorPriceParser(floorPrice)) 402 | setName(response.collection.primary_asset_contracts[0].name) 403 | setImage(response.collection.image_url) 404 | setSales(stats.total_sales) 405 | setSupply(stats.total_supply) 406 | setVol(Math.round(stats.total_volume)) 407 | setHolders(stats.num_owners) 408 | setRatio((stats.total_supply/stats.num_owners).toFixed(2)) 409 | setFee(fee()) 410 | setOS(`https://opensea.io/collection/${slug}`) 411 | setNerd(`https://nftnerds.ai/collection/${contract}/liveview`) 412 | setES(`https://etherscan.io/address/${contract}`) 413 | if (collectionName.length > 18) { 414 | setcname('cname2') 415 | } else if (collectionName.length > 12) { 416 | setcname('cname1') 417 | } 418 | 419 | }) 420 | 421 | } 422 | 423 | const ModuleImg = ( 424 | 425 | ) 426 | 427 | 428 | useEffect(() => { 429 | 430 | fetchCollection(url); 431 | }, []) 432 | 433 | 434 | return ( 435 |
436 |
437 |
438 | delete button {delHandler()}} src={delButton} height="40px" width="40px" /> 439 |
440 |
441 | refresh button {refHandler()}} src={refButton} height="40px" width="40px" /> 442 |
443 |
444 | {refHelpClick()}}alt="questionMark" src={questionMark} className="question-mark" height="16px" width="16px" /> 445 |
446 | {refreshDiv()} 447 | {!savePrompt && ModuleImg} 448 | {savePrompt && SavePrompt} 449 |
450 |
451 | 452 |
453 |
454 |

{name}

455 |
456 |
457 |
458 |
459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 | ) 474 | } 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | //this component handles the loading screen animation in between the search module and the initialized module. 487 | //the loading screen is purely for entertainment, stylistic purposes since it makes the module look more robust. 488 | function LoadingScreenComp (props) { 489 | // animation/style handling here for the loading screen 490 | const [animationClass, setClass] = useState("loadingScreen1") 491 | const [loading, setLoading] = useState(true); 492 | 493 | 494 | useEffect(() => { 495 | if (props.refresh || props.autoRefresh !== 0) { 496 | setLoading(true) 497 | } 498 | 499 | setTimeout(() => { 500 | setClass("loadingScreen2") 501 | setTimeout(() => { 502 | setClass("loadingScreen3") 503 | setTimeout(() => { 504 | setClass("loadingScreen2") 505 | setTimeout(() => { 506 | setClass("loadingScreen3") 507 | setTimeout(() => { 508 | setLoading(false) 509 | }, 100); 510 | }, 200); 511 | }, 200); 512 | }, 300); 513 | }, 50); 514 | }, []) 515 | 516 | 517 | // this clause will always run first before the ModuleInit is rendered because the useState of loading is set to true by default 518 | // -> Because this runs first, the useEffect will be activated afterwards to set Loading to false thus returning ModuleInit next. 519 | 520 | return ( 521 |
522 |
523 | loading screen 524 |
525 |
526 | ) 527 | } -------------------------------------------------------------------------------- /src/Styles/ModuleHandler.css: -------------------------------------------------------------------------------- 1 | .row { 2 | display: flex; 3 | flex-direction: row; 4 | width: 95%; 5 | margin-top: 10px; 6 | justify-content: space-evenly; 7 | } 8 | 9 | 10 | @media only screen and (max-width: 1280px) { 11 | .module { 12 | width: 500px; 13 | margin-left: 10px; 14 | margin-right: 10px; 15 | } 16 | 17 | .scroll { 18 | max-width: 310px; 19 | height: 90px; 20 | } 21 | 22 | 23 | .bigPlayButtonTrue { 24 | left: -48.5px; 25 | transition: height .2s linear; 26 | transition: width .1s linear; 27 | } 28 | 29 | .bigPlayButtonFalse { 30 | left: -48.5px; 31 | transition: height .05s linear; 32 | transition: width .05s linear; 33 | } 34 | 35 | 36 | 37 | .stats-info { 38 | white-space: nowrap; 39 | } 40 | 41 | .bigstat { 42 | position: absolute; 43 | left: 6px; 44 | transition: left .05s linear; 45 | } 46 | 47 | .stats-left:hover > .bigstat { 48 | left: 6.3px; 49 | position: absolute; 50 | transition: left .05s linear; 51 | } 52 | 53 | 54 | .stats-right { 55 | max-width: 70%; 56 | } 57 | 58 | .stats-left { 59 | min-width: 20%; 60 | max-width: 30%; 61 | } 62 | 63 | .stats { 64 | gap: 0px; 65 | max-width: 80%; 66 | margin: 0; 67 | justify-content: center; 68 | padding: 0; 69 | } 70 | } 71 | 72 | 73 | 74 | .module { 75 | border: 4px solid rgb(0, 0, 0); 76 | width: 400px; 77 | height: 810px; 78 | background-color: #A8DBA8; 79 | border-radius: 20px; 80 | caret-color: transparent!important; 81 | display: flex; 82 | justify-content: center; 83 | filter:drop-shadow(1px 5px 10px black) ; 84 | align-items: center; 85 | flex-direction: column; 86 | box-shadow: inset 0 2px 5px 1px #807e7e; 87 | } 88 | 89 | .module:hover { 90 | filter:drop-shadow(1px 5px 10px rgba(199, 186, 2, .5)); 91 | transition: all 0.1s ease-in-out; 92 | z-index: 8888; 93 | } 94 | 95 | 96 | .mainModuleSearchDiv { 97 | display: flex; 98 | flex-direction: column; 99 | align-items: center; 100 | width: 100%; 101 | justify-content: space-between; 102 | height: 80%; 103 | cursor: pointer; 104 | } 105 | 106 | .swordImg:hover { 107 | filter:drop-shadow(1px 5px 25px rgb(255, 208, 0)); 108 | transition: filter 0.1s linear; 109 | } 110 | 111 | .swordFlipped:hover { 112 | filter:drop-shadow(1px 5px 25px rgb(255, 208, 0)); 113 | transition: filter 0.1s linear; 114 | } 115 | 116 | .scrollcontainer2:hover .scroll2 { 117 | filter:drop-shadow(1px 5px 20px rgb(255, 208, 0)); 118 | transition: filter 0.1s linear; 119 | } 120 | 121 | .searchInputContainer:hover .scroll2 { 122 | filter:drop-shadow(1px 5px 20px rgb(255, 208, 0)); 123 | transition: filter 0.1s linear; 124 | } 125 | 126 | .searchInputContainer:hover .search { 127 | caret-color: black; 128 | } 129 | 130 | .searchDiv { 131 | display: flex; 132 | flex-direction: column; 133 | align-items: center; 134 | width: 100%; 135 | cursor: pointer 136 | ; 137 | } 138 | 139 | 140 | .searchInputContainer { 141 | height: auto; 142 | position: relative; 143 | width: 50%; 144 | z-index: 3; 145 | margin-bottom: 10px; 146 | display: flex; 147 | flex-direction: column; 148 | align-items: center; 149 | user-select: none; 150 | caret-color: darkslategrey!important; 151 | } 152 | 153 | .searchInputContainer input { 154 | width: 100%; 155 | position: relative; 156 | user-select: none; 157 | height: 50px; 158 | text-align: center; 159 | background-color: transparent; 160 | z-index: 3; 161 | outline: none; 162 | border: none; 163 | font-family: 'watermelondays'; 164 | font-size: 1.3rem; 165 | color: darkslategrey; 166 | text-decoration: underline; 167 | } 168 | 169 | .searchSubmitContainer { 170 | z-index: 3; 171 | margin: 0; 172 | position: relative; 173 | display: flex; 174 | flex-direction: column; 175 | align-items: center; 176 | width: 57.5%; 177 | height: auto; 178 | } 179 | 180 | .searchButtonDiv { 181 | z-index: 3; 182 | cursor: pointer; 183 | position: absolute; 184 | top: 32.5px; 185 | display: flex; 186 | flex-direction: column; 187 | align-items: center; 188 | width: 98%; 189 | } 190 | 191 | .searchSubmitContainer input { 192 | cursor: pointer; 193 | position: relative; 194 | background-color: transparent; 195 | width: 100%; 196 | border: none; 197 | font-family: 'candy_beansregular'; 198 | padding: 5px; 199 | height: 32.5px; 200 | } 201 | 202 | 203 | .searchSubmitContainer span { 204 | position: absolute; 205 | bottom: 35%; 206 | -webkit-text-stroke: 0.5px; 207 | font-size: 1.3rem; 208 | padding-bottom: 2.5px; 209 | font-family: 'watermelondays'; 210 | color: #0B486B; 211 | -webkit-text-stroke-color: rgb(213,195,149); 212 | } 213 | 214 | 215 | .searchSubmitContainer:hover span { 216 | text-decoration: underline; 217 | text-decoration-color: black; 218 | } 219 | 220 | .searchSubmitContainer:hover img { 221 | width: 315px; 222 | transition: width 0.05s linear; 223 | } 224 | 225 | .info { 226 | display: flex; 227 | position: relative; 228 | 229 | flex-direction: column; 230 | align-items: center; 231 | align-content: flex-start; 232 | border-bottom: 2px solid #000000; 233 | width: 100%; 234 | padding: 10px 0 25px; 235 | overflow: hidden; 236 | height: 42.5%; 237 | } 238 | 239 | .bottom { 240 | height: 71.5%; 241 | width: 100%; 242 | margin-left: auto; 243 | margin-right: auto; 244 | padding: 15px 0; 245 | line-height: 1px; 246 | align-items: center; 247 | display: flex; 248 | overflow: hidden; 249 | flex-direction: column; 250 | 251 | } 252 | 253 | 254 | .ImageDiv { 255 | height: 132px; 256 | width: 132px; 257 | margin-top: 15px; 258 | margin-bottom: 15px; 259 | 260 | } 261 | 262 | 263 | .start-btn{ 264 | text-align: center; 265 | display: inline-block; 266 | margin:5px; 267 | user-select: none; 268 | letter-spacing: 1px; 269 | font-size: 1.2rem; 270 | font-family: 'watermelondays'; 271 | padding: 10px 10px 10px 10px ; 272 | background-color: rgb(211, 211, 211); 273 | text-shadow: -1px -1px rgb(255, 255, 255), 1px 1px white; 274 | color: rgb(0, 0, 0); 275 | -webkit-border-radius: 7px; 276 | -moz-border-radius: 7px; 277 | -o-border-radius: 7px; 278 | border-radius: 7px; 279 | box-shadow: 0 .2em gray; 280 | cursor: pointer; 281 | width: 100px; 282 | position: relative; 283 | border: 2px solid rgb(119, 117, 117); 284 | top: 57px; 285 | } 286 | 287 | .start-btn:active { 288 | box-shadow: 0 .0em gray; 289 | top: 60px; 290 | } 291 | 292 | .moduleImg { 293 | border: 1px solid black; 294 | user-select: none!important; 295 | padding: 5px; 296 | cursor: pointer; 297 | margin-top: 15px; 298 | margin-bottom: 15px; 299 | background-color: grey; 300 | filter:drop-shadow(1px 5px 12px rgb(0, 0, 0)); 301 | } 302 | 303 | .moduleImg:hover { 304 | filter:drop-shadow(1px 5px 15px rgb(255, 208, 0)) 305 | drop-shadow(-1px -1px 0 rgb(121,189,154)); 306 | } 307 | 308 | 309 | .stats { 310 | display: flex; 311 | flex-direction: row; 312 | align-items: center; 313 | width: 90%; 314 | height: 20%; 315 | gap: 100px; 316 | margin-left: 3px; 317 | margin-top: 5px; 318 | margin-bottom: 5px; 319 | padding: 0 10px 5px; 320 | border-bottom: 1px DOTTED rgba(0, 0, 0, .5); 321 | position: relative; 322 | } 323 | 324 | .stats:hover { 325 | border-bottom: 2px DOTTED rgb(255, 255, 255); 326 | } 327 | 328 | .nameContainer { 329 | width: 100%; 330 | height: 100px; 331 | display: flex; 332 | cursor: pointer; 333 | justify-content: center; 334 | align-items: center; 335 | } 336 | 337 | .scrollcontainer { 338 | user-select: none; 339 | position: absolute; 340 | cursor: pointer; 341 | } 342 | 343 | .scroll { 344 | filter:drop-shadow(1px 5px 10px black) ; 345 | width: 375px; 346 | user-select: none; 347 | cursor: pointer; 348 | height: 110px; 349 | transition: filter 0.2s ease-out; 350 | } 351 | 352 | .scrollcontainer2 { 353 | position: absolute; 354 | z-index: 1; 355 | cursor: pointer; 356 | bottom: -25px; 357 | } 358 | 359 | .scroll2 { 360 | width: 300px; 361 | height: 100px; 362 | filter:drop-shadow(1px 5px 10px black); 363 | } 364 | 365 | .submitPlayButtonDiv { 366 | position: absolute; 367 | z-index: 1; 368 | bottom: -50x; 369 | cursor: pointer; 370 | display: flex; 371 | justify-content: center; 372 | } 373 | 374 | .submitPlayButton { 375 | width: 300px; 376 | height: 100px; 377 | filter:drop-shadow(1px 2px 1px black) ; 378 | } 379 | 380 | .nameContainer:hover .scroll { 381 | filter:drop-shadow(1px 5px 20px rgb(255, 208, 0)); 382 | transition: filter 0.1s linear; 383 | } 384 | 385 | .nameContainer:hover .cname { 386 | font-size: 2.7rem; 387 | -webkit-text-stroke-color: rgba(255, 255, 255, 0.7); 388 | transition: font-size .2s ease-in; 389 | transition: -webkit-text-stroke-color .1s linear; 390 | } 391 | 392 | 393 | .nameContainer:hover .cname1 { 394 | font-size: 2.2rem; 395 | -webkit-text-stroke-color: rgba(255, 255, 255, 0.7); 396 | transition: font-size .2s ease-in; 397 | transition: -webkit-text-stroke-color .1s linear; 398 | } 399 | 400 | .nameContainer:hover .cname2 { 401 | font-size: 1.85rem; 402 | -webkit-text-stroke-color: rgba(255, 255, 255, 0.7); 403 | transition: font-size .2s ease-in; 404 | transition: -webkit-text-stroke-color .1s linear; 405 | } 406 | 407 | 408 | 409 | .cname { 410 | white-space: nowrap; 411 | text-align: center; 412 | font-family:'watermelondays'; 413 | user-select: text; 414 | padding: 15px 0 0; 415 | font-size: 2.6rem; 416 | color: rgb(0, 0, 0); 417 | letter-spacing: 1.6px; 418 | -webkit-text-stroke-width: 0.1px; 419 | -webkit-text-stroke-color: rgba(255, 255, 255, .7); 420 | } 421 | 422 | .cname1 { 423 | white-space: nowrap; 424 | text-align: center; 425 | font-family:'watermelondays'; 426 | padding: 15px 0 0; 427 | font-size: 2rem; 428 | color: rgb(0, 0, 0); 429 | letter-spacing: 1.6px; 430 | -webkit-text-stroke-width: 0.1px; 431 | -webkit-text-stroke-color: rgba(255, 255, 255, .7); 432 | } 433 | 434 | 435 | .cname2 { 436 | white-space: nowrap; 437 | text-align: center; 438 | font-family:'watermelondays'; 439 | padding: 15px 0 0; 440 | font-size: 1.7rem; 441 | color: rgb(0, 0, 0); 442 | letter-spacing: 1.6px; 443 | -webkit-text-stroke-width: 0.1px; 444 | -webkit-text-stroke-color: rgba(255, 255, 255, .7); 445 | } 446 | 447 | 448 | .name { 449 | z-index: 100; 450 | width: 50%; 451 | display: flex; 452 | padding-bottom: 5px; 453 | margin-bottom: 10px; 454 | justify-content: center; 455 | } 456 | 457 | .stats-info { 458 | font-family: 'candy_beansregular'; 459 | user-select: none; 460 | cursor: pointer; 461 | font-size: 1.125rem; 462 | z-index: 200; 463 | -webkit-text-stroke: 1px; 464 | position: relative; 465 | color: #0B486B; 466 | -webkit-text-stroke-color: rgb(213,195,149); 467 | } 468 | 469 | .swordDiv { 470 | margin: 15px 0; 471 | } 472 | 473 | .swordImg { 474 | user-select: none; 475 | filter:drop-shadow(1px 5px 10px black); 476 | transition: filter 0.1s linear; 477 | 478 | } 479 | 480 | .swordFlipped { 481 | transform: scaleX(-1); 482 | transition: filter 0.1s linear; 483 | filter:drop-shadow(1px 5px 10px black); 484 | } 485 | 486 | 487 | .stats-left { 488 | 489 | width: 60%; 490 | height: 100%; 491 | display: flex; 492 | align-items: center; 493 | justify-content: center; 494 | } 495 | 496 | .stats-right { 497 | width: 70%; 498 | justify-content: center; 499 | position: relative; 500 | height: 100%; 501 | display: flex; 502 | align-items: center; 503 | } 504 | 505 | .controls { 506 | display: flex; 507 | cursor: default; 508 | 509 | flex-direction: row; 510 | box-shadow: 0px 2px 7px 0px rgba(0,0,0,.5); 511 | align-items: center; 512 | width: 90%; 513 | height: 15%; 514 | justify-content: space-evenly; 515 | margin-left: 3px; 516 | margin-top: 5px; 517 | margin-bottom: 5px; 518 | padding: 5px 3px 5px; 519 | border-radius: 5px; 520 | border: 2px solid rgba(0, 0, 0, 0.5); 521 | background-color: rgba(205,215,182, 1); 522 | } 523 | 524 | .osdiv, .esdiv { 525 | border: 1px solid rgba(0, 0, 0, 0.2); 526 | border-radius: 50%; 527 | filter:drop-shadow(1px 2px 1px rgba(0, 0, 0, .3)); 528 | cursor: pointer; 529 | } 530 | 531 | .nerddiv { 532 | filter:drop-shadow(1px 2px 1px rgba(0, 0, 0, .3)); 533 | display: flex; 534 | align-items: center; 535 | flex-direction: column; 536 | border: 1px solid rgba(0, 0, 0, 0.1); 537 | border-radius: 50%; 538 | height: 25px; 539 | width: 25px; 540 | background-color: rgba(85, 85, 84, 0.2); 541 | cursor: pointer; 542 | } 543 | 544 | .osdiv:hover, .esdiv:hover, .nerddiv:hover { 545 | border: 1px solid rgba(0, 0, 0, 1); 546 | } 547 | 548 | #bigVal { 549 | padding-left: 5px; 550 | white-space: nowrap; 551 | } 552 | 553 | 554 | .stats-val { 555 | z-index: 100; 556 | cursor: pointer; 557 | font-size: 1.3rem; 558 | font-family: 'candy_beansregular'; 559 | letter-spacing: 2px; 560 | -webkit-text-stroke: 1px; 561 | color: rgba(0, 0, 0, 0.67); 562 | transition: font-size 0.1s linear; 563 | -webkit-text-fill-color: rgb(219, 132, 212); 564 | } 565 | 566 | .bigPlayButtonTrue { 567 | width: 210px; 568 | height: 90px; 569 | padding-top: 2px; 570 | user-select: none; 571 | position: absolute; 572 | transition: height .2s linear; 573 | transition: width .1s linear; 574 | cursor:pointer; 575 | filter:drop-shadow(1px 2px 1px black); 576 | } 577 | 578 | .bigPlayButtonFalse { 579 | user-select: none; 580 | width: 200px; 581 | height: 70px; 582 | padding-top: 2px; 583 | cursor:pointer; 584 | position: absolute; 585 | transition: height .05s linear; 586 | transition: width .05s linear; 587 | filter:drop-shadow(1px 2px 1px black); 588 | } 589 | 590 | .playButtonHoverFalse { 591 | width: 120px; 592 | height: 70px; 593 | user-select: none; 594 | cursor:pointer; 595 | padding-top: 2px; 596 | position: absolute; 597 | transition: heigh width 2s; 598 | filter:drop-shadow(1px 2px 1px black); 599 | 600 | } 601 | 602 | .playButtonHoverTrue { 603 | width: 150px; 604 | height: 90px; 605 | padding-top: 2px; 606 | user-select: none; 607 | cursor:pointer; 608 | position: absolute; 609 | transition: height .2s linear; 610 | transition: width .1s linear; 611 | filter:drop-shadow(1px 2px 1px black); 612 | 613 | } 614 | 615 | 616 | .bmo { 617 | border: 2px solid rgba(0, 0, 0, .3); 618 | border-radius: 2px; 619 | position: absolute; 620 | top: -6px; 621 | cursor: pointer; 622 | filter:drop-shadow(1px 2px 3px rgba(216, 211, 211,.3)) 623 | drop-shadow(-1px -1px 0 rgba(228, 228, 228, .3)); 624 | } 625 | 626 | .bmo:hover { 627 | border: 2px solid rgba(255, 255, 255, .1); 628 | transform: scale(1.05); 629 | transition: transform 0.1s linear; 630 | filter:drop-shadow(1px 2px 5px rgba(216, 211, 211,.3)); 631 | } 632 | 633 | .stats:hover .stats-val { 634 | font-size: 1.6rem; 635 | transition: font-size 0.1s linear; 636 | } 637 | 638 | #floorprice { 639 | display: flex; 640 | flex-direction: row; 641 | align-items: center; 642 | gap: 2px; 643 | } 644 | 645 | .eth { 646 | color: #1f1d1d; 647 | filter:drop-shadow(1px 1px 3px rgb(167, 170, 7)) ; 648 | } 649 | 650 | .loadingScreen1 { 651 | opacity: 0.1; 652 | transition: opacity 0.5s ease-in; 653 | } 654 | 655 | .loadingScreen2 { 656 | opacity: 1; 657 | transition: opacity 0.5s ease-in; 658 | } 659 | 660 | .loadingScreen3 { 661 | opacity: 0.05; 662 | transition: opacity 0.3s ease-out; 663 | } 664 | 665 | .refreshButtonDiv { 666 | user-select: none!important; 667 | position: absolute; 668 | cursor: pointer; 669 | right: 10%; 670 | top: 9%; 671 | filter:drop-shadow(1px 1px 2px rgb(0, 0, 0)) 672 | drop-shadow(-1px -1px 0 rgba(228, 228, 228, .3)); 673 | } 674 | 675 | .refreshButtonDiv img { 676 | filter: grayscale(80%); 677 | -webkit-transition: all 0.5s linear; 678 | -moz-transition: all 0.5s linear; 679 | -o-transition: all 0.5s linear; 680 | -ms-transition: all 0.5s linear; 681 | transition: all 0.5s linear; 682 | } 683 | 684 | .refreshButtonDiv:hover > img { 685 | filter: grayscale(0%); 686 | transform: rotate(-170deg); 687 | } 688 | 689 | .deleteButtonDiv { 690 | user-select: none!important; 691 | position: absolute; 692 | cursor: pointer; 693 | left: 27.5px; 694 | top: 30px; 695 | filter:drop-shadow(1px 1px 5px rgb(0, 0, 0)) 696 | drop-shadow(-1px -1px 0 rgba(228, 228, 228, .3)); 697 | } 698 | 699 | .deleteButtonDiv img { 700 | filter: grayscale(80%); 701 | -webkit-transition: all 0.2s linear; 702 | -moz-transition: all 0.2s linear; 703 | -o-transition: all 0.2s linear; 704 | -ms-transition: all 0.2s linear; 705 | transition: all 0.2s linear; 706 | } 707 | 708 | .deleteButtonDiv:hover > img { 709 | filter: grayscale(0%); 710 | transform: rotate(-10deg); 711 | 712 | } 713 | 714 | .questionMarkDiv { 715 | position: absolute; 716 | right: 5%; 717 | top: 5%; 718 | cursor: pointer; 719 | } 720 | 721 | .questionMarkDiv img { 722 | filter: grayscale(80%); 723 | } 724 | 725 | .questionMarkDiv:hover img { 726 | filter: grayscale(0%); 727 | } 728 | 729 | .refreshHelpDiv { 730 | position: absolute; 731 | z-index: 8000; 732 | height: 100px; 733 | width: 300px; 734 | background-color: rgba(255, 255, 255, .7); 735 | border: 3px solid black; 736 | border-radius: 10px; 737 | font-family: 'watermelondays'; 738 | cursor: pointer; 739 | text-align: center; 740 | left: 50px; 741 | line-height: 20px; 742 | padding: 20px; 743 | } 744 | 745 | .refreshHelpContent { 746 | position: absolute; 747 | top: 10px; 748 | right: 0; 749 | font-size: 1.2rem; 750 | text-shadow: 751 | 0.07em 0 #a2c505, 752 | 0 0.07em #a2c505, 753 | -0.07em 0 #a2c505, 754 | 0 -0.07em #a2c505; 755 | color: black; 756 | } 757 | 758 | img.delButton2 { 759 | position: absolute; 760 | top: 1%; 761 | right: 1%; 762 | filter: grayscale(100%); 763 | padding: 2px; 764 | border: 2px solid black; 765 | border-radius: 16px; 766 | background-color: wheat; 767 | } 768 | 769 | .delButton2:hover { 770 | filter: grayscale(0); 771 | } 772 | 773 | .lightBulbDiv { 774 | position: relative; 775 | z-index: 5555; 776 | } 777 | 778 | .lightBulbDiv img { 779 | position: relative; 780 | bottom: 125px; 781 | opacity: 30%; 782 | filter:drop-shadow(1px 5px 10px black) ; 783 | transition: all 0.15s ease-out; 784 | 785 | } 786 | 787 | .lightBulbDiv img:hover { 788 | filter:drop-shadow(1px 5px 25px rgb(255, 208, 0)) ; 789 | transition: all 0.1s ease-in; 790 | transform: rotate(10deg); 791 | opacity: 80%; 792 | } 793 | 794 | div.slugHelperDiv { 795 | position: relative; 796 | bottom: 12%; 797 | background-color: wheat; 798 | max-width: 300px; 799 | right: 0%; 800 | padding: 20px 15px 0; 801 | border: 2px solid black; 802 | border-radius: 15px; 803 | display: flex; 804 | flex-direction: column; 805 | align-items: center; 806 | justify-content: center; 807 | z-index: 7777; 808 | opacity: 0; 809 | filter:drop-shadow(1px 5px 10px black) ; 810 | transition: all 0.5s ease-out; 811 | } 812 | 813 | .slugHelperDiv:hover { 814 | filter:drop-shadow(1px 5px 15px rgb(85, 77, 1)); 815 | 816 | } 817 | 818 | .slugHelperDiv p:hover { 819 | filter:drop-shadow(1px 5px 12px rgb(0, 0, 0)) ; 820 | font-size: 1.05rem; 821 | transition: all 0.1s linear; 822 | } 823 | 824 | 825 | .slugHelperContent { 826 | padding-top: 25px; 827 | margin-top: 10px; 828 | } 829 | 830 | img.exampleSlug { 831 | filter:drop-shadow(1px 5px 10px black) ; 832 | border: 2px solid black; 833 | border-radius: 10px; 834 | transform: scale(1); 835 | 836 | } 837 | 838 | img.exampleSlug:hover { 839 | transform: scale(1.05); 840 | transition: all 0.2s linear; 841 | } 842 | 843 | .slugHelperContent strong { 844 | font-weight: 550; 845 | text-decoration: underline; 846 | } 847 | 848 | .slugHelperContent p { 849 | text-align: center; 850 | text-shadow: 851 | 0.07em 0 #a2c505, 852 | 0 0.07em #a2c505, 853 | -0.07em 0 #a2c505, 854 | 0 -0.07em #a2c505; 855 | line-height: 22px; 856 | filter:drop-shadow(1px 5px 8px rgb(0, 0, 0)) ; 857 | font-family: 'watermelondays'; 858 | } 859 | 860 | img.delButton3 { 861 | border: none; 862 | filter: grayscale(50%); 863 | z-index: 5555; 864 | top: 5%; 865 | right: 45%; 866 | position: absolute; 867 | } 868 | 869 | img.delButton3:hover { 870 | filter: grayscale(0%); 871 | filter:drop-shadow(1px 5px 10px black) ; 872 | } 873 | 874 | -------------------------------------------------------------------------------- /src/assets/vector.svg: -------------------------------------------------------------------------------- 1 | --------------------------------------------------------------------------------