├── .eslintrc.json ├── public ├── favicon.ico └── og-image.png ├── next.config.js ├── pages ├── _app.js └── index.js ├── .gitignore ├── package.json ├── components ├── LoggedIn.js ├── LoggedOut.js └── LoginModal.js └── README.md /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleemrehmtulla/impossifocus/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/og-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleemrehmtulla/impossifocus/HEAD/public/og-image.png -------------------------------------------------------------------------------- /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 { ChakraProvider } from "@chakra-ui/react"; 2 | 3 | function MyApp({ Component, pageProps }) { 4 | return ( 5 | 6 | 7 | 8 | ); 9 | } 10 | 11 | export default MyApp; 12 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "negative", 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 | "@chakra-ui/react": "^2.2.0", 13 | "@emotion/react": "^11.9.0", 14 | "@emotion/styled": "^11.8.1", 15 | "@neurosity/notion": "^5.17.0", 16 | "framer-motion": "^6.3.10", 17 | "next": "12.1.6", 18 | "react": "18.1.0", 19 | "react-dom": "18.1.0" 20 | }, 21 | "devDependencies": { 22 | "eslint": "8.17.0", 23 | "eslint-config-next": "12.1.6" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /components/LoggedIn.js: -------------------------------------------------------------------------------- 1 | import { 2 | Text, 3 | CircularProgress, 4 | CircularProgressLabel, 5 | } from "@chakra-ui/react"; 6 | 7 | const LoggedIn = ({ progress }) => { 8 | return ( 9 | <> 10 | 11 | Your current focus is at:  {progress}%. 12 | 13 | 14 | Hit over 50% and youre done baby 😈 15 | 16 | 17 | 22 | 23 | {progress}% 24 | 25 | 26 | 27 | ); 28 | }; 29 | export default LoggedIn; 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # impossifocus 🕺 2 | 3 | ## What is this? 4 | 5 | ImpossiFocus will measure focus by reading your brainwaves -- and if you're in the zone, it'll ensure that changes with a snazzy rick-roll :-) 6 | 7 | *this is jokes if not noticed* 8 | 9 | 10 | https://www.loom.com/share/36d478d528d249d1b09db84288b6fa7f 11 | 12 | 13 | ## Usage 🤝 14 | 15 | 1. head to `impossifocus.vercel.app` 16 | 2. click `sign in with neurosity` 17 | 3. hit a score of 50+ and boom. rick rolled baby 18 | 19 | ## Deployments 💻 20 | 21 | Vercel: https://impossifocus.vercel.app 22 | 23 | 24 | ## For development 🧑‍💻 25 | 26 | ### Scripts 27 | 28 | npm install 29 | 30 | npm run dev 31 | 32 | 33 | ### Important notes 34 | 35 | - Used neurosity's native SDK for measuring values 36 | - ChakraUI & Next for frontend 37 | - Made for fun -- not for a serious value add 😉 38 | 39 | 40 | 41 | ## Connect with me 🤗 42 | 43 | https://twitter.com/aleemrehmtulla 44 | 45 | https://aleemrehmtulla.com 46 | 47 | https://www.linkedin.com/in/aleemrehmtulla/ 48 | 49 | -------------------------------------------------------------------------------- /components/LoggedOut.js: -------------------------------------------------------------------------------- 1 | import { Box, Center, Text, Image, Link } from "@chakra-ui/react"; 2 | 3 | const LoggedOut = ({ onOpen }) => { 4 | return ( 5 | <> 6 | 7 | 8 | by connecting your Neurosity (a Brain Computer Interface), we can 9 | measure your brainwaves to detect focus. 10 | 11 | 12 | if focused {" -> "} distract 13 | 14 | 15 | 16 | 17 |
29 | 34 | Sign In With Neurosity 35 |
36 | 37 | don't have a neurosity? grab one{" "} 38 | 43 | here 44 | 45 | 46 |
47 | 48 | ); 49 | }; 50 | export default LoggedOut; 51 | -------------------------------------------------------------------------------- /components/LoginModal.js: -------------------------------------------------------------------------------- 1 | import { 2 | Text, 3 | Button, 4 | Modal, 5 | ModalOverlay, 6 | ModalContent, 7 | ModalHeader, 8 | ModalFooter, 9 | ModalBody, 10 | Input, 11 | ModalCloseButton, 12 | } from "@chakra-ui/react"; 13 | 14 | const LoginModal = ({ onClose, isOpen, setEmail, setPassword, login }) => { 15 | return ( 16 | 17 | 18 | 19 | 20 | Sign In Using Your Neurosity Account 21 | 22 | note: we store nothing. this is just to connect your device 23 | 24 | 25 | 26 | 27 | setEmail(e.target.value)} 29 | autoComplete="email" 30 | placeholder="Email" 31 | /> 32 | setPassword(e.target.value)} 34 | mt={4} 35 | placeholder="Password" 36 | type="password" 37 | /> 38 | 39 | 40 | 43 | 52 | 53 | 54 | 55 | ); 56 | }; 57 | export default LoginModal; 58 | -------------------------------------------------------------------------------- /pages/index.js: -------------------------------------------------------------------------------- 1 | import Head from "next/head"; 2 | import { useState } from "react"; 3 | import { 4 | Center, 5 | Heading, 6 | VStack, 7 | useDisclosure, 8 | useToast, 9 | Text, 10 | Link, 11 | } from "@chakra-ui/react"; 12 | import { Notion } from "@neurosity/notion"; 13 | import LoginModal from "../components/LoginModal"; 14 | import LoggedOut from "../components/LoggedOut"; 15 | import LoggedIn from "../components/LoggedIn"; 16 | 17 | export default function Home() { 18 | const notion = new Notion(); 19 | const { isOpen, onOpen, onClose } = useDisclosure(); 20 | const toast = useToast(); 21 | const [email, setEmail] = useState(); 22 | const [password, setPassword] = useState(); 23 | const [progress, setProgress] = useState(null); 24 | 25 | // whenever your focus score is over 50 -- rick roll the homie :) 26 | if (progress > 50) { 27 | window.open("https://www.youtube.com/watch?v=dQw4w9WgXcQ", "_blank"); 28 | } 29 | 30 | const login = async () => { 31 | console.log("Email Result", email); 32 | console.log("Password Result", password); 33 | if (!email || !password) { 34 | toast({ 35 | title: `NAH. email or password is empty`, 36 | status: "error", 37 | isClosable: true, 38 | }); 39 | return; 40 | } 41 | notion.login({ email, password }).catch((error) => { 42 | if (error.message) { 43 | throw toast({ 44 | title: `ERROR! ${error.message}`, 45 | status: "error", 46 | isClosable: true, 47 | }); 48 | } 49 | if (error == "Already logged in.") { 50 | throw alreadyLoggedIn(); 51 | } 52 | }); 53 | 54 | notion.focus().subscribe((focus) => { 55 | const percentage = Math.round(focus.probability * 100); 56 | 57 | // if all is good, go ahead and close modal 58 | if (percentage) onClose(); 59 | 60 | // if completely unfocused, set as 1 (otherwise is null, and shows login) 61 | if (percentage < 1) { 62 | setProgress(1); 63 | return; 64 | } 65 | 66 | setProgress(Math.round(percentage)); 67 | }); 68 | }; 69 | 70 | // deals with weird already login sdk error 71 | const alreadyLoggedIn = async () => { 72 | await notion.logout(); 73 | login(); 74 | }; 75 | 76 | return ( 77 | <> 78 |
79 | 80 | ImpossiFocus 81 | 85 | 86 | 90 | 91 | 92 | ImpossiFocus 93 | {progress ? ( 94 | 95 | ) : ( 96 | 97 | )} 98 | 99 | 106 |
107 | 108 | Made with very little focus by{" "} 109 | @aleemrehmtulla 110 | 111 | 112 | ); 113 | } 114 | --------------------------------------------------------------------------------