├── .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 |
--------------------------------------------------------------------------------