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.{" "}
-
- 😎
-
-
-
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
)
}
-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"