├── api ├── .gitignore ├── src │ ├── models │ │ ├── api │ │ │ ├── ISearchRequest.ts │ │ │ ├── IFeedbackListRequest.ts │ │ │ ├── IMissingListRequest.ts │ │ │ ├── IEmailCreateRquest.ts │ │ │ ├── ISearchQueryListRequest.ts │ │ │ ├── IResponse.ts │ │ │ ├── IMissingCreateRequest.ts │ │ │ ├── ISearchResponse.ts │ │ │ ├── IFeedbackCreateRequest.ts │ │ │ ├── ISearchResultItem.ts │ │ │ ├── IDataResponse.ts │ │ │ └── IEvent.ts │ │ ├── db │ │ │ ├── ISearchQuery.ts │ │ │ ├── IEmail.ts │ │ │ ├── IMissing.ts │ │ │ └── IFeedback.ts │ │ ├── configuration │ │ │ ├── ISolrConfiguration.ts │ │ │ ├── IAWSDynamoDbConfiguration.ts │ │ │ └── IConfiguration.ts │ │ └── app │ │ │ ├── IHttpRequest.ts │ │ │ ├── IHttpResponse.ts │ │ │ └── IRoute.ts │ ├── initServices.ts │ ├── data │ │ └── config.template.json │ ├── services │ │ ├── emailService.ts │ │ ├── missingService.ts │ │ ├── feedbackService.ts │ │ ├── searchQueryService.ts │ │ └── amazonDynamoDbService.ts │ ├── routes │ │ ├── emailCreate.ts │ │ ├── init.ts │ │ ├── feedbackCreate.ts │ │ ├── missingCreate.ts │ │ ├── searchQueryList.ts │ │ ├── feedbackList.ts │ │ └── missingList.ts │ ├── routes.ts │ ├── index.ts │ ├── api │ │ └── handler.ts │ └── utils │ │ └── validationHelper.ts ├── now.json ├── tsconfig.json ├── README.md ├── package.json └── DEPLOYMENT.md ├── public ├── robots.txt ├── favicon.ico ├── assets │ ├── iota-icons.ttf │ └── document.svg ├── favicon │ ├── favicon.ico │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── mstile-150x150.png │ ├── apple-touch-icon.png │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ ├── browserconfig.xml │ └── site.webmanifest └── package.json ├── .nowignore ├── src ├── style.css ├── components │ ├── molecules │ │ ├── VersionPicker │ │ │ ├── index.css │ │ │ └── index.js │ │ ├── Feedback │ │ │ ├── FeedbackOverlay.js │ │ │ ├── FeedbackButton.js │ │ │ ├── index.js │ │ │ └── FeedbackForm.js │ │ ├── HomePageCard │ │ │ ├── index.js │ │ │ └── Card.js │ │ ├── EmailSignup │ │ │ ├── index.js │ │ │ ├── email.css │ │ │ └── InputRegister.js │ │ ├── ProjectTopicsContainer │ │ │ ├── index.js │ │ │ ├── ProjectTopics.js │ │ │ └── ProjectTopicsInner.js │ │ ├── MessageBox │ │ │ └── index.js │ │ ├── SearchResult │ │ │ └── index.js │ │ ├── Navigator │ │ │ └── index.js │ │ ├── InputSearch │ │ │ └── index.js │ │ ├── SubHeader │ │ │ └── index.js │ │ ├── Pagination │ │ │ └── index.js │ │ ├── FloatingMenu │ │ │ └── index.js │ │ ├── Tabs │ │ │ └── index.js │ │ ├── EventCard │ │ │ ├── eventCard.css │ │ │ └── index.js │ │ ├── Table │ │ │ └── index.js │ │ └── TreeMenu │ │ │ └── index.js │ ├── atoms │ │ ├── Disclaimer │ │ │ ├── disclaimer.css │ │ │ └── index.js │ │ ├── ScrollToTop │ │ │ └── index.js │ │ ├── MapMarker │ │ │ ├── mapMarker.css │ │ │ └── index.js │ │ ├── Paragraph │ │ │ └── index.js │ │ ├── Image │ │ │ └── index.js │ │ ├── HorizontalRule │ │ │ └── index.js │ │ ├── ClickOutside.js │ │ ├── ParallaxContainer │ │ │ ├── index.js │ │ │ └── parallaxContainer.css │ │ ├── Text │ │ │ └── index.js │ │ ├── Label │ │ │ └── index.js │ │ ├── GoogleAnalytics │ │ │ └── index.js │ │ ├── HotJar │ │ │ └── index.js │ │ ├── HeadingLabel │ │ │ └── index.js │ │ ├── Heading │ │ │ └── index.js │ │ ├── Link │ │ │ └── index.js │ │ ├── Button │ │ │ └── index.js │ │ ├── MarkdownCard │ │ │ └── index.js │ │ ├── Select │ │ │ └── index.js │ │ ├── DropSelector │ │ │ └── index.js │ │ ├── BottomSticky.js │ │ └── ScrollInContainer.js │ └── organisms │ │ ├── StickyHeader │ │ └── index.js │ │ ├── Header │ │ └── index.js │ │ ├── Markdown │ │ └── markdown.css │ │ └── Footer │ │ └── index.js ├── config.template.json ├── utils │ ├── contentMenuItemsPropTypes.js │ ├── paths.js │ ├── scroll.js │ ├── homeDataPropTypes.js │ ├── search.js │ ├── localStorage.js │ ├── clipboard.js │ ├── foundationDataPropTypes.js │ ├── projectsPropTypes.js │ ├── api.js │ └── foundationDataHelper.jsx ├── App.js ├── index.js └── containers │ ├── Container.js │ ├── notFound.css │ ├── NotFound.js │ └── Home.js ├── CHANGELOG.md ├── .babelrc ├── .dockerignore ├── now.json ├── .gitignore ├── .eslintrc.js ├── .github ├── ISSUE_TEMPLATE │ └── documentation-issue-template.md └── workflows │ ├── client-prod.yaml │ ├── client-staging.yaml │ ├── api-prod.yaml │ └── api-staging.yaml ├── DEPLOYMENT.md ├── README.md └── package.json /api/.gitignore: -------------------------------------------------------------------------------- 1 | .vercel -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | -------------------------------------------------------------------------------- /.nowignore: -------------------------------------------------------------------------------- 1 | api 2 | .history 3 | .github 4 | dist 5 | tmp 6 | -------------------------------------------------------------------------------- /src/style.css: -------------------------------------------------------------------------------- 1 | #root { 2 | min-height: 100vh; 3 | } 4 | 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## Version 1.0.0 4 | 5 | Release -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["react-static/babel-preset.js"] 3 | } 4 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iotaledger-archive/documentation-platform/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/components/molecules/VersionPicker/index.css: -------------------------------------------------------------------------------- 1 | .version-picker__not-current { 2 | color: #DD0000 !important; 3 | } -------------------------------------------------------------------------------- /public/assets/iota-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iotaledger-archive/documentation-platform/HEAD/public/assets/iota-icons.ttf -------------------------------------------------------------------------------- /public/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iotaledger-archive/documentation-platform/HEAD/public/favicon/favicon.ico -------------------------------------------------------------------------------- /public/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iotaledger-archive/documentation-platform/HEAD/public/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iotaledger-archive/documentation-platform/HEAD/public/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /public/favicon/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iotaledger-archive/documentation-platform/HEAD/public/favicon/mstile-150x150.png -------------------------------------------------------------------------------- /public/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iotaledger-archive/documentation-platform/HEAD/public/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /api/src/models/api/ISearchRequest.ts: -------------------------------------------------------------------------------- 1 | export interface ISearchRequest { 2 | /** 3 | * The query to search for. 4 | */ 5 | query: string; 6 | } 7 | -------------------------------------------------------------------------------- /public/favicon/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iotaledger-archive/documentation-platform/HEAD/public/favicon/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/favicon/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iotaledger-archive/documentation-platform/HEAD/public/favicon/android-chrome-512x512.png -------------------------------------------------------------------------------- /api/src/models/api/IFeedbackListRequest.ts: -------------------------------------------------------------------------------- 1 | export interface IFeedbackListRequest { 2 | /** 3 | * The administrator key. 4 | */ 5 | adminKey: string; 6 | } 7 | -------------------------------------------------------------------------------- /api/src/models/api/IMissingListRequest.ts: -------------------------------------------------------------------------------- 1 | export interface IMissingListRequest { 2 | /** 3 | * The administrator key. 4 | */ 5 | adminKey: string; 6 | } 7 | -------------------------------------------------------------------------------- /api/src/models/api/IEmailCreateRquest.ts: -------------------------------------------------------------------------------- 1 | export interface IEmailCreateRequest { 2 | /** 3 | * The email address for the signup. 4 | */ 5 | email: string; 6 | } 7 | -------------------------------------------------------------------------------- /api/src/models/api/ISearchQueryListRequest.ts: -------------------------------------------------------------------------------- 1 | export interface ISearchQueryListRequest { 2 | /** 3 | * The administrator key. 4 | */ 5 | adminKey: string; 6 | } 7 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | /.github 2 | /.history 3 | /api 4 | /dist 5 | /node_modules 6 | /tmp 7 | /src/searchData 8 | /public/assets/docs 9 | /projects.json 10 | /projects-summary.log 11 | /*.bat 12 | -------------------------------------------------------------------------------- /src/config.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "siteName": "IOTA Documentation", 3 | "siteRoot": "SITE-ROOT", 4 | "apiEndpoint": "API-ENDPOINT", 5 | "hotJarId": "HOTJAR-ID", 6 | "googleAnalyticsId": "GOOGLE-ANALYTICS-ID" 7 | } -------------------------------------------------------------------------------- /api/src/models/db/ISearchQuery.ts: -------------------------------------------------------------------------------- 1 | export interface ISearchQuery { 2 | /** 3 | * The query that was searched for. 4 | */ 5 | query: string; 6 | 7 | /** 8 | * The number of times. 9 | */ 10 | count: number; 11 | } 12 | -------------------------------------------------------------------------------- /api/src/models/api/IResponse.ts: -------------------------------------------------------------------------------- 1 | export interface IResponse { 2 | /** 3 | * What the request successful. 4 | */ 5 | success: boolean; 6 | 7 | /** 8 | * A message for the response. 9 | */ 10 | message: string; 11 | } 12 | -------------------------------------------------------------------------------- /api/src/models/db/IEmail.ts: -------------------------------------------------------------------------------- 1 | export interface IEmail { 2 | /** 3 | * The email address for the signup. 4 | */ 5 | email: string; 6 | 7 | /** 8 | * The date the email was added. 9 | */ 10 | timestamp: number; 11 | } 12 | -------------------------------------------------------------------------------- /api/src/models/api/IMissingCreateRequest.ts: -------------------------------------------------------------------------------- 1 | export interface IMissingCreateRequest { 2 | /** 3 | * The document that was missing. 4 | */ 5 | document: string; 6 | 7 | /** 8 | * Where the document was linked from. 9 | */ 10 | fromDocument?: string; 11 | } 12 | -------------------------------------------------------------------------------- /api/src/models/api/ISearchResponse.ts: -------------------------------------------------------------------------------- 1 | import { IResponse } from "./IResponse"; 2 | import { ISearchResultItem } from "./ISearchResultItem"; 3 | 4 | export interface ISearchResponse extends IResponse { 5 | /** 6 | * The search results. 7 | */ 8 | items?: ISearchResultItem[]; 9 | } 10 | -------------------------------------------------------------------------------- /public/favicon/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #ffffff 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /api/now.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "builds": [ 4 | { 5 | "src": "src/api/handler.ts", 6 | "use": "@now/node" 7 | } 8 | ], 9 | "routes": [ 10 | { 11 | "src": "(.*)", 12 | "dest": "/src/api/handler.ts" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /public/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "documentation", 3 | "version": "1.0.0", 4 | "description": "Used by zeit/now to launch serve which automatically handles 404 redirects to 404.html", 5 | "devDependencies": { 6 | "serve": "latest" 7 | }, 8 | "scripts": { 9 | "start": "serve" 10 | } 11 | } -------------------------------------------------------------------------------- /api/src/initServices.ts: -------------------------------------------------------------------------------- 1 | import { IConfiguration } from "./models/configuration/IConfiguration"; 2 | 3 | /** 4 | * Initialise all the services. 5 | * @param config The configuration to initialisation the service with. 6 | */ 7 | export async function initServices(config: IConfiguration): Promise { 8 | // No services for this project 9 | } 10 | -------------------------------------------------------------------------------- /src/utils/contentMenuItemsPropTypes.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | 3 | const ContentMenuItemsPropTypes = PropTypes.arrayOf( 4 | PropTypes.shape({ 5 | name: PropTypes.string.isRequired, 6 | folder: PropTypes.string, 7 | link: PropTypes.string.isRequired 8 | }) 9 | ); 10 | 11 | export default ContentMenuItemsPropTypes; -------------------------------------------------------------------------------- /api/src/models/api/IFeedbackCreateRequest.ts: -------------------------------------------------------------------------------- 1 | export interface IFeedbackCreateRequest { 2 | /** 3 | * The document the feedback was provided for. 4 | */ 5 | document: string; 6 | /** 7 | * The was it useful response. 8 | */ 9 | wasItUseful: string; 10 | /** 11 | * Any additional comments. 12 | */ 13 | comments: string; 14 | } 15 | -------------------------------------------------------------------------------- /api/src/models/configuration/ISolrConfiguration.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition of Solr configuration. 3 | */ 4 | export interface ISolrConfiguration { 5 | /** 6 | * The endpoint for the solr server. 7 | */ 8 | endpoint: string; 9 | 10 | /** 11 | * Authorization. 12 | */ 13 | authorization?: string; 14 | 15 | /** 16 | * The document core. 17 | */ 18 | core: string; 19 | } 20 | -------------------------------------------------------------------------------- /src/components/atoms/Disclaimer/disclaimer.css: -------------------------------------------------------------------------------- 1 | .disclaimer { 2 | display: flex; 3 | position: fixed; 4 | right: 0; 5 | bottom: 0; 6 | left: 0; 7 | flex-direction: row; 8 | align-items: center; 9 | justify-content: space-between; 10 | padding: 20px; 11 | border-top: 1px solid var(--jade); 12 | background: #f3f2f1; 13 | color: rgba(64, 66, 73, 0.9); 14 | z-index: 1000; 15 | } -------------------------------------------------------------------------------- /api/src/models/api/ISearchResultItem.ts: -------------------------------------------------------------------------------- 1 | export interface ISearchResultItem { 2 | /** 3 | * The id of the document result. 4 | */ 5 | id: string; 6 | 7 | /** 8 | * The title of the document result. 9 | */ 10 | title: string; 11 | 12 | /** 13 | * The snippet of the document result. 14 | */ 15 | snippet: string; 16 | 17 | /** 18 | * The matches. 19 | */ 20 | matches: string[]; 21 | } 22 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import 'iota-css-theme'; 2 | import React from 'react'; 3 | import { Root, Routes } from 'react-static'; 4 | import './style.css'; 5 | 6 | class App extends React.Component { 7 | render() { 8 | return ( 9 | 10 | }> 11 | 12 | 13 | 14 | ); 15 | } 16 | } 17 | 18 | export default App; 19 | -------------------------------------------------------------------------------- /now.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "builds": [ 4 | { 5 | "src": "package.json", 6 | "use": "@now/static-build" 7 | } 8 | ], 9 | "routes": [ 10 | { 11 | "src": "/(.*)", 12 | "dest": "/$1" 13 | }, 14 | { 15 | "handle": "filesystem" 16 | }, 17 | { 18 | "src": "/(.*)", 19 | "status": 404, 20 | "dest": "/404.html" 21 | } 22 | ] 23 | } -------------------------------------------------------------------------------- /src/components/atoms/ScrollToTop/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const ScrollToTop = () => { 4 | 5 | const onScrollToTop = () => { 6 | const target = document.querySelector('#root'); 7 | target.scrollIntoView({ behavior: 'smooth', block: 'start' }); 8 | }; 9 | 10 | return ( 11 | 15 | ); 16 | }; 17 | 18 | export default ScrollToTop; -------------------------------------------------------------------------------- /api/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "es2015", 7 | "es2015.iterable" 8 | ], 9 | "esModuleInterop": true, 10 | "module": "commonjs", 11 | "moduleResolution": "node", 12 | "noUnusedLocals": true, 13 | "typeRoots": [ 14 | "node_modules/@types", 15 | "types" 16 | ], 17 | "outDir": "dist", 18 | "resolveJsonModule": true 19 | }, 20 | "include": [ 21 | "src" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /api/src/models/api/IDataResponse.ts: -------------------------------------------------------------------------------- 1 | export interface IDataResponse { 2 | /** 3 | * Success 4 | */ 5 | success: boolean; 6 | /** 7 | * The content type of the data response. 8 | */ 9 | contentType?: string; 10 | /** 11 | * Show the content inline. 12 | */ 13 | inline?: boolean; 14 | /** 15 | * The buffer of data to return. 16 | */ 17 | data: Buffer; 18 | /** 19 | * The filename for an attachment. 20 | */ 21 | filename?: string; 22 | } 23 | -------------------------------------------------------------------------------- /api/src/data/config.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "dynamoDbConnection": { 3 | "region": "DB-AWS-REGION", 4 | "accessKeyId": "DB-AWS-ACCESS-KEY-ID", 5 | "secretAccessKey": "DB-AWS-SECRET-ACCESS-KEY", 6 | "dbTablePrefix": "DB-TABLE-PREFIX" 7 | }, 8 | "search": { 9 | "endpoint": "SEARCH-ENDPOINT", 10 | "core": "SEARCH-CORE", 11 | "authorization": "SEARCH-AUTHORIZATION" 12 | }, 13 | "adminKey": "ADMIN-KEY", 14 | "allowedDomains": [ 15 | ALLOWED-DOMAIN 16 | ] 17 | } -------------------------------------------------------------------------------- /api/src/models/configuration/IAWSDynamoDbConfiguration.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition of AWS configuration. 3 | */ 4 | export interface IAWSDynamoDbConfiguration { 5 | /** 6 | * The region for the AWS connection. 7 | */ 8 | region: string; 9 | /** 10 | * The AWS access key. 11 | */ 12 | accessKeyId: string; 13 | /** 14 | * The AWS secret access key. 15 | */ 16 | secretAccessKey: string; 17 | 18 | /** 19 | * Prefix for all tables. 20 | */ 21 | dbTablePrefix: string; 22 | } 23 | -------------------------------------------------------------------------------- /src/utils/paths.js: -------------------------------------------------------------------------------- 1 | export function sanitizeHashId(id, skipLowerCase, isForAnchor) { 2 | // make lower case 3 | // de-escape spaces 4 | // replace spaces with hyphens 5 | if (!id) { 6 | return id; 7 | } 8 | if (!skipLowerCase) { 9 | id = id.toLowerCase(); 10 | } 11 | if (isForAnchor) { 12 | id = id.replace(/\./g, ''); 13 | } 14 | return id 15 | .replace(/\\ /g, ' ') 16 | .replace(/\?/g, '') 17 | .replace(/'/g, '') 18 | .replace(/ /g, '-'); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /public/favicon/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "IOTA Documentation", 3 | "short_name": "IOTA Documentation", 4 | "icons": [ 5 | { 6 | "src": "/favicon/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/favicon/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /api/src/models/db/IMissing.ts: -------------------------------------------------------------------------------- 1 | export interface IMissing { 2 | /** 3 | * The document that was missing. 4 | */ 5 | document: string; 6 | 7 | /** 8 | * Where the document was linked from. 9 | */ 10 | fromDocument?: string[]; 11 | 12 | /** 13 | * Where the document was linked from. 14 | */ 15 | fromDocumentTime?: { 16 | /** 17 | * The document linked. 18 | */ 19 | document: string; 20 | /** 21 | * The date of the missing. 22 | */ 23 | timestamp: number; 24 | }[]; 25 | } 26 | -------------------------------------------------------------------------------- /api/src/models/db/IFeedback.ts: -------------------------------------------------------------------------------- 1 | export interface IFeedback { 2 | /** 3 | * The document the feedback was provided for. 4 | */ 5 | document: string; 6 | 7 | /** 8 | * Feedback entries for the document. 9 | */ 10 | entries: { 11 | /** 12 | * The was it useful response. 13 | */ 14 | wasItUseful: string; 15 | /** 16 | * Any additional comments. 17 | */ 18 | comments: string; 19 | 20 | /** 21 | * The date of the feedback. 22 | */ 23 | timestamp: number; 24 | }[]; 25 | } 26 | -------------------------------------------------------------------------------- /src/components/atoms/MapMarker/mapMarker.css: -------------------------------------------------------------------------------- 1 | .map-marker { 2 | display: -webkit-inline-flex; 3 | display: inline-flex; 4 | -webkit-align-items: center; 5 | align-items: center; 6 | -webkit-justify-content: center; 7 | justify-content: center; 8 | padding: 10px; 9 | -webkit-transform: translate(-50%, -50%); 10 | transform: translate(-50%, -50%); 11 | border-radius: 5px; 12 | background: var(--jade); 13 | color: var(--white); 14 | text-align: center; 15 | } 16 | 17 | .map-marker img { 18 | width: 20px; 19 | height: 20px; 20 | margin-right: 10px; 21 | border: none !important; 22 | } 23 | -------------------------------------------------------------------------------- /src/components/atoms/Paragraph/index.js: -------------------------------------------------------------------------------- 1 | import classNames from 'classnames'; 2 | import PropTypes from 'prop-types'; 3 | import React from 'react'; 4 | 5 | class Paragraph extends React.PureComponent { 6 | static propTypes = { 7 | children: PropTypes.oneOfType([ 8 | PropTypes.arrayOf(PropTypes.node), 9 | PropTypes.node 10 | ]), 11 | className: PropTypes.string, 12 | }; 13 | 14 | render() { 15 | return ( 16 |

