diff --git a/gatsby-config.js b/gatsby-config.js index 1747b0e..23325df 100644 --- a/gatsby-config.js +++ b/gatsby-config.js @@ -2,6 +2,7 @@ module.exports = { siteMetadata: { siteUrl: "https://www.pingbot.cf", title: "Ping Bot", + description: "Ping Bot" }, plugins: [], -}; +} diff --git a/package.json b/package.json index 296c5d8..ff7dc84 100644 --- a/package.json +++ b/package.json @@ -15,8 +15,12 @@ "clean": "gatsby clean" }, "dependencies": { + "axios": "^0.21.1", "gatsby": "^3.10.2", + "prop-types": "^15.7.2", "react": "^17.0.1", - "react-dom": "^17.0.1" + "react-dom": "^17.0.1", + "react-helmet": "^6.1.0", + "react-notifications": "^1.7.2" } } diff --git a/src/axios.js b/src/axios.js new file mode 100644 index 0000000..71c0097 --- /dev/null +++ b/src/axios.js @@ -0,0 +1,7 @@ +import axios from 'axios' + +const instance = axios.create({ + baseURL: process.env.API_URL || 'https://backend.pingbot.cf/api', +}) + +export default instance diff --git a/src/components/seo.js b/src/components/seo.js new file mode 100644 index 0000000..bff1e3b --- /dev/null +++ b/src/components/seo.js @@ -0,0 +1,66 @@ +import React from "react" +import PropTypes from "prop-types" +import { Helmet } from "react-helmet" +import { useStaticQuery, graphql } from "gatsby" + +function Seo(props) { + const { site } = useStaticQuery( + graphql` + query { + site { + siteMetadata { + title + description + } + } + } + ` + ) + + const defaultDesc = props.description || site.siteMetadata.description + const defaultTitle = site.siteMetadata?.title + + return ( + + ) +} + +Seo.defaultProps = { + lang: "en", + meta: [], + embedColor: "#282c34" +} + +Seo.propTypes = { + description: PropTypes.string, + lang: PropTypes.string, + meta: PropTypes.arrayOf(PropTypes.object), + title: PropTypes.string, + embedColor: PropTypes.string +} + +export default Seo diff --git a/src/css/base.css b/src/css/base.css new file mode 100644 index 0000000..8052307 --- /dev/null +++ b/src/css/base.css @@ -0,0 +1,51 @@ +body { + color: #fff; + background-color: #111; + + margin: 0; + padding: 96px; + text-align: center; + + font-family: "-apple-system, Roboto, sans-serif, serif"; +} + +a, .link { + color: #61dafb; + cursor: pointer; + text-decoration: none; +} + +.url-link { + display: inline-block; + padding: 10px; +} + +.url-link a { + color: rgba(255, 255, 255, 0.712); +} + +button { + margin-top: 2rem; + padding: 10px 30px; + font-weight: bold; + border: 2px solid white; + color: white; + border-radius: 100px; + background: transparent; + transition: all 1000ms; +} + +.red-button { + border: 2px solid red; + color: red; +} + +.yellow-button { + border: 2px solid greenyellow; + color: greenyellow; +} + +.blue-buton { + border: 2px solid blue; + color: blue; +} diff --git a/src/css/url.css b/src/css/url.css new file mode 100644 index 0000000..40e28f3 --- /dev/null +++ b/src/css/url.css @@ -0,0 +1,73 @@ +form { + --text-color: #afafaf; +} + +.input { + outline: none; + border: none; + overflow: hidden; + margin: 0; + width: 100%; + padding: 0.25rem 0; + background: none; + color: white; + font-size: 1.2em; + font-weight: bold; + transition: border 500ms; +} + +.input:valid { + color: yellowgreen; +} + +.input:invalid { + color: orangered; +} + +/* Border animation */ +.field::after { + content: ""; + position: relative; + display: block; + height: 4px; + width: 100%; + background: #d16dff; + transform: scaleX(0); + transform-origin: 0%; + opacity: 0; + transition: all 500ms ease; + top: 2px; +} + +.field:focus-within { + border-color: transparent; +} + +.field:focus-within::after { + transform: scaleX(1); + opacity: 1; +} + +/* Label animation */ +.label { + z-index: -1; + position: absolute; + transform: translateY(-2rem); + transform-origin: 0%; + transition: transform 400ms; +} + +.field:focus-within .label, +.input:not(:placeholder-shown) + .label { + transform: scale(0.8) translateY(-5rem); + opacity: 1; +} + +button:disabled { + border-color: var(--text-color); + color: var(--text-color); +} + +button:hover { + cursor: pointer; +} diff --git a/src/images/icon.png b/src/images/icon.png deleted file mode 100644 index 38b2fb0..0000000 Binary files a/src/images/icon.png and /dev/null differ diff --git a/src/pages/404.js b/src/pages/404.js index 053ae0e..2a9d439 100644 --- a/src/pages/404.js +++ b/src/pages/404.js @@ -1,53 +1,21 @@ -import * as React from "react" +import React from "react" import { Link } from "gatsby" -// styles -const pageStyles = { - color: "#232129", - padding: "96px", - fontFamily: "-apple-system, Roboto, sans-serif, serif", -} -const headingStyles = { - marginTop: 0, - marginBottom: 64, - maxWidth: 320, -} +import "../css/base.css" -const paragraphStyles = { - marginBottom: 48, -} -const codeStyles = { - color: "#8A6534", - padding: 4, - backgroundColor: "#FFF4DB", - fontSize: "1.25rem", - borderRadius: 4, -} - -// markup const NotFoundPage = () => { return ( -
+ <> Not found -

Page not found

-

- Sorry{" "} - - 😔 - {" "} - we couldn’t find what you were looking for. +

Page not found

+

+ Sorry we couldn’t find what you were looking for.
- {process.env.NODE_ENV === "development" ? ( - <> -
- Try creating a page in src/pages/. -
- - ) : null} -
- Go home. + + +

-
+ ) } diff --git a/src/pages/add.js b/src/pages/add.js new file mode 100644 index 0000000..d2ae319 --- /dev/null +++ b/src/pages/add.js @@ -0,0 +1,81 @@ +import React from "react" +import { Link } from "gatsby" +import { NotificationManager, NotificationContainer } from 'react-notifications' +import 'react-notifications/lib/notifications.css' + +import Seo from "../components/seo" +import axios from "../axios" + +import "../css/base.css" +import "../css/url.css" + +const AddURLPage = () => { + const [url, setURL] = React.useState('') + + const changeURLHandler = event => { + const value = event.target.value + setURL(value) + } + + const addURL = async () => { + setURL('') + + if (url === '') { + return NotificationManager.error('Empty') + } + + try { + const res = await axios.post('/url', { + url: url, + }) + + const data = res.data + + NotificationManager.success(data.url, 'Added') + } catch (err) { + let e = '' + + if (err.response && err.response.data.message) { + e = err.response.data.message + } else { + e = err.toString() + } + + NotificationManager.error(e) + } + } + + return ( + <> + + + + +
+ +
+ + + +
+ + + + + + ) +} + +export default AddURLPage diff --git a/src/pages/delete.js b/src/pages/delete.js new file mode 100644 index 0000000..ad83337 --- /dev/null +++ b/src/pages/delete.js @@ -0,0 +1,83 @@ +import React from "react" +import { Link } from "gatsby" +import { NotificationManager, NotificationContainer } from 'react-notifications' +import 'react-notifications/lib/notifications.css' + +import Seo from "../components/seo" +import axios from "../axios" + +import "../css/base.css" +import "../css/url.css" + +const DeleteURLPage = () => { + const [url, setURL] = React.useState('') + + const changeURLHandler = event => { + const value = event.target.value + setURL(value) + } + + const deleteURL = async () => { + setURL('') + + if (url === '') { + return NotificationManager.error('Empty') + } + + try { + const id = btoa(url) + + console.log(`/url/${id}`) + + const res = await axios.delete(`/url/${id}`) + + const data = res.data + + NotificationManager.success(data.url, 'Deleted') + } catch (err) { + let e = '' + + if (err.response && err.response.data.message) { + e = err.response.data.message + } else { + e = err.toString() + } + + NotificationManager.error(e) + } + } + + return ( + <> + + + + +
+ +
+ + + +
+ + + + + + ) +} + +export default DeleteURLPage diff --git a/src/pages/index.js b/src/pages/index.js index dbc0fb9..f919284 100644 --- a/src/pages/index.js +++ b/src/pages/index.js @@ -1,184 +1,33 @@ -import * as React from "react" +import React from "react" +import { Link } from "gatsby" +import { NotificationContainer } from 'react-notifications' -// styles -const pageStyles = { - color: "#232129", - padding: 96, - fontFamily: "-apple-system, Roboto, sans-serif, serif", -} -const headingStyles = { - marginTop: 0, - marginBottom: 64, - maxWidth: 320, -} -const headingAccentStyles = { - color: "#663399", -} -const paragraphStyles = { - marginBottom: 48, -} -const codeStyles = { - color: "#8A6534", - padding: 4, - backgroundColor: "#FFF4DB", - fontSize: "1.25rem", - borderRadius: 4, -} -const listStyles = { - marginBottom: 96, - paddingLeft: 0, -} -const listItemStyles = { - fontWeight: 300, - fontSize: 24, - maxWidth: 560, - marginBottom: 30, -} +import Seo from "../components/seo" -const linkStyle = { - color: "#8954A8", - fontWeight: "bold", - fontSize: 16, - verticalAlign: "5%", -} +import "../css/base.css" -const docLinkStyle = { - ...linkStyle, - listStyleType: "none", - marginBottom: 24, -} - -const descriptionStyle = { - color: "#232129", - fontSize: 14, - marginTop: 10, - marginBottom: 0, - lineHeight: 1.25, -} - -const docLink = { - text: "Documentation", - url: "https://www.gatsbyjs.com/docs/", - color: "#8954A8", -} - -const badgeStyle = { - color: "#fff", - backgroundColor: "#088413", - border: "1px solid #088413", - fontSize: 11, - fontWeight: "bold", - letterSpacing: 1, - borderRadius: 4, - padding: "4px 6px", - display: "inline-block", - position: "relative", - top: -2, - marginLeft: 10, - lineHeight: 1, -} - -// data -const links = [ - { - text: "Tutorial", - url: "https://www.gatsbyjs.com/docs/tutorial/", - description: - "A great place to get started if you're new to web development. Designed to guide you through setting up your first Gatsby site.", - color: "#E95800", - }, - { - text: "How to Guides", - url: "https://www.gatsbyjs.com/docs/how-to/", - description: - "Practical step-by-step guides to help you achieve a specific goal. Most useful when you're trying to get something done.", - color: "#1099A8", - }, - { - text: "Reference Guides", - url: "https://www.gatsbyjs.com/docs/reference/", - description: - "Nitty-gritty technical descriptions of how Gatsby works. Most useful when you need detailed information about Gatsby's APIs.", - color: "#BC027F", - }, - { - text: "Conceptual Guides", - url: "https://www.gatsbyjs.com/docs/conceptual/", - description: - "Big-picture explanations of higher-level Gatsby concepts. Most useful for building understanding of a particular topic.", - color: "#0D96F2", - }, - { - text: "Plugin Library", - url: "https://www.gatsbyjs.com/plugins", - description: - "Add functionality and customize your Gatsby site or app with thousands of plugins built by our amazing developer community.", - color: "#8EB814", - }, - { - text: "Build and Host", - url: "https://www.gatsbyjs.com/cloud", - badge: true, - description: - "Now you’re ready to show the world! Give your Gatsby site superpowers: Build and host on Gatsby Cloud. Get started for free!", - color: "#663399", - }, -] - -// markup -const IndexPage = () => { +const LoginPage = () => { return ( -
- Home Page -

