diff --git a/website/.gitignore b/website/.gitignore index b2d6de30..b083ed4f 100644 --- a/website/.gitignore +++ b/website/.gitignore @@ -10,6 +10,7 @@ # Misc .DS_Store +.env .env.local .env.development.local .env.test.local diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index 305401ab..8bb3474f 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -12,8 +12,6 @@ module.exports = { organizationName: "Dagger", projectName: "Dagger", stylesheets: [ - "https://fonts.gstatic.com", - "https://fonts.googleapis.com/css2?family=Poppins:wght@700&display=swap", "https://fonts.googleapis.com/css2?family=Karla&family=Poppins:wght@700&display=swap", ], themeConfig: { @@ -58,5 +56,12 @@ module.exports = { }, ], ], - plugins: ["docusaurus-plugin-sass"], + plugins: [ + "docusaurus-plugin-sass", + [ + "docusaurus2-dotenv", { + systemvars: true, + }, + ] + ], }; diff --git a/website/package.json b/website/package.json index 795dccc3..575a5e80 100644 --- a/website/package.json +++ b/website/package.json @@ -20,9 +20,11 @@ "@svgr/webpack": "^5.5.0", "clsx": "^1.1.1", "docusaurus-plugin-sass": "^0.2.0", + "docusaurus2-dotenv": "^1.4.0", "file-loader": "^6.2.0", "react": "^17.0.1", "react-dom": "^17.0.1", + "react-social-login-buttons": "^3.4.0", "sass": "^1.34.1", "url-loader": "^4.1.1" }, diff --git a/website/src/api/github.js b/website/src/api/github.js new file mode 100644 index 00000000..d95064c9 --- /dev/null +++ b/website/src/api/github.js @@ -0,0 +1,68 @@ +import axios from 'axios'; + +const AxiosInstance = axios.create({ + headers: { 'Accept': 'application/vnd.github.v3+json' }, +}); + +function bindApiCall({ url, config, errorMessage }) { + try { + const apiCall = AxiosInstance.get(url, { + ...config, + validateStatus: function (status) { + return status < 500; // Resolve only if the status code is less than 500 + } + }) + + return apiCall + } catch (error) { + console.log(errorMessage, error.message) + } +} + +async function getAccessToken(code) { + const accessToken = await bindApiCall({ + url: 'https://github.com/login/oauth/access_token', + config: { + params: { + code, + client_id: process.env.REACT_APP_CLIENT_ID, + client_secret: process.env.REACT_APP_CLIENT_SECRET, + }, + errorMessage: 'error getAccessToken' + } + }) + + return accessToken.data +} + +export async function getUser(access_token) { + const user = await bindApiCall({ + url: 'https://api.github.com/user', + config: { + headers: { Authorization: `token ${access_token}` }, + }, + errorMessage: 'error getUser' + }) + + return { + login: user.data?.login, + error: user.data?.error_description, + status: user.status + } + +} + +export async function checkUserCollaboratorStatus(code) { + const { access_token } = await getAccessToken(code) + const { login } = await getUser(access_token) + + const isUserCollaborator = await bindApiCall({ + url: `https://docs-access.dagger.io/u/${login}`, + errorMessage: 'error checkUserCollaboratorStatus' + }) + + return { + isAllowed: isUserCollaborator.data, + access_token + } +} \ No newline at end of file diff --git a/website/src/components/DocPageAuthentication.js b/website/src/components/DocPageAuthentication.js new file mode 100644 index 00000000..8264aaeb --- /dev/null +++ b/website/src/components/DocPageAuthentication.js @@ -0,0 +1,13 @@ +import React from "react"; +import { GithubLoginButton } from 'react-social-login-buttons'; +import style from './DocPageAuthentication.module.css' + +export default function DocAuthentication() { + return ( +
+

Welcome on Dagger documentation

+

Please Sign In to Github to get access to the doc