{this.props.children}

17 | ); 18 | } 19 | } 20 | 21 | export default Paragraph; 22 | -------------------------------------------------------------------------------- /src/components/atoms/Image/index.js: -------------------------------------------------------------------------------- 1 | import classNames from 'classnames'; 2 | import PropTypes from 'prop-types'; 3 | import React from 'react'; 4 | 5 | class Image extends React.PureComponent { 6 | static propTypes = { 7 | id: PropTypes.string, 8 | src: PropTypes.string.isRequired, 9 | alt: PropTypes.string.isRequired, 10 | className: PropTypes.string, 11 | }; 12 | 13 | render() { 14 | return ( 15 | {this.props.alt} 16 | ); 17 | } 18 | } 19 | 20 | export default Image; 21 | -------------------------------------------------------------------------------- /api/src/models/app/IHttpRequest.ts: -------------------------------------------------------------------------------- 1 | import { IncomingHttpHeaders} from "http"; 2 | 3 | export interface IHttpRequest { 4 | /** 5 | * The request method. 6 | */ 7 | method?: string; 8 | 9 | /** 10 | * The request url. 11 | */ 12 | url?: string; 13 | 14 | /** 15 | * The request body. 16 | */ 17 | // tslint:disable-next-line: no-any 18 | body: any; 19 | 20 | /** 21 | * The query parameters. 22 | */ 23 | // tslint:disable-next-line: no-any 24 | query: { [key: string]: any }; 25 | 26 | /** 27 | * Incoming Http Headers. 28 | */ 29 | headers: IncomingHttpHeaders; 30 | } 31 | -------------------------------------------------------------------------------- /src/components/atoms/MapMarker/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React, { Component } from 'react'; 3 | import './mapMarker.css'; 4 | 5 | /** 6 | * Component to display an event map marker. 7 | */ 8 | class MapMarker extends Component { 9 | static propTypes = { 10 | children: PropTypes.any, 11 | lat: PropTypes.number.isRequired, 12 | lng: PropTypes.number.isRequired, 13 | }; 14 | 15 | render() { 16 | return ( 17 |
18 | {this.props.children} 19 |
20 | ); 21 | } 22 | } 23 | 24 | export default MapMarker; 25 | -------------------------------------------------------------------------------- /src/components/atoms/HorizontalRule/index.js: -------------------------------------------------------------------------------- 1 | import classNames from 'classnames'; 2 | import PropTypes from 'prop-types'; 3 | import React from 'react'; 4 | 5 | // 6 | // 7 | 8 | class HorizontalRule extends React.Component { 9 | static propTypes = { 10 | small: PropTypes.bool 11 | }; 12 | 13 | render() { 14 | return ( 15 |
21 | ); 22 | } 23 | } 24 | 25 | export default HorizontalRule; 26 | -------------------------------------------------------------------------------- /api/README.md: -------------------------------------------------------------------------------- 1 | # Documentation API 2 | 3 | This package facilitates all the services required by `documentation` Web UI. 4 | 5 | It is a set of services running on NodeJS connecting to AWS DynamoDB. 6 | 7 | ## Prerequisites 8 | 9 | ```shell 10 | npm install 11 | ``` 12 | 13 | ## Development 14 | 15 | You will need to create a `./src/data/config.dev.json` file based on the `./src/data.config.template.json`, see the [DEPLOYMENT.md](./DEPLOYMENT.md) for more details. 16 | 17 | By running the following command the web API will be available at 18 | 19 | ```shell 20 | npm run start-dev 21 | ``` 22 | 23 | ## Deployment 24 | 25 | See [DEPLOYMENT.md](./DEPLOYMENT.md) for deployment instructions. -------------------------------------------------------------------------------- /src/utils/scroll.js: -------------------------------------------------------------------------------- 1 | export const scrollIntoView = (elem, cb) => { 2 | const animate = (start, from, to, duration) => { 3 | const time = Math.min(1, ((Date.now() - start) / duration)); 4 | const eased = 0.5 * (1 - Math.cos(Math.PI * time)); 5 | 6 | document.scrollingElement.scrollTop = (eased * (to - from)) + from; 7 | 8 | if (time < 1) { 9 | setTimeout(() => animate(start, from , to, duration), 0); 10 | } else if (cb) { 11 | cb(); 12 | } 13 | }; 14 | 15 | animate(Date.now(), document.scrollingElement.scrollTop, elem.offsetTop, 1000); 16 | }; 17 | 18 | export const currentScrollTop = () => { 19 | return document.scrollingElement.scrollTop; 20 | }; -------------------------------------------------------------------------------- /src/components/atoms/ClickOutside.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { PureComponent } from 'react'; 3 | import reactClickOutside from 'react-click-outside'; 4 | 5 | class ClickOutside extends PureComponent { 6 | static propTypes = { 7 | onClickOutside: PropTypes.func, 8 | children: PropTypes.oneOfType([ 9 | PropTypes.arrayOf(PropTypes.node), 10 | PropTypes.node 11 | ]) 12 | }; 13 | 14 | handleClickOutside() { 15 | if (this.props.onClickOutside) { 16 | this.props.onClickOutside(); 17 | } 18 | } 19 | 20 | render() { 21 | return this.props.children; 22 | } 23 | } 24 | 25 | export default reactClickOutside(ClickOutside); 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | node_modules 3 | .history 4 | 5 | # testing 6 | /coverage 7 | 8 | # production 9 | /dist 10 | /tmp 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | *.log* 20 | 21 | .editorconfig 22 | .prettierrc 23 | 24 | /docs* 25 | /dist 26 | /src/config.dev.json 27 | /src/config.local.json 28 | /src/config.staging.json 29 | /src/config.prod.json 30 | /api/dist 31 | /api/src/data/config.local.json 32 | /api/src/data/config.dev.json 33 | /api/src/data/config.staging.json 34 | /api/src/data/config.prod.json 35 | /public/assets/docs 36 | /projects.json 37 | /projects-summary.log 38 | /*.bat 39 | .vercel 40 | dictionary.json 41 | artifacts 42 | client 43 | -------------------------------------------------------------------------------- /api/src/services/emailService.ts: -------------------------------------------------------------------------------- 1 | import { IAWSDynamoDbConfiguration } from "../models/configuration/IAWSDynamoDbConfiguration"; 2 | import { IEmail } from "../models/db/IEmail"; 3 | import { AmazonDynamoDbService } from "./amazonDynamoDbService"; 4 | 5 | /** 6 | * Service to handle the emails. 7 | */ 8 | export class EmailService extends AmazonDynamoDbService { 9 | /** 10 | * The name of the database table. 11 | */ 12 | public static readonly TABLE_NAME: string = "email"; 13 | 14 | /** 15 | * Create a new instance of EmailService. 16 | * @param config The configuration for db connection. 17 | */ 18 | constructor(config: IAWSDynamoDbConfiguration) { 19 | super(config, EmailService.TABLE_NAME, "email"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /api/src/models/api/IEvent.ts: -------------------------------------------------------------------------------- 1 | export interface IEvent { 2 | /** 3 | * The title of the event. 4 | */ 5 | title: string; 6 | 7 | /** 8 | * The description of the event. 9 | */ 10 | description: string; 11 | 12 | /** 13 | * The start time/date in utc. 14 | */ 15 | startUtc: string; 16 | 17 | /** 18 | * The url for more details. 19 | */ 20 | urlDetails?: string; 21 | 22 | /** 23 | * Venue name. 24 | */ 25 | venueName?: string; 26 | 27 | /** 28 | * Venue address. 29 | */ 30 | venueAddress?: string[]; 31 | 32 | /** 33 | * Venue latitude. 34 | */ 35 | venueLatitude?: number; 36 | 37 | /** 38 | * Venue longitude. 39 | */ 40 | venueLongitude?: number; 41 | } 42 | -------------------------------------------------------------------------------- /api/src/models/app/IHttpResponse.ts: -------------------------------------------------------------------------------- 1 | export interface IHttpResponse { 2 | /** 3 | * Set a header on the response. 4 | * @param name The name of the header. 5 | * @param value The value of the header. 6 | */ 7 | setHeader(name: string, value: number | string | string[]): void; 8 | 9 | /** 10 | * Set a status code on the response. 11 | * @param statusCode The status code to send. 12 | * @returns The response. 13 | */ 14 | status(statusCode: number): IHttpResponse; 15 | 16 | /** 17 | * Send data in the response. 18 | * @param body The data to send. 19 | * @returns The response. 20 | */ 21 | send(body: unknown): IHttpResponse; 22 | 23 | /** 24 | * End the response. 25 | */ 26 | end(): void; 27 | } 28 | -------------------------------------------------------------------------------- /api/src/services/missingService.ts: -------------------------------------------------------------------------------- 1 | import { IAWSDynamoDbConfiguration } from "../models/configuration/IAWSDynamoDbConfiguration"; 2 | import { IMissing } from "../models/db/IMissing"; 3 | import { AmazonDynamoDbService } from "./amazonDynamoDbService"; 4 | 5 | /** 6 | * Service to handle the missing. 7 | */ 8 | export class MissingService extends AmazonDynamoDbService { 9 | /** 10 | * The name of the database table. 11 | */ 12 | public static readonly TABLE_NAME: string = "missing"; 13 | 14 | /** 15 | * Create a new instance of MissingService. 16 | * @param config The configuration for db connection. 17 | */ 18 | constructor(config: IAWSDynamoDbConfiguration) { 19 | super(config, MissingService.TABLE_NAME, "document"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /api/src/services/feedbackService.ts: -------------------------------------------------------------------------------- 1 | import { IAWSDynamoDbConfiguration } from "../models/configuration/IAWSDynamoDbConfiguration"; 2 | import { IFeedback } from "../models/db/IFeedback"; 3 | import { AmazonDynamoDbService } from "./amazonDynamoDbService"; 4 | 5 | /** 6 | * Service to handle the feedback. 7 | */ 8 | export class FeedbackService extends AmazonDynamoDbService { 9 | /** 10 | * The name of the database table. 11 | */ 12 | public static readonly TABLE_NAME: string = "feedback"; 13 | 14 | /** 15 | * Create a new instance of FeedbackService. 16 | * @param config The configuration for db connection. 17 | */ 18 | constructor(config: IAWSDynamoDbConfiguration) { 19 | super(config, FeedbackService.TABLE_NAME, "document"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /api/src/services/searchQueryService.ts: -------------------------------------------------------------------------------- 1 | import { IAWSDynamoDbConfiguration } from "../models/configuration/IAWSDynamoDbConfiguration"; 2 | import { ISearchQuery } from "../models/db/ISearchQuery"; 3 | import { AmazonDynamoDbService } from "./amazonDynamoDbService"; 4 | 5 | /** 6 | * Service to handle the queries. 7 | */ 8 | export class SearchQueryService extends AmazonDynamoDbService { 9 | /** 10 | * The name of the database table. 11 | */ 12 | public static readonly TABLE_NAME: string = "search-query"; 13 | 14 | /** 15 | * Create a new instance of SearchQueryService. 16 | * @param config The configuration for db connection. 17 | */ 18 | constructor(config: IAWSDynamoDbConfiguration) { 19 | super(config, SearchQueryService.TABLE_NAME, "query"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/components/atoms/ParallaxContainer/index.js: -------------------------------------------------------------------------------- 1 | import Parallax from 'parallax-js'; 2 | import PropTypes from 'prop-types'; 3 | import React from 'react'; 4 | import './parallaxContainer.css'; 5 | 6 | 7 | class ParallaxContainer extends React.PureComponent { 8 | static propTypes = { 9 | children: PropTypes.oneOfType([ 10 | PropTypes.arrayOf(PropTypes.node), 11 | PropTypes.node 12 | ]) 13 | }; 14 | 15 | componentDidMount() { 16 | this.parallaxInstance = new Parallax(this.parallaxEl, {}); 17 | } 18 | 19 | render() { 20 | return ( 21 |
(this.parallaxEl = el)}> 22 | {this.props.children} 23 |
24 | ); 25 | } 26 | } 27 | 28 | export default ParallaxContainer; 29 | -------------------------------------------------------------------------------- /src/components/atoms/Text/index.js: -------------------------------------------------------------------------------- 1 | import classNames from 'classnames'; 2 | import React from 'react'; 3 | import PropTypes from 'prop-types'; 4 | 5 | class Text extends React.PureComponent { 6 | static propTypes = { 7 | children: PropTypes.oneOfType([ 8 | PropTypes.arrayOf(PropTypes.node), 9 | PropTypes.node 10 | ]), 11 | className: PropTypes.string, 12 | html: PropTypes.bool, 13 | }; 14 | 15 | render() { 16 | if (this.props.html) { 17 | return ; 18 | } 19 | 20 | return ({this.props.children}); 21 | } 22 | } 23 | 24 | export default Text; 25 | -------------------------------------------------------------------------------- /src/utils/homeDataPropTypes.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | 3 | const HomeDataPropTypes = PropTypes.shape({ 4 | headerTopLinks: PropTypes.arrayOf( 5 | PropTypes.shape({ 6 | href: PropTypes.string.isRequired, 7 | name: PropTypes.string.isRequired 8 | }) 9 | ).isRequired, 10 | popularTopics: PropTypes.arrayOf( 11 | PropTypes.shape({ 12 | query: PropTypes.string.isRequired, 13 | name: PropTypes.string.isRequired 14 | }) 15 | ), 16 | cards: PropTypes.arrayOf( 17 | PropTypes.shape({ 18 | href: PropTypes.string.isRequired, 19 | image: PropTypes.string.isRequired, 20 | name: PropTypes.string.isRequired 21 | }) 22 | ).isRequired 23 | }); 24 | 25 | export default HomeDataPropTypes; -------------------------------------------------------------------------------- /src/components/molecules/Feedback/FeedbackOverlay.js: -------------------------------------------------------------------------------- 1 | import classNames from 'classnames'; 2 | import PropTypes from 'prop-types'; 3 | import React from 'react'; 4 | 5 | class FeedbackOverlay extends React.Component { 6 | static propTypes = { 7 | isExpanded: PropTypes.bool, 8 | children: PropTypes.oneOfType([ 9 | PropTypes.arrayOf(PropTypes.node), 10 | PropTypes.node 11 | ]) 12 | }; 13 | 14 | render() { 15 | return ( 16 |
22 | {this.props.children} 23 |
24 | ); 25 | } 26 | } 27 | export default FeedbackOverlay; 28 | -------------------------------------------------------------------------------- /src/components/molecules/HomePageCard/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | import Card from './Card'; 4 | 5 | class CardContainer extends React.PureComponent { 6 | static propTypes = { 7 | content: PropTypes.arrayOf(PropTypes.shape({ 8 | image: PropTypes.string.isRequired, 9 | href: PropTypes.string.isRequired, 10 | name: PropTypes.string, 11 | })).isRequired 12 | }; 13 | 14 | render() { 15 | return ( 16 |
17 | { 18 | this.props.content.map((card) => 19 | 20 | ) 21 | } 22 |
23 | ); 24 | } 25 | } 26 | 27 | export default CardContainer; 28 | -------------------------------------------------------------------------------- /src/components/atoms/Label/index.js: -------------------------------------------------------------------------------- 1 | import classNames from 'classnames'; 2 | import PropTypes from 'prop-types'; 3 | import React from 'react'; 4 | 5 | class Label extends React.PureComponent { 6 | static propTypes = { 7 | id: PropTypes.string, 8 | text: PropTypes.node, 9 | className: PropTypes.string, 10 | children: PropTypes.oneOfType([ 11 | PropTypes.arrayOf(PropTypes.node), 12 | PropTypes.node 13 | ]) 14 | }; 15 | 16 | render() { 17 | if (this.props.text) { 18 | return ( 19 | 22 | ); 23 | } 24 | return null; 25 | } 26 | } 27 | 28 | export default Label; 29 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import { AppContainer } from 'react-hot-loader'; 4 | 5 | // Your top level component 6 | import App from './App'; 7 | 8 | // Export your top level component as JSX (for static rendering) 9 | export default App; 10 | 11 | // Render your app 12 | if (typeof document !== 'undefined') { 13 | const target = document.getElementById('root'); 14 | 15 | const renderMethod = target.hasChildNodes() 16 | ? ReactDOM.hydrate 17 | : ReactDOM.render; 18 | 19 | const render = Comp => { 20 | renderMethod( 21 | 22 | 23 | , 24 | target 25 | ); 26 | }; 27 | 28 | // Render! 29 | render(App); 30 | 31 | // Hot Module Replacement 32 | if (module && module.hot) { 33 | module.hot.accept('./App', () => { 34 | render(App); 35 | }); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/components/atoms/GoogleAnalytics/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | 4 | class GoogleAnalytics extends React.PureComponent { 5 | static propTypes = { 6 | id: PropTypes.string 7 | }; 8 | 9 | render() { 10 | if (!this.props.id || this.props.id.trim().length === 0) { 11 | return null; 12 | } 13 | 14 | const src = `window.dataLayer = window.dataLayer || []; 15 | function gtag(){dataLayer.push(arguments);} 16 | gtag('js', new Date()); 17 | gtag('config', '${this.props.id}'); 18 | `; 19 | 20 | return ( 21 | 22 | 23 |