- Congratulations -
- — you just made a Gatsby site! - - 🎉🎉🎉 - -

-

- Edit src/pages/index.js to see this page - update in real-time.{" "} - - 😎 - -

- - Gatsby G Logo + -
+ + + +
+ + + +
+ +
+ + + +
+ ) } -export default IndexPage +export default LoginPage diff --git a/yarn.lock b/yarn.lock index 1d41914..8fd5672 100644 --- a/yarn.lock +++ b/yarn.lock @@ -999,7 +999,7 @@ core-js-pure "^3.16.0" regenerator-runtime "^0.13.4" -"@babel/runtime@^7.10.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.14.6", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.10.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.14.6", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.14.8" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.8.tgz#7119a56f421018852694290b9f9148097391b446" integrity sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg== @@ -1874,6 +1874,11 @@ acorn-jsx@^5.0.0, acorn-jsx@^5.3.1: resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== +acorn@6.4.1: + version "6.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474" + integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA== + acorn@^7.4.0: version "7.4.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" @@ -2777,6 +2782,11 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" +classnames@^2.1.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" + integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== + clean-stack@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" @@ -3616,6 +3626,14 @@ dom-converter@^0.2.0: dependencies: utila "~0.4" +dom-helpers@^5.0.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902" + integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA== + dependencies: + "@babel/runtime" "^7.8.7" + csstype "^3.0.2" + dom-serializer@^1.0.1: version "1.3.2" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91" @@ -8177,7 +8195,7 @@ prompts@^2.3.2: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types@^15.6.1, prop-types@^15.7.2: +prop-types@^15.5.10, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== @@ -8388,6 +8406,21 @@ react-error-overlay@^6.0.9: resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a" integrity sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew== +react-fast-compare@^3.1.1: + version "3.2.0" + resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" + integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== + +react-helmet@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/react-helmet/-/react-helmet-6.1.0.tgz#a750d5165cb13cf213e44747502652e794468726" + integrity sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw== + dependencies: + object-assign "^4.1.1" + prop-types "^15.7.2" + react-fast-compare "^3.1.1" + react-side-effect "^2.1.0" + react-is@^16.12.0, react-is@^16.8.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" @@ -8398,11 +8431,36 @@ react-lifecycles-compat@^3.0.4: resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== +react-notifications@^1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/react-notifications/-/react-notifications-1.7.2.tgz#e70e2c053f86321c0a7fa81ff638922e2fdd572f" + integrity sha512-3mlMiNLDQtp64IP+EnYx3xgmbdpzrLQiSO8AP+8o4LiYQC6HcgdVB+MMdGuYZ1ttfKeLgTgol2ESFQJhmz0O3Q== + dependencies: + acorn "6.4.1" + classnames "^2.1.1" + prop-types "^15.5.10" + react-transition-group "^4.4.1" + react-refresh@^0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.9.0.tgz#71863337adc3e5c2f8a6bfddd12ae3bfe32aafbf" integrity sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ== +react-side-effect@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/react-side-effect/-/react-side-effect-2.1.1.tgz#66c5701c3e7560ab4822a4ee2742dee215d72eb3" + integrity sha512-2FoTQzRNTncBVtnzxFOk2mCpcfxQpenBMbk5kSVBg5UcPqV9fRbgY2zhb7GTWWOlpFmAxhClBDlIq8Rsubz1yQ== + +react-transition-group@^4.4.1: + version "4.4.2" + resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.2.tgz#8b59a56f09ced7b55cbd53c36768b922890d5470" + integrity sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg== + dependencies: + "@babel/runtime" "^7.5.5" + dom-helpers "^5.0.1" + loose-envify "^1.4.0" + prop-types "^15.6.2" + react@^17.0.1: version "17.0.2" resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037"