+ window.location.href = `//github.com/login/oauth/authorize?client_id=cd8f9be2562bfc8d6cfc&scope=user&allow_signup=false`} /> +
+ ) +} \ No newline at end of file diff --git a/website/src/components/DocPageAuthentication.module.css b/website/src/components/DocPageAuthentication.module.css new file mode 100644 index 00000000..5fd0ada2 --- /dev/null +++ b/website/src/components/DocPageAuthentication.module.css @@ -0,0 +1,13 @@ +.container { + background: url("/img/Dagger_Website_Space_Uranus.png") no-repeat; + background-size: cover; + height: 100vh; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.btn__github { + width: 240px !important; +} \ No newline at end of file diff --git a/website/src/components/DocPageRedirect.js b/website/src/components/DocPageRedirect.js new file mode 100644 index 00000000..e172ed20 --- /dev/null +++ b/website/src/components/DocPageRedirect.js @@ -0,0 +1,29 @@ +import React, { useEffect, useState } from "react"; +import style from './DocPageRedirect.module.css' + + +export default function DocPageRedirect() { + const [counter, setCounter] = useState(10) + + useEffect(() => { + setTimeout(() => window.location.href = "https://dagger.io", 10000) + setInterval(() => setCounter((prevState) => prevState - 1), 1000) + }, []) + + return ( +
+
+
+

Oups!

+

It seems you don't have the permission to see Dagger's documentation. But don't worry you can request an Eary Access :). You'll be redirect to Dagger website in {counter} seconds

+

See you soon !

+
+ If nothing happen, click here to go to Dagger website +
+
+ +
+
+
+ ) +} \ No newline at end of file diff --git a/website/src/components/DocPageRedirect.module.css b/website/src/components/DocPageRedirect.module.css new file mode 100644 index 00000000..32f717b2 --- /dev/null +++ b/website/src/components/DocPageRedirect.module.css @@ -0,0 +1,25 @@ +.wrapper { + background: linear-gradient(180deg, #131226, #0e2b3d); + height: 100vh; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + color: var(--ifm-color-primary-light); + max-width: 100%; +} + +.wrapper a { + color: var(--ifm-color-primary-light); + text-decoration: underline; +} + +.h1 { + margin-bottom: 2rem; +} + +.row { + justify-content: center; + align-content: center; + align-items: center; +} diff --git a/website/src/components/Spinner.js b/website/src/components/Spinner.js new file mode 100644 index 00000000..1cdb3161 --- /dev/null +++ b/website/src/components/Spinner.js @@ -0,0 +1,8 @@ +import React from 'react'; +import styles from './Spinner.module.css'; + +export default function Spinner() { + return ( +
+ ) +} \ No newline at end of file diff --git a/website/src/components/Spinner.module.css b/website/src/components/Spinner.module.css new file mode 100644 index 00000000..15f5d9de --- /dev/null +++ b/website/src/components/Spinner.module.css @@ -0,0 +1,64 @@ +.ellipsis { + display: inline-block; + position: absolute; + top: 50vh; + z-index: 99999; + left: 50vw; + transform: translate(-50%, -50%); + width: 80px; + height: 80px; +} +.ellipsis div { + position: absolute; + top: 33px; + width: 13px; + height: 13px; + border-radius: 50%; + background: var(--ifm-color-primary-dark); + animation-timing-function: cubic-bezier(0, 1, 1, 0); +} + +html[data-theme="dark"] .ellipsis div { + background: var(--ifm-color-primary-light); +} + +.ellipsis div:nth-child(1) { + left: 8px; + animation: lds-ellipsis1 0.6s infinite; +} +.ellipsis div:nth-child(2) { + left: 8px; + animation: lds-ellipsis2 0.6s infinite; +} +.ellipsis div:nth-child(3) { + left: 32px; + animation: lds-ellipsis2 0.6s infinite; +} +.ellipsis div:nth-child(4) { + left: 56px; + animation: lds-ellipsis3 0.6s infinite; +} +@keyframes lds-ellipsis1 { + 0% { + transform: scale(0); + } + 100% { + transform: scale(1); + } +} +@keyframes lds-ellipsis3 { + 0% { + transform: scale(1); + } + 100% { + transform: scale(0); + } +} +@keyframes lds-ellipsis2 { + 0% { + transform: translate(0, 0); + } + 100% { + transform: translate(24px, 0); + } +} diff --git a/website/src/theme/DocPage/index.js b/website/src/theme/DocPage/index.js new file mode 100644 index 00000000..6d0e9b20 --- /dev/null +++ b/website/src/theme/DocPage/index.js @@ -0,0 +1,197 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +import React, { useState, useEffect, useCallback } from 'react'; +import { MDXProvider } from '@mdx-js/react'; +import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; +import renderRoutes from '@docusaurus/renderRoutes'; +import Layout from '@theme/Layout'; +import DocSidebar from '@theme/DocSidebar'; +import MDXComponents from '@theme/MDXComponents'; +import NotFound from '@theme/NotFound'; +import IconArrow from '@theme/IconArrow'; +import { matchPath } from '@docusaurus/router'; +import { translate } from '@docusaurus/Translate'; +import clsx from 'clsx'; +import styles from './styles.module.css'; +import { ThemeClassNames, docVersionSearchTag } from '@docusaurus/theme-common'; +import { Redirect } from "react-router"; +import qs from 'querystringify'; +import isEmpty from 'lodash/isEmpty'; +import { checkUserCollaboratorStatus, getUser } from '../../api/github' +import { GithubLoginButton } from 'react-social-login-buttons'; +import Spinner from '../../components/Spinner'; +import DocPageAuthentication from '../../components/DocPageAuthentication'; +import DocPageRedirect from '../../components/DocPageRedirect'; + +function DocPageContent({ currentDocRoute, versionMetadata, children }) { + const { siteConfig, isClient } = useDocusaurusContext(); + const { pluginId, permalinkToSidebar, docsSidebars, version } = versionMetadata; + const sidebarName = permalinkToSidebar[currentDocRoute.path]; + const sidebar = docsSidebars[sidebarName]; + const [hiddenSidebarContainer, setHiddenSidebarContainer] = useState(false); + const [hiddenSidebar, setHiddenSidebar] = useState(false); + const toggleSidebar = useCallback(() => { + if (hiddenSidebar) { + setHiddenSidebar(false); + } + + setHiddenSidebarContainer(!hiddenSidebarContainer); + }, [hiddenSidebar]); + return ( + +
+ {sidebar && ( +
{ + if ( + !e.currentTarget.classList.contains(styles.docSidebarContainer) + ) { + return; + } + + if (hiddenSidebarContainer) { + setHiddenSidebar(true); + } + }} + role="complementary"> + + + {hiddenSidebar && ( +
+ +
+ )} +
+ )} +
+
+ {children} +
+
+
+
+ ); +} + +function DocPage(props) { + const { + route: { routes: docRoutes }, + versionMetadata, + location, + } = props; + const currentDocRoute = docRoutes.find((docRoute) => + matchPath(location.pathname, docRoute), + ); + + // CUSTOM DOCPAGE + if (typeof window === "undefined" || (typeof window !== "undefined" && window?.location?.hostname !== "localhost")) { + const [isUserAuthorized, setIsUserAuthorized] = useState() + const [isLoading, setIsLoading] = useState(true) + const [redirectState, setRedirectState] = useState() + const authQuery = qs.parse(location.search); + const [userAccessToken, setUserAccessToken] = useState((() => { + if (typeof window !== "undefined") return window.localStorage.getItem('user-github-key') + })()) + + useEffect(async () => { + if (userAccessToken) { + const user = await getUser(userAccessToken) + setIsUserAuthorized(user) + } else { + if (!isEmpty(authQuery)) { //callback after successful auth with github + const isUserCollaborator = await checkUserCollaboratorStatus(authQuery.code); + if (isUserCollaborator?.isAllowed) { + setUserAccessToken(isUserCollaborator.access_token) + if (typeof window !== "undefined") window.localStorage.setItem('user-github-key', isUserCollaborator.access_token); + } + + setIsUserAuthorized(isUserCollaborator?.isAllowed) + } + } + setIsLoading(false) + }, [userAccessToken]) + + + if (isLoading) return + + if (isUserAuthorized === false) { + return + } + + if (typeof isUserAuthorized == 'undefined' || isUserAuthorized?.status === 401) { + return ( + + ) + } + } + // END CUSTOM DOCPAGE + + if (!currentDocRoute) { + return ; + } + + return ( + + {renderRoutes(docRoutes)} + + ); +} + +export default DocPage; diff --git a/website/src/theme/DocPage/styles.module.css b/website/src/theme/DocPage/styles.module.css new file mode 100644 index 00000000..19bfa5fc --- /dev/null +++ b/website/src/theme/DocPage/styles.module.css @@ -0,0 +1,98 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +:root { + --doc-sidebar-width: 300px; +} + +:global(.docs-wrapper) { + display: flex; +} + +.docPage, +.docMainContainer { + display: flex; + width: 100%; +} + +@media (min-width: 997px) { + .docMainContainer { + flex-grow: 1; + max-width: calc(100% - var(--doc-sidebar-width)); + } + + .docMainContainerEnhanced { + max-width: none; + } + + .docSidebarContainer { + width: var(--doc-sidebar-width); + margin-top: calc(-1 * var(--ifm-navbar-height)); + border-right: 1px solid var(--ifm-toc-border-color); + will-change: width; + transition: width var(--ifm-transition-fast) ease; + clip-path: inset(0); + } + + .docSidebarContainerHidden { + width: 30px; + cursor: pointer; + } + + .collapsedDocSidebar { + position: sticky; + top: 0; + height: 100%; + max-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + transition: background-color var(--ifm-transition-fast) ease; + } + + .collapsedDocSidebar:hover, + .collapsedDocSidebar:focus { + background-color: var(--ifm-color-emphasis-200); + } + + .expandSidebarButtonIcon { + transform: rotate(0); + } + html[dir='rtl'] .expandSidebarButtonIcon { + transform: rotate(180deg); + } + + html[data-theme='dark'] .collapsedDocSidebar:hover, + html[data-theme='dark'] .collapsedDocSidebar:focus { + background-color: var(--collapse-button-bg-color-dark); + } + + .docItemWrapperEnhanced { + max-width: calc(var(--ifm-container-width) + var(--doc-sidebar-width)); + } +} + +@media (max-width: 996px) { + .docSidebarContainer { + margin-top: 0; + } +} + +@media (min-width: 997px) and (max-width: 1320px) { + .docItemWrapper { + max-width: calc( + var(--ifm-container-width) - var(--doc-sidebar-width) - + var(--ifm-spacing-horizontal) * 2 + ); + } + + .docItemWrapperEnhanced { + max-width: calc( + var(--ifm-container-width) - var(--ifm-spacing-horizontal) * 2 + ); + } +} diff --git a/website/static/img/Dagger_Website_Space_Uranus.png b/website/static/img/Dagger_Website_Space_Uranus.png new file mode 100644 index 00000000..b1b3f4bf Binary files /dev/null and b/website/static/img/Dagger_Website_Space_Uranus.png differ diff --git a/website/static/img/dagger-astronaute.png b/website/static/img/dagger-astronaute.png new file mode 100644 index 00000000..07dec833 Binary files /dev/null and b/website/static/img/dagger-astronaute.png differ diff --git a/website/yarn.lock b/website/yarn.lock index d9d89caf..6c248b52 100644 --- a/website/yarn.lock +++ b/website/yarn.lock @@ -3382,6 +3382,13 @@ docusaurus-plugin-sass@^0.2.0: dependencies: sass-loader "^10.1.1" +docusaurus2-dotenv@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/docusaurus2-dotenv/-/docusaurus2-dotenv-1.4.0.tgz#9ab900e29de9081f9f1f28f7224ff63760385641" + integrity sha512-iWqem5fnBAyeBBtX75Fxp71uUAnwFaXzOmade8zAhN4vL3RG9m27sLSRwjJGVVgIkEo3esjGyCcTGTiCjfi+sg== + dependencies: + dotenv-webpack "1.7.0" + dom-converter@^0.2: version "0.2.0" resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" @@ -3478,6 +3485,25 @@ dot-prop@^5.2.0: dependencies: is-obj "^2.0.0" +dotenv-defaults@^1.0.2: + version "1.1.1" + resolved "https://registry.yarnpkg.com/dotenv-defaults/-/dotenv-defaults-1.1.1.tgz#032c024f4b5906d9990eb06d722dc74cc60ec1bd" + integrity sha512-6fPRo9o/3MxKvmRZBD3oNFdxODdhJtIy1zcJeUSCs6HCy4tarUpd+G67UTU9tF6OWXeSPqsm4fPAB+2eY9Rt9Q== + dependencies: + dotenv "^6.2.0" + +dotenv-webpack@1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/dotenv-webpack/-/dotenv-webpack-1.7.0.tgz#4384d8c57ee6f405c296278c14a9f9167856d3a1" + integrity sha512-wwNtOBW/6gLQSkb8p43y0Wts970A3xtNiG/mpwj9MLUhtPCQG6i+/DSXXoNN7fbPCU/vQ7JjwGmgOeGZSSZnsw== + dependencies: + dotenv-defaults "^1.0.2" + +dotenv@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-6.2.0.tgz#941c0410535d942c8becf28d3f357dbd9d476064" + integrity sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w== + duplexer3@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" @@ -6891,6 +6917,11 @@ react-side-effect@^2.1.0: resolved "https://registry.yarnpkg.com/react-side-effect/-/react-side-effect-2.1.1.tgz#66c5701c3e7560ab4822a4ee2742dee215d72eb3" integrity sha512-2FoTQzRNTncBVtnzxFOk2mCpcfxQpenBMbk5kSVBg5UcPqV9fRbgY2zhb7GTWWOlpFmAxhClBDlIq8Rsubz1yQ== +react-social-login-buttons@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/react-social-login-buttons/-/react-social-login-buttons-3.4.0.tgz#7b3f249c661624435e01881cf163ef4c4a960409" + integrity sha512-bECnTNfRSPKMnwVdfsLNNi0Fv5A8btJw3ANLg1Zj95DCjP11KPKUuhqOj9AQWLmQeyrLjMO7orEFE5M2QiDY9A== + react-textarea-autosize@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-8.3.2.tgz#4f9374d357b0a6f6469956726722549124a1b2db"