8
.gitignore
vendored
@ -34,6 +34,8 @@ build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
node_modules_pc/
|
||||
node_modules_surface/
|
||||
jspm_packages/
|
||||
|
||||
# Typescript v1 declaration files
|
||||
@ -57,8 +59,8 @@ typings/
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
|
||||
dist/
|
||||
/package-lock.json
|
||||
/dist
|
||||
src/private/data
|
||||
/nbproject/private/
|
||||
.vscode
|
||||
.serverless
|
||||
.cache
|
32
.travis.yml
Normal file
@ -0,0 +1,32 @@
|
||||
language: node_js
|
||||
|
||||
node_js:
|
||||
- "10.16.3"
|
||||
|
||||
cache:
|
||||
yarn: true
|
||||
directories:
|
||||
- node_modules
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- env: PROJECT=src/private/
|
||||
include:
|
||||
- env: PROJECT=src/public/
|
||||
|
||||
install:
|
||||
- cd $PROJECT
|
||||
- yarn global add serverless
|
||||
- yarn install
|
||||
|
||||
script:
|
||||
- yarn test
|
||||
- yarn build
|
||||
|
||||
deploy:
|
||||
provider: script
|
||||
script:
|
||||
- yarn deploy
|
||||
skip_cleanup: true
|
||||
on:
|
||||
branch: master
|
21
LICENSE
@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Dominic Masters
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
25
README.md
@ -1,25 +0,0 @@
|
||||
|
||||
<p align="center"><font size="36" face=" ms pgothic,courier new,lucida consolas,monospace">domsPlace(); </font></p>
|
||||
|
||||
My personal website, written in Javascript, HTML, CSS using Node, React, SCSS, Webpack and Babel.
|
||||
|
||||
Yet another redesign after many, the site is permanently stuck in limbo as I don't have as much time to work on it as I would like.
|
||||
|
||||
## Roadmap
|
||||
Plans to add are:
|
||||
|
||||
- ~~Favicon~~
|
||||
- Short Blog Page
|
||||
- Featured Video (Code is ready, video needs to be made)
|
||||
- More Social integration and show off my social pages
|
||||
- Faster loading (SVG Backgrounds are quite large)
|
||||
- ~~Responsive Image Loading~~
|
||||
- ~~Async Image/Video loading for content (no point just yet)~~
|
||||
- ~~Async page offsetting,~~ as well as proper loading templates
|
||||
- Improved SEO
|
||||
- Reduce Divitis
|
||||
- Restore previously removed page transitions
|
||||
- ~~Convert some of the SVGs into responsive PNGs~~ Unsure if I'll stick with this permanently
|
||||
- Work on Async Sections
|
||||
- Proper Server
|
||||
- Adjust the order import order so to help CSS Overrides.
|
45
package.json
@ -1,45 +0,0 @@
|
||||
{
|
||||
"name": "domsplace",
|
||||
"version": "6.0.1",
|
||||
"description": "Personal website for Dominic \"YouWish\" Masters.",
|
||||
"main": "dist/private/",
|
||||
"scripts": {
|
||||
"test": "jest",
|
||||
"start": "node dist/private/",
|
||||
"build": "tsc -p . && webpack -p --env.production",
|
||||
"watch": "cross-env NODE_ENV=DEVELOPMENT npm run start",
|
||||
"heroku-postbuild": "tsc -p . && webpack -p --env.production"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/YourWishes/domsPlaceNew.git"
|
||||
},
|
||||
"keywords": [
|
||||
"domsplace",
|
||||
"personal",
|
||||
"portfolio",
|
||||
"website"
|
||||
],
|
||||
"author": "Dominic Masters",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/YourWishes/domsPlaceNew/issues"
|
||||
},
|
||||
"homepage": "https://github.com/YourWishes/domsPlaceNew#readme",
|
||||
"dependencies": {
|
||||
"@types/animejs": "^2.0.2",
|
||||
"@yourwishes/app-email": "^1.0.3",
|
||||
"@yourwishes/app-simple-react": "^2.8.7",
|
||||
"animejs": "^3.0.1",
|
||||
"react-helmet": "^5.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^24.0.15",
|
||||
"cross-env": "^5.2.0",
|
||||
"jest": "^24.1.0",
|
||||
"typescript": "^3.5.3",
|
||||
"webpack-cli": "^3.3.5",
|
||||
"webpack-dev-middleware": "^3.6.1",
|
||||
"webpack-hot-middleware": "^2.24.3"
|
||||
}
|
||||
}
|
3
src/private/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
dist/
|
||||
*.log
|
||||
*.lock
|
@ -1,78 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicen se, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { RESPONSE_OK, RESPONSE_BAD_REQUEST, RESPONSE_INTERNAL_ERROR } from '@yourwishes/app-api';
|
||||
import { ServerAPIRequest, ServerAPIResponse, ServerAPIHandler } from '@yourwishes/app-server';
|
||||
import { isValidEmail } from '@yourwishes/app-email';
|
||||
import { domsPlaceApp } from './../../app/';
|
||||
|
||||
export const EMAIL_MAXLENGTH = 256;
|
||||
export const NAME_MAXLENGTH = 128;
|
||||
export const MESSAGE_MAXLENGTH = 8192;
|
||||
|
||||
export class sendContact extends ServerAPIHandler {
|
||||
constructor() {
|
||||
super('POST', '/contact/send');
|
||||
}
|
||||
|
||||
async onRequest(request:ServerAPIRequest):Promise<ServerAPIResponse> {
|
||||
if(!request.hasString('email', EMAIL_MAXLENGTH)) return { code: RESPONSE_BAD_REQUEST, data: 'Missing or invalid email' };
|
||||
if(!request.hasString('name', NAME_MAXLENGTH)) return { code: RESPONSE_BAD_REQUEST, data: 'Missing or invalid name' };
|
||||
if(!request.hasString('message', MESSAGE_MAXLENGTH)) return { code: RESPONSE_BAD_REQUEST, data: 'Missing or invalid message' };
|
||||
|
||||
let email = request.getString('email', EMAIL_MAXLENGTH);
|
||||
if(!isValidEmail(email)) return { code: RESPONSE_BAD_REQUEST, data: 'Missing or invalid email' };
|
||||
|
||||
let name = request.getString('name', NAME_MAXLENGTH);
|
||||
let message = request.getString('message', MESSAGE_MAXLENGTH);
|
||||
|
||||
//Prepare to send email
|
||||
let app:domsPlaceApp = request.owner.app as domsPlaceApp;
|
||||
|
||||
//First send an email to the site owner
|
||||
request.owner.logger.debug(`Sending email from ${email}...`);
|
||||
let ownRes = await app.email.sendMail(app.domsPlace.contact, 'Contact Message Received', `
|
||||
Contact Message received from ${email}, who wrote:
|
||||
${message}
|
||||
`, `
|
||||
<p>Contact Message received from ${email} who wrote:</p>
|
||||
<p>
|
||||
${ message.replace(/</g, '<').replace(/>/g, '>').replace(/\n/g, '<br />') }
|
||||
</p>
|
||||
`);
|
||||
if(!ownRes) return { code: RESPONSE_INTERNAL_ERROR, data: false };
|
||||
|
||||
//Now Send an email to the client
|
||||
let clientRes = await app.email.sendMail(app.domsPlace.contact, 'Contact Message Sent', `
|
||||
Contact Message Sent! Thanks for reaching out,
|
||||
if this was not you then ignore this email.
|
||||
`, `
|
||||
<p>Contact Message Sent! Thanks for reaching out. If this was not you then ignore this email.</p>
|
||||
`);
|
||||
if(!clientRes) return { code: RESPONSE_INTERNAL_ERROR, data: false };
|
||||
request.owner.logger.debug(`...Done`);
|
||||
|
||||
//OK!
|
||||
return { code: RESPONSE_OK, data: true };
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
export * from './contact/';
|
@ -1,57 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { App } from '@yourwishes/app-base';
|
||||
import { ServerModule } from '@yourwishes/app-server';
|
||||
import { ReactModule } from '@yourwishes/app-react';
|
||||
import { ISimpleReactApp, SimpleReactModule } from '@yourwishes/app-simple-react';
|
||||
import { IEmailApp, EmailModule } from '@yourwishes/app-email';
|
||||
import { domsPlaceModule } from './../module/';
|
||||
|
||||
import { domsPlaceCompiler } from './../compiler/';
|
||||
|
||||
export class domsPlaceApp extends App implements ISimpleReactApp, IEmailApp {
|
||||
server:ServerModule;
|
||||
email:EmailModule;
|
||||
react:ReactModule;
|
||||
simpleReact:SimpleReactModule;
|
||||
domsPlace:domsPlaceModule;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.server = new ServerModule(this);
|
||||
this.email = new EmailModule(this);
|
||||
this.react = new ReactModule(this);
|
||||
this.simpleReact = new SimpleReactModule(this);
|
||||
this.domsPlace = new domsPlaceModule(this);
|
||||
|
||||
[
|
||||
this.server, this.email, this.react, this.simpleReact, this.domsPlace
|
||||
].forEach(e => this.modules.addModule(e));
|
||||
}
|
||||
|
||||
getCompiler() {
|
||||
return new domsPlaceCompiler();
|
||||
}
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { SimpleReactCompiler } from '@yourwishes/app-simple-react';
|
||||
|
||||
const gtag = `<script type="text/javascript" async src="https://www.googletagmanager.com/gtag/js?id=UA-66393210-1"></script>
|
||||
<script type="text/javascript">
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'UA-66393210-1');
|
||||
</script>`;
|
||||
|
||||
const content = `
|
||||
Please Wait...
|
||||
`;
|
||||
|
||||
export class domsPlaceCompiler extends SimpleReactCompiler {
|
||||
constructor() {
|
||||
super({
|
||||
title: 'domsPlace - Personal Site of Dominic Masters',
|
||||
keywords: 'domsplace, programming, gaming, shopify, livestreaming, dominic, masters, dom',
|
||||
description: 'domsPlace is the home of programmer and developer Dominic Masters, specialising in eCommerce and full-stack development solutions for a wide range of platforms, primarily Shopify.',
|
||||
app_handle: 'domsPlace',
|
||||
language: 'en-AU',
|
||||
gtag,
|
||||
page_content: content
|
||||
});
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { domsPlaceApp } from './app/';
|
||||
|
||||
const app = new domsPlaceApp();
|
||||
|
||||
app.init().catch(e => app.logger.error(e));
|
14
src/private/jest.config.js
Normal file
@ -0,0 +1,14 @@
|
||||
module.exports = {
|
||||
"roots": [
|
||||
"<rootDir>/src"
|
||||
],
|
||||
"transform": {
|
||||
"^.+\\.ts?$": "ts-jest"
|
||||
},
|
||||
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.ts?$",
|
||||
"moduleFileExtensions": [
|
||||
"ts",
|
||||
"js",
|
||||
"json"
|
||||
]
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { Module } from '@yourwishes/app-base';
|
||||
import { domsPlaceApp } from './../app/';
|
||||
import { sendContact } from './../api/';
|
||||
|
||||
export const CONFIG_CONTACT = 'domsplace.contact';
|
||||
|
||||
export class domsPlaceModule extends Module {
|
||||
app:domsPlaceApp;
|
||||
contact:string;
|
||||
|
||||
constructor(app:domsPlaceApp) {
|
||||
super(app);
|
||||
|
||||
app.server.api.addAPIHandler(new sendContact());
|
||||
}
|
||||
|
||||
loadPackage() {return require('./../../../package.json');}
|
||||
|
||||
async init(): Promise<void> {
|
||||
let { config } = this.app;
|
||||
if(!config.has(CONFIG_CONTACT)) throw new Error("Missing contact reciving details from configuration!");
|
||||
|
||||
this.contact = config.get(CONFIG_CONTACT);
|
||||
}
|
||||
|
||||
async destroy(): Promise<void> {
|
||||
}
|
||||
}
|
51
src/private/package.json
Normal file
@ -0,0 +1,51 @@
|
||||
{
|
||||
"name": "domsplace-backend",
|
||||
"version": "7.0.0",
|
||||
"description": "Personal website for Dominic \"YouWish\" Masters.",
|
||||
"main": "./dist/private/",
|
||||
"scripts": {
|
||||
"build": "tsc -p .",
|
||||
"start:prod": "cross-env NODE_ENV=production \"serverless offline\"",
|
||||
"start:dev": "cross-env NODE_ENV=development \"serverless offline --port 3001\"",
|
||||
"start": "npm run start:prod",
|
||||
"watch": "npm run start:dev",
|
||||
"deploy": "serverless deploy",
|
||||
"test": "yarn jest"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/YourWishes/domsPlace.git"
|
||||
},
|
||||
"keywords": [
|
||||
"domsplace",
|
||||
"personal",
|
||||
"portfolio",
|
||||
"website"
|
||||
],
|
||||
"author": "Dominic Masters",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/YourWishes/domsPlace/issues"
|
||||
},
|
||||
"homepage": "https://github.com/YourWishes/domsPlace#readme",
|
||||
"dependencies": {
|
||||
"email-validator": "^2.0.4",
|
||||
"nodemailer": "^6.3.0",
|
||||
"serverless-plugin-include-dependencies": "^3.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^25.1.1",
|
||||
"@types/node": "^12.7.1",
|
||||
"@types/nodemailer": "^6.2.1",
|
||||
"cross-env": "^5.2.0",
|
||||
"escape-html": "^1.0.3",
|
||||
"jest": "^24.9.0",
|
||||
"serverless": "^1.51.0",
|
||||
"serverless-finch": "^2.4.3",
|
||||
"serverless-offline": "^5.11.0",
|
||||
"ts-jest": "^24.1.0",
|
||||
"ts-node": "^8.3.0",
|
||||
"typescript": "^3.5.3",
|
||||
"utility-types": "^3.7.0"
|
||||
}
|
||||
}
|
53
src/private/serverless.yml
Normal file
@ -0,0 +1,53 @@
|
||||
org: yourwishes
|
||||
service: domsplace
|
||||
|
||||
frameworkVersion: ">=1.26.0"
|
||||
|
||||
package:
|
||||
excludeDevDependencies: false
|
||||
individually: true
|
||||
include:
|
||||
- dist/**
|
||||
|
||||
provider:
|
||||
name: aws
|
||||
runtime: nodejs10.x
|
||||
stage: ${opt:stage, "prod"}
|
||||
region: ap-southeast-2
|
||||
memorySize: 512
|
||||
deploymentBucket:
|
||||
name: domsplace-${self:provider.stage}-${self:provider.region}-private
|
||||
environment:
|
||||
EMAIL_HOST: ${self:custom.variables.email.host}
|
||||
EMAIL_PORT: ${self:custom.variables.email.port}
|
||||
EMAIL_USER: ${self:custom.variables.email.user}
|
||||
EMAIL_PASS: ${self:custom.variables.email.pass}
|
||||
EMAIL_DEST: ${self:custom.variables.email.dest}
|
||||
|
||||
functions:
|
||||
ping:
|
||||
handler: dist/functions/ping/ping.ping
|
||||
events:
|
||||
- http:
|
||||
method: GET
|
||||
path: ping
|
||||
cors: true
|
||||
sendMail:
|
||||
handler: dist/functions/mail/send.sendMail
|
||||
events:
|
||||
- http:
|
||||
method: POST
|
||||
path: mail/send
|
||||
cors: true
|
||||
|
||||
plugins:
|
||||
- serverless-plugin-include-dependencies
|
||||
- serverless-offline
|
||||
|
||||
custom:
|
||||
ssm: '/aws/reference/secretsmanager/prod.domsPlace.'
|
||||
serverless-offline:
|
||||
disableCookieValidation: true
|
||||
port: 3001
|
||||
variables:
|
||||
email: ${ssm:${self:custom.ssm}email~true}
|
8
src/private/src/functions/mail/__tests__/send.test.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { sendMail } from './../send';
|
||||
|
||||
describe('sendMail', () => {
|
||||
it('should require a body', async () => {
|
||||
await expect(sendMail({ body: null })).resolves.toHaveProperty('statusCode', 400);
|
||||
});
|
||||
|
||||
})
|
56
src/private/src/functions/mail/send.ts
Normal file
@ -0,0 +1,56 @@
|
||||
import { withHandler } from "../../handler/handler";
|
||||
import { validate } from 'email-validator';
|
||||
import { createTransport } from 'nodemailer';
|
||||
import * as escapeHTML from 'escape-html';
|
||||
|
||||
export interface sendMailParams {
|
||||
name:string;
|
||||
email:string;
|
||||
message:string;
|
||||
}
|
||||
|
||||
export const sendMail = withHandler<sendMailParams>(async (e,c) => {
|
||||
if(!e.body) return { statusCode: 400, body: 'Missing Contact Details' };
|
||||
|
||||
let { name, email, message } = e.body;
|
||||
if(!name) return { statusCode: 400, body: 'Missing Contact Name' };
|
||||
if(!email) return { statusCode: 400, body: 'Missing Contact Email' };
|
||||
if(!message) return { statusCode: 400, body: 'Missing Contact Message' };
|
||||
|
||||
//Validate
|
||||
if(name.length > 128 || !name.replace(/\s/g, '').length) return { statusCode: 400, body: 'Invalid Name' };
|
||||
if(!validate(email)) return { statusCode: 400, body: 'Invalid Email' };
|
||||
if(message.length > 10000 || !message.replace(/\s/g,'').length) {
|
||||
return { statusCode: 400, body: 'Invalid Messatge' };
|
||||
}
|
||||
|
||||
//Prepare mail
|
||||
let {
|
||||
EMAIL_HOST, EMAIL_PORT, EMAIL_USER, EMAIL_PASS, EMAIL_DEST, EMAIL_FROM
|
||||
} = process.env
|
||||
|
||||
let transporter = createTransport({
|
||||
host: EMAIL_HOST,
|
||||
port: parseInt(EMAIL_PORT),
|
||||
secure: true,
|
||||
auth: {
|
||||
user: EMAIL_USER, pass: EMAIL_PASS
|
||||
}
|
||||
});
|
||||
|
||||
let x = await transporter.sendMail({
|
||||
from: `${name} <${email}>`,
|
||||
to: EMAIL_DEST,
|
||||
subject: 'Contact Message Received',
|
||||
text: `Contact Message Received:\n${message}\nFrom: ${name} ${email}`,
|
||||
html: `
|
||||
<h1>Contact Message Received</h1>
|
||||
<p>You have received a contact message from ${escapeHTML(name)} - ${escapeHTML(email)} who wrote:</p>
|
||||
<p>
|
||||
${escapeHTML(message)}
|
||||
</p>
|
||||
<span>Time: ${new Date().toLocaleString()}
|
||||
`
|
||||
});
|
||||
return { statusCode: 200, body: x && x.accepted && x.accepted.length ? true : false }
|
||||
});
|
8
src/private/src/functions/ping/__tests__/ping.test.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { ping } from './../ping';
|
||||
|
||||
describe('ping', () => {
|
||||
it('shold return a hello world and a 200 code', async () => {
|
||||
await expect(ping()).resolves.toHaveProperty('body', 'Thank funk!');
|
||||
await expect(ping()).resolves.toHaveProperty('statusCode', 200);
|
||||
})
|
||||
})
|
5
src/private/src/functions/ping/ping.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { withHandler } from "../../handler/handler";
|
||||
|
||||
export const ping = withHandler(async () => {
|
||||
return { statusCode: 200, body: 'Thank funk!' };
|
||||
});
|
43
src/private/src/handler/__tests__/handler.test.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import { withHandler, APICallable, DEFAULT_HEADERS } from './../handler';
|
||||
|
||||
describe('withHandler', () => {
|
||||
it('should wrap an async function into a serverless callbackable function', () => {
|
||||
let callbackable = jest.fn(async () => ({ body: 'Hello World', statusCode: 200 }));
|
||||
let x = withHandler(callbackable);
|
||||
expect(typeof x).toBe('function');
|
||||
});
|
||||
|
||||
it('should call the promise and pass the result to the callback', async () => {
|
||||
let callbackable = async () => ({ body: 'Hello World', statusCode: 200 });
|
||||
let x = withHandler(callbackable);
|
||||
let fn = jest.fn();
|
||||
|
||||
x({} as any, null, fn);
|
||||
|
||||
await new Promise(resolve => setImmediate(resolve));
|
||||
|
||||
expect(fn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should set the content type', async () => {
|
||||
let x = withHandler(async () => ({ body: 'Hello World', statusCode: 200 }));
|
||||
let fn = jest.fn();
|
||||
|
||||
x({} as any, null, fn);
|
||||
|
||||
await new Promise(resolve => setImmediate(resolve));
|
||||
|
||||
expect(fn).toHaveBeenCalledWith(null, { body: '"Hello World"', statusCode: 200,
|
||||
headers: DEFAULT_HEADERS
|
||||
});
|
||||
});
|
||||
|
||||
it('should return the invoked functions returned promise', async () => {
|
||||
let x = withHandler(async () => ({ body: 'Hello World', statusCode: 200 }));
|
||||
let fn = jest.fn();
|
||||
let prom = x({} as any, null, fn);
|
||||
|
||||
let result = await prom;
|
||||
expect(result).toStrictEqual({ body: 'Hello World', statusCode: 200 });
|
||||
})
|
||||
})
|
71
src/private/src/handler/handler.ts
Normal file
@ -0,0 +1,71 @@
|
||||
export const DEFAULT_HEADERS = {
|
||||
'Content-Type': 'application/json',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Credentials': true
|
||||
}
|
||||
|
||||
export type APIResponse = {
|
||||
statusCode?:number;
|
||||
body:any;
|
||||
headers?:{
|
||||
[key:string]:string,
|
||||
"Content-Type"?:string
|
||||
};
|
||||
}
|
||||
|
||||
export type APICallable<T=any> = (event:APIEvent<T>, context:any) => Promise<APIResponse>;
|
||||
|
||||
export type APIMethod = 'GET'|'POST'|'PUT'|'PATCH'|'DELETE'|'TRACE'|'OPTIONS'|'CONNECT';
|
||||
|
||||
export interface APIEvent<T=any> {
|
||||
body:T;
|
||||
headers?:{[key:string]:string};
|
||||
httpMethod?:APIMethod;
|
||||
isOffline?:boolean;
|
||||
multiValueHeaders?:{[key:string]:string};
|
||||
multiValueQueryStringParameters?:{[key:string]:string};
|
||||
path?:string;
|
||||
pathParameters?:never;
|
||||
queryStringParameters?:{[key:string]:string};
|
||||
requestContext?:{[key:string]:string};
|
||||
resource?:string;
|
||||
stageVariables?:any;
|
||||
}
|
||||
|
||||
export const withHandler = <T=any>(callable:APICallable<T>) => {
|
||||
return (event?:APIEvent<T>, context?, callback?) => {
|
||||
try {
|
||||
if(!event) throw new Error();
|
||||
if(event.body) event.body = JSON.parse(event.body as any) as T;
|
||||
} catch(e) {
|
||||
console.error(e);
|
||||
callback(null, {
|
||||
statusCode: 400, headers: DEFAULT_HEADERS,
|
||||
body: JSON.stringify('Invalid body')
|
||||
});
|
||||
}
|
||||
|
||||
return callable(event, context).then(d => {
|
||||
if(!callback) return d;
|
||||
let contentType = (d.headers?d.headers['Content-Type']:null) || 'application/json';
|
||||
let json = contentType.indexOf('application/json') !== -1;
|
||||
|
||||
callback(null, {
|
||||
...d,
|
||||
body: json ? JSON.stringify(d.body) : d.body,
|
||||
statusCode: d.statusCode || 200,
|
||||
headers: {
|
||||
...DEFAULT_HEADERS,
|
||||
...(d.headers||{})
|
||||
}
|
||||
});
|
||||
|
||||
return d;
|
||||
}).catch(ex => {
|
||||
if(callback) {
|
||||
callback(null, { statusCode: 500, body: null, headers: DEFAULT_HEADERS });
|
||||
}
|
||||
throw ex;
|
||||
})
|
||||
};
|
||||
}
|
14
src/private/tsconfig.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist",
|
||||
"target": "es5",
|
||||
"module": "commonjs",
|
||||
"noImplicitAny": false,
|
||||
"sourceMap": true,
|
||||
"baseUrl": "./src/"
|
||||
},
|
||||
"include": [
|
||||
"./src/**/*.ts"
|
||||
],
|
||||
"exclude": ["node_modules", "**/*.test.ts"]
|
||||
}
|
2
src/public/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
public/
|
||||
*.lock
|
@ -1,26 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
export type domsPlaceActions = (
|
||||
null
|
||||
);
|
@ -1,47 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import './../styles/theme';
|
||||
|
||||
import * as React from 'react';
|
||||
import { App, Router } from '@yourwishes/app-simple-react/dist/public';
|
||||
|
||||
import { domsPlaceState } from './../state/';
|
||||
import { domsPlaceActions } from './../actions/';
|
||||
import { domsPlaceReducer } from './../reducer/';
|
||||
|
||||
import { LayoutComponent } from './../components/layout/layout';
|
||||
|
||||
export class domsPlaceApp extends App<domsPlaceState, domsPlaceActions> {
|
||||
constructor() {
|
||||
super("domsPlace");
|
||||
}
|
||||
|
||||
getReducer() { return domsPlaceReducer; }
|
||||
|
||||
getComponent() {
|
||||
return (
|
||||
<LayoutComponent history={this.history} />
|
||||
);
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
<svg version="1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 1080">
|
||||
<style type="text/css">
|
||||
@keyframes fade-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(12%);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0%);
|
||||
}
|
||||
}
|
||||
|
||||
.o-circle {
|
||||
opacity: 0;
|
||||
animation: fade-in 3s forwards cubic-bezier(0.165, 0.84, 0.44, 1);
|
||||
}
|
||||
|
||||
.o-circle.is-first { animation-delay: 0.5s; }
|
||||
.o-circle.is-second { animation-delay: 0.75s; }
|
||||
.o-circle.is-third { animation-delay: 1s; }
|
||||
</style>
|
||||
|
||||
<linearGradient id="sky" gradientUnits="userSpaceOnUse" y1="540" x2="1920" y2="540">
|
||||
<stop offset="0"/>
|
||||
<stop offset="1"/>
|
||||
</linearGradient>
|
||||
|
||||
<path fill="#000010" d="M0 0h1920v1080H0z"/>
|
||||
<path d="M1919 1v1078H1V1h1918m1-1H0v1080h1920V0z" fill="url(#sky)"/>
|
||||
|
||||
<g>
|
||||
<circle cx="960" cy="5540" r="5000" fill="#00001e" class="o-circle is-first" />
|
||||
<circle cx="960" cy="5540" r="4850" fill="#000329" class="o-circle is-second" />
|
||||
<circle cx="960" cy="5540" r="4700" fill="#000730" class="o-circle is-third"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.1 KiB |
@ -1,37 +0,0 @@
|
||||
<svg version="1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 1080">
|
||||
<style type="text/css">
|
||||
@keyframes fade-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(12%);
|
||||
}
|
||||
to {
|
||||
opacity: 0.4;
|
||||
transform: translateY(0%);
|
||||
}
|
||||
}
|
||||
|
||||
.o-circle {
|
||||
opacity: 0;
|
||||
animation: fade-in 3s forwards cubic-bezier(0.165, 0.84, 0.44, 1);
|
||||
}
|
||||
|
||||
.o-circle.is-first { animation-delay: 0.5s; }
|
||||
.o-circle.is-second { animation-delay: 0.75s; }
|
||||
.o-circle.is-third { animation-delay: 1s; }
|
||||
</style>
|
||||
|
||||
<linearGradient id="sky-twilight" x2="0%" y2="100%">
|
||||
<stop offset="00%" style="stop-color:#200044;stop-opacity:1" />
|
||||
<stop offset="40%" style="stop-color:#260036;stop-opacity:1" />
|
||||
<stop offset="100%" style="stop-color:#703;stop-opacity:1"/>
|
||||
</linearGradient>
|
||||
|
||||
<path d="M0 0h1920v1080H0z" fill="url(#sky-twilight)"/>
|
||||
|
||||
<g>
|
||||
<circle cx="960" cy="5640" r="5000" fill="#00001e" class="o-circle is-first" />
|
||||
<circle cx="960" cy="5600" r="4850" fill="#000329" class="o-circle is-second" />
|
||||
<circle cx="960" cy="5540" r="4700" fill="#000730" class="o-circle is-third"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.1 KiB |
@ -1,3 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50">
|
||||
<path d="M9.2 6.3L6.3 9.2 22.2 25l-16 16L9 43.8l16-16 16 16 2.8-2.9-16-15.9L43.7 9.2l-2.9-2.9L25 22.2z"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 176 B |
@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32.58 31.77"><path d="M16.29 0a16.29 16.29 0 0 0-5.15 31.75c.81.15 1.11-.35 1.11-.79l-.02-2.77c-4.53.98-5.49-2.18-5.49-2.18-.74-1.88-1.81-2.39-1.81-2.39-1.48-1.01.11-.99.11-.99 1.63.12 2.5 1.68 2.5 1.68 1.45 2.49 3.81 1.77 4.74 1.35a3.54 3.54 0 0 1 1.03-2.18c-3.61-.4-7.41-1.8-7.41-8.04 0-1.78.63-3.23 1.68-4.37a5.86 5.86 0 0 1 .15-4.31s1.37-.44 4.48 1.67a15.8 15.8 0 0 1 4.08-.55c1.38.01 2.78.19 4.08.55 3.11-2.11 4.48-1.67 4.48-1.67.89 2.24.33 3.9.16 4.31a6.3 6.3 0 0 1 1.67 4.37c0 6.26-3.81 7.63-7.44 8.04.58.5 1.11 1.5 1.11 3.02l-.02 4.47c0 .44.29.94 1.12.78A16.3 16.3 0 0 0 16.29 0z" fill-rule="evenodd" clip-rule="evenodd" fill="#181616"/></svg>
|
Before Width: | Height: | Size: 705 B |
@ -1,3 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24">
|
||||
<path d="M2 11h20v2H2zM2 5h20v2H2zM2 17h20v2H2z" fill="#FFF" />
|
||||
</svg>
|
Before Width: | Height: | Size: 137 B |
@ -1,6 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<path
|
||||
d="M12.2 6.2C10 12.1 9.5 12.6 4.9 14c-2.7.8-4.9 1.7-4.9 2 0 .3 2.2 1.2 4.9 2 4.6 1.4 5.1 1.9 7.3 7.7 1.3 3.5 2.7 6.3 3.1 6.3.4 0 1.8-2.8 3.1-6.3 2.2-5.8 2.7-6.3 7.3-7.7 2.7-.8 4.9-1.7 4.9-2 0-.3-2.2-1.2-4.9-2-4.6-1.4-5.1-1.9-7.3-7.8A25.6 25.6 0 0 0 15.3 0c-.4 0-1.8 2.8-3.1 6.2z"
|
||||
fill="white"
|
||||
/>
|
||||
</svg>
|
Before Width: | Height: | Size: 382 B |
Before Width: | Height: | Size: 7.1 KiB |
@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><linearGradient id="a" gradientUnits="userSpaceOnUse" y1="128" x2="256" y2="128" gradientTransform="rotate(90 128 128)"><stop offset="0" stop-color="#9300bf"/><stop offset="1" stop-color="#3f0073"/></linearGradient><path fill="url(#a)" d="M0 0h256v256H0z"/><g fill="#FFF"><path d="M31.6 108.1l4.8-.2 10.7 30 4 .9v2.9h-14v-2.9l4.5-.9-1.8-5.4H27.3l-1.9 5.4 4.5.9v2.9H16.7v-2.9l4-.9 10.9-29.8zm2.1 6l-5.1 14.5h9.9l-4.8-14.5zM60.4 118.4c1.6-1.3 4.1-2.8 7.2-2.8 7 0 10.1 5.1 10.1 12.6 0 8.2-4.6 14-13.3 14-5.3 0-8.9-1.2-8.9-1.2v-32.6l-3.9-1v-2.7l8.7-.2v13.9zm0 19.4s1.3.5 4.8.5c5.6 0 7.5-4.3 7.5-9.7 0-5.3-1.7-9.2-6-9.2a7.7 7.7 0 0 0-6.3 3.1v15.3zM105.5 128.4c0 8.2-4.8 13.8-12.1 13.8s-11.6-4.3-11.6-13c0-8.2 5.1-13.5 12.3-13.5s11.4 5 11.4 12.7zm-18.5.5c0 5.8 1.9 9.4 6.8 9.4 4.8 0 6.8-3.4 6.8-9.7 0-5.3-1.7-9.2-6.5-9.2-5 .1-7.1 3.2-7.1 9.5zM137.7 141.4l-8 .2-.5-3.4c-1.2 1-5 3.9-8.9 3.9-5.3 0-7.7-3.3-7.7-8.6v-13.6l-4.1-1v-2.7l8.9-.2v17c0 3.4 1.2 5 4.3 5 4.1 0 7-3.8 7-3.8v-14.3l-4.1-1v-2.7l8.9-.2v21.7l4.1 1v2.7zM156.5 119.9h-7v15.5c0 2.2 1.1 2.9 2.4 2.9 1.2 0 2.5-.5 3.8-1.2l1.3 2.6a11 11 0 0 1-6.8 2.4c-2.9 0-5.6-1.6-5.6-7v-15.2h-4.8v-3.1l4.8-.5v-6.1l4.8-1v7.1h7v3.6zM200.9 113.7l-1.4 3.6-7.5 15.2-3.9.2-7.5-15.7-1.2-3.4v24.1l4.6 1v2.9h-13v-2.9l4.1-1v-26.1l-4.1-1v-2.7l10.9-.2 8.7 19.3 9.1-19.1 10.1-.2v2.9l-4.1 1v26.1l4.1 1v2.9h-13.5v-2.9l4.6-1v-24zM218.8 129.6c0 5.3 2.8 8.7 7 8.7 4.8 0 8.1-2.7 8.1-2.7l1.7 2.5s-4.5 4-10.3 4c-7.7 0-11.6-5.1-11.6-13 0-7.7 4.8-13.5 11.8-13.5s10.1 4.1 10.1 11.3l-.2 2.7h-16.6zm11.8-3.6c0-3.6-1.4-6.6-5.3-6.6s-6 3-6.3 6.6h11.6z"/></g></svg>
|
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 2.3 KiB |
@ -1,31 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 256 256" enable-background="new 0 0 256 256" xml:space="preserve">
|
||||
<g id="Layer_1">
|
||||
<g>
|
||||
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="0" y1="128" x2="256" y2="128" gradientTransform="matrix(0 1 -1 0 256 0)">
|
||||
<stop offset="1.953869e-07" style="stop-color:#9300BF"/>
|
||||
<stop offset="1" style="stop-color:#3F0073"/>
|
||||
</linearGradient>
|
||||
<rect fill="url(#SVGID_1_)" width="256" height="256"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="G">
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M83.5,111.7l-4.1-1v-2.7l8.9-0.2h5.6c6,0,10.4,2.7,10.4,8.5c0,4.3-2.2,6.8-6.3,7.8c5.1,1.2,7.5,4,7.5,7.9
|
||||
c0,6.8-4.3,9.7-12.3,9.7H79.4v-2.9l4.1-1V111.7z M92,122.4c4.3,0,7.2-1.7,7.2-5.6c0-3.4-2.4-5.1-5.6-5.1h-5.3v10.6H92z
|
||||
M93.4,137.8c4.6,0,7-1.9,7-5.6c0-4.8-3.1-6.3-8.5-6.3h-3.6v11.8H93.4z"/>
|
||||
<path fill="#FFFFFF" d="M122.5,141.7h-13.4V139l4.1-1.2v-29.5l-4.1-1v-2.7l9-0.2v33.3l4.3,1.2V141.7z"/>
|
||||
<path fill="#FFFFFF" d="M148.3,128.4c0,8.2-4.8,13.8-12.1,13.8s-11.6-4.3-11.6-13c0-8.2,5.1-13.5,12.3-13.5
|
||||
S148.3,120.7,148.3,128.4z M129.7,128.9c0,5.8,1.9,9.4,6.8,9.4c4.8,0,6.8-3.4,6.8-9.7c0-5.3-1.7-9.2-6.5-9.2
|
||||
C131.9,119.5,129.7,122.6,129.7,128.9z"/>
|
||||
<path fill="#FFFFFF" d="M172.6,119.6c0,0,1.3,1.7,1.3,4.9c0,6.5-4.3,9.4-10.6,9.4c-2.2,0-3.6-0.4-3.6-0.4l-0.2,4.5h7.5
|
||||
c6.3,0,9.7,2.4,9.7,7c0,5.3-4.1,8.7-12.6,8.7c-6.8,0-11.6-1.7-11.6-7c0-4.3,5.1-6,5.1-6s-2.9-0.2-2.9-2.8c0-1.6,2.5-5.5,2.5-5.5
|
||||
s-3.7-1.7-3.7-7.5c0-6.3,4.3-9.4,10.6-9.4c3.1,0,4.8,0.9,4.8,0.9l8.5-0.2v2.7L172.6,119.6z M160.4,141.7c0,0-3.1,1.4-3.1,4.3
|
||||
c0,3.4,2.9,4.1,7.5,4.1c4.8,0,7.2-1.4,7.2-4.6c0-3.1-2.4-3.9-6.3-3.9H160.4z M158.2,124.8c0,3.4,1.7,5.8,5.3,5.8
|
||||
c3.9,0,5.6-1.7,5.6-5.8c0-3.6-1.7-5.8-5.3-5.8C159.9,119,158.2,120.9,158.2,124.8z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.9 KiB |
@ -1,35 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 256 256" enable-background="new 0 0 256 256" xml:space="preserve">
|
||||
<g id="Layer_1">
|
||||
<g>
|
||||
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="0" y1="128" x2="256" y2="128" gradientTransform="matrix(0 1 -1 0 256 0)">
|
||||
<stop offset="1.953869e-07" style="stop-color:#9300BF"/>
|
||||
<stop offset="1" style="stop-color:#3F0073"/>
|
||||
</linearGradient>
|
||||
<rect fill="url(#SVGID_1_)" width="256" height="256"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="G">
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M61.8,112.5c0,0-2.6-1-6.2-1c-6.5,0-10.1,4.8-10.1,13.8c0,8.7,4.3,12.6,10.4,12.6c5.1,0,9.7-3.9,9.7-3.9
|
||||
l1.9,3.1c0,0-4.8,5.1-12.1,5.1c-9.7,0-15.5-5.8-15.5-16.7c0-11.1,6.3-18.1,16.2-18.1c5.3,0,10.9,2.4,10.9,2.4l-0.2,8.2h-3.6
|
||||
L61.8,112.5z"/>
|
||||
<path fill="#FFFFFF" d="M94.8,128.4c0,8.2-4.8,13.8-12.1,13.8s-11.6-4.3-11.6-13c0-8.2,5.1-13.5,12.3-13.5S94.8,120.7,94.8,128.4z
|
||||
M76.2,128.9c0,5.8,1.9,9.4,6.8,9.4c4.8,0,6.8-3.4,6.8-9.7c0-5.3-1.7-9.2-6.5-9.2C78.4,119.5,76.2,122.6,76.2,128.9z"/>
|
||||
<path fill="#FFFFFF" d="M107.1,119.5c1.2-1,5-3.9,9-3.9c5.3,0,7.7,3.4,7.7,8.7v13.5l3.6,1.2v2.7h-11.6V139l3.1-1.2v-13
|
||||
c0-3.4-1.2-5.1-4.3-5.1c-4.1,0-7,3.9-7,3.9v14.2l3.1,1.2v2.7H98.7V139l4.1-1.2v-17.9l-4.1-1v-2.7l8-0.2L107.1,119.5z"/>
|
||||
<path fill="#FFFFFF" d="M146.5,119.9h-7v15.5c0,2.2,1.1,2.9,2.4,2.9c1.2,0,2.5-0.5,3.8-1.2l1.3,2.6c-2.2,1.6-4.3,2.4-6.8,2.4
|
||||
c-2.9,0-5.6-1.6-5.6-7v-15.2h-4.8v-3.1l4.8-0.5v-6.1l4.8-1v7.1h7V119.9z"/>
|
||||
<path fill="#FFFFFF" d="M151.5,117.5c0,0,5.3-1.9,9.4-1.9c5.6,0,8.9,1.9,8.9,7.5v14.7l3.9,1v2.7l-7.5,0.2l-1-3.4
|
||||
c-1.6,1.6-4.5,3.9-7.9,3.9c-4.6,0-7.2-2.7-7.2-7.2c0-5.6,4.3-7.5,11.1-7.5h3.9v-3.9c0-2.9-1.7-4.3-4.6-4.3c-2.9,0-4.9,0.7-4.9,0.7
|
||||
l-0.7,3.6h-3.1L151.5,117.5z M161.7,130.6c-4.8,0-6.7,1.2-6.7,4.1c0,2.2,1.4,3.6,3.5,3.6c3.6,0,6.5-3.9,6.5-3.9v-3.9H161.7z"/>
|
||||
<path fill="#FFFFFF" d="M193.8,119.9c0,0-1.9-0.5-4.3-0.5c-4.6,0-7.2,2.9-7.2,8.9c0,6.5,2.9,9.9,7.5,9.9s7.5-2.9,7.5-2.9l1.7,2.9
|
||||
c0,0-4.3,3.9-9.7,3.9c-8,0-12.1-5.1-12.1-13.3c0-7.7,4.8-13.3,12.6-13.3c4.3,0,8.2,1.9,8.2,1.9l-0.2,6.5h-3.1L193.8,119.9z"/>
|
||||
<path fill="#FFFFFF" d="M217.5,119.9h-7v15.5c0,2.2,1.1,2.9,2.4,2.9c1.2,0,2.5-0.5,3.8-1.2l1.3,2.6c-2.2,1.6-4.3,2.4-6.8,2.4
|
||||
c-2.9,0-5.6-1.6-5.6-7v-15.2h-4.8v-3.1l4.8-0.5v-6.1l4.8-1v7.1h7V119.9z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 2.4 KiB |
@ -1,53 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as React from 'react';
|
||||
|
||||
import './styles.scss';
|
||||
|
||||
export const Star = (props:{star:number}) => {
|
||||
return (
|
||||
<div className={`c-star-background__star is-star-${props.star+1}`}>
|
||||
<div className="c-star-background__star-image" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export class StarBackground extends React.Component<any,any> {
|
||||
constructor(props:any) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
let stars =[];
|
||||
for(let i = 0; i < 12; i++) stars.push(<Star key={i} star={i} />);
|
||||
|
||||
return (
|
||||
<div className="c-star-background">
|
||||
<div className="c-star-background__inner">
|
||||
{ stars }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
@import './../../../styles/global';
|
||||
|
||||
@keyframes c-star-background--wobble {
|
||||
0% {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
.c-star-background {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: $s-z--background;
|
||||
|
||||
&__inner {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
z-index: $s-z--background;
|
||||
}
|
||||
|
||||
&__star {
|
||||
position: absolute;
|
||||
|
||||
&-image {
|
||||
width: 1.2em;
|
||||
height: 1.2em;
|
||||
transform: translate(-50%, -50%);
|
||||
background: url('./../../../assets/icons/icon-star.svg');
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
|
||||
animation: c-star-background--wobble $s-animation--time-very-long $s-animation--ease-in-out infinite;
|
||||
}
|
||||
|
||||
//Styles
|
||||
&.is-star-1 { left: 5%; top: 10%; transform: scale(0.5); }
|
||||
&.is-star-2 { left: 10%; top: 50%; opacity: 0.5; }
|
||||
&.is-star-3 { left: 20%; top: 25%; opacity: 0.9; transform: scale(0.75); }
|
||||
&.is-star-4 { left: 35%; top: 35%; opacity: 0.7; }
|
||||
&.is-star-5 { left: 45%; top: 5%; transform: scale(0.8); }
|
||||
&.is-star-6 { left: 65%; top: 15%; transform: scale(0.5); }
|
||||
&.is-star-7 { left: 75%; top: 30%; opacity: 0.75; transform: scale(0.75); }
|
||||
&.is-star-8 { left: 85%; top: 10%; }
|
||||
&.is-star-9 { left: 85%; top: 45%; opacity: 0.55; transform: scale(0.5); }
|
||||
&.is-star-10 { left: 95%; top: 35%; opacity: 0.7; }
|
||||
&.is-star-11 { left: 50%; top: 50%; }
|
||||
&.is-star-12 { left: 45%; top: 40%; transform: scale(0.7); }
|
||||
}
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as React from 'react';
|
||||
import { Link, LinkProps } from '@yourwishes/app-simple-react/dist/public';
|
||||
import { Logo } from './../../../objects/logo/';
|
||||
|
||||
import './styles.scss';
|
||||
|
||||
//FooterLinks
|
||||
export const FooterLink = (props:LinkProps) => (
|
||||
<Link {...props} className={`c-footer__navigation-link ${props.className||""}`} />
|
||||
);
|
||||
|
||||
//Footer
|
||||
export interface FooterProps extends React.HTMLAttributes<HTMLElement> {}
|
||||
export interface FooterState {
|
||||
now:Date
|
||||
};
|
||||
|
||||
export class Footer extends React.Component<FooterProps, FooterState> {
|
||||
interval:NodeJS.Timeout;
|
||||
|
||||
constructor(props:FooterProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
now: new Date()
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.interval = setInterval(() => this.setState({ now: new Date() }), 1000);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if(this.interval) clearInterval(this.interval);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<footer {...this.props} className={`c-footer ${this.props.className||""}`}>
|
||||
<span className="c-footer__copyright">
|
||||
© 2012 ~ { this.state.now.getFullYear() } Dominic Masters
|
||||
</span>
|
||||
|
||||
<Logo className="c-footer__logo" />
|
||||
|
||||
<nav className="c-footer__navigation">
|
||||
<FooterLink to="/contact">Contact Me</FooterLink>
|
||||
<FooterLink to="/legal/privacy">Privacy Policy</FooterLink>
|
||||
</nav>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
@import './../../../styles/global';
|
||||
|
||||
.c-footer {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
padding: $s-gutter--small;
|
||||
background: $s-color--background-footer;
|
||||
|
||||
&__copyright,
|
||||
&__navigation {
|
||||
font-family: $s-font--family-heading;
|
||||
width: 100%;
|
||||
font-size: 0.75em;
|
||||
margin-bottom: 1em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__navigation {
|
||||
&-link {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
|
||||
+ #{&} {
|
||||
margin-left: 1em;
|
||||
|
||||
&::before {
|
||||
content: "|";
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
transform: translateX(-0.5em) translateX(-50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__logo {
|
||||
display: none;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
width: auto;
|
||||
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
|
||||
img { width: 120px; margin: auto; }
|
||||
}
|
||||
|
||||
@include t-media-query($s-small-up) {
|
||||
&__copyright,
|
||||
&__navigation {
|
||||
width: auto;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
&__logo {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
@include t-media-query($s-medium-up) {
|
||||
&__copyright,
|
||||
&__navigation {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
&__logo img { width: 150px; }
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as React from 'react';
|
||||
import { Link, LinkProps } from '@yourwishes/app-simple-react/dist/public';
|
||||
|
||||
export interface MenuLinkProps extends LinkProps {
|
||||
to:string,
|
||||
title:string,
|
||||
exact?:boolean
|
||||
};
|
||||
|
||||
export const MenuLink = (props:MenuLinkProps) => {
|
||||
return (
|
||||
<Link className="c-hamburger__link" {...props} activeClassName="is-active">
|
||||
{ props.title }
|
||||
</Link>
|
||||
);
|
||||
};
|
@ -1,42 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as React from 'react';
|
||||
|
||||
import { Link, Image, ImageSource } from '@yourwishes/app-simple-react/dist/public';
|
||||
|
||||
export interface MenuSocialProps {
|
||||
to:string,
|
||||
title?:string,
|
||||
src:ImageSource
|
||||
};
|
||||
|
||||
export const MenuSocial = (props:MenuSocialProps) => {
|
||||
let { to, title, src } = props;
|
||||
|
||||
return (
|
||||
<Link to={to} title={title} className={`c-hamburger__social-link is-${title.toLowerCase()}`}>
|
||||
<Image src={src} className="c-hamburger__social-link-image" />
|
||||
</Link>
|
||||
);
|
||||
};
|
@ -1,99 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as React from 'react';
|
||||
import { Image } from '@yourwishes/app-simple-react/dist/public/';
|
||||
import { MenuLink, MenuLinkProps } from './MenuLink';
|
||||
import { MenuSocial, MenuSocialProps } from './MenuSocial';
|
||||
|
||||
import './styles.scss';
|
||||
|
||||
export interface HamburgerMenuProps { className?:string, links:MenuLinkProps[], social:MenuSocialProps[] }
|
||||
export interface HamburgerMenuState { open:boolean }
|
||||
|
||||
export class HamburgerMenu extends React.Component<HamburgerMenuProps, HamburgerMenuState> {
|
||||
menu:HTMLDivElement;
|
||||
clickEvent;
|
||||
|
||||
constructor(props:HamburgerMenuProps) {
|
||||
super(props);
|
||||
|
||||
this.clickEvent = this.onClickMenu.bind(this);
|
||||
this.state = { open: false };
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.menu.addEventListener('click', this.clickEvent);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.menu.removeEventListener('click', this.clickEvent);
|
||||
}
|
||||
|
||||
onClick(e:React.MouseEvent<HTMLButtonElement, MouseEvent>) {
|
||||
this.setState({ open: !this.state.open });
|
||||
}
|
||||
|
||||
onClickMenu(e:MouseEvent) {
|
||||
if(e.target !== this.menu) return;
|
||||
e.preventDefault();
|
||||
this.setState({ open: !this.state.open });
|
||||
}
|
||||
|
||||
onItemClick(e:React.MouseEvent<HTMLAnchorElement, MouseEvent>) {
|
||||
this.setState({ open: false });
|
||||
}
|
||||
|
||||
render () {
|
||||
let { className, links, social } = this.props;
|
||||
let { open } = this.state;
|
||||
|
||||
return (
|
||||
<nav className={`c-hamburger ${className||""} ${open?'is-open':'is-closed'}`}>
|
||||
<button className="c-hamburger__btn" type="button" onClick={e => this.onClick(e)}>
|
||||
<div className="c-hamburger__btn-inner">
|
||||
<Image
|
||||
src={require('./../../../../assets/icons/icon-hamburger.svg')}
|
||||
className="c-hamburger__btn-icon is-open"
|
||||
/>
|
||||
|
||||
<Image
|
||||
src={require('./../../../../assets/icons/icon-close.svg')}
|
||||
className="c-hamburger__btn-icon is-close"
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<div className="c-hamburger__menu" ref={e => this.menu = e }>
|
||||
<div className="c-hamburger__menu-body">
|
||||
{ links.map((link,i) => <MenuLink {...link} key={i} onClick={e => this.onItemClick(e)} /> )}
|
||||
|
||||
<div className="c-hamburger__social">
|
||||
{ social.map((sc,i) => <MenuSocial {...sc} key={i} />) }
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
};
|
@ -1,91 +0,0 @@
|
||||
@import './../../../../styles/global';
|
||||
|
||||
.c-hamburger {
|
||||
$self: &;
|
||||
|
||||
&__btn {
|
||||
display: inline-block;
|
||||
padding: $s-gutter--xsmall;
|
||||
|
||||
&-inner {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&-icon{
|
||||
transition: all $s-animation--time-fast $s-animation--ease-out;
|
||||
z-index: $s-z--menu + 1;
|
||||
|
||||
&.is-close {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
heigth: 100%;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#{$self}.is-open & {
|
||||
&-icon {
|
||||
opacity: 0;
|
||||
&.is-close { opacity: 1; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__menu {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
transform: translateX(-100%);
|
||||
transition: all $s-animation--time-fast $s-animation--ease-out;
|
||||
z-index: $s-z--menu;
|
||||
|
||||
&-body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: white;
|
||||
max-width: 300px;
|
||||
padding-top: $s-gutter--large;
|
||||
}
|
||||
|
||||
#{$self}.is-open & {
|
||||
transform: translateX(0);
|
||||
&-body {
|
||||
box-shadow: 0px 0px 2em rgba(0,0,0,0.9);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__link {
|
||||
display: block;
|
||||
padding: $s-gutter--small $s-gutter--small;
|
||||
border-left: 0.4em solid transparent;
|
||||
color: black;
|
||||
|
||||
&.is-active { border-color: $s-color--primary; }
|
||||
}
|
||||
|
||||
&__social {
|
||||
width: 100%;
|
||||
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
&-link {
|
||||
display: block;
|
||||
width: 20%;
|
||||
width: calc(20% - #{$s-gutter--xsmall / 2});
|
||||
margin-top: $s-gutter--xsmall;
|
||||
padding: $s-gutter--xsmall;
|
||||
border-radius: 100%;
|
||||
|
||||
&.is-github { background: $s-social--github-background; }
|
||||
|
||||
+ #{&} { margin-left: calc(#{$s-gutter--xsmall} + 0); }
|
||||
}
|
||||
}
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as React from 'react';
|
||||
import { Logo } from './../../../objects/logo/';
|
||||
import { HamburgerMenu } from './hamburger/';
|
||||
import { HeaderNav } from './nav/';
|
||||
|
||||
import './styles.scss';
|
||||
|
||||
|
||||
export const Links = [
|
||||
{ title: 'Home', exact: true, to: '/' },
|
||||
{ title: 'About', exact: true, to: '/about' },
|
||||
{ title: 'Blog', exact: true, to: '/blog' }
|
||||
];
|
||||
|
||||
|
||||
export const Social = [
|
||||
{ title: 'GitHub', to: '//github.com/YourWishes', src: require('./../../../assets/icons/icon-github.svg') }
|
||||
];
|
||||
|
||||
|
||||
export interface HeaderProps extends React.HTMLAttributes<HTMLElement> { }
|
||||
export interface HeaderState {
|
||||
now:Date
|
||||
}
|
||||
|
||||
export class Header extends React.Component<HeaderProps, HeaderState> {
|
||||
time:NodeJS.Timeout;
|
||||
|
||||
constructor(props:HeaderProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
now: new Date()
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.time = setInterval(() => {
|
||||
this.setState({ now: new Date() });
|
||||
}, 500);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if(this.time) clearInterval(this.time);
|
||||
}
|
||||
|
||||
render() {
|
||||
let { className } = this.props;
|
||||
let { now } = this.state;
|
||||
|
||||
let pz = (n:number) => (`${n}`).padStart(2,'0');
|
||||
|
||||
return (
|
||||
<header {...this.props} className={`c-header ${className||""}`}>
|
||||
<HamburgerMenu className="c-header__hamburger" links={Links} social={Social} />
|
||||
<Logo className="c-header__logo" />
|
||||
<HeaderNav className="c-header__nav" links={Links} social={Social} />
|
||||
|
||||
<span className="c-header__time">
|
||||
{pz(now.getHours())}<span className="c-header__time-colon">:</span>{pz(now.getMinutes())}
|
||||
</span>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as React from 'react';
|
||||
import { Link } from '@yourwishes/app-simple-react/dist/public';
|
||||
|
||||
export interface HeaderNavLinkProps {
|
||||
to:string,
|
||||
title:string,
|
||||
exact?:boolean
|
||||
}
|
||||
|
||||
export const HeaderNavLink = (props:HeaderNavLinkProps) => {
|
||||
|
||||
return (
|
||||
<Link className="c-header-nav__link" {...props} activeClassName="is-active">
|
||||
<span className="c-header-nav__link-inner">
|
||||
{ props.title }
|
||||
</span>
|
||||
</Link>
|
||||
);
|
||||
};
|
@ -1,41 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as React from 'react';
|
||||
import { Link, Image, ImageSource } from '@yourwishes/app-simple-react/dist/public';
|
||||
|
||||
export interface HeaderNavSocialProps {
|
||||
to:string,
|
||||
title?:string,
|
||||
src:ImageSource
|
||||
}
|
||||
|
||||
export const HeaderNavSocial = (props:HeaderNavSocialProps) => {
|
||||
let { to, title, src } = props;
|
||||
|
||||
return (
|
||||
<Link to={to} title={title} className={`c-header-nav__social-link is-${title.toLowerCase()}`}>
|
||||
<Image src={src} className="c-header-nav__social-link-image" />
|
||||
</Link>
|
||||
);
|
||||
};
|
@ -1,51 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as React from 'react';
|
||||
import { Link, Image } from '@yourwishes/app-simple-react/dist/public';
|
||||
import { HeaderNavLink, HeaderNavLinkProps } from './HeaderNavLink';
|
||||
import { HeaderNavSocial, HeaderNavSocialProps } from './HeaderNavSocial';
|
||||
|
||||
import './styles.scss';
|
||||
|
||||
export interface HeaderNavProps {
|
||||
className?:string,
|
||||
links:HeaderNavLinkProps[],
|
||||
social:HeaderNavSocialProps[]
|
||||
};
|
||||
|
||||
export const HeaderNav = (props:HeaderNavProps) => {
|
||||
let { className, links, social } = props;
|
||||
|
||||
return <nav className={`c-header-nav ${className||""}`}>
|
||||
{ links.map((link,i) =>
|
||||
<HeaderNavLink {...link} key={i} />
|
||||
)}
|
||||
|
||||
<div className="c-header-nav__social">
|
||||
{ social.map((sc,i) =>
|
||||
<HeaderNavSocial {...sc} key={i} />
|
||||
)}
|
||||
</div>
|
||||
</nav>
|
||||
};
|
@ -1,77 +0,0 @@
|
||||
@import './../../../../styles/global';
|
||||
|
||||
.c-header-nav {
|
||||
$self: &;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 75px;
|
||||
|
||||
&__link {
|
||||
padding-bottom: 100%;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
border: 0.2em solid transparent;
|
||||
|
||||
|
||||
&,&-inner {
|
||||
transition: all $s-animation--time-fast $s-animation--ease-out;
|
||||
}
|
||||
|
||||
&-inner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
font-family: $s-font--family-heading;
|
||||
}
|
||||
|
||||
&:hover #{$self}__link-inner {
|
||||
transform: translateX(5%);
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
border-right-color: $s-color--primary;
|
||||
}
|
||||
}
|
||||
|
||||
&__nav {}
|
||||
|
||||
&__social {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-wrap: wrap;
|
||||
|
||||
align-content: flex-end;
|
||||
justify-content: space-between;
|
||||
|
||||
padding: $s-gutter--small;
|
||||
|
||||
&-link {
|
||||
width: 50%;
|
||||
width: calc(50% - #{$s-gutter--xsmall / 2});
|
||||
margin-top: $s-gutter--xsmall;
|
||||
padding: $s-gutter--xsmall;
|
||||
border-radius: 100%;
|
||||
transition: all $s-animation--time-fast $s-animation--ease-out;
|
||||
|
||||
&:hover { transform: scale(1.05); }
|
||||
|
||||
&.is-github { background: $s-social--github-background; }
|
||||
}
|
||||
}
|
||||
|
||||
@include t-media-query($s-small-up) {
|
||||
width: 100px;
|
||||
&__link-inner { font-size: $s-font--size-4; }
|
||||
}
|
||||
|
||||
@include t-media-query($s-large-up) {
|
||||
width: 125px;
|
||||
}
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
@import './../../../styles/global';
|
||||
|
||||
@keyframes c-header--time-tick {
|
||||
0% { opacity: 1; }
|
||||
50% { opacity: 0; }
|
||||
100% { opacity: 1;}
|
||||
}
|
||||
|
||||
.c-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: $s-gutter--small $s-gutter--xsmall;
|
||||
|
||||
&__hamburger,
|
||||
&__time {
|
||||
flex-basis: (100% - 55%) / 2;
|
||||
}
|
||||
|
||||
&__logo {
|
||||
width: 100%;
|
||||
flex-basis: 55%;
|
||||
|
||||
img {
|
||||
display: block;
|
||||
max-width: 175px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
&__time {
|
||||
text-align: right;
|
||||
padding: $s-gutter--xsmall;
|
||||
&-colon { animation: 2s c-header--time-tick infinite step-end; }
|
||||
}
|
||||
|
||||
&__nav { display: none; }
|
||||
|
||||
|
||||
@include t-media-query($s-xsmall-up) {
|
||||
padding: 0;
|
||||
flex-direction: column;
|
||||
background: $s-color--background-footer;
|
||||
|
||||
&__nav {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
&__hamburger,
|
||||
&__time {
|
||||
flex-basis: auto;
|
||||
display: none;
|
||||
}
|
||||
|
||||
&__logo { display: none; }
|
||||
}
|
||||
}
|
@ -1,101 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
import * as React from 'react';
|
||||
import { History } from 'history';
|
||||
import { AnimatedSwitch, Router, Link } from '@yourwishes/app-simple-react/dist/public';
|
||||
import { StarBackground } from './../../background/stars/';
|
||||
import { Header } from './../header/';
|
||||
import { Footer } from './../footer/';
|
||||
import { Page } from './../../page/';
|
||||
|
||||
import './styles.scss';
|
||||
|
||||
const CLASS_ROUTE_CHANGE = 'is-route-changing';
|
||||
|
||||
//Paths (this will generate the necessary pages)
|
||||
export interface LayoutProps {
|
||||
history:History
|
||||
};
|
||||
|
||||
export class LayoutComponent extends React.Component<LayoutProps> {
|
||||
view:HTMLDivElement;
|
||||
|
||||
constructor(props:LayoutProps) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
//We use these to let the body know we're changing routes, which is a fake
|
||||
//way of stopping a user changing the route mid transition.
|
||||
onTransitionStart() {
|
||||
if(document.body.classList.contains(CLASS_ROUTE_CHANGE)) return;
|
||||
console.log('Transition Start');
|
||||
document.body.classList.add(CLASS_ROUTE_CHANGE);
|
||||
}
|
||||
|
||||
onTransitionEnd() {
|
||||
if(!document.body.classList.contains(CLASS_ROUTE_CHANGE)) return;
|
||||
console.log('Transition End');
|
||||
document.body.classList.remove(CLASS_ROUTE_CHANGE);
|
||||
}
|
||||
|
||||
render() {
|
||||
let PageProps = {
|
||||
onEnter: e => this.onTransitionStart(),
|
||||
onEntered: e => this.onTransitionEnd(),
|
||||
timeout: 2*1000
|
||||
}
|
||||
return (
|
||||
<Router history={this.props.history}>
|
||||
<>
|
||||
<StarBackground />
|
||||
<div className="c-layout">
|
||||
|
||||
{/* Header and Layout Wrapper */}
|
||||
<div className="c-layout__inner">
|
||||
<Header className="c-layout__header" />
|
||||
|
||||
<div className="c-layout__view" ref={e => this.view = e}>
|
||||
<AnimatedSwitch>
|
||||
<Page {...PageProps} exact path="/" name="home" />
|
||||
<Page {...PageProps} exact path="/about" name="about" />
|
||||
<Page {...PageProps} exact path="/contact" name="contact" />
|
||||
<Page {...PageProps} exact path="/projects" name="projects" />
|
||||
|
||||
<Page {...PageProps} exact path="/legal/privacy" name="privacy" />
|
||||
|
||||
<Page {...PageProps} exact path="/blog" name="blog" />
|
||||
<Page {...PageProps} exact path="/blog/article/:handle" name="article" />
|
||||
</AnimatedSwitch>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<Footer className="c-layout__footer" />
|
||||
</div>
|
||||
</>
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
@import './../../../styles/global';
|
||||
|
||||
$c-layout--menu-width: 275px;
|
||||
|
||||
.c-layout {
|
||||
height: 100%;
|
||||
|
||||
//Set position relative and a z-index to allow the layout to draw over the
|
||||
//background
|
||||
position: relative;
|
||||
z-index: $s-z--layout;
|
||||
|
||||
&__header,&__footer { width: 100%; }
|
||||
&__view { position: relative; }
|
||||
|
||||
&__inner {
|
||||
body.is-route-changing & { overflow: hidden; }
|
||||
}
|
||||
|
||||
@include t-media-query($s-xsmall-up) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-height: 100%;
|
||||
|
||||
&__inner {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-grow: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
&__view {
|
||||
//position: relative;
|
||||
flex-basis: 100%;
|
||||
flex-grow: 1;
|
||||
//overflow: hidden;
|
||||
}
|
||||
|
||||
&__header {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
&__footer { }
|
||||
}
|
||||
|
||||
|
||||
//Entering transition
|
||||
//&.is-not-ready { opacity: 0; }
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as React from 'react';
|
||||
import { AnimatedRouteProps, AnimatedRoute } from '@yourwishes/app-simple-react/dist/public';
|
||||
import { Loader as LoaderObject } from './../../objects/loader/';
|
||||
import { PageEffect } from './../../objects/page/effect/';
|
||||
import { Helmet } from 'react-helmet';
|
||||
|
||||
import './styles.scss';
|
||||
|
||||
//Title can be either a string (a title), or null (to indicate that this is a
|
||||
//title-less page (e.g. the Home Page would be considered title-less)
|
||||
export interface PageProps extends AnimatedRouteProps {
|
||||
name:string,
|
||||
load?:undefined
|
||||
}
|
||||
|
||||
export class PageAnimatedRouteWrapper extends React.Component<any> {
|
||||
constructor(props:any) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
let { loadKey, className, simulate, children } = this.props;
|
||||
let Effect = PageEffect(loadKey);
|
||||
|
||||
return (
|
||||
<main className="c-page">
|
||||
<Effect className={`c-page__effect ${className||""}`} simulate={simulate}>
|
||||
{ children }
|
||||
</Effect>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export const PageLoading = () => {
|
||||
return (
|
||||
<div className="c-page__loader">
|
||||
<LoaderObject className="c-page__loader-element" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export class Page extends React.Component<any> {
|
||||
constructor(props:PageProps) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
let { name } = this.props;
|
||||
|
||||
return <AnimatedRoute
|
||||
{...this.props} className={`c-page--${name} p-${name}`}
|
||||
|
||||
animateWrapper={PageAnimatedRouteWrapper as any}
|
||||
classNames="c-page__transition"
|
||||
|
||||
loading={PageLoading} loadKey={`pages/${name}`}
|
||||
load={() => import(`./../../pages/${name}/`)}
|
||||
/>;
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
@import './../../styles/global';
|
||||
|
||||
.c-page {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
&__effect {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
//Transitioning styles
|
||||
&__transition {
|
||||
//Define the timings, both enter and exit should share timings.
|
||||
&-enter,&-exit {
|
||||
transition: all $s-animation--time-extended $s-animation--ease-in-out;
|
||||
&-active .c-page__effect { overflow-y: visible; }
|
||||
}
|
||||
|
||||
&-enter {
|
||||
transform: translateY(100vh);
|
||||
z-index: 1;
|
||||
|
||||
&-active {
|
||||
transform: translateY(0);
|
||||
.c-page__effect { overflow-y: hidden; }
|
||||
}
|
||||
}
|
||||
|
||||
&-exit {
|
||||
position: absolute;
|
||||
transform: translateY(0%);
|
||||
top: 0;
|
||||
left: 0;
|
||||
opacity: 1;
|
||||
|
||||
&-active {
|
||||
transform: translateY(-100vh);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as React from 'react';
|
||||
import { Helmet } from 'react-helmet';
|
||||
|
||||
const DefaultTitle = document.title;
|
||||
|
||||
export interface PageWrapperProps {
|
||||
children:React.ReactNode,
|
||||
title:string
|
||||
};
|
||||
|
||||
export const PageWrapper = (props:PageWrapperProps) => {
|
||||
let { title, children } = props;
|
||||
|
||||
if(title == null) {
|
||||
title = DefaultTitle;
|
||||
} else {
|
||||
title = `${title} - domsPlace`
|
||||
}
|
||||
|
||||
return <>
|
||||
<Helmet>
|
||||
<title>{ title }</title>
|
||||
</Helmet>
|
||||
{ children }
|
||||
</>;
|
||||
};
|
@ -1,32 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as React from 'react';
|
||||
|
||||
export interface SectionProps extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> {
|
||||
|
||||
};
|
||||
|
||||
export const Section = (props:SectionProps) => (
|
||||
<section {...props} className={`c-section ${props.className||""}`} />
|
||||
);
|
@ -1,88 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as React from 'react';
|
||||
|
||||
import { Image } from '@yourwishes/app-simple-react/dist/public';
|
||||
import { ArticleProps } from './../../../../pages/article/';
|
||||
|
||||
import './styles.scss';
|
||||
|
||||
export const DomBotRedevelopmentArticle = (props:ArticleProps) => {
|
||||
let { article } = props;
|
||||
|
||||
return <>
|
||||
<meta itemProp="lastUpdated" content={new Date('2019-05-26 09:32:00').toString()} />
|
||||
|
||||
<Image className="c-dbr__image" src={article.image} />
|
||||
|
||||
<div className="c-dbr__description" itemProp="description">
|
||||
<p>
|
||||
It's no secret that I play video games, I particularly enjoy online
|
||||
multiplayer games such as Team Fortress 2. These games often require
|
||||
a good means of communication with fellow teammates, so that gameplay
|
||||
can be coordinated and teams can win more often.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Generally, gamers will tend to use <a href="//discord.com">Discord</a> due
|
||||
to it's high install base, as well as great quality and free service.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
I use tend to use Discord as well, and have had some fun digging around
|
||||
with the Discord API, to build some software for me and my friends'
|
||||
chatrooms.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
One of my older projects is DomBot, a free to install and use Discord
|
||||
Music Bot, that I recently had the privilage of updating as a proof
|
||||
of concept.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
While the concept of a Music Bot for Discord is not new, I had built it
|
||||
to build up and demonstrate the capabilities of my new TypeScript
|
||||
based application framework, that I plan to use in a lot of my new
|
||||
and upcoming projects.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you're interested in having DomBot on your server, head over to
|
||||
the <a href="//dombot.domsplace.com">dedicated page I have setup</a> and
|
||||
you can install the bot onto your Discord server for free.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For now I look forward to bringing more applications on my new app
|
||||
framework, and you'll likely see my personal site merged with the
|
||||
framework in the next coming months.
|
||||
<br /><br />
|
||||
Thanks,<br />Dominic
|
||||
</p>
|
||||
</div>
|
||||
</>;
|
||||
}
|
||||
|
||||
export default DomBotRedevelopmentArticle;
|
Before Width: | Height: | Size: 8.0 KiB |
@ -1,40 +0,0 @@
|
||||
// Copyright (c) 2018 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
|
||||
|
||||
import * as React from 'react';
|
||||
import { BlogArticle } from './../../../../types/';
|
||||
|
||||
export const DomBotRedevelopment:BlogArticle = {
|
||||
title: 'DomBot Redevelopment',
|
||||
date: new Date('2018-11-26T21:56:15.920Z'),
|
||||
description: () => import('./Article'),
|
||||
short: () => (
|
||||
<p>
|
||||
Sharing music between long distance friends is easier than ever with my
|
||||
updated Music bot. Learn about it's development and how I plan to improve
|
||||
it in the future.
|
||||
</p>
|
||||
),
|
||||
handle: 'dombot-redevelopment',
|
||||
image: require('./banner.jpg')
|
||||
};
|
@ -1,27 +0,0 @@
|
||||
@import './../../../../styles/global';
|
||||
|
||||
.c-dbr {
|
||||
&__image {
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
margin: 0 auto;
|
||||
margin-bottom: $s-gutter--large;
|
||||
}
|
||||
|
||||
&__description {}
|
||||
|
||||
@include t-media-query($s-small-up) {
|
||||
padding-top: $s-gutter--large;
|
||||
|
||||
&__image {
|
||||
display: inline-block;
|
||||
float: left;
|
||||
max-width: 370px;
|
||||
margin: 0 $s-gutter--small $s-gutter--small 0;
|
||||
}
|
||||
|
||||
&__description {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { BlogArticle } from './../../../types/';
|
||||
|
||||
import { DomBotRedevelopment } from './11-26-dombot/';
|
||||
|
||||
export const Articles:BlogArticle[] = [
|
||||
DomBotRedevelopment
|
||||
];
|
@ -1,67 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as React from 'react';
|
||||
import { Image, Link } from '@yourwishes/app-simple-react/dist/public';
|
||||
|
||||
export const Article = () => {
|
||||
return <>
|
||||
<p>
|
||||
It's finally here! After months in development my newly designed site has
|
||||
arrived, a whopping 11 months after I launched my previous site redesign!
|
||||
<br />Yes, I know I redesign the site a lot.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
As stated in my
|
||||
post about <Link to="/blog/article/dombot-redevelopment">
|
||||
DomBot ReDevelopment</Link>, I am building and upgrading a TypeScript
|
||||
based full-stack app framework to handle my various projects. As such this
|
||||
makes this website the second publicly available implementation of the
|
||||
framework, to great success.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The domsPlace site redesign added many great features I've been trying to
|
||||
find time to implement easier, such as a simple method of creating a store,
|
||||
easier CSS based page transitions, loadable components and loadable routes.
|
||||
Not to mention they all work together at the same time, another task that
|
||||
was quite difficult to achieve.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
I do plan to go back to writing blog posts more often, and perhaps build
|
||||
a projects section of the site, where I can host coding curiousities that
|
||||
make it to a near production stage, but perhaps aren't worthy of build.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In the mean time, take a look around and feel free to critique the new
|
||||
design, I'm not a UX/UI designer and don't claim to be particularly artistic
|
||||
in any way, so I would appreciate all feedback.
|
||||
<br /><br />Thanks,<br />Dominic.
|
||||
</p>
|
||||
</>;
|
||||
};
|
||||
|
||||
export default Article;
|
Before Width: | Height: | Size: 45 KiB |
@ -1,41 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
|
||||
|
||||
import * as React from 'react';
|
||||
import { BlogArticle } from './../../../../types/';
|
||||
|
||||
export const SiteRebuild2019:BlogArticle = {
|
||||
title: 'New Site Rebuild',
|
||||
date: new Date('2018-11-26T21:56:15.920Z'),
|
||||
description: () => import('./Article'),
|
||||
short: () => (
|
||||
<p>
|
||||
After a lengthy build process, and fixing many bugs in my low level app
|
||||
framework, I have finally launched my updated web design. Read about my
|
||||
thought process and how I came to this design, and all the developmental
|
||||
troubles through the process.
|
||||
</p>
|
||||
),
|
||||
handle: 'site-redesign',
|
||||
image: require('./banner.jpg')
|
||||
};
|
@ -1,30 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { BlogArticle } from './../../../types/';
|
||||
|
||||
import { SiteRebuild2019 } from './26-05-site/';
|
||||
|
||||
export const Articles:BlogArticle[] = [
|
||||
SiteRebuild2019
|
||||
];
|
@ -1,35 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { BlogArticle } from './../../types/';
|
||||
|
||||
import { Articles as Articles2018 } from './2018/';
|
||||
import { Articles as Articles2019 } from './2019/';
|
||||
|
||||
export const Articles:BlogArticle[] = [
|
||||
...Articles2019,
|
||||
...Articles2018
|
||||
];
|
||||
|
||||
export const getArticleByHandle = (handle:string) => Articles.find(article => article.handle == handle);
|
||||
export const getArticleURL = (article:BlogArticle) => `/blog/article/${article.handle}`;
|
1
src/public/gatsby-browser.js
Normal file
@ -0,0 +1 @@
|
||||
import 'normalize.css';
|
42
src/public/gatsby-config.js
Normal file
@ -0,0 +1,42 @@
|
||||
const path = require('path');
|
||||
const TSConfig = require('./tsconfig.json');
|
||||
|
||||
module.exports = {
|
||||
plugins: [
|
||||
{
|
||||
resolve: `gatsby-source-filesystem`,
|
||||
options: {
|
||||
path: path.join(__dirname, 'src', 'assets', 'images'),
|
||||
name: 'images'
|
||||
}
|
||||
},
|
||||
|
||||
'gatsby-plugin-typescript',
|
||||
'gatsby-plugin-react-helmet',
|
||||
'gatsby-plugin-styled-components',
|
||||
'gatsby-transformer-sharp',
|
||||
'gatsby-plugin-sharp',
|
||||
|
||||
{
|
||||
resolve: 'gatsby-plugin-alias-imports',
|
||||
options: {
|
||||
alias: Object.entries(TSConfig.compilerOptions.paths).reduce((x, [key, value]) => {
|
||||
let k = key.split('/').filter(f => f && f != '*').join('/');
|
||||
let v = value.find(v => v).split('/').filter(f => f && f != '*');
|
||||
return { ...x, [k]: path.resolve(__dirname, TSConfig.compilerOptions.baseUrl, ...v) };
|
||||
}, {})
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
resolve: 'gatsby-plugin-google-fonts',
|
||||
options: {
|
||||
fonts: [
|
||||
'Bitter',
|
||||
'Nanum Gothic'
|
||||
],
|
||||
display: 'swap'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
// Copyright (c) 2018 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
'use strict';
|
||||
|
||||
import { domsPlaceApp } from './app/domsPlaceApp';
|
||||
const app = new domsPlaceApp();
|
||||
setTimeout(() => {
|
||||
app.render();
|
||||
}, 0*1000);
|
@ -1,46 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as React from 'react';
|
||||
|
||||
import './styles.scss';
|
||||
|
||||
export interface LoaderProps {
|
||||
className?:string
|
||||
}
|
||||
|
||||
export const Loader = (props:LoaderProps) => {
|
||||
return (
|
||||
<span className={`o-loader ${props.className||""}`}>
|
||||
<svg width="38" height="38" viewBox="0 0 38 38" xmlns="http://www.w3.org/2000/svg" className="o-loader__image">
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<g transform="translate(1 1)" strokeWidth="2">
|
||||
<circle strokeOpacity=".75" cx="18" cy="18" r="18" />
|
||||
<path id="test" d="M36 18c0-9.94-8.06-18-18-18">
|
||||
</path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</span>
|
||||
);
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
@import './../../styles/global';
|
||||
|
||||
@keyframes o-loader--spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.o-loader {
|
||||
display: block;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
&__image {
|
||||
animation: o-loader--spin $s-animation--time-long $s-animation--ease-in-out infinite;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
> * {
|
||||
stroke: $s-color--primary;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as React from 'react';
|
||||
import { Link, Image } from '@yourwishes/app-simple-react/dist/public';
|
||||
|
||||
import './styles.scss';
|
||||
|
||||
export interface LogoProps {
|
||||
className?:string
|
||||
};
|
||||
|
||||
export const Logo = (props:LogoProps) => {
|
||||
return (
|
||||
<Link to="/" className={`o-logo ${props.className||""}`}>
|
||||
<Image src={require('./../../assets/logo.svg')} className="o-logo__image" />
|
||||
</Link>
|
||||
);
|
||||
};
|
@ -1,10 +0,0 @@
|
||||
@import './../../styles/global';
|
||||
|
||||
.o-logo {
|
||||
display: block;
|
||||
|
||||
&__image {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as React from 'react';
|
||||
import './styles.scss';
|
||||
|
||||
export enum Size { SMALL = 'small', MEDIUM = 'medium', LARGE = 'large' };
|
||||
|
||||
export type PageWrapperProps = (
|
||||
{
|
||||
size?:Size|string,
|
||||
|
||||
medium?:boolean,
|
||||
small?:boolean,
|
||||
large?:boolean
|
||||
} &
|
||||
React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
|
||||
);
|
||||
|
||||
export const PageBoundary = (props:PageWrapperProps) => {
|
||||
let {
|
||||
size, className, small, medium, large
|
||||
} = props;
|
||||
|
||||
let np = {...props};
|
||||
['small','medium','large'].forEach(e => delete np[e]);
|
||||
|
||||
size = size || Size.LARGE;
|
||||
|
||||
if(small) size = Size.SMALL;
|
||||
if(medium) size = Size.MEDIUM;
|
||||
if(large) size = Size.LARGE;
|
||||
|
||||
let clazz = `o-page-wrapper is-size-${size} ${className||""}`;
|
||||
return <div {...np} className={clazz} />
|
||||
};
|
@ -1,17 +0,0 @@
|
||||
@import './../../../styles/global';
|
||||
|
||||
.o-page-wrapper {
|
||||
margin: auto;
|
||||
|
||||
&.is-size-small {
|
||||
max-width: $s-screen-small;
|
||||
}
|
||||
|
||||
&.is-size-medium {
|
||||
max-width: $s-screen-medium;
|
||||
}
|
||||
|
||||
&.is-size-large {
|
||||
max-width: $s-screen-xlarge;
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as React from 'react';
|
||||
import { withLoader, withLoaderProps } from '@yourwishes/app-simple-react/dist/public';
|
||||
|
||||
import './styles.scss';
|
||||
|
||||
export interface PageEffectProps extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, withLoaderProps {
|
||||
}
|
||||
|
||||
export const PageEffectComponent = (props:PageEffectProps) => {
|
||||
let { loading, error, loaded, className } = props;
|
||||
let np = {...props};
|
||||
['loading','loaded','error','simulate'].forEach(e => delete np[e]);
|
||||
|
||||
let ec = '';
|
||||
if(loading) ec = 'is-loading';
|
||||
if(loaded) ec = 'is-loaded';
|
||||
if(error) ec = 'has-error';
|
||||
|
||||
return (
|
||||
<div {...np} className={`${className||""} o-page-effect ${ec}`} />
|
||||
);
|
||||
}
|
||||
|
||||
export const PageEffect = (loadKey:string) => withLoader<PageEffectProps>(loadKey, PageEffectComponent);
|
@ -1,36 +0,0 @@
|
||||
@import './../../../styles/global';
|
||||
|
||||
@keyframes o-page-effect--fade-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(1vh);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.o-page-effect {
|
||||
opacity: 0;
|
||||
transform: translateY(1vh);
|
||||
transition:
|
||||
opacity $s-animation--time-long $s-animation--ease-out,
|
||||
transform $s-animation--time-long $s-animation--ease-out
|
||||
;
|
||||
transition-delay: 200ms;
|
||||
|
||||
&.is-loading {
|
||||
transition: none;
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
&.is-loaded {
|
||||
opacity: 1;
|
||||
transform: translate(0);
|
||||
//animation: o-page-effect--fade-in forwards $s-animation--time-long $s-animation--ease-out;
|
||||
//animation-delay: $s-animation--time-long;//Animation delay to try and hide the "flicker" when a component loads
|
||||
}
|
||||
}
|
@ -1,125 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as React from 'react';
|
||||
import './styles.scss';
|
||||
|
||||
export enum Type {
|
||||
H1='h1', H2='h2', H3='h3', H4='h4', H5='h5', H6='h6',
|
||||
SPAN='span'
|
||||
}
|
||||
|
||||
export enum Size {
|
||||
TITLE='is-title',
|
||||
TITLE_LARGE='is-title-large',
|
||||
SUBTTITLE='is-subtitle',
|
||||
S1='is-size-1',
|
||||
S2='is-size-2',
|
||||
S3='is-size-3',
|
||||
S4='is-size-4',
|
||||
S5='is-size-5',
|
||||
S6='is-size-6'
|
||||
}
|
||||
|
||||
export interface HeadingProps extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement> {
|
||||
type?:Type,
|
||||
size?:Size
|
||||
}
|
||||
|
||||
export const Heading = (props:HeadingProps) => {
|
||||
let { size, type, className } = props;
|
||||
|
||||
let np = {...props};
|
||||
['size','type','large'].forEach(e => delete np[e]);
|
||||
|
||||
size = size || Size.S1;
|
||||
|
||||
let clazz = `o-heading ${size}`;
|
||||
|
||||
if(!type) {
|
||||
switch(size) {
|
||||
case Size.TITLE:
|
||||
type = Type.H1; break;
|
||||
case Size.TITLE_LARGE:
|
||||
type = Type.H1; break;
|
||||
case Size.S1:
|
||||
type = Type.H1; break;
|
||||
case Size.S2:
|
||||
type = Type.H2; break;
|
||||
case Size.S3:
|
||||
type = Type.H3; break;
|
||||
case Size.S4:
|
||||
type = Type.H4; break;
|
||||
case Size.S5:
|
||||
type = Type.H5; break;
|
||||
case Size.S6:
|
||||
type = Type.H6; break;
|
||||
default:
|
||||
type = Type.SPAN; break;
|
||||
}
|
||||
}
|
||||
|
||||
if(size == Size.TITLE) clazz = 'o-title';
|
||||
if(size == Size.TITLE_LARGE) clazz = 'o-title is-large';
|
||||
if(size == Size.SUBTTITLE) clazz = 'o-subtitle';
|
||||
if(className) clazz += ` ${className}`;
|
||||
|
||||
let ElementType = type;
|
||||
return <ElementType {...np} className={clazz} />;
|
||||
};
|
||||
|
||||
//Types
|
||||
export const Title = (props:(
|
||||
HeadingProps & { large?:boolean }
|
||||
)) => (
|
||||
<Heading {...props} size={props.size||(
|
||||
props.large ? Size.TITLE_LARGE : Size.TITLE
|
||||
)} type={props.type||Type.H1} />
|
||||
);
|
||||
|
||||
export const Subtitle = (props:HeadingProps) => (
|
||||
<Heading {...props} size={props.size||Size.SUBTTITLE} type={props.type||Type.H2} />
|
||||
);
|
||||
|
||||
|
||||
export const Heading1 = Heading;
|
||||
|
||||
export const Heading2 = (props:HeadingProps) => (
|
||||
<Heading {...props} type={props.type||Type.H2} size={props.size||Size.S2} />
|
||||
);
|
||||
|
||||
export const Heading3 = (props:HeadingProps) => (
|
||||
<Heading {...props} type={props.type||Type.H3} size={props.size||Size.S3} />
|
||||
);
|
||||
|
||||
export const Heading4 = (props:HeadingProps) => (
|
||||
<Heading {...props} type={props.type||Type.H4} size={props.size||Size.S4} />
|
||||
);
|
||||
|
||||
export const Heading5 = (props:HeadingProps) => (
|
||||
<Heading {...props} type={props.type||Type.H5} size={props.size||Size.S5} />
|
||||
);
|
||||
|
||||
export const Heading6 = (props:HeadingProps) => (
|
||||
<Heading {...props} type={props.type||Type.H6} size={props.size||Size.S6} />
|
||||
);
|
@ -1,28 +0,0 @@
|
||||
@import './../../../styles/global';
|
||||
|
||||
.o-heading {
|
||||
@extend %s-font--heading;
|
||||
margin: 0.4em 0 0.5em;
|
||||
|
||||
@for $i from 1 through 6 {
|
||||
&.is-size-#{$i} { @extend %s-font--heading-#{$i}; }
|
||||
}
|
||||
}
|
||||
|
||||
.o-title {
|
||||
@extend %s-font--heading;
|
||||
font-size: $s-font--size-title;
|
||||
|
||||
+ .o-subtitle {
|
||||
margin-top: -1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
@include t-media-query($s-small-up) {
|
||||
.o-title {
|
||||
&.is-large {
|
||||
font-size: $s-font--size-title-large;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as React from 'react';
|
||||
import { Link } from '@yourwishes/app-simple-react/dist/public';
|
||||
|
||||
import './styles.scss';
|
||||
|
||||
|
||||
export interface BreacrumbCrumbProps {
|
||||
title:string, to:string
|
||||
}
|
||||
|
||||
export interface BreadcrumbProps {
|
||||
className?:string
|
||||
crumbs:BreacrumbCrumbProps[]
|
||||
}
|
||||
|
||||
|
||||
export const BreadcrumbCrumb = (props:BreacrumbCrumbProps) => (
|
||||
<li className="o-breadcrumb__list-item">
|
||||
<Link to={ props.to } className="o-breadcrumb__list-item-link" activeClassName="is-active" exact>
|
||||
{ props.title }
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
|
||||
export const Breadcrumb = (props:BreadcrumbProps) => {
|
||||
let crumbs = [
|
||||
{to:'/',title:'Home'}, ...props.crumbs
|
||||
].map((crumb,i) => <BreadcrumbCrumb {...crumb} key={'crumb'+i} />);
|
||||
|
||||
return (
|
||||
<nav className={`o-breadcrumb ${props.className||""}`}>
|
||||
<ul className="o-breadcrumb__list">{ crumbs }</ul>
|
||||
</nav>
|
||||
);
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
@import './../../../styles/global';
|
||||
|
||||
.o-breadcrumb {
|
||||
margin: $s-gutter--medium 0 $s-gutter--large;
|
||||
|
||||
&__list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
|
||||
&-item {
|
||||
display: inline-block;
|
||||
font-size: 0.8em;
|
||||
|
||||
&-link, &::before {
|
||||
opacity: 0.9;
|
||||
transition: all $s-animation--time-fast $s-animation--ease-out;
|
||||
}
|
||||
|
||||
&-link.is-active {
|
||||
color: $s-color--primary;
|
||||
}
|
||||
|
||||
&:hover &-link {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
|
||||
+ #{&} {
|
||||
&::before {
|
||||
content: '/';
|
||||
margin: 0 $s-gutter--xsmall;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include t-media-query($s-xsmall-up) {
|
||||
&__list-item { font-size: 0.9em; }
|
||||
}
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as React from 'react';
|
||||
import { LinkProps, Link } from '@yourwishes/app-simple-react/dist/public';
|
||||
import { Loader } from './../../loader/';
|
||||
import './styles.scss';
|
||||
|
||||
export enum ButtonStyle {
|
||||
PRIMARY='is-primary',
|
||||
SECONDARY='is-secondary'
|
||||
};
|
||||
|
||||
export enum ButtonSize {
|
||||
NORMAL = 'is-normal',
|
||||
LARGE = 'is-large'
|
||||
}
|
||||
|
||||
|
||||
export type ButtonProps = LinkProps & {
|
||||
className?:string,
|
||||
style?:ButtonStyle,
|
||||
to?:string,
|
||||
disabled?:boolean,
|
||||
loading?:boolean,
|
||||
|
||||
size?:ButtonSize,
|
||||
large?:boolean,
|
||||
|
||||
primary?:boolean,
|
||||
secondary?:boolean
|
||||
}
|
||||
|
||||
export const Button = (props:ButtonProps) => {
|
||||
let { className, children, style, size, large, disabled, loading } = props;
|
||||
|
||||
if(large) size = ButtonSize.LARGE;
|
||||
|
||||
if(props.primary) style = ButtonStyle.PRIMARY;
|
||||
if(props.secondary) style = ButtonStyle.SECONDARY;
|
||||
|
||||
let clazz = `o-btn ${style||ButtonStyle.PRIMARY}`;
|
||||
if(className) clazz += ` ${className}`;
|
||||
if(size && size != ButtonSize.NORMAL) clazz += ` ${size}`;
|
||||
if(disabled) clazz += ' is-disabled';
|
||||
|
||||
if(loading) {
|
||||
children = <> { children } <Loader /> </>;
|
||||
clazz += ' is-loading';
|
||||
}
|
||||
|
||||
let np = {...props};
|
||||
[
|
||||
'style','large','size','primary','secondary', 'loading'
|
||||
].forEach(e => delete np[e]);
|
||||
|
||||
return (
|
||||
<Link {...np} className={clazz}>
|
||||
{ children }
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
export const ButtonGroup = (props:React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>) => (
|
||||
<div {...props} className={`o-btn-group ${props.className||""}`} />
|
||||
);
|
@ -1,71 +0,0 @@
|
||||
@import './../../../styles/global';
|
||||
|
||||
.o-btn {
|
||||
display: inline-block;
|
||||
padding: 0.5em 1em;
|
||||
text-align: center;
|
||||
background: $s-color--primary;
|
||||
border: $s-outline--medium solid $s-color--primary;
|
||||
font-weight: $s-font--weight-default;
|
||||
transition: background $s-animation--time-fast $s-animation--ease-out;
|
||||
|
||||
&:hover {
|
||||
background: $s-color--primary-hover;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&[disabled],&.is-disabled {
|
||||
cursor: not-allowed;
|
||||
background: $s-color--disabled;
|
||||
color: $s-color--disabled-text;
|
||||
border-color: $s-color--disabled;
|
||||
.o-loader * { stroke: $s-color--disabled-text; }
|
||||
}
|
||||
|
||||
&.is-loading {
|
||||
position: relative;
|
||||
color: transparent;
|
||||
|
||||
.o-loader {
|
||||
height: calc(100% - 1em);
|
||||
}
|
||||
}
|
||||
|
||||
&.is-large {
|
||||
padding: 1em 2em;
|
||||
font-weight: $s-font--weight-bold;
|
||||
|
||||
&.is-loading .o-loader { height: calc(100% - 2em); }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Button group
|
||||
.o-btn-group {
|
||||
.o-btn {
|
||||
width: 100%;
|
||||
display: block;
|
||||
|
||||
+ .o-btn {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
@include t-media-query($s-xsmall-up) {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.o-btn {
|
||||
width: calc(50% - 0.5em);
|
||||
|
||||
+ .o-btn {
|
||||
margin-top: 0;
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include t-media-query($s-small-up) {
|
||||
.o-btn { width: auto; }
|
||||
}
|
||||
}
|
@ -1,170 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as React from 'react';
|
||||
import { Button, ButtonProps } from './../button/';
|
||||
import { Assign } from 'utility-types';
|
||||
import './styles.scss';
|
||||
|
||||
//Input Types, e.g. email, text, etc.
|
||||
export enum InputType {
|
||||
//HTML5:
|
||||
COLOR = "color",
|
||||
DATE = "date",
|
||||
DATETIME_LOCAL = "datetime-local",
|
||||
EMAIL = "email",
|
||||
MONTH = "month",
|
||||
NUMBER = "number",
|
||||
RANGE = "range",
|
||||
SEARCH = "search",
|
||||
TEL = "tel",
|
||||
TIME = "time",
|
||||
URL = "url",
|
||||
WEEK = "week",
|
||||
|
||||
//HTML4~
|
||||
TEXT = "text",
|
||||
HIDDEN = "hidden",
|
||||
PASSWORD = "password",
|
||||
RADIO = "radio",
|
||||
CHECKBOX = "checkbox",
|
||||
TEXTAREA = "textarea",
|
||||
FILE = "file",
|
||||
IMAGE = "image",
|
||||
|
||||
//Button types
|
||||
BUTTON = "button",
|
||||
SUBMIT = "submit",
|
||||
RESET = "reset"
|
||||
};
|
||||
|
||||
//Input values, e.g. the values the inputs can have
|
||||
export type InputValue = (
|
||||
string | number | boolean |
|
||||
(string|number|boolean)[]
|
||||
);
|
||||
|
||||
//Props
|
||||
type InputPropsPicked = {
|
||||
className?:string,
|
||||
|
||||
to?:undefined,
|
||||
type?:InputType,
|
||||
|
||||
//Value Management
|
||||
value?:InputValue,
|
||||
children?:string,//Acts more like defaultValue than value, for textareas
|
||||
defaultValue?:InputValue,
|
||||
readOnly?:boolean,
|
||||
|
||||
maxLength?:string|number,
|
||||
|
||||
//Readability
|
||||
placeholder?:string,
|
||||
title?:string,
|
||||
name?:string,
|
||||
error?:string,
|
||||
|
||||
//Specifics.
|
||||
rows?:string|number,
|
||||
|
||||
//Events
|
||||
onChange?:React.FormEventHandler<any>
|
||||
}
|
||||
|
||||
//We are going to override some of the buttons stuff.
|
||||
export type InputProps = Assign<Assign<InputPropsPicked, ButtonProps>, {
|
||||
ref?:any
|
||||
}>;
|
||||
|
||||
export class InputElement extends React.Component<InputProps> {
|
||||
constructor(props:InputProps) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return true;
|
||||
}
|
||||
|
||||
render() {
|
||||
//Fetch from props
|
||||
let { className, type, children, value, defaultValue } = this.props;
|
||||
|
||||
//Determine default value
|
||||
if(children && typeof children === "string") {
|
||||
defaultValue = `${children}` as string;
|
||||
}
|
||||
|
||||
let np = {};
|
||||
|
||||
//Begin building class
|
||||
let clazz = `o-input is-${type} `;
|
||||
|
||||
//Determine input type
|
||||
type = type || InputType.TEXT;
|
||||
let ElementType:any = "input";
|
||||
|
||||
/*** Begin Type Specific Processing... */
|
||||
|
||||
//Textarea? Adjust the values a bit
|
||||
if(type == InputType.TEXTAREA) {
|
||||
ElementType = "textarea";
|
||||
type = undefined;
|
||||
children = undefined;
|
||||
}
|
||||
|
||||
//Button?
|
||||
if([InputType.BUTTON,InputType.SUBMIT,InputType.RESET].some(e => type === e)) {
|
||||
ElementType = Button;
|
||||
children = (value || defaultValue) as any;
|
||||
value = undefined;
|
||||
clazz = ' ';
|
||||
[
|
||||
'to','primary','secondary','size','style','large','loading'
|
||||
].forEach(e => np[e] = this.props[e]);
|
||||
}
|
||||
|
||||
//Add Custom classes`
|
||||
clazz += className||"";
|
||||
|
||||
//Now Build new props
|
||||
np['className'] = clazz;
|
||||
np['type'] = type;
|
||||
np['children'] = children;
|
||||
np['value'] = value;
|
||||
np['defaultValue'] = defaultValue;
|
||||
|
||||
[
|
||||
'readOnly','placeholder','title','rows','maxLength',
|
||||
'onChange', 'disabled'
|
||||
].forEach(e => np[e] = this.props[e]);
|
||||
|
||||
return <ElementType {...np} />
|
||||
}
|
||||
}
|
||||
|
||||
export const Input = InputElement;
|
||||
|
||||
export const TextArea = (props:InputProps) => (
|
||||
<InputElement {...props} type={props.type || InputType.TEXTAREA} />
|
||||
);
|
@ -1,51 +0,0 @@
|
||||
@import './../../../styles/global';
|
||||
|
||||
.o-input {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
padding: 0.5em 1em;
|
||||
margin: 0;
|
||||
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
font-weight: inherit;
|
||||
vertical-align: bottom;
|
||||
|
||||
border: $s-outline--medium solid $s-color--primary;
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
transition: border $s-animation--time-fast $s-animation--ease-out;
|
||||
|
||||
//Pseudo's
|
||||
&::placeholder {
|
||||
color: inherit;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
//States
|
||||
&:hover,&:focus {
|
||||
border-color: $s-color--primary-hover;
|
||||
&::placeholder { opacity: 0.7; }
|
||||
}
|
||||
|
||||
&[disabled],&.is-disabled {
|
||||
cursor: not-allowed;
|
||||
background: rgba($s-color--disabled, 0.7);
|
||||
color: $s-color--disabled-text;
|
||||
border-color: $s-color--disabled;
|
||||
&::placeholder {opacity: 0.5;}
|
||||
}
|
||||
|
||||
&:focus {}
|
||||
&:active {}
|
||||
|
||||
//Types
|
||||
&.is-textarea {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
//Nexts
|
||||
+ #{&}, + .o-btn, + .o-btn-group {
|
||||
margin-top: $s-gutter--small;
|
||||
}
|
||||
}
|
67
src/public/package.json
Normal file
@ -0,0 +1,67 @@
|
||||
{
|
||||
"name": "domsplace-frontend",
|
||||
"version": "8.0.0",
|
||||
"description": "Personal website for Dominic \"YourWishes\" Masters.",
|
||||
"scripts": {
|
||||
"build": "gatsby build",
|
||||
"develop": "gatsby develop",
|
||||
"start": "npm run develop",
|
||||
"serve": "gatsby serve",
|
||||
"deploy": "serverless client deploy --no-confirm",
|
||||
"clean": "gatsby clean",
|
||||
"test": "echo \"No tests defined\""
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/YourWishes/domsPlaceNew.git"
|
||||
},
|
||||
"keywords": [
|
||||
"domsplace",
|
||||
"personal",
|
||||
"portfolio",
|
||||
"website"
|
||||
],
|
||||
"author": "Dominic Masters",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/YourWishes/domsPlaceNew/issues"
|
||||
},
|
||||
"homepage": "https://domsplace.com",
|
||||
"dependencies": {
|
||||
"babel-plugin-styled-components": "^1.10.7",
|
||||
"gatsby": "^2.18.12",
|
||||
"gatsby-image": "^2.2.39",
|
||||
"gatsby-plugin-alias-imports": "^1.0.5",
|
||||
"gatsby-plugin-google-fonts": "^1.0.1",
|
||||
"gatsby-plugin-react-helmet": "^3.1.21",
|
||||
"gatsby-plugin-sharp": "^2.4.3",
|
||||
"gatsby-plugin-styled-components": "^3.1.18",
|
||||
"gatsby-plugin-typescript": "^2.1.26",
|
||||
"gatsby-source-filesystem": "^2.1.46",
|
||||
"gatsby-transformer-sharp": "^2.3.13",
|
||||
"normalize.css": "^8.0.1",
|
||||
"react": "^16.12.0",
|
||||
"react-dom": "^16.12.0",
|
||||
"react-helmet": "^5.2.1",
|
||||
"react-hook-form": "^4.8.0",
|
||||
"styled-components": "^5.0.0",
|
||||
"yup": "^0.28.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"serverless": "^1.63.0",
|
||||
"serverless-finch": "^2.5.2",
|
||||
"serverless-plugin-include-dependencies": "^4.0.1",
|
||||
"@types/node": "^13.5.0",
|
||||
"@types/react": "^16.9.19",
|
||||
"@types/react-dom": "^16.9.5",
|
||||
"@types/react-helmet": "^5.0.15",
|
||||
"@types/styled-components": "^4.4.2",
|
||||
"@types/yup": "^0.26.29"
|
||||
},
|
||||
"browserslist": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not ie <= 11",
|
||||
"not op_mini all"
|
||||
]
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as React from 'react';
|
||||
import { Title } from './../../objects/typography/heading/';
|
||||
import { PageBoundary } from './../../objects/page/boundary/';
|
||||
import { ButtonGroup, Button } from './../../objects/widgets/button/';
|
||||
import { PageWrapper } from './../../components/page/wrapper/';
|
||||
|
||||
import './styles.scss';
|
||||
|
||||
export class NotFoundPage extends React.Component<any> {
|
||||
constructor(props:any) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
return <PageWrapper title={null}>
|
||||
<PageBoundary small className="c-404-page">
|
||||
<Title className="c-404-page__title">
|
||||
404 - Not Found
|
||||
</Title>
|
||||
|
||||
<div className="c-404-page__content">
|
||||
<p>
|
||||
Sorry, the page you requested could not be found. It may've been
|
||||
deleted or relocated. If you feel this is an error you can contact me,
|
||||
otherwise you can go back home and take a look around.
|
||||
</p>
|
||||
|
||||
<ButtonGroup className="c-404-page__buttons">
|
||||
<Button to="/" primary>Home</Button>
|
||||
<Button to="/contact" secondary>Contact Me</Button>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
</PageBoundary>
|
||||
</PageWrapper>;
|
||||
}
|
||||
}
|
||||
|
||||
export default NotFoundPage;
|
@ -1,20 +0,0 @@
|
||||
@import './../../styles/global';
|
||||
|
||||
.c-404-page {
|
||||
padding: $s-gutter--xlarge $s-gutter--small;
|
||||
|
||||
&__title {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__content {
|
||||
max-width: 500px;
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__buttons {
|
||||
margin-top: $s-gutter--large;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as React from 'react';
|
||||
|
||||
import { BannerSection } from './sections/banner/';
|
||||
import { ProgrammerSection } from './sections/programmer/';
|
||||
import { ShopifySection } from './sections/shopify/';
|
||||
import { WebDevSection } from './sections/webdev/';
|
||||
import { TechStackSection } from './sections/tech/';
|
||||
import { ContactSection } from './sections/contact/';
|
||||
import { PageWrapper } from './../../components/page/wrapper/';
|
||||
|
||||
export class AboutPage extends React.Component<any> {
|
||||
constructor(props:any) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return <PageWrapper title="About Me">
|
||||
<BannerSection />
|
||||
|
||||
<ProgrammerSection />
|
||||
<ShopifySection />
|
||||
<WebDevSection />
|
||||
|
||||
<TechStackSection />
|
||||
<ContactSection />
|
||||
</PageWrapper>
|
||||
}
|
||||
}
|
||||
|
||||
export default AboutPage;
|
@ -1,46 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as React from 'react';
|
||||
|
||||
import { Title } from './../../../../objects/typography/heading/';
|
||||
import { PageBoundary } from './../../../../objects/page/boundary/';
|
||||
import { Section } from './../../../../components/section/';
|
||||
|
||||
import './styles.scss';
|
||||
|
||||
export const BannerSection = () => (
|
||||
<Section className="c-about-banner">
|
||||
<PageBoundary className="c-about-banner__boundary">
|
||||
<div className="c-about-banner__pad" />
|
||||
|
||||
<header role="banner" className="c-about-banner__content">
|
||||
<Title large className="c-about-banner__title">About Me</Title>
|
||||
<p className="c-about-banner__blurb">
|
||||
I'm just a nerd with a passion for coding, coffee, and video games.<br/>
|
||||
Programming since before the internet was cool.
|
||||
</p>
|
||||
</header>
|
||||
</PageBoundary>
|
||||
</Section>
|
||||
);
|
@ -1,32 +0,0 @@
|
||||
@import './../../../../styles/global';
|
||||
|
||||
.c-about-banner {
|
||||
&__boundary {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__pad {
|
||||
width: 100%;
|
||||
padding-bottom: 60%;
|
||||
}
|
||||
|
||||
&__content {
|
||||
top: 0;
|
||||
left: 50%;
|
||||
top: 75%;
|
||||
transform: translate(-50%, -50%);
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
padding: 0 $s-gutter--small;
|
||||
}
|
||||
|
||||
&__title,&__blurb {
|
||||
}
|
||||
|
||||
@include t-media-query($s-small-up) {
|
||||
&__content { top: 50%; }
|
||||
&__pad { padding-bottom: 40%; }
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as React from 'react';
|
||||
import { Section } from './../../../../components/section/';
|
||||
import { PageBoundary } from './../../../../objects/page/boundary/';
|
||||
import { Heading2 } from './../../../../objects/typography/heading/';
|
||||
import { Button } from './../../../../objects/widgets/button/';
|
||||
|
||||
import './styles.scss';
|
||||
|
||||
export const ContactSection = () => (
|
||||
<Section className="c-contact-section">
|
||||
<PageBoundary size="small" className="c-contact-section__boundary">
|
||||
<Heading2>Get in touch</Heading2>
|
||||
<p>
|
||||
Want to get in touch, pick my brain or just have a chat?<br />
|
||||
Head over to my contact page and feel free to reach out.
|
||||
</p>
|
||||
|
||||
<Button to="/contact" large>Contact Me</Button>
|
||||
</PageBoundary>
|
||||
</Section>
|
||||
);
|
@ -1,13 +0,0 @@
|
||||
@import './../../../../styles/global';
|
||||
|
||||
.c-contact-section {
|
||||
&__boundary {
|
||||
padding: $s-gutter--xlarge $s-gutter--small;
|
||||
text-align: center;
|
||||
|
||||
p {
|
||||
max-width: 500px;
|
||||
margin: $s-gutter--medium auto;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as React from 'react';
|
||||
import { Section } from './../../../../components/section/';
|
||||
import { PageBoundary } from './../../../../objects/page/boundary/';
|
||||
import { Heading2 } from './../../../../objects/typography/heading/';
|
||||
|
||||
import './styles.scss';
|
||||
|
||||
export const ProgrammerSection = () => (
|
||||
<Section className="c-programmer-section">
|
||||
<PageBoundary size="small" className="c-programmer-section__boundary">
|
||||
<Heading2>Programmer</Heading2>
|
||||
<p>
|
||||
I am a programmer, born and bred. I have been programming since I was
|
||||
around 11 years old and continue to advance my skills more and more
|
||||
everyday.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Programming is my work and my passion. With over 15 years of experience,
|
||||
and countless lines of code written, there isn't much I can't develop.
|
||||
</p>
|
||||
</PageBoundary>
|
||||
</Section>
|
||||
);
|
@ -1,11 +0,0 @@
|
||||
@import './../../../../styles/global';
|
||||
|
||||
.c-programmer-section {
|
||||
overflow-x: hidden;
|
||||
|
||||
&__boundary {
|
||||
padding: $s-gutter--xlarge $s-gutter--small;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as React from 'react';
|
||||
import { Link, Image, ImageSource } from '@yourwishes/app-simple-react/dist/public';
|
||||
import { Section } from './../../../../components/section/';
|
||||
import { PageBoundary } from './../../../../objects/page/boundary/';
|
||||
import { Heading3 } from './../../../../objects/typography/heading/';
|
||||
|
||||
import './styles.scss';
|
||||
|
||||
export type SiteBoxProps = {
|
||||
to:string,
|
||||
src: ImageSource
|
||||
};
|
||||
|
||||
export const SiteBox = (props:SiteBoxProps) => (
|
||||
<Link to={props.to} className="c-shopify-section__mosaic-box" {...{target: "_blank"}}>
|
||||
<Image src={props.src} className="c-shopify-section__mosaic-box-image" width={500} maxWidth={500} />
|
||||
</Link>
|
||||
);
|
||||
|
||||
export const ShopifySection = () => (
|
||||
<Section className="c-shopify-section">
|
||||
<PageBoundary className="c-shopify-section__boundary">
|
||||
<div className="c-shopify-section__mosaic">
|
||||
<SiteBox src={require('./../../../../assets/images/websites/bundlfresh.jpg')} to="//bundlfresh.com/" />
|
||||
<SiteBox src={require('./../../../../assets/images/websites/cocksox.jpg')} to="//cocksox.com" />
|
||||
<SiteBox src={require('./../../../../assets/images/websites/stateofescape.jpg')} to="//stateofescape.com" />
|
||||
|
||||
<div className="c-shopify-section__mosaic-pad" />
|
||||
</div>
|
||||
|
||||
<div className="c-shopify-section__content">
|
||||
<Heading3 className="c-shopify-section__title">
|
||||
Shopify Plus
|
||||
</Heading3>
|
||||
|
||||
<p>
|
||||
I'm currently working full-time as a Senior Full-Stack Developer for
|
||||
Shopify Plus at <a href="//processcreative.com.au">Process Creative</a>.
|
||||
I have been working with it every day since September 2017 and enjoy
|
||||
working with the platform immensely.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Working with Liquid, REST and GraphQL App Development and general
|
||||
Shopify tools development, I have had the privilage of working with
|
||||
over 40 different Shopify Plus clients, and over 50 Shopify core clients.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Despite Shopify's seemingly limited development environment, I have
|
||||
been able to make it do tricks thought impossible. I love finding
|
||||
unique solution's to Shopify's limitations, and will continuously
|
||||
find ways to surprise everyone, including myself.
|
||||
</p>
|
||||
</div>
|
||||
</PageBoundary>
|
||||
</Section>
|
||||
);
|
@ -1,72 +0,0 @@
|
||||
@import './../../../../styles/global';
|
||||
|
||||
.c-shopify-section {
|
||||
margin-bottom: $s-gutter--large;
|
||||
|
||||
&__boundary {}
|
||||
&__content { padding: 0 $s-gutter--small; }
|
||||
&__title { text-align: center; }
|
||||
|
||||
&__mosaic {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
&-pad {
|
||||
width: 100%;
|
||||
padding-bottom: 80%;
|
||||
}
|
||||
|
||||
&-box {
|
||||
position: absolute;
|
||||
transition: all $s-animation--time-fast $s-animation--ease-out;
|
||||
|
||||
&:nth-child(1) {
|
||||
bottom: 10%;
|
||||
left: 15%;
|
||||
width: 50%;
|
||||
z-index: 3;
|
||||
|
||||
&:hover { transform: translateY(-0.5em); }
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
bottom: 20%;
|
||||
left: 25%;
|
||||
width: 45%;
|
||||
|
||||
&:hover { transform: translateX(-0.5em); }
|
||||
}
|
||||
|
||||
&:nth-child(3) {
|
||||
width: 50%;
|
||||
right: 5%;
|
||||
top: 25%;
|
||||
|
||||
&:hover { transform: translate(0.5em, -0.5em); }
|
||||
}
|
||||
|
||||
&-image { width: 100%; }
|
||||
}
|
||||
}
|
||||
|
||||
@include t-media-query($s-small-up) {
|
||||
&__boundary {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__title { text-align: left; }
|
||||
|
||||
&__mosaic { width: 50%; order: 10; }
|
||||
&__content {
|
||||
width: 50%;
|
||||
p { padding-left: $s-gutter--medium; }
|
||||
}
|
||||
}
|
||||
|
||||
@include t-media-query($s-medium-up) {
|
||||
&__content {
|
||||
transform: translate(13%, -20%);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,103 +0,0 @@
|
||||
// Copyright (c) 2019 Dominic Masters
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as React from 'react';
|
||||
import { Image, ImageSource } from '@yourwishes/app-simple-react/dist/public';
|
||||
import { PageBoundary } from './../../../../objects/page/boundary/';
|
||||
import { Section } from './../../../../components/section/';
|
||||
import { Heading2 } from './../../../../objects/typography/heading';
|
||||
|
||||
import './styles.scss';
|
||||
|
||||
export interface TechIconProps {
|
||||
src:ImageSource,
|
||||
title:string
|
||||
}
|
||||
|
||||
export const TechIcon = (props:TechIconProps) => (
|
||||
<div className="c-tech-stack__platform-icon" title={props.title}>
|
||||
<div className="c-tech-stack__platform-icon-inner">
|
||||
<Image
|
||||
{...props}
|
||||
className="c-tech-stack__platform-icon-image"
|
||||
alt={props.title}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const TechStackSection = () => (
|
||||
<Section className="c-tech-stack">
|
||||
<PageBoundary size="small" className="c-tech-stack__boundary">
|
||||
<Heading2 className="c-tech-stack__title">
|
||||
Platforms I work with
|
||||
</Heading2>
|
||||
|
||||
<div className="c-tech-stack__platform">
|
||||
{/* First Row */}
|
||||
<TechIcon title="C#" src={ require('./../../../../assets/images/branding/csharp/csharp-logo.svg')} />
|
||||
<TechIcon title="NodeJS" src={ require('./../../../../assets/images/branding/nodejs/nodejs-logo.svg')} />
|
||||
<TechIcon title="Java" src={ require('./../../../../assets/images/branding/java/java-logo.svg')} />
|
||||
<TechIcon title="PHP" src={ require('./../../../../assets/images/branding/php/php-logo.svg')} />
|
||||
<TechIcon title="C++" src={ require('./../../../../assets/images/branding/cpp/cpp-logo.svg')} />
|
||||
|
||||
{/* Second Row */}
|
||||
<TechIcon title="TypeScript" src={ require('./../../../../assets/images/branding/typescript/typescript-logo.svg')} />
|
||||
<TechIcon title="React" src={ require('./../../../../assets/images/branding/react/react-logo.svg')} />
|
||||
<TechIcon title="Redux" src={ require('./../../../../assets/images/branding/redux/redux-logo.svg')} />
|
||||
<TechIcon title="webpack" src={ require('./../../../../assets/images/branding/webpack/webpack-logo.svg')} />
|
||||
<TechIcon title="jQuery" src={ require('./../../../../assets/images/branding/jquery/jquery-logo.svg')} />
|
||||
|
||||
{/* Third Row */}
|
||||
<TechIcon title="Shopify" src={ require('./../../../../assets/images/branding/shopify/shopify-logo.svg')} />
|
||||
<TechIcon title="Heroku" src={ require('./../../../../assets/images/branding/heroku/heroku-logo.svg')} />
|
||||
<TechIcon title="Google Cloud Platform" src={ require('./../../../../assets/images/branding/google-cloud/google-cloud-logo.svg')} />
|
||||
<TechIcon title="Digital Ocean" src={ require('./../../../../assets/images/branding/digitalocean/digitalocean-logo.svg')} />
|
||||
<TechIcon title="neto" src={ require('./../../../../assets/images/branding/neto/neto-logo.svg')} />
|
||||
|
||||
{/* Fourth Row */}
|
||||
<TechIcon title="MonoGame" src={ require('./../../../../assets/images/branding/monogame/monogame-logo.svg')} />
|
||||
<TechIcon title="OpenGL" src={ require('./../../../../assets/images/branding/opengl/opengl-logo.svg')} />
|
||||
<TechIcon title="Unity" src={ require('./../../../../assets/images/branding/unity/unity-logo.svg')} />
|
||||
<TechIcon title="LWJGL" src={ require('./../../../../assets/images/branding/lwjgl/lwjgl-logo.svg')} />
|
||||
{/* ??? */}
|
||||
|
||||
|
||||
{/* Fifth Row */}
|
||||
<TechIcon title="GraphQL" src={ require('./../../../../assets/images/branding/graphql/graphql-logo.svg')} />
|
||||
<TechIcon title="MySQL" src={ require('./../../../../assets/images/branding/mysql/mysql-logo.svg')} />
|
||||
<TechIcon title="PGSQL" src={ require('./../../../../assets/images/branding/pgsql/pgsql-logo.svg')} />
|
||||
{/* ??? */}
|
||||
{/* ??? */}
|
||||
|
||||
{/* Sixth Row */}
|
||||
<TechIcon title="Discord" src={ require('./../../../../assets/images/branding/discord/discord-logo.svg')} />
|
||||
<TechIcon title="Twitch" src={ require('./../../../../assets/images/branding/twitch/twitch-logo.svg')} />
|
||||
<TechIcon title="Twitter" src={ require('./../../../../assets/images/branding/twitter/twitter-logo.svg')} />
|
||||
{/* ??? */}
|
||||
{/* ??? */}
|
||||
|
||||
</div>
|
||||
</PageBoundary>
|
||||
</Section>
|
||||
);
|
@ -1,74 +0,0 @@
|
||||
@import './../../../../styles/global';
|
||||
|
||||
$c-tech-stack--spacing: 60%;
|
||||
$c-tech-stack--rows: 5;
|
||||
$c-tech-stack--columns: 5;
|
||||
$c-tech-stack--rows-width: $c-tech-stack--spacing * ( $c-tech-stack--rows - 1 );
|
||||
$c-tech-stack--half-rows-width: ($c-tech-stack--rows-width / 2) - $c-tech-stack--rows-width;
|
||||
|
||||
.c-tech-stack {
|
||||
//overflow: hidden;
|
||||
|
||||
&__title {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__platform {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
|
||||
&-icon {
|
||||
width: 20%;
|
||||
|
||||
&-inner {
|
||||
position: relative;
|
||||
padding-bottom: 100%;
|
||||
}
|
||||
|
||||
&-image {
|
||||
padding: $s-gutter--xsmall;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
object-fit: contain;
|
||||
object-position: center;
|
||||
transition: padding $s-animation--time-fast $s-animation--ease-out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include t-media-query($s-xsmall-up) {
|
||||
&__platform-icon {
|
||||
&-image { padding: $s-gutter--small; }
|
||||
}
|
||||
}
|
||||
|
||||
@include t-media-query($s-medium-up) {
|
||||
&__platform-icon {
|
||||
transform: translateX($c-tech-stack--half-rows-width);
|
||||
|
||||
@for $i from 1 through $c-tech-stack--rows {
|
||||
$x: $c-tech-stack--half-rows-width + ($c-tech-stack--spacing * $i);
|
||||
&:nth-child( n+#{$i * $c-tech-stack--columns + 1}) {
|
||||
transform: translateX($x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include t-media-query($s-large-up) {
|
||||
&__platform{
|
||||
max-width: 700px;
|
||||
|
||||
&-icon{
|
||||
&-image { padding: $s-gutter--medium; }
|
||||
//&:hover &-image { padding: $s-gutter--small; }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|