├── .eslintrc.json ├── public ├── favicon.ico └── vercel.svg ├── postcss.config.js ├── .idea ├── .gitignore ├── vcs.xml ├── prettier.xml ├── discord.xml ├── inspectionProfiles │ └── Project_Default.xml ├── modules.xml └── server-count.iml ├── next.config.js ├── pages ├── _app.js ├── api │ ├── login.js │ └── cb.js ├── cb.jsx ├── Components │ └── Footer.jsx └── index.js ├── README.md ├── tailwind.config.js ├── styles ├── globals.css └── Home.module.css ├── .gitignore └── package.json /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flowergardn/server-counter/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | } 5 | 6 | module.exports = nextConfig 7 | -------------------------------------------------------------------------------- /pages/_app.js: -------------------------------------------------------------------------------- 1 | import '../styles/globals.css' 2 | 3 | function MyApp({ Component, pageProps }) { 4 | return 5 | } 6 | 7 | export default MyApp 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # server-count 2 | 3 | My friend was trying to come up with a way to get the count of all your servers on Discord, so i decided to just ease his process to make 100x easier :) 4 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/prettier.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | content: [ 3 | "./pages/**/*.{js,ts,jsx,tsx}", 4 | "./components/**/*.{js,ts,jsx,tsx}", 5 | ], 6 | theme: { 7 | extend: {}, 8 | }, 9 | plugins: [], 10 | } 11 | -------------------------------------------------------------------------------- /.idea/discord.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /pages/api/login.js: -------------------------------------------------------------------------------- 1 | export default async function handler(req, res) { 2 | res.redirect( 3 | "https://discord.com/api/oauth2/authorize?client_id=969790016496746516&redirect_uri=https%3A%2F%2Fserver-counter.vercel.app%2Fcb&response_type=token&scope=identify%20guilds" 4 | ); 5 | } 6 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /pages/cb.jsx: -------------------------------------------------------------------------------- 1 | import { useRouter } from 'next/router' 2 | import { useEffect } from 'react' 3 | 4 | export default function Callback() { 5 | const router = useRouter() 6 | 7 | useEffect(() => { 8 | const querySplit = router.asPath.split('&') 9 | const access_token = querySplit[1].split('=')[1] 10 | window.location.href = `/api/cb?token=${access_token}` 11 | }, []) 12 | 13 | return <> 14 | } 15 | -------------------------------------------------------------------------------- /styles/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | html, 6 | body { 7 | padding: 0; 8 | margin: 0; 9 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 10 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 11 | background-color: #0F172A; 12 | } 13 | 14 | a { 15 | color: inherit; 16 | text-decoration: none; 17 | } 18 | 19 | * { 20 | box-sizing: border-box; 21 | } 22 | -------------------------------------------------------------------------------- /.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 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | .pnpm-debug.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | -------------------------------------------------------------------------------- /.idea/server-count.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /pages/api/cb.js: -------------------------------------------------------------------------------- 1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction 2 | 3 | import axios from 'axios' 4 | import { serialize } from 'cookie' 5 | 6 | export default async function handler(req, res) { 7 | const { token: discordToken } = req.query 8 | 9 | // If no token was passed through, send a 400 status code 10 | if (!discordToken) 11 | res.status(400).json({ success: false, err: `Malformed token` }) 12 | 13 | res.setHeader( 14 | 'Set-Cookie', 15 | serialize('token', discordToken, { path: '/', maxAge: 60 * 60 * 24 * 7 }) 16 | ) 17 | 18 | res.redirect('/') 19 | } 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "server-count", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "axios": "^0.27.2", 13 | "cookie": "^0.5.0", 14 | "js-cookie": "^3.0.1", 15 | "next": "12.1.5", 16 | "react": "18.1.0", 17 | "react-dom": "18.1.0" 18 | }, 19 | "devDependencies": { 20 | "autoprefixer": "^10.4.5", 21 | "eslint": "8.14.0", 22 | "eslint-config-next": "12.1.5", 23 | "postcss": "^8.4.13", 24 | "prettier": "^2.6.2", 25 | "tailwindcss": "^3.0.24" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /pages/Components/Footer.jsx: -------------------------------------------------------------------------------- 1 | export default function Footer() { 2 | return ( 3 | 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /styles/Home.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | padding: 0 2rem; 3 | } 4 | 5 | .main { 6 | min-height: 100vh; 7 | padding: 4rem 0; 8 | flex: 1; 9 | display: flex; 10 | flex-direction: column; 11 | justify-content: center; 12 | align-items: center; 13 | } 14 | 15 | .footer { 16 | display: flex; 17 | flex: 1; 18 | padding: 2rem 0; 19 | border-top: 1px solid #eaeaea; 20 | justify-content: center; 21 | align-items: center; 22 | } 23 | 24 | .footer a { 25 | display: flex; 26 | justify-content: center; 27 | align-items: center; 28 | flex-grow: 1; 29 | } 30 | 31 | .title a { 32 | color: #0070f3; 33 | text-decoration: none; 34 | } 35 | 36 | .title a:hover, 37 | .title a:focus, 38 | .title a:active { 39 | text-decoration: underline; 40 | } 41 | 42 | .title { 43 | margin: 0; 44 | line-height: 1.15; 45 | font-size: 4rem; 46 | } 47 | 48 | .title, 49 | .description { 50 | text-align: center; 51 | } 52 | 53 | .description { 54 | margin: 4rem 0; 55 | line-height: 1.5; 56 | font-size: 1.5rem; 57 | } 58 | 59 | .code { 60 | background: #fafafa; 61 | border-radius: 5px; 62 | padding: 0.75rem; 63 | font-size: 1.1rem; 64 | font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, 65 | Bitstream Vera Sans Mono, Courier New, monospace; 66 | } 67 | 68 | .grid { 69 | display: flex; 70 | align-items: center; 71 | justify-content: center; 72 | flex-wrap: wrap; 73 | max-width: 800px; 74 | } 75 | 76 | .card { 77 | margin: 1rem; 78 | padding: 1.5rem; 79 | text-align: left; 80 | color: inherit; 81 | text-decoration: none; 82 | border: 1px solid #eaeaea; 83 | border-radius: 10px; 84 | transition: color 0.15s ease, border-color 0.15s ease; 85 | max-width: 300px; 86 | } 87 | 88 | .card:hover, 89 | .card:focus, 90 | .card:active { 91 | color: #0070f3; 92 | border-color: #0070f3; 93 | } 94 | 95 | .card h2 { 96 | margin: 0 0 1rem 0; 97 | font-size: 1.5rem; 98 | } 99 | 100 | .card p { 101 | margin: 0; 102 | font-size: 1.25rem; 103 | line-height: 1.5; 104 | } 105 | 106 | .logo { 107 | height: 1em; 108 | margin-left: 0.5rem; 109 | } 110 | 111 | @media (max-width: 600px) { 112 | .grid { 113 | width: 100%; 114 | flex-direction: column; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /pages/index.js: -------------------------------------------------------------------------------- 1 | import Cookies from "js-cookie"; 2 | import { useEffect, useState } from "react"; 3 | import axios from "axios"; 4 | import Head from "next/head"; 5 | import Footer from "./Components/Footer"; 6 | 7 | export default function Home() { 8 | const [token, setToken] = useState(""); 9 | const [servers, setServers] = useState([]); 10 | 11 | useEffect(() => { 12 | const _token = Cookies.get("token"); 13 | if (_token && _token.length > 5) { 14 | setToken(Cookies.get("token")); 15 | (async () => { 16 | if (!localStorage.getItem("servers")) { 17 | console.log( 18 | `Calling Discord API with the token: ${Cookies.get("token")}` 19 | ); 20 | let discordInfo; 21 | try { 22 | discordInfo = ( 23 | await axios.get(`https://discord.com/api/users/@me/guilds`, { 24 | // We specify the access token in the headers, to tell Discord that we want this specific users' information. 25 | headers: { Authorization: `Bearer ${Cookies.get("token")}` }, 26 | }) 27 | ).data; 28 | } catch (err) { 29 | console.error(err); 30 | } 31 | setServers(discordInfo); 32 | } else setServers(JSON.parse(localStorage.getItem("servers"))); 33 | })(); 34 | } 35 | }, []); 36 | 37 | useEffect(() => { 38 | if (servers && servers.length !== 0) { 39 | localStorage.setItem("servers", JSON.stringify(servers, null, 4)); 40 | } 41 | }, [servers]); 42 | 43 | function Page(props) { 44 | return ( 45 | <> 46 |
47 |
{props.children}
48 |
49 | 50 | ); 51 | } 52 | 53 | function loggedIn() { 54 | return ( 55 | 56 |

57 | You are in {servers.length} servers! 58 |

59 |
60 | ); 61 | } 62 | 63 | function loggedOut() { 64 | return ( 65 | 66 |

67 | You are currently not logged in 68 |

69 |

70 | Click{" "} 71 | 75 | here 76 | {" "} 77 | to login with Discord 78 |

79 |
80 | ); 81 | } 82 | 83 | return ( 84 | <> 85 | 86 | 90 | 91 | 92 | 93 | 94 | 98 | Server counter 99 | 100 | {token === "" ? loggedOut() : loggedIn()} 101 |