Merge branch 'master' into 'production'

Prod deploy

* NextJS

* Contact Page

* CSS fixes

See merge request sahkoinsinoorikilta/vtmk/web2.0-frontend!26
This commit is contained in:
Aarni Halinen
2021-01-19 15:55:41 +00:00
214 changed files with 13615 additions and 16029 deletions
+11 -28
View File
@@ -1,33 +1,16 @@
{
"presets": [
["env", {"modules": false}],
"react"
"next/babel"
],
"plugins": [
"react-hot-loader/babel",
[
"babel-plugin-styled-components",
{ "ssr": true, "displayName": true, "preprocess": false }
]
],
"env": {
"production": {
"plugins": [
[
[
"babel-plugin-styled-components",
{ "ssr": true, "displayName": true, "preprocess": false }
]
],
"presets": ["minify"]
},
"test": {
"plugins": [
[
"babel-plugin-styled-components",
{ "ssr": true, "displayName": true, "preprocess": false }
]
],
"presets": ["env", "react"]
}
}
}
{
"ssr": true,
"displayName": true,
"preprocess": false,
"pure": true
}
]
]
}
+15 -3
View File
@@ -1,3 +1,15 @@
node_modules/
dist/
.env
.next
.vscode
e2e-screenshots
node_modules
tests
.env*
.eslintrc.json
.gitattributes
.gitignore
.gitlab-ci.yml
.nvmrc
.stylelintrc
LICENSE
README*
stack-compose*
+1
View File
@@ -0,0 +1 @@
NEXT_PUBLIC_API_URL=https://api.dev.sahkoinsinoorikilta.fi/api
+1
View File
@@ -0,0 +1 @@
NEXT_PUBLIC_API_URL=https://api.sahkoinsinoorikilta.fi/api
-1
View File
@@ -1 +0,0 @@
API_URL=https://api.dev.sik.party/api
+1
View File
@@ -0,0 +1 @@
NEXT_PUBLIC_API_URL=https://api.dev.sahkoinsinoorikilta.fi/api
+30 -65
View File
@@ -5,7 +5,8 @@
"node": true
},
"extends": [
"eslint:recommended",
"airbnb",
"airbnb/hooks",
"plugin:@typescript-eslint/recommended",
"plugin:react/recommended"
],
@@ -32,73 +33,37 @@
}
},
"rules": {
"arrow-parens": ["off", "always"],
"comma-dangle": [
"error",
{
"arrays": "ignore",
"objects": "ignore",
"imports": "ignore",
"exports": "ignore",
"functions": "ignore"
}
],
"consistent-return": "warn",
"global-require": "warn",
"linebreak-style": "off",
"camelcase": "off",
"max-len": [
"off",
"warn",
160
],
"no-console": "warn",
"no-extra-boolean-cast": "warn",
"no-param-reassign": "error",
"no-shadow": "warn",
"no-unused-vars": "off",
"no-useless-constructor": "warn",
"object-curly-newline": "error",
"prefer-destructuring": "warn",
"prefer-template": "error",
"quote-props": ["error", "consistent"],
"quotes": [
],
"no-mixed-operators": "off",
"no-shadow": "off",
"no-use-before-define": "off",
"quotes": [
"error",
"double"
],
"import/no-unresolved": "off",
"import/first": "off",
"import/order": "off",
"import/no-extraneous-dependencies": "off",
"import/newline-after-import": "off",
"import/prefer-default-export": "off",
"indent": ["error", 2],
"jsx-a11y/anchor-is-valid": "off",
"jsx-a11y/alt-text": "off",
"jsx-a11y/click-events-have-key-events": "off",
"jsx-a11y/iframe-has-title": "off",
"jsx-a11y/no-static-element-interactions": "off",
"jsx-a11y/label-has-associated-control": "off",
"jsx-a11y/label-has-for": "off",
"react/display-name": "off",
"react/destructuring-assignment": "off",
"react/jsx-closing-bracket-location": "off",
"react/jsx-closing-tag-location": "off",
"react/jsx-curly-brace-presence": "off",
"react/jsx-first-prop-new-line": "off",
"react/jsx-filename-extension": "off",
"react/jsx-indent-props": "off",
"react/jsx-one-expression-per-line": "off",
"react/jsx-wrap-multilines": "off",
"react/no-access-state-in-setstate": "warn",
"react/prop-types": "off",
"react/prefer-stateless-function": "off",
"react/self-closing-comp": "off",
"@typescript-eslint/camelcase": "off",
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/explicit-member-accessibility": "off",
"@typescript-eslint/indent": "off",
"@typescript-eslint/interface-name-prefix": "off",
"@typescript-eslint/no-empty-interface": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unused-vars": "warn"
],
"import/extensions": "off",
"import/no-unresolved": "off",
"import/order": "off",
"import/prefer-default-export": "warn",
"operator-linebreak": "off",
"no-unused-vars": "off",
"react/jsx-filename-extension": "off",
"react/jsx-one-expression-per-line": "off",
"react/jsx-props-no-spreading": "off",
"react/prop-types": "off",
"@typescript-eslint/no-shadow": "error",
// Temp
"react/no-array-index-key": "off",
"@typescript-eslint/explicit-function-return-type": "off",
"jsx-a11y/alt-text": "off",
"jsx-a11y/iframe-has-title": "off",
"jsx-a11y/label-has-associated-control": "off",
"jsx-a11y/click-events-have-key-events": "off",
"jsx-a11y/no-noninteractive-element-interactions": "off",
"jsx-a11y/no-static-element-interactions": "off"
}
}
+37 -7
View File
@@ -1,10 +1,40 @@
.idea/
dist/
node_modules/
src/**/*.jsx
.vscode/
tests/jest/__coverage__/
tests/jest/**/*.jsx
tests/testcafe/screenshots
.vscode/
e2e-screenshots/
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
# vercel
.vercel
/public/favicons/
+30 -15
View File
@@ -1,5 +1,6 @@
stages:
- setup
- audit
- lint
- build
- test
@@ -7,7 +8,7 @@ stages:
- deploy
install:
image: node:12
image: node:14
stage: setup
script:
- npm ci
@@ -16,53 +17,67 @@ install:
- node_modules
expire_in: 1 week
audit:
image: node:14
needs: ["install"]
stage: audit
script:
- npm audit --audit-level=critical
es:lint:
image: node:12
image: node:14
needs: ["install"]
stage: lint
script:
- npm run lint:es
sass:lint:
image: node:12
css:lint:
image: node:14
needs: ["install"]
stage: lint
script:
- npm run lint:sass
- npm run lint:css
# test:unit:
# image: node:12
# image: node:14
# stage: test
# script:
# - npm run test:unit
build:
image: node:12
image: node:14
needs: ["install"]
stage: build
script:
- API_URL=https://api.dev.sik.party/api npm run build
- NODE_ENV=test npm run build
dependencies:
- install
artifacts:
paths:
- dist
- .next
expire_in: 1 week
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- node_modules/
- .next/cache/
test:e2e:
image: circleci/node:12-browsers
image: circleci/node:14-browsers
needs: ["install", "build"]
stage: test
only:
- master
script:
- npm run test:e2e
artifacts:
paths:
- e2e-screenshots
expire_in: 1 week
when: on_failure
publish:dev:
stage: publish
image: docker:stable
needs: ["build", "test:e2e", "es:lint", "sass:lint"]
needs: ["build", "test:e2e", "es:lint", "css:lint"]
services:
- docker:stable-dind
only:
@@ -93,7 +108,7 @@ deploy:dev:
- master
environment:
name: dev
url: dev.sik.party
url: dev.sahkoinsinoorikilta.fi
variables:
DOCKER_HOST: $DEV_CI_DOCKER_HOST
DOCKER_TLS_VERIFY: 1
@@ -115,7 +130,7 @@ deploy:prod:
- production
environment:
name: production
url: sika.sik.party
url: prod.sahkoinsinoorikilta.fi
when: manual
variables:
DOCKER_HOST: $CI_DOCKER_HOST
+1
View File
@@ -0,0 +1 @@
14
+8 -1
View File
@@ -1,3 +1,10 @@
{
"extends": "stylelint-config-recommended-scss"
"processors": [
"stylelint-processor-styled-components"
],
"extends": [
"stylelint-config-recommended",
"stylelint-config-styled-components"
],
"syntax": "css"
}
+19 -9
View File
@@ -1,15 +1,25 @@
FROM node:12-alpine as builder
FROM node:14-alpine as builder
RUN apk add --no-cache libpng-dev gcc make g++ zlib-dev bash lcms2-dev autoconf automake libtool nasm
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --only-prod
RUN npm install
COPY . ./
ENV API_URL https://api.dev.sik.party/api
COPY tsconfig.json next-env.d.ts .babelrc next.config.js ./
COPY src src/
COPY public public/
COPY types types/
ENV NEXT_TELEMETRY_DISABLED=1
ENV NEXT_PUBLIC_API_URL=https://api.dev.sahkoinsinoorikilta.fi/api
RUN npm run build
FROM fnichol/uhttpd AS server
FROM node:14-alpine as server
WORKDIR /www
COPY package.json package-lock.json next.config.js ./
COPY --from=builder .next .next
COPY --from=builder node_modules node_modules
COPY --from=builder public public
RUN npm prune --production
EXPOSE 3000
COPY --from=builder /app/dist /www
ENTRYPOINT ["/usr/sbin/run_uhttpd", "-f", "-p", "3000", "-h", "/www", "-E", "/"]
ENTRYPOINT ["npm", "run", "serve"]
+19 -9
View File
@@ -1,15 +1,25 @@
FROM node:12-alpine as builder
FROM node:14-alpine as builder
RUN apk add --no-cache libpng-dev gcc make g++ zlib-dev bash lcms2-dev autoconf automake libtool nasm
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --only-prod
RUN npm install
COPY . ./
ENV API_URL https://sika.sik.party/api
COPY tsconfig.json next-env.d.ts .babelrc next.config.js ./
COPY src src/
COPY public public/
COPY types types/
ENV NEXT_TELEMETRY_DISABLED=1
ENV NEXT_PUBLIC_API_URL=https://api.sahkoinsinoorikilta.fi/api
RUN npm run build
FROM fnichol/uhttpd AS server
FROM node:14-alpine as server
WORKDIR /www
COPY package.json package-lock.json next.config.js ./
COPY --from=builder .next .next
COPY --from=builder node_modules node_modules
COPY --from=builder public public
RUN npm prune --production
EXPOSE 3000
COPY --from=builder /app/dist /www
ENTRYPOINT ["/usr/sbin/run_uhttpd", "-f", "-p", "3000", "-h", "/www", "-E", "/"]
ENTRYPOINT ["npm", "run", "serve"]
+30
View File
@@ -0,0 +1,30 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/import?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
+2 -1
View File
@@ -17,7 +17,8 @@ Minimal starter kit with hot module replacement (HMR) for rapid development.
## Installation
1. Clone/download repo
2. `npm install`
2. Install node v14
3. `npm install`
## Usage
-58
View File
@@ -1,58 +0,0 @@
// Shared config (dev and prod)
const {resolve} = require("path");
const TsconfigPathsPlugin = require("tsconfig-paths-webpack-plugin");
const StyleLintPlugin = require("stylelint-webpack-plugin");
const webpack = require('webpack');
const Dotenv = require("dotenv-webpack");
module.exports = function (env, argv) {
const config = {};
config.output = {
publicPath: "/",
};
config.resolve = {
extensions: [".ts", ".tsx", ".js", ".jsx"],
plugins: [new TsconfigPathsPlugin()]
};
config.context = resolve(__dirname, "../../src");
config.module = {
rules: [],
};
config.module.rules.push({
test: /\.js$/,
use: ["babel-loader", "source-map-loader"],
exclude: /node_modules/
});
config.module.rules.push({
test: /\.tsx?$/,
use: ["babel-loader", "ts-loader"]
});
config.module.rules.push({
test: /\.(jpe?g|png|gif|svg)$/i,
loaders: [
"file-loader?hash=sha512&digest=hex&name=assets/img/[hash].[ext]",
"image-webpack-loader?bypassOnDebug&optipng.optimizationLevel=7&gifsicle.interlaced=false"
]
});
const envVars = {};
Object.keys(process.env).forEach((key) => {
envVars[`process.env.${key}`] = JSON.stringify(process.env[key]);
});
config.plugins = [
new webpack.DefinePlugin(envVars),
new StyleLintPlugin(),
new Dotenv({
path: "./.env"
}),
];
config.performance = {
hints: false
};
return config;
};
-72
View File
@@ -1,72 +0,0 @@
// Development config
const merge = require("webpack-merge");
const webpack = require("webpack");
const FaviconsWebpackPlugin = require("favicons-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const commonConfig = require("./common.js");
module.exports = function (env, argv) {
const base = commonConfig(env, argv);
base.mode = "development";
base.entry = [
"react-hot-loader/patch", // Activate HMR for React
"webpack-dev-server/client?http://0.0.0.0:3000", // Bundle the client for webpack-dev-server and connect to the provided endpoint
"webpack/hot/only-dev-server", // Bundle the client for hot reloading, only- means to only hot reload for successful updates
"./index.tsx" // The entry point of our app
];
base.devServer = {
hot: true, // Enable HMR on the server
historyApiFallback: true,
host: '0.0.0.0',
port: '3000',
allowedHosts: [
'.sik.party',
'.sahkoinsinoorikilta.fi',
],
};
base.devtool = "cheap-module-eval-source-map";
base.plugins = base.plugins.concat([
new FaviconsWebpackPlugin({
logo: "./assets/img/favicon.png",
prefix: "assets/icons/",
icons: {
android: false,
appleIcon: false,
appleStartup: false,
coast: false,
favicons: true,
firefox: false,
opengraph: false,
twitter: false,
yandex: false,
windows: false
}
}),
new webpack.HotModuleReplacementPlugin(), // Enable HMR globally
new webpack.NamedModulesPlugin(), // Prints more readable module names in the browser console on HMR updates
new HtmlWebpackPlugin({template: "index.html.ejs"}),
]);
base.module.rules.push({
test: /\.css$/,
use: ["style-loader", {loader: "css-loader", options: {importLoaders: 1}}, "postcss-loader"]
});
base.module.rules.push({
test: /\.scss$/,
loaders: [
"style-loader",
{loader: "css-loader", options: {importLoaders: 1}},
"postcss-loader",
{
loader: 'sass-loader',
options: {
// Prefer `dart-sass`
implementation: require('sass'),
},
},
]
});
return base;
};
-127
View File
@@ -1,127 +0,0 @@
// Production config
const path = require("path");
const merge = require("webpack-merge");
const resolve = path.resolve;
const FaviconsWebpackPlugin = require("favicons-webpack-plugin");
const nodeExternals = require('webpack-node-externals');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const WebpackCdnPlugin = require('webpack-cdn-plugin');
/* NOTE: This is a list of all routes that are prerendered for production use.
Please list all routes that contain search engine accessible content, i.e.,
stuff that you would like to find with a Google Search. */
const commonConfig = require("./common");
module.exports = function (env, argv) {
const base = commonConfig(env, argv);
base.mode = "production";
base.entry = "./index.tsx";
base.output = {
path: resolve(__dirname, "../../dist"),
publicPath: "/",
};
base.devtool = "source-map";
base.plugins.push(
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: "assets/styles.css?[hash]",
}),
);
if (env.platform === 'server') {
base.entry = "./server/index.ts";
base.output.filename = 'js/server.js?[hash]';
base.target = 'node';
base.externals = [nodeExternals()];
base.module.rules.push({
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
{loader: "css-loader", options: {importLoaders: 1}},
"postcss-loader"
],
});
base.module.rules.push({
test: /\.scss$/,
loaders: [
MiniCssExtractPlugin.loader,
{loader: "css-loader", options: {importLoaders: 1}},
"postcss-loader",
{
loader: 'sass-loader',
options: {
// Prefer `dart-sass`
implementation: require('sass'),
},
},
]
});
}
else if (env.platform === 'client') {
base.entry = './client/index.ts';
base.output.filename = 'js/client.js?[hash]';
base.target = 'web';
base.module.rules.push({
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
{loader: "css-loader", options: {importLoaders: 1}},
"postcss-loader"
],
});
base.module.rules.push({
test: /\.scss$/,
loaders: [
MiniCssExtractPlugin.loader,
{loader: "css-loader", options: {importLoaders: 1}},
"postcss-loader",
{
loader: 'sass-loader',
options: {
// Prefer `dart-sass`
implementation: require('sass'),
},
},
]
});
base.plugins.push(
new HtmlWebpackPlugin({
template: "index.html.ejs",
}),
new FaviconsWebpackPlugin({
logo: "./assets/img/favicon.png",
prefix: "assets/icons/",
icons: {
android: true,
appleIcon: true,
appleStartup: true,
coast: true,
favicons: true,
firefox: true,
opengraph: true,
twitter: true,
yandex: true,
windows: true
}
}),
new WebpackCdnPlugin({
modules: [
{ name: 'react', var: 'React', path: `umd/react.${process.env.NODE_ENV}.min.js` },
{ name: 'react-dom', var: 'ReactDOM', path: `umd/react-dom.${process.env.NODE_ENV}.min.js` },
],
}),
);
}
return base;
};
-11
View File
@@ -1,11 +0,0 @@
version: '3'
services:
frontend:
build: .
image: registry.gitlab.com/sahkoinsinoorikilta/vtmk/web2.0-frontend/frontend-prod
ports:
- "3000:3000"
environment:
API_URL: ${API_URL}
command: npm run start-prod
-17
View File
@@ -1,17 +0,0 @@
version: '3'
services:
frontend:
build: .
image: registry.gitlab.com/sahkoinsinoorikilta/vtmk/web2.0-frontend
ports:
- "3000:3000"
environment:
API_URL: ${API_URL}
mock-backend:
build: .
image: registry.gitlab.com/sahkoinsinoorikilta/vtmk/web2.0-frontend/frontend-mock-backend
ports:
- "1234:1234"
command: npm run mock-backend
+2
View File
@@ -0,0 +1,2 @@
/// <reference types="next" />
/// <reference types="next/types/global" />
+30
View File
@@ -0,0 +1,30 @@
const FaviconsWebpackPlugin = require("favicons-webpack-plugin");
const withBundleAnalyzer = require("@next/bundle-analyzer")({
enabled: process.env.ANALYZE === "true",
});
module.exports = withBundleAnalyzer({
target: "server",
images: {
domains: [
"sahkoinsinoorikilta.fi",
"prod.sahkoinsinoorikilta.fi",
"api.sahkoinsinoorikilta.fi",
"static.sahkoinsinoorikilta.fi",
"api.dev.sahkoinsinoorikilta.fi",
"placehold.it"
],
},
webpack: (config) => {
config.plugins.push(
new FaviconsWebpackPlugin({
logo: "./public/favicon.png",
outputPath: "../public/favicons",
prefix: "/favicons",
inject: false
})
);
return config;
}
});
+8716 -12219
View File
File diff suppressed because it is too large Load Diff
+40 -85
View File
@@ -20,118 +20,73 @@
"license": "MIT",
"homepage": "https://sik.ayy.fi",
"scripts": {
"build": "NODE_ENV=production npm-run-all build:client build:server",
"build:server": "webpack -p --config=configs/webpack/prod.js --env.platform=server",
"build:client": "webpack -p --config=configs/webpack/prod.js --env.platform=client",
"lint": "npm run lint:es && npm run lint:sass",
"build": "next build",
"lint": "npm run lint:es && npm run lint:css",
"lint:es": "eslint \"./src/**/*.{ts,tsx}\"",
"lint:es:fix": "eslint --fix \"./src/**/*.{ts,tsx}\"",
"lint:sass": "stylelint \"./src/**/*.{scss,css}\"",
"start": "npm run start-dev",
"start-dev": "webpack-dev-server --config=configs/webpack/dev.js",
"serve": "node dist/js/server.js",
"start-prod": "npm run build && npm run serve",
"lint:css": "stylelint \"./src/**/*.{ts,tsx}\"",
"start": "next dev",
"start-prod": "next start --port ${SERVER_PORT:=80}",
"serve": "next start --port 3000",
"test": "npm run test:e2e:verbose",
"test:e2e": "npm-run-all -p -r serve test:e2e:testcafe",
"test:e2e:verbose": "npm-run-all -p -r serve test:e2e:testcafe:verbose",
"test:e2e:testcafe": "testcafe -S -s 'tests/testcafe/screenshots' --app-init-delay 2000 chrome:headless tests/testcafe",
"test:e2e:testcafe:verbose": "testcafe -S -s 'tests/testcafe/screenshots' --app-init-delay 2000 chrome tests/testcafe"
"test:e2e": "testcafe --list-browsers && npm-run-all -p -r serve testcafe",
"test:e2e:verbose": "npm-run-all -p -r serve testcafe:verbose",
"testcafe": "testcafe --skip-js-errors -S -s 'e2e-screenshots' --app-init-delay 2000 chrome:headless tests/testcafe",
"testcafe:verbose": "testcafe --skip-js-errors -S -s 'e2e-screenshots' --app-init-delay 2000 chrome tests/testcafe",
"build-analyze": "ANALYZE=true npm run build"
},
"husky": {
"hooks": {
"pre-push": "npm-run-all -s lint build test"
"pre-push": "npm run lint"
}
},
"devDependencies": {
"@types/jest": "24.0.22",
"@types/js-cookie": "2.2.4",
"@types/node": "10.14.7",
"@types/react": "16.8.18",
"@types/react-beautiful-dnd": "13.0.0",
"@types/react-csv": "1.1.1",
"@types/react-dom": "16.8.4",
"@types/react-helmet": "6.0.0",
"@types/react-jsonschema-form": "1.7.3",
"@types/react-router-dom": "5.1.5",
"@types/shortid": "0.0.29",
"@types/styled-components": "5.1.1",
"@typescript-eslint/eslint-plugin": "^4.8.2",
"@typescript-eslint/parser": "^4.8.2",
"babel-cli": "6.26.0",
"babel-core": "6.26.3",
"babel-loader": "7.1.5",
"@typescript-eslint/eslint-plugin": "4.8.2",
"@typescript-eslint/parser": "4.8.2",
"babel-plugin-styled-components": "1.10.7",
"babel-preset-env": "1.7.0",
"babel-preset-minify": "0.4.3",
"babel-preset-react": "6.24.1",
"compression": "1.7.4",
"css-loader": "2.1.1",
"dotenv": "6.2.0",
"dotenv-webpack": "1.7.0",
"eslint": "^7.14.0",
"eslint-config-standard": "^16.0.2",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-jsx-a11y": "^6.4.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-react": "^7.21.5",
"eslint-plugin-standard": "^5.0.0",
"express": "4.17.0",
"favicons-webpack-plugin": "1.0.2",
"file-loader": "4.2.0",
"fs-extra": "6.0.1",
"helmet": "3.21.2",
"html-webpack-plugin": "3.2.0",
"eslint": "7.14.0",
"eslint-config-airbnb": "18.2.1",
"eslint-plugin-import": "2.22.1",
"eslint-plugin-jsx-a11y": "6.4.1",
"eslint-plugin-react": "7.21.5",
"eslint-plugin-react-hooks": "4.2.0",
"husky": "1.3.1",
"image-webpack-loader": "6.0.0",
"mini-css-extract-plugin": "0.4.5",
"module-to-cdn": "3.1.2",
"morgan": "1.9.1",
"npm-run-all": "4.1.5",
"postcss-loader": "2.1.6",
"react": "16.8.6",
"react-addons-test-utils": "15.6.2",
"react-dom": "16.8.6",
"react-hot-loader": "4.8.8",
"sass": "1.29.0",
"sass-loader": "7.1.0",
"serve": "11.3.2",
"style-loader": "0.21.0",
"stylelint": "11.1.1",
"stylelint-config-recommended-scss": "4.0.0",
"stylelint-config-standard": "19.0.0",
"stylelint-scss": "3.12.1",
"stylelint-webpack-plugin": "1.0.3",
"testcafe": "1.6.1",
"testcafe-react-selectors": "2.1.0",
"ts-loader": "7.0.5",
"tsconfig-paths-webpack-plugin": "3.2.0",
"stylelint": "13.8.0",
"stylelint-config-recommended": "3.0.0",
"stylelint-config-styled-components": "0.1.1",
"stylelint-processor-styled-components": "1.10.0",
"testcafe": "1.10.1",
"typescript": "3.9.5",
"typescript-plugin-styled-components": "1.4.4",
"uglifyjs-webpack-plugin": "1.3.0",
"webpack": "4.41.2",
"webpack-cdn-plugin": "3.2.0",
"webpack-cli": "3.3.10",
"webpack-dev-middleware": "3.7.2",
"webpack-dev-server": "3.11.0",
"webpack-merge": "4.2.2",
"webpack-node-externals": "1.7.2"
"typescript-plugin-styled-components": "1.4.4"
},
"dependencies": {
"axios": "0.19.0",
"@next/bundle-analyzer": "10.0.5",
"axios": "0.21.1",
"date-fns": "2.0.0-alpha.27",
"favicons-webpack-plugin": "4.2.0",
"js-cookie": "2.2.0",
"lodash": "4.17.20",
"next": "10.0.5",
"normalize.css": "8.0.1",
"query-string": "6.5.0",
"react-beautiful-dnd": "10.1.1",
"react": "17.0.1",
"react-beautiful-dnd": "13.0.0",
"react-csv": "2.0.3",
"react-helmet": "5.2.1",
"react-jsonschema-form": "^1.8.1",
"react-markdown": "4.3.1",
"react-dom": "17.0.1",
"react-jsonschema-form": "1.8.1",
"react-markdown": "5.0.3",
"react-mde": "11.0.0",
"react-router-dom": "4.3.1",
"react-router-hash-link": "1.2.1",
"shortid": "2.2.14",
"styled-components": "5.1.1"
},
"postcss": {}
"styled-components": "5.1.1",
"swr": "0.3.11"
}
}

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

+1 -12
View File
@@ -1,4 +1,3 @@
<!DOCTYPE html>
<!--
-` o` .s h` -///.
.o+/o `d m /s```y: -+:.
@@ -45,14 +44,4 @@
:y`/Nm. /do/- /M` Nm/.M: sd-`/M:`hy++d+
/- .y+oN: sd NyhhM: om/-+m- .:-`
`-:- o+ h/ /h: -/+:`
-->
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://fonts.googleapis.com/css?family=Montserrat:100,100i,200,200i,300,300i,400,400i,500,500i,600,600i,700,800,900" rel="stylesheet">
</head>
<body>
<div id="root"></div>
</body>
</html>
-->

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Before

Width:  |  Height:  |  Size: 409 B

After

Width:  |  Height:  |  Size: 409 B

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Before

Width:  |  Height:  |  Size: 425 B

After

Width:  |  Height:  |  Size: 425 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Before

Width:  |  Height:  |  Size: 615 B

After

Width:  |  Height:  |  Size: 615 B

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

+159
View File
@@ -0,0 +1,159 @@
{
"name_fi": "Hallitus",
"name_en": "Board",
"roles": [
{
"name_fi": "Puheenjohtaja",
"name_en": "Chairman",
"representatives": [
{
"name": "Johannes Ora"
}
]
},
{
"name_fi": "Sihteeri",
"name_en": "Secretary",
"representatives": [
{
"name": "Salla Lyytikäinen",
"phone_number": null,
"email": null,
"image": null
}
]
},
{
"name_fi": "Rahastonhoitaja",
"name_en": "",
"representatives": [
{
"name": "Santeri Huhtala",
"phone_number": null,
"email": null,
"image": null
}
]
},
{
"name_fi": "Fuksitoimikunnan Puheenjohtaja",
"name_en": "",
"representatives": [
{
"name": "Toni Ojala",
"phone_number": null,
"email": null,
"image": null
}
]
},
{
"name_fi": "Fuksitoimikunnan puheenjohtajan adjutantti",
"name_en": "",
"representatives": [
{
"name": "Toni Lyttinen",
"phone_number": null,
"email": null,
"image": null
}
]
},
{
"name_fi": "Hovimestari",
"name_en": "",
"representatives": [
{
"name": "Eveliina Ahonen",
"phone_number": null,
"email": null,
"image": null
}
]
},
{
"name_fi": "Hovineuvos",
"name_en": "",
"representatives": [
{
"name": "Melissa Dönmez",
"phone_number": null,
"email": null,
"image": null
}
]
},
{
"name_fi": "ISOvastaava",
"name_en": "",
"representatives": [
{
"name": "Heidi Mäkitalo",
"phone_number": null,
"email": null,
"image": null
}
]
},
{
"name_fi": "Hyvinvointimestari",
"name_en": "",
"representatives": [
{
"name": "Sauli Norja",
"phone_number": null,
"email": null,
"image": null
}
]
},
{
"name_fi": "Opintomestari",
"name_en": "",
"representatives": [
{
"name": "Simo Hakanummi",
"phone_number": null,
"email": null,
"image": null
}
]
},
{
"name_fi": "Teknologiamestari",
"name_en": "",
"representatives": [
{
"name": "Oskari Ponkala",
"phone_number": null,
"email": null,
"image": null
}
]
},
{
"name_fi": "Ulkomestari",
"name_en": "",
"representatives": [
{
"name": "Oliver Hiekkamies",
"phone_number": null,
"email": null,
"image": null
}
]
},
{
"name_fi": "Yrityssuhdemestari",
"name_en": "",
"representatives": [
{
"name": "Otto Julkunen",
"phone_number": null,
"email": null,
"image": null
}
]
}
]
}
+55
View File
@@ -0,0 +1,55 @@
{
"name_fi": "Hyvinvointitoimikunta",
"name_en": "",
"roles": [
{
"name_fi": "Hyvinvointimestari",
"name_en": "",
"representatives": [
{ "name": "Sauli Norja" }
]
},
{
"name_fi": "Kulttuurivastaava",
"name_en": "",
"representatives": [
{ "name": "Juha Anttila" },
{ "name": "Aino Suomi" },
{ "name": "Nestori Ylönjoki" }
]
},
{
"name_fi": "Liikuntavastaava",
"name_en": "",
"representatives": [
{ "name": "Elmeri Pälikkö" },
{ "name": "Joel Wickström" }
]
},
{
"name_fi": "Kiltahuonevastaava",
"name_en": "",
"representatives": [
{ "name": "Ilari Ojakorpi" }
]
},
{
"name_fi": "Kiltapäiväkerhovastaava",
"name_en": "",
"representatives": [
{ "name": "Samuel Laine" },
{ "name": "Aleksanteri Vesala" }
]
},
{
"name_fi": "Retkivastaava",
"name_en": "",
"representatives": [
{ "name": "Jarno Mustonen" },
{ "name": "Suvi Karanta" },
{ "name": "Jesse Räisänen" },
{ "name": "Mikko Suhonen" }
]
}
]
}
+89
View File
@@ -0,0 +1,89 @@
{
"name_fi": "Mediatoimikunta",
"name_en": "",
"roles": [
{
"name_fi": "Puheenjohtaja",
"name_en": "",
"representatives": [
{
"name": "Salla Lyytikäinen",
"phone_number": null,
"email": null,
"image": null
}
]
},
{
"name_fi": "Päätoimittaja",
"name_en": "",
"representatives": [
{ "name": "Sasu Salasti" }
]
},
{
"name_fi": "Toimittaja",
"name_en": "",
"representatives": [
{ "name": "Tuukka Syrjänen" },
{ "name": "Ilmari Kasvi" },
{ "name": "Elias Hirvonen" },
{ "name": "Miika Koskela" },
{ "name": "Taneli Myllykangas" },
{ "name": "Emmaleena Ahonen" },
{ "name": "Ville-Pekka Laakkonen" },
{ "name": "Sofia Öhman" },
{ "name": "Nestori Yrjönkoski" },
{ "name": "Jami Hyytiäinen" },
{ "name": "Aleksanteri Vesala" }
]
},
{
"name_fi": "Toimittaja & Valokuvaaja",
"name_en": "",
"representatives": [
{ "name": "Kiia-Einola" }
]
},
{
"name_fi": "Taittaja",
"name_en": "",
"representatives": [
{ "name": "Aino Suomi" },
{ "name": "Olli Komulainen" },
{ "name": "Emilia Kortelainen" }
]
},
{
"name_fi": "Taittaja & Valokuvaaja",
"name_en": "",
"representatives": [
{ "name": "Jonna Tammikivi" }
]
},
{
"name_fi": "Valokuvaaja",
"name_en": "",
"representatives": [
{ "name": "Suvi Karanta" },
{ "name": "Mikko Haaparanta" },
{ "name": "Johannes Viirimäki" }
]
},
{
"name_fi": "Valokuvaaja & Graafikko",
"name_en": "",
"representatives": [
{ "name": "Kalle Petäjäaho" },
{ "name": "Maria Pöllä" }
]
},
{
"name_fi": "Videokuvaaja",
"name_en": "",
"representatives": [
{ "name": "Aaro Rasilainen" }
]
}
]
}
+31
View File
@@ -0,0 +1,31 @@
{
"name_fi": "Opintotoimikunta",
"name_en": "",
"roles": [
{
"name_fi": "Opintomestari",
"name_en": "",
"representatives": [
{ "name": "Simo Hakanummi" }
]
},
{
"name_fi": "Opintovastaava",
"name_en": "",
"representatives": [
{ "name": "Miina-Maija Simonen" },
{ "name": "Tomi Valkonen" },
{ "name": "Leo Lahti" },
{ "name": "Ville-Pekka Laakkonen" },
{ "name": "Samu Nyman" }
]
},
{
"name_fi": "Abimarkkinointi Vastaava",
"name_en": "",
"representatives": [
{ "name": "Ilkka Huttu" }
]
}
]
}
+63
View File
@@ -0,0 +1,63 @@
{
"name_fi": "Ohjelmatoimikunta",
"name_en": "",
"roles": [
{
"name_fi": "Hovimestari",
"name_en": "",
"representatives": [
{ "name": "Eveliina Ahonen" }
]
},
{
"name_fi": "Hovineuvos",
"name_en": "",
"representatives": [
{ "name": "Melissa Dönmez" }
]
},
{
"name_fi": "Emäntä",
"name_en": "",
"representatives": [
{ "name": "Oona Karjalainen" },
{ "name": "Emilia Kortemäki" },
{ "name": "Venla Vastamäki" }
]
},
{
"name_fi": "Isäntä",
"name_en": "",
"representatives": [
{ "name": "Henry Jaakkola" },
{ "name": "Sakke Kangas" },
{ "name": "Otto Torkkeli" },
{ "name": "Tommi Oinen" },
{ "name": "Eero Ketonen" }
]
},
{
"name_fi": "Lukkari",
"name_en": "",
"representatives": [
{ "name": "Tuomo Leino" },
{ "name": "Hami Hyytinen" },
{ "name": "Tuomas Pajunpää" },
{ "name": "Samuel Laine" },
{ "name": "Toni Miilunpalo" }
]
},
{
"name_fi": "Lukkarikisällit",
"name_en": "",
"representatives": [
{ "name": "Jesse Räisänen" },
{ "name": "Eino Laakso" },
{ "name": "Sakari Harjunpää" },
{ "name": "Niilo Ojala" },
{ "name": "Ilkka Huttu" },
{ "name": "Akseli Järvinen" }
]
}
]
}
+29
View File
@@ -0,0 +1,29 @@
{
"name_fi": "Pajatoimikunta",
"name_en": "",
"roles": [
{
"name_fi": "Pajavastaava",
"name_en": "",
"representatives": [
{ "name": "Karl Lipping" }
]
},
{
"name_fi": "Pajakisälli",
"name_en": "",
"representatives": [
{ "name": "Tommi Sytelä" },
{ "name": "Eerikki Eskola" },
{ "name": "Arkadii Kolchin" },
{ "name": "Samu Nyman" },
{ "name": "Konsta Langi" },
{ "name": "Johannes Viirimäki" },
{ "name": "Justus Ojala" },
{ "name": "Ville Tujunen" },
{ "name": "Antti Tarkka" },
{ "name": "Pyry Vaara" }
]
}
]
}
+70
View File
@@ -0,0 +1,70 @@
{
"name_fi": "SIK100-toimikunta",
"name_en": "",
"roles": [
{
"name_fi": "Puheenjohtaja",
"name_en": "",
"representatives": [
{ "name": "Erna Virtanen" }
]
},
{
"name_fi": "Webivastaava",
"name_en": "",
"representatives": [
{ "name": "Jaakko Koskela" }
]
},
{
"name_fi": "Markkinointivastaava",
"name_en": "",
"representatives": [
{ "name": "Sasu Salasti" }
]
},
{
"name_fi": "Yritysvastaava",
"name_en": "",
"representatives": [
{ "name": "Juuli Leppänen" }
]
},
{
"name_fi": "Seminaarivastaava",
"name_en": "",
"representatives": [
{ "name": "Sini Huhtinen" }
]
},
{
"name_fi": "Kevätkarnevaalimajuri",
"name_en": "",
"representatives": [
{ "name": "Olli Komulainen" }
]
},
{
"name_fi": "PoTa100-pääjuhlatirehtööri",
"name_en": "",
"representatives": [
{ "name": "Emmaleena Ahonen" },
{ "name": "Jonna Tammikivi" }
]
},
{
"name_fi": "PoTa100-jatkokuvernööri",
"name_en": "",
"representatives": [
{ "name": "Mikael Liimatainen" }
]
},
{
"name_fi": "PoTa100-sillistirehtööri",
"name_en": "",
"representatives": [
{ "name": "Tuomo Leino" }
]
}
]
}
+35
View File
@@ -0,0 +1,35 @@
{
"name_fi": "Teknologiatoimikunta",
"name_en": "",
"roles": [
{
"name_fi": "Teknologiamestari",
"name_en": "",
"representatives": [
{ "name": "Oskari Ponkala" }
]
},
{
"name_fi": "Tekniikkavastaava",
"name_en": "",
"representatives": [
{ "name": "Antti Mäki" }
]
},
{
"name_fi": "Web-Kisälli",
"name_en": "",
"representatives": [
{ "name": "Ilari Ojakorpi" },
{ "name": "Leo Lahti" },
{ "name": "Jyri Korhonen" },
{ "name": "Tuukka Syrjänen" },
{ "name": "Emmaleena Ahonen" },
{ "name": "Mikko Suhonen" },
{ "name": "Jaakko Koskela" },
{ "name": "Justus Ojala" }
]
}
]
}
+43
View File
@@ -0,0 +1,43 @@
{
"name_fi": "Ulkotoimikunta",
"name_en": "",
"roles": [
{
"name_fi": "Ulkomestari",
"name_en": "",
"representatives": [
{ "name": "Oliver Hiekkamies" }
]
},
{
"name_fi": "Kv-ISOvastaava",
"name_en": "",
"representatives": [
{ "name": "Elias Hirvonen" }
]
},
{
"name_fi": "International Helper",
"name_en": "",
"representatives": [
{ "name": "Ville-Pekka Laakkonen" }
]
},
{
"name_fi": "Ulkosuhdevastaava",
"name_en": "",
"representatives": [
{ "name": "Leo Muller" },
{ "name": "Eino Tyrvänen" },
{ "name": "Pekka Aho" }
]
},
{
"name_fi": "Ulkowanhus",
"name_en": "",
"representatives": [
{ "name": "Jyri Korhonen" }
]
}
]
}
+33
View File
@@ -0,0 +1,33 @@
{
"name_fi": "Yrityssuhdetoimikunta",
"name_en": "",
"roles": [
{
"name_fi": "Yrityssuhdemestari",
"name_en": "",
"representatives": [
{ "name": "Otto Julkunen" }
]
},
{
"name_fi": "Excursiopäävastaava",
"name_en": "",
"representatives": [
{ "name": "Henry Gustafsson" }
]
},
{
"name_fi": "Yrityssuhdevastaava",
"name_en": "",
"representatives": [
{ "name": "Ilkka Huttu" },
{ "name": "Arkadii Kolchin" },
{ "name": "Oskari Luukkonen" },
{ "name": "Niilo Ojala" },
{ "name": "Emma Reinikainen" },
{ "name": "Melina Sundell" },
{ "name": "Elma Tuohimetsä" }
]
}
]
}
-39
View File
@@ -1,39 +0,0 @@
$font: 'Montserrat', sans-serif;
$colors: (
// Name Color ?Hover?
dark-blue: 'dark-blue' #002d3a,
light-blue: 'light-blue' #bfdbd9,
white1: 'white1' #fff,
black1: 'black1' #000,
grey1: 'grey1' #d4d0c7,
grey2: 'grey2' #efece4,
orange1: 'orange1' #d57a2d,
orange2: 'orange2' #dd934e,
blue1: 'blue1' #57b2df,
light-turquoise: 'light-turquoise' #beddeb,
green1: 'green1' #c0dcd9,
sand: 'sand' #fdf9d7
);
@function color($label) {
$color: map-get($colors, $label);
@if $color {
@return nth($color, 2);
}
@warn 'No specified color for '#{$label}'; add your own to _colors.scss';
@return null;
}
@function hover($label) {
$color: map-get($colors, $label);
@if $color {
@return nth($color, 2);
}
@warn 'No specified hover color for '#{$label}'; add your own to _colors.scss';
@return lighten($color, 20%);
}
-341
View File
@@ -1,341 +0,0 @@
/*! normalize.css v8.0.0 | MIT License | github.com/necolas/normalize.css */
/* Document
========================================================================== */
/**
* 1. Correct the line height in all browsers.
* 2. Prevent adjustments of font size after orientation changes in iOS.
*/
html {
line-height: 1.15; /* 1 */
-webkit-text-size-adjust: 100%; /* 2 */
}
/* Sections
========================================================================== */
/**
* Remove the margin in all browsers.
*/
body {
margin: 0;
}
/**
* Correct the font size and margin on `h1` elements within `section` and
* `article` contexts in Chrome, Firefox, and Safari.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/* Grouping content
========================================================================== */
/**
* 1. Add the correct box sizing in Firefox.
* 2. Show the overflow in Edge and IE.
*/
hr {
box-sizing: content-box; /* 1 */
height: 0; /* 1 */
overflow: visible; /* 2 */
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
pre {
font-family: monospace; /* 1 */
font-size: 1em; /* 2 */
}
/* Text-level semantics
========================================================================== */
/**
* Remove the gray background on active links in IE 10.
*/
a {
background-color: transparent;
}
/**
* 1. Remove the bottom border in Chrome 57-
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
*/
abbr[title] {
border-bottom: none; /* 1 */
text-decoration: underline; /* 2 */
text-decoration: underline dotted; /* 2 */
}
/**
* Add the correct font weight in Chrome, Edge, and Safari.
*/
b,
strong {
font-weight: bolder;
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
samp {
font-family: monospace; /* 1 */
font-size: 1em; /* 2 */
}
/**
* Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` elements from affecting the line height in
* all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/* Embedded content
========================================================================== */
/**
* Remove the border on images inside links in IE 10.
*/
img {
border-style: none;
}
/* Forms
========================================================================== */
/**
* 1. Change the font styles in all browsers.
* 2. Remove the margin in Firefox and Safari.
*/
button,
input,
optgroup,
select,
textarea {
font-family: inherit; /* 1 */
font-size: 100%; /* 1 */
line-height: 1.15; /* 1 */
margin: 0; /* 2 */
}
/**
* Show the overflow in IE.
* 1. Show the overflow in Edge.
*/
button,
input { /* 1 */
overflow: visible;
}
/**
* Remove the inheritance of text transform in Edge, Firefox, and IE.
* 1. Remove the inheritance of text transform in Firefox.
*/
button,
select { /* 1 */
text-transform: none;
}
/**
* Correct the inability to style clickable types in iOS and Safari.
*/
button,
[type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
/**
* Remove the inner border and padding in Firefox.
*/
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
border-style: none;
padding: 0;
}
/**
* Restore the focus styles unset by the previous rule.
*/
button:-moz-focusring,
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring {
outline: 1px dotted ButtonText;
}
/**
* Correct the padding in Firefox.
*/
fieldset {
padding: 0.35em 0.75em 0.625em;
}
/**
* 1. Correct the text wrapping in Edge and IE.
* 2. Correct the color inheritance from `fieldset` elements in IE.
* 3. Remove the padding so developers are not caught out when they zero out
* `fieldset` elements in all browsers.
*/
legend {
box-sizing: border-box; /* 1 */
color: inherit; /* 2 */
display: table; /* 1 */
max-width: 100%; /* 1 */
padding: 0; /* 3 */
white-space: normal; /* 1 */
}
/**
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
*/
progress {
vertical-align: baseline;
}
/**
* Remove the default vertical scrollbar in IE 10+.
*/
textarea {
overflow: auto;
}
/**
* 1. Add the correct box sizing in IE 10.
* 2. Remove the padding in IE 10.
*/
[type="checkbox"],
[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* Correct the cursor style of increment and decrement buttons in Chrome.
*/
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
/**
* 1. Correct the odd appearance in Chrome and Safari.
* 2. Correct the outline style in Safari.
*/
[type="search"] {
-webkit-appearance: textfield; /* 1 */
outline-offset: -2px; /* 2 */
}
/**
* Remove the inner padding in Chrome and Safari on macOS.
*/
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* 1. Correct the inability to style clickable types in iOS and Safari.
* 2. Change font properties to `inherit` in Safari.
*/
::-webkit-file-upload-button {
-webkit-appearance: button; /* 1 */
font: inherit; /* 2 */
}
/* Interactive
========================================================================== */
/*
* Add the correct display in Edge, IE 10+, and Firefox.
*/
details {
display: block;
}
/*
* Add the correct display in all browsers.
*/
summary {
display: list-item;
}
/* Misc
========================================================================== */
/**
* Add the correct display in IE 10+.
*/
template {
display: none;
}
/**
* Add the correct display in IE 10.
*/
[hidden] {
display: none;
}
-9
View File
@@ -1,9 +0,0 @@
import React from "react";
import { BrowserRouter } from "react-router-dom";
import Routes from "../routes";
export default () => (
<BrowserRouter>
<Routes />
</BrowserRouter>
);
-7
View File
@@ -1,7 +0,0 @@
import React from "react";
import { hydrate } from "react-dom";
import App from "./App";
const elem = document.getElementById("root");
hydrate(React.createElement(App), elem);
+3 -3
View File
@@ -39,7 +39,7 @@ const Container = styled.div`
`;
const Panel = styled.div<{visible?: boolean}>`
margin-top: ${(p) => p.visible ? "0" : "-100%"};
margin-top: ${(p) => (p.visible ? "0" : "-100%")};
display: flex;
max-height: 15rem;
@@ -59,7 +59,7 @@ const Accordion: React.FC<AccordionProps> = ({ title, children }) => {
const handleClick = () => {
setOpen(!isOpen);
}
};
return (
<Container>
<button type="button" onClick={handleClick}>
@@ -73,6 +73,6 @@ const Accordion: React.FC<AccordionProps> = ({ title, children }) => {
</div>
</Container>
);
}
};
export default Accordion;
+7 -7
View File
@@ -10,14 +10,14 @@ const Icon = styled.div<AccordionIconProps>`
display: flex;
justify-content: center;
align-items: center;
background-color: ${(p) => p.open ? colors.orange1 : colors.blue1};
background-color: ${(p) => (p.open ? colors.orange1 : colors.blue1)};
color: ${colors.white};
min-width: 40px;
max-width: 40px;
min-height: 40px;
max-height: 40px;
min-width: 2.5rem;
max-width: 2.5rem;
min-height: 2.5rem;
max-height: 2.5rem;
margin: 0.2em;
font-size: 40px;
font-size: 2.5rem;
${(p) => p.open && (`
span {
@@ -27,7 +27,7 @@ const Icon = styled.div<AccordionIconProps>`
`;
const AccordionIcon: React.FC<AccordionIconProps> = ({ open } ) => (
const AccordionIcon: React.FC<AccordionIconProps> = ({ open }) => (
<Icon open={open}>
<span>+</span>
</Icon>
+15
View File
@@ -0,0 +1,15 @@
import React from "react";
import Image from "next/image";
const Icon = "/img/add-icon.png";
const AddIcon: React.FC = () => (
<Image
src={Icon}
width={20}
height={20}
alt="Add"
/>
);
export default AddIcon;
+13 -14
View File
@@ -1,10 +1,10 @@
import React, { ComponentProps } from "react";
import styled from "styled-components";
import { colors }from "@theme/colors";
import Anchor from "@components/Anchor";
import AddIcon from "@assets/img/add-icon.png";
import { colors } from "@theme/colors";
import { Link } from "@components/index";
import AddIcon from "@components/AddIcon";
const Link = styled(Anchor)`
const StyledLink = styled(Link)`
display: flex;
flex-flow: row nowrap;
align-items: center;
@@ -14,22 +14,21 @@ const Link = styled(Anchor)`
color: ${colors.orange2};
}
img {
margin-right: 8px;
margin-top: -2px;
width: 20px;
& > div {
margin-right: 8px !important;
margin-top: -2px !important;
}
`;
type AddLinkProps = ComponentProps<typeof Anchor> & {
type AddLinkProps = ComponentProps<typeof Link> & {
text: string;
}
const AddLink: React.FC<AddLinkProps> = ({ text, ...props }) => (
<Link {...props}>
<img src={AddIcon} />
<StyledLink passHref {...props}>
<AddIcon />
{text}
</Link>
)
</StyledLink>
);
export default AddLink;
export default AddLink;
+7 -5
View File
@@ -5,14 +5,16 @@ import { colors } from "@theme/colors";
const Header = styled.header`
background-color: ${colors.darkBlue};
display: flex;
flex-flow: row nowrap;
justify-content: center;
a {
flex: 1 0 auto;
margin: 0.5rem auto;
max-width: 600px;
img {
display: block;
margin: 0.5rem auto;
padding: 2rem;
width: 100%;
max-width: 800px;
fill: ${colors.white};
}
}
+15 -14
View File
@@ -1,7 +1,8 @@
import React from "react";
import styled from "styled-components";
import Anchor from "@components/Anchor";
import { colors } from "@theme/colors";
import { Link } from "@components/index";
import colors from "@theme/colors";
import breakpoints from "@theme/breakpoints";
interface AdminSidebarProps {
path: string;
@@ -13,23 +14,23 @@ const SideBar = styled.nav`
margin-right: 1rem;
background-color: ${colors.blue1};
@media screen and (max-width: 800px) {
@media screen and (max-width: ${breakpoints.mobile}) {
margin-right: 0;
margin-bottom: 1rem;
}
`;
const StyledLink = styled(Anchor)<{path: string}>`
const StyledLink = styled(Link)<{$path: string}>`
padding: 1rem 3rem 1rem 1rem;
letter-spacing: 3px;
text-transform: uppercase;
line-height: 20px;
line-height: 1.25;
font-weight: bold;
white-space: nowrap;
color: ${colors.white};
border-left: 4px solid transparent;
${p => p.path === p.to && `
${(p) => p.$path === p.to && `
border-left: 4px solid ${colors.white};
`}
@@ -37,20 +38,20 @@ const StyledLink = styled(Anchor)<{path: string}>`
border-left: 4px solid ${colors.white};
}
@media screen and (max-width: 800px) {
@media screen and (max-width: ${breakpoints.mobile}) {
margin-bottom: 1px;
}
`;
const AdminSidebar: React.FC<AdminSidebarProps> = ({ path }) => (
<SideBar>
<StyledLink to="/admin" path={path}>Home&nbsp;</StyledLink>
<StyledLink to="/admin/events" path={path}>Events&nbsp;</StyledLink>
<StyledLink to="/admin/feed" path={path}>Feed&nbsp;</StyledLink>
<StyledLink to="/admin/signups" path={path}>Signup forms&nbsp;</StyledLink>
<StyledLink to="/admin/jobads" path={path}>Job advertisements&nbsp;</StyledLink>
<StyledLink to="https://static.sika.sik.party/admin" path={path}>Files&nbsp;</StyledLink>
<StyledLink id="admin-sidebar-logout" to="/admin/logout" path={path}>Logout&nbsp;</StyledLink>
<StyledLink to="/admin" passHref $path={path}>Home&nbsp;</StyledLink>
<StyledLink to="/admin/events" passHref $path={path}>Events&nbsp;</StyledLink>
<StyledLink to="/admin/feed" passHref $path={path}>Feed&nbsp;</StyledLink>
<StyledLink to="/admin/signups" passHref $path={path}>Signup forms&nbsp;</StyledLink>
<StyledLink to="/admin/jobads" passHref $path={path}>Job advertisements&nbsp;</StyledLink>
<StyledLink to="https://static.sahkoinsinoorikilta.fi/admin" passHref $path={path}>Files&nbsp;</StyledLink>
<StyledLink data-e2e="admin-sidebar-logout" to="/admin/logout" passHref $path={path}>Logout&nbsp;</StyledLink>
</SideBar>
);
-25
View File
@@ -1,25 +0,0 @@
import React from "react";
import { Link } from "react-router-dom";
import { HashLink } from "react-router-hash-link";
interface AnchorProps extends React.HTMLAttributes<HTMLAnchorElement> {
to: string;
}
const Anchor: React.FC<AnchorProps> = ({ to, ...props }) => {
if (to.startsWith("/")) {
return (
<Link to={to} {...props} />
);
} else if (to.startsWith("#")) {
return (
<HashLink to={to} {...props} />
);
}
else {
return (
<a href={to} {...props} />
);
}
}
export default Anchor;
+10 -12
View File
@@ -4,22 +4,18 @@ import { colors } from "@theme/colors";
interface ButtonProps {
onClick: () => void;
type: "hero" | "filled" | "filter" | "bordered";
buttonStyle: "hero" | "filled" | "filter" | "bordered";
selected?: boolean;
}
const StyledButton = styled.button<ButtonProps>`
const StyledButton = styled.button<{ $selected: boolean }>`
border-radius: none;
padding: 0.8rem 2rem;
margin: 0.5rem;
font-size: 13px;
font-size: 0.8rem;
background: none;
text-transform: uppercase;
@media screen and (max-width: 800px) {
font-size: 13px;
}
&.hero {
background-color: ${colors.darkBlue};
color: ${colors.blue1};
@@ -38,7 +34,7 @@ const StyledButton = styled.button<ButtonProps>`
}
&.bordered {
font-size: 12px;
font-size: 0.75rem;
font-weight: 800;
color: ${colors.blue1};
border: 1px solid ${colors.blue1};
@@ -50,7 +46,7 @@ const StyledButton = styled.button<ButtonProps>`
font-weight: 300;
border: 2px solid ${colors.grey1};
${(p) => p.selected && (`
${(p) => p.$selected && (`
background-color: ${colors.grey1};
color: ${colors.white};
`)}
@@ -66,8 +62,10 @@ const StyledButton = styled.button<ButtonProps>`
}
`;
const Button: React.FC<ButtonProps> = ({ type, selected, onClick, ...props }) => (
<StyledButton type="button" onClick={onClick} className={type} selected={selected} {...props} />
)
const Button: React.FC<ButtonProps> = ({
buttonStyle, selected, onClick, ...props
}) => (
<StyledButton type="button" onClick={onClick} className={buttonStyle} $selected={selected} {...props} />
);
export default Button;
+41 -57
View File
@@ -1,7 +1,9 @@
import React from "react";
import Image from "next/image";
import styled from "styled-components";
import { colors } from "@theme/colors";
import Anchor from "@components/Anchor";
import { Link } from "@components/index";
import breakpoints from "@theme/breakpoints";
interface WrappedCardProps {
title: string;
@@ -13,41 +15,27 @@ interface WrappedCardProps {
buttonOnClick?: () => void;
}
interface CardProps {
title: string;
start_time: string;
text: string;
img: JSX.Element;
button: JSX.Element;
}
const StyledCard = styled.article`
display: flex;
flex-direction: column;
color: ${colors.black};
margin: 1rem;
text-align: center;
img {
width: 100%;
max-height: 300px;
margin-bottom: 1rem;
}
p {
font-size: 16px;
font-size: 1rem;
text-overflow: ellipsis;
margin: 0 0 0.5rem;
font-weight: 200;
line-height: 22px;
line-height: 1.375;
}
p:first-of-type {
color: ${colors.orange1};
font-size: 0.9rem !important;
font-weight: 600 !important;
@media screen and (max-width: 1200px) {
@media screen and (max-width: ${breakpoints.medium}) {
margin: 0.5rem 0;
font-size: 16px;
}
}
@@ -58,62 +46,58 @@ const StyledCard = styled.article`
font-weight: 300;
}
button {
cursor: pointer;
a {
margin-top: auto;
padding: 0.8rem 2rem;
margin: 0.5rem;
font-size: 13px;
background: none;
text-transform: uppercase;
background-color: ${colors.blue1};
color: ${colors.white};
font-weight: 800;
letter-spacing: 1.5px;
border: none;
button {
cursor: pointer;
padding: 0.8rem 2rem;
margin: 0.5rem;
font-size: 0.8rem;
background: none;
text-transform: uppercase;
background-color: ${colors.blue1};
color: ${colors.white};
font-weight: 800;
letter-spacing: 1.5px;
border: none;
}
}
`;
const Card: React.FC<CardProps> = ({ title, start_time, text, img, button }) => (
<StyledCard>
{img}
<p>{start_time}</p>
<h3>{title}</h3>
<p>{text}</p>
{button}
</StyledCard>
);
const WrappedCard: React.FC<WrappedCardProps> = ({ title, text, link, image, imageAlt, start_time, buttonOnClick }) => {
const WrappedCard: React.FC<WrappedCardProps> = ({
title, text, link, image, imageAlt, start_time, buttonOnClick, ...props
}) => {
const options = {
day: "numeric",
month: "numeric",
year: "numeric",
hour: "numeric",
minute: "2-digit"
minute: "2-digit",
};
const datetime = new Date(start_time).toLocaleString("fi-FI", options);
const img = image ? (
<img src={image} alt={imageAlt} />
<Image src={image} alt={imageAlt} layout="responsive" width={0} height={0} objectFit="scale-down" />
) : null;
const button = (
<Anchor to={link}>
<button onClick={buttonOnClick}>
Lue lisää&nbsp;
<Link to={link}>
<button type="button" onClick={buttonOnClick}>
Lue lisää&nbsp;
</button>
</Anchor>
</Link>
);
return (
<Card
title={title}
start_time={datetime}
text={text}
img={img}
button={button}
/>
<StyledCard {...props}>
{img}
<p>{datetime}</p>
<h3>{title}</h3>
<p>{text}</p>
{button}
</StyledCard>
);
}
};
export default WrappedCard;
+19 -20
View File
@@ -1,18 +1,19 @@
import React from "react";
import styled from "styled-components";
import { Occupation } from "@models/Contacts";
import ContactCard from "./ContactCard";
import { Committee } from "@views/ContactsPage/ContactsPageView";
import { colors } from "@theme/colors";
const blank_profile = "/img/blank_profile.png";
interface CommitteeContainerProps {
name_fi: string;
name_en: string;
contacts: Occupation[];
committee: Committee;
}
const Container = styled.div`
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
color: ${colors.darkBlue};
@@ -21,36 +22,34 @@ const Container = styled.div`
justify-content: center;
text-transform: uppercase;
letter-spacing: 3px;
line-height: 14px;
line-height: 0.75;
font-weight: bold;
}
& > div {
display: flex;
flex-flow: row wrap;
justify-content: flex-start;
justify-content: center;
}
`;
const CommitteeContainer: React.FC<CommitteeContainerProps> = ({ name_fi, name_en, contacts }) => (
const CommitteeContainer: React.FC<CommitteeContainerProps> = ({ committee }) => (
<Container>
<p>
{name_fi}
</p>
<p>
{name_en}
{committee.name_fi || committee.name_en}
</p>
<div>
{contacts.map(occupation => (
occupation.officials.map(official => (
{committee.roles.map((role) => (
role.representatives.map((representative) => (
<ContactCard
key={official.first_name}
first_name={official.first_name}
last_name={official.last_name}
phone={official.phone_number}
email={official.email}
image={official.image}
role={occupation.role}
key={representative.name}
name={representative.name}
phone={representative.phone_number}
email={representative.email}
// conditional image for dev
image={!(committee.name_en === "Board") ? representative.image : blank_profile}
role_fi={role.name_fi}
role_en={role.name_en}
/>
))
))}
+44 -34
View File
@@ -1,28 +1,28 @@
import React from "react";
import Image from "next/image";
import styled from "styled-components";
import blank_profile from "@assets/img/blank_profile.png";
import { Role } from "@models/Contacts";
import { colors } from "@theme/colors";
const Card = styled.article`
display: flex;
align-items: flex-start;
flex-flow: row nowrap;
padding: 0.5rem;
color: ${colors.darkBlue};
margin: 1rem;
width: 19rem;
`;
const ImageContainer = styled.div`
padding: 15px;
position: relative;
display: flex;
flex-shrink: 0;
justify-content: center;
align-items: center;
max-height: 100px;
max-width: 100px;
height: 5rem;
width: 5rem;
& > img {
width: 100%;
height: 100%;
img {
padding: 0.5rem !important;
border-radius: 50%;
}
`;
@@ -30,41 +30,51 @@ const ImageContainer = styled.div`
const Info = styled.div`
display: flex;
flex-direction: column;
padding: 0.5rem;
justify-content: flex-start;
font-size: 1rem;
font-weight: 300;
align-items: flex-start;
padding: 0.25rem;
color: ${colors.darkBlue};
& > p {
font-size: 0.8rem;
margin: 0;
}
& > h1 {
font-size: 0.9rem;
font-weight: 500;
}
`;
interface ContactCardProps {
first_name: string;
last_name: string;
phone: number;
name: string;
phone: string;
email: string;
image: string;
role: Role;
role_fi: string;
role_en: string;
}
const ContactCard: React.FC<ContactCardProps> = ({ first_name, last_name, phone, email, image, role }) => {
const fullName = `${first_name} ${last_name}`;
return(
<Card>
const ContactCard: React.FC<ContactCardProps> = ({
name, phone, email, image, role_fi, role_en,
}) => (
<Card>
{image ? (
<ImageContainer>
<img
src={image || blank_profile}
alt={fullName}
<Image
src={image}
alt={name}
layout="fill"
objectFit="scale-down"
/>
</ImageContainer>
<Info>
<p>{fullName}</p>
<p>{phone}</p>
<p>{email}</p>
<p>{role.name_fi}</p>
<p>{role.name_en}</p>
</Info>
</Card>
)
}
) : null}
<Info>
<h1>{name}</h1>
<p>{role_fi || role_en}</p>
{phone ? <p>{phone}</p> : null}
{email ? <p>{email}</p> : null}
</Info>
</Card>
);
export default ContactCard;
+4 -2
View File
@@ -13,7 +13,7 @@ const Box = styled.div`
margin-top: 0.8rem;
position: absolute;
left: 0;
top: 30px;
top: 2.5rem;
z-index: 20;
a {
@@ -23,7 +23,9 @@ const Box = styled.div`
}
`;
const DropDownBox: React.FC<DropDownBoxProps> = ({ children, onMouseEnter, onMouseLeave, visible }) => (
const DropDownBox: React.FC<DropDownBoxProps> = ({
children, onMouseEnter, onMouseLeave, visible,
}) => (
<Box
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
+56
View File
@@ -0,0 +1,56 @@
import React from "react";
// eslint-disable-next-line react/display-name
export default (): JSX.Element => (
<>
<link rel="shortcut icon" href="/favicons/favicon.ico" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicons/favicon-16x16.png" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicons/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="48x48" href="/favicons/favicon-48x48.png" />
<link rel="manifest" href="/favicons/manifest.json" />
<meta name="mobile-web-app-capable" content="yes" />
<meta name="theme-color" content="#fff" />
<meta name="application-name" content="web2.0-frontend" />
<link rel="apple-touch-icon" sizes="57x57" href="/favicons/apple-touch-icon-57x57.png" />
<link rel="apple-touch-icon" sizes="60x60" href="/favicons/apple-touch-icon-60x60.png" />
<link rel="apple-touch-icon" sizes="72x72" href="/favicons/apple-touch-icon-72x72.png" />
<link rel="apple-touch-icon" sizes="76x76" href="/favicons/apple-touch-icon-76x76.png" />
<link rel="apple-touch-icon" sizes="114x114" href="/favicons/apple-touch-icon-114x114.png" />
<link rel="apple-touch-icon" sizes="120x120" href="/favicons/apple-touch-icon-120x120.png" />
<link rel="apple-touch-icon" sizes="144x144" href="/favicons/apple-touch-icon-144x144.png" />
<link rel="apple-touch-icon" sizes="152x152" href="/favicons/apple-touch-icon-152x152.png" />
<link rel="apple-touch-icon" sizes="167x167" href="/favicons/apple-touch-icon-167x167.png" />
<link rel="apple-touch-icon" sizes="180x180" href="/favicons/apple-touch-icon-180x180.png" />
<link rel="apple-touch-icon" sizes="1024x1024" href="/favicons/apple-touch-icon-1024x1024.png" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="apple-mobile-web-app-title" content="web2.0-frontend" />
<link rel="apple-touch-startup-image" media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/favicons/apple-touch-startup-image-640x1136.png" />
<link rel="apple-touch-startup-image" media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/favicons/apple-touch-startup-image-750x1334.png" />
<link rel="apple-touch-startup-image" media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/favicons/apple-touch-startup-image-828x1792.png" />
<link rel="apple-touch-startup-image" media="(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" href="/favicons/apple-touch-startup-image-1125x2436.png" />
<link rel="apple-touch-startup-image" media="(device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" href="/favicons/apple-touch-startup-image-1242x2208.png" />
<link rel="apple-touch-startup-image" media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" href="/favicons/apple-touch-startup-image-1242x2688.png" />
<link rel="apple-touch-startup-image" media="(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/favicons/apple-touch-startup-image-1536x2048.png" />
<link rel="apple-touch-startup-image" media="(device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/favicons/apple-touch-startup-image-1668x2224.png" />
<link rel="apple-touch-startup-image" media="(device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/favicons/apple-touch-startup-image-1668x2388.png" />
<link rel="apple-touch-startup-image" media="(device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/favicons/apple-touch-startup-image-2048x2732.png" />
<link rel="apple-touch-startup-image" media="(device-width: 810px) and (device-height: 1080px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/favicons/apple-touch-startup-image-1620x2160.png" />
<link rel="apple-touch-startup-image" media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/favicons/apple-touch-startup-image-1136x640.png" />
<link rel="apple-touch-startup-image" media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/favicons/apple-touch-startup-image-1334x750.png" />
<link rel="apple-touch-startup-image" media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/favicons/apple-touch-startup-image-1792x828.png" />
<link rel="apple-touch-startup-image" media="(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" href="/favicons/apple-touch-startup-image-2436x1125.png" />
<link rel="apple-touch-startup-image" media="(device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" href="/favicons/apple-touch-startup-image-2208x1242.png" />
<link rel="apple-touch-startup-image" media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" href="/favicons/apple-touch-startup-image-2688x1242.png" />
<link rel="apple-touch-startup-image" media="(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/favicons/apple-touch-startup-image-2048x1536.png" />
<link rel="apple-touch-startup-image" media="(device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/favicons/apple-touch-startup-image-2224x1668.png" />
<link rel="apple-touch-startup-image" media="(device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/favicons/apple-touch-startup-image-2388x1668.png" />
<link rel="apple-touch-startup-image" media="(device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/favicons/apple-touch-startup-image-2732x2048.png" />
<link rel="apple-touch-startup-image" media="(device-width: 810px) and (device-height: 1080px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/favicons/apple-touch-startup-image-2160x1620.png" />
<link rel="icon" type="image/png" sizes="228x228" href="/favicons/coast-228x228.png" />
<meta name="msapplication-TileColor" content="#fff" />
<meta name="msapplication-TileImage" content="/favicons/mstile-144x144.png" />
<meta name="msapplication-config" content="/favicons/browserconfig.xml" />
<link rel="yandex-tableau-widget" href="/favicons/yandex-browser-manifest.json" />
</>
);
+7 -6
View File
@@ -1,6 +1,7 @@
import React from "react";
import styled from "styled-components";
import { colors } from "@theme/colors";
import colors from "@theme/colors";
import breakpoints from "@theme/breakpoints";
import FooterContent from "./FooterContent";
const StyledFooter = styled.footer`
@@ -16,27 +17,27 @@ const CopyRight = styled.div`
background-color: ${colors.black};
text-align: center;
justify-content: center;
font-size: 12px;
font-size: 0.75rem;
padding: 1rem 0;
p {
padding: 0.5rem 1rem;
margin: 0;
font-size: 14px;
font-size: 0.8rem;
}
a {
display: block;
text-decoration: underline;
padding: 0.4rem 0;
font-size: 14px;
font-size: 0.8rem;
&:hover {
text-decoration: none;
}
}
@media screen and (max-width: 600px) {
@media screen and (max-width: ${breakpoints.mobile}) {
flex-flow: column nowrap;
}
`;
@@ -49,6 +50,6 @@ const Footer: React.FC = () => (
<a href="mailto:sik-vtmk@list.ayy.fi">webmaster: sik-vtmk@list.ayy.fi</a>
</CopyRight>
</StyledFooter>
)
);
export default Footer;
+24 -23
View File
@@ -1,23 +1,32 @@
import React from "react";
import styled from "styled-components";
import Anchor from "../Anchor";
import { colors } from "@theme/colors";
import { Link } from "@components/index";
import colors from "@theme/colors";
import breakpoints from "@theme/breakpoints";
const Columns = styled.div`
display: flex;
justify-content: space-between;
& > div > div {
margin-bottom: 1rem;
}
`;
const Content = styled.div`
display: flex;
& > div:first-of-type {
padding: 48px 0;
padding: 3rem 0;
flex: 2 1;
& > * {
padding: 0 24px;
padding: 0 1.5rem;
}
}
h4 {
color: ${colors.lightBlue};
padding: 24px 0;
padding: 1.5rem 0;
}
a {
@@ -25,7 +34,7 @@ const Content = styled.div`
display: block;
text-decoration: underline;
padding: 0.4rem 0;
font-size: 14px;
font-size: 0.8rem;
&:hover {
text-decoration: none;
@@ -36,26 +45,18 @@ const Content = styled.div`
color: ${colors.white};
margin: 0;
padding: 0.4rem 0;
font-size: 14px;
font-size: 0.8rem;
}
`;
const MarginSpace = styled.div`
max-width: 600px;
max-width: 67%;
margin: auto;
`;
const Columns = styled.div`
display: flex;
justify-content: space-between;
& > div > div {
margin-bottom: 1rem;
}
`;
const Map = styled.div`
flex: 1;
@media screen and (max-width: 800px) {
@media screen and (max-width: ${breakpoints.mobile}) {
display: none;
}
iframe {
@@ -78,14 +79,14 @@ const FooterContent: React.FC = () => (
<div>
<p>Y-tunnus: 1627010-1</p>
<p>sik-hallitus@list.ayy.fi</p>
<Anchor to="/yhteystiedot">Yhteystiedot</Anchor>
<Link to="/yhteystiedot">Yhteystiedot</Link>
</div>
</div>
<div>
<Anchor to="/jaseneksi">Jäseneksi</Anchor>
<Anchor to="/palaute">Palaute</Anchor>
<Anchor to="https://static.sika.sik.party">Arkisto</Anchor>
<Anchor to="https://static.sika.sik.party">Materiaalipankki</Anchor>
<Link to="/jaseneksi">Jäseneksi</Link>
<Link to="/palaute">Palaute</Link>
<Link to="https://static.sahkoinsinoorikilta.fi">Arkisto</Link>
<Link to="https://static.sahkoinsinoorikilta.fi">Materiaalipankki</Link>
</div>
</Columns>
</MarginSpace>
@@ -99,6 +100,6 @@ const FooterContent: React.FC = () => (
/>
</Map>
</Content>
)
);
export default FooterContent;
+56
View File
@@ -0,0 +1,56 @@
import React from "react";
// eslint-disable-next-line react/display-name
export default (): JSX.Element => (
<head dangerouslySetInnerHTML={{
__html:
`<!--
-\` o\` .s h\` -///.
.o+/o \`d m /s\`\`\`y: -+:.
.///. \`-. -m\` m::/ \`d /s.\`.y: \`h..o/
/o.\`.y- ..\` :\` \`\`\`\` \` .://. ho+/o- \`y.
./+ +o\` .y- . \` .y- \`+//\`
/+y/ :/+/. .-::/+++++//:--\` o. \`.h--/
\` \`/s. hNNMMMMMMMMMMNNy o::d\` -o-
:+. . .\` mMMMMMMMMMMMMMMd --- \`/y++
-o+-o: \`-/oNMMMMMMMMMMMMMMNo:-\` :o:\` .
\`:--..\`-/\` \`-+ymNMMMMMMMMMMMMMMMMMMMMNmy+-\` \`\` \`\` -++++.
\`h+/y/: \`\` .odNMMMMMMMMMNNmmmmmmNNMMMMMMMMMNdo..:sdd/ d. .h
\`sh\` \`+mds:.:yNMMMMMMMmds+:-...\`\`...-:+ydmMMMMMMMNmMmh+- . o/--+o
\`\`\`\`\`\`+\` .hMMMMMNMMMMMMMms:. .:yMMMMNds:.\`-+hms .::. \`--
\`yo/y+/ :mMMMMMMMMMMMNy:\` \`\`... \`.+ymMNh+-\`.:sdMNds:\`\` -/oom:
.oos /NMMMMMMMMMMNy- \`-oydmNNM :h+:odNNms/.\`.+hmMNh+-\`.:sh- .\`\`y/.:\`
-s\` /MMMMMMMMMMMd: \`-smMMMMMMMM /MMMNh+-\`\`:sdMNms:.\`.+hNMNh: hy+/-
.NMMMMMMMMMMy\` -hMMMMMMMMMMM /MMo.\`./ymMNh+-\`\`:sdMNms:\`\`./\` \`
yMMMMMMMMMMy \`sMMMMMMMMMMMMM /MM+odNNmy/.\`.+yNMNh+- \`-odMNo
\`:odMMMMMMd\` \`hMMMMMMMMMMMMMM /MMMNdo-\`\`-odMMms/\` \`/ymMMdo-
\`NMMMMM- sMMMMMMMMMMMMMMM /MMN+\`\`/yNMNdo- \`-odMMMMMN\`
/MMMMMd .MMMMMMMMMMMMMMMM /MMMMNMMNy/\` \`/ymMMdmMMMMM/
sMMMMMo +MMMMMMMMMMMMMMMM /MMMMdmMMdsodMMNy/\` oMMMMMs
yMMMMM+ +MMMMMMMMMMMMMNdh /MMm/ \`oNMMMMMy. +MMMMMy
oMMMMMs .MMMMMMMMMMMs- /MMMMNMMNy/:smMMdo: sMMMMMo
/MMMMMd oMMMMMMMMN- /MMMMdmMMmo:\` .+hNMNNMMMMM/
\`+ /hy. \`NMMMMM: oMMMMMMM+ /MMm/\` .ohNMNy/. \`/ymMMMMM\` .-/+o-
.N\`m+oh \`/smMMMMMMm\` /NMMMMMo /MMMMNy/. \`/ymMNdo:\`\`-ohNMNy/. sNysd.
+yh..- yMMMMMMMMMMh\` .sNMMMN/ /MM//ymMNdo:\`\`-ohNMNy/.\`\`/ymMo \`-smh.
::--..:- .NMMMMMMMMMMh. .sNMMMh: /MMs:\`\`-ohNNmy/.\`./ymMNdo:\`\`-\` \`h- \`/.
/oNodm:s :NMMMMMMMMMMm/ \`+hNMNms: /MMNNmy/.\`./ymMNdo:\`\`-ohNNmo smys/-
\`dds. :NMMMMMMMMMMMh: \`.+hNMM :s-./ymMNdo-\`\`-ohNNmy/.\`./y- \`s.\`-/+
.s. ./s. -mMMMMMMMMMMMNh/. .:s .\` \`-odNNmy/.\`./ymMNdo\` -\` -.
/yhN:\`\` .yMMMMMmNMMMMMMmy/-\` \`:odN/ \`./ymMNdo-\`\`-ods\` \`oyy//d.
--\`ydyy- /ddo-\`-smMMMMMMMNmho/-\` \`mMNdo. \`:odNNmy/ \` oo-\`-+y-
oyo-.:s\` \`\` ./hmMMMMMMMMMNmhs+y/.\`.\` \`./yh/ :-./yy+
\` \`/hNy/:. ./sdmMMMMMMMMMM\`-+hm/ . ho\`\`\`-/
.s:my::-\`\`.-\` .-/NMMMMMMMdNMMM/ \`\`yydmsso\`
m- .sysho+ mMMMMMMMMMMMN: /h:\`:yd-
. hh\` :M- \`\` hNNNMMMMMmh+- \`-+o+\`:dy. -\`
/h+/yh\`.h+ .\` \`.-::://:. --/\` ym:/M+ \`+:
\`-:- -ms .md\`\`/\` .\`: syyys.\`ydhos/
s+ \`dymoyd\`-yss/ \`: .\` .\` \`syho- .M: yd oo
:y\`/Nm. /do/- /M\` Nm/.M: sd-\`/M:\`hy++d+
/- .y+oN: sd NyhhM: om/-+m- .:-\`
\`-:- o+ h/ /h: -/+:\`
-->`,
}}
/>
);
+22 -25
View File
@@ -2,19 +2,20 @@ import React, { useState, useEffect, useRef } from "react";
import Navigation from "./Navigation";
import throttle from "lodash/throttle";
import styled from "styled-components";
import { colors } from "@theme/colors";
import colors from "@theme/colors";
import breakpoints from "@theme/breakpoints";
import NavigationMobile from "./NavigationMobile";
import HeaderLogo from "./HeaderLogo";
const StyledHeader = styled.header<{isHidden?: boolean}>`
const StyledHeader = styled.header`
display: flex;
flex-flow: row nowrap;
@media screen and (max-width: 600px) {
@media screen and (max-width: ${breakpoints.mobile}) {
flex-flow: column nowrap;
}
`;
const Sticky = styled.div`
const Sticky = styled.div<{$isHidden?: boolean}>`
position: sticky;
top: 0;
z-index: 10;
@@ -23,50 +24,46 @@ const Sticky = styled.div`
background-color: ${colors.darkBlue};
transition: all 200ms ease-out;
${(p) => p.isHidden ? (`
${(p) => (p.$isHidden ? (`
transition: all 200ms ease-in;
transform: translateY(-100%);
`) : null}
`) : null)}
`;
const PREVENT_IS_HIDDEN_Y = 150;
const Header: React.FC = () => {
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
const [isHidden, setHidden] = useState(false);
const yCoord = useRef(0);
const handleScroll = () => {
const newCoord = window.pageYOffset;
if (!mobileMenuOpen && newCoord > yCoord.current && newCoord > PREVENT_IS_HIDDEN_Y) {
setHidden(true);
} else {
setHidden(false);
}
yCoord.current = newCoord;
};
const handleMobileMenuClick = () => setMobileMenuOpen(!mobileMenuOpen);
useEffect(() => {
const handleScroll = () => {
const newCoord = window.pageYOffset;
if (!mobileMenuOpen && newCoord > yCoord.current && newCoord > PREVENT_IS_HIDDEN_Y) {
setHidden(true);
} else {
setHidden(false);
}
yCoord.current = newCoord;
};
const func = throttle(handleScroll, 200);
// Prevents hide when clicking mobileMenuOpen
handleScroll();
window.addEventListener("scroll", func);
return () => window.removeEventListener("scroll", func);
}, [isHidden, mobileMenuOpen]);
}, [mobileMenuOpen]);
return (
<Sticky>
<StyledHeader isHidden={isHidden}>
<Sticky $isHidden={isHidden}>
<StyledHeader>
<HeaderLogo />
<Navigation onMobileMenuOpen={handleMobileMenuClick} />
</StyledHeader>
<NavigationMobile mobileMenuOpen={mobileMenuOpen} />
</Sticky>
)
}
);
};
export default Header;
+15 -13
View File
@@ -1,25 +1,27 @@
import React from "react";
import Image from "next/image";
import styled from "styled-components";
import { Link } from "react-router-dom";
import TitleImage from "@assets/img/SIK_RGB_W_side.png";
import { Link } from "@components/index";
const Logo = styled.img`
max-width: 300px;
margin: 1rem 1rem;
const TitleImage = "/img/SIK_RGB_W_side.png";
@media screen and (max-width: 600px) {
max-width: 100% !important;
margin: 1rem 0 !important;
}
const Logo = styled(Link)`
position: relative;
min-width: 200px;
min-height: 100px;
margin: 1rem 0 !important;
flex: 1 0 auto;
`;
const HeaderLogo: React.FC = () => (
<Link to="/">
<Logo
<Logo to="/">
<Image
src={TitleImage}
alt="logo"
layout="fill"
objectFit="scale-down"
/>
</Link>
)
</Logo>
);
export default HeaderLogo;
+9 -6
View File
@@ -1,6 +1,7 @@
import React from "react";
import styled from "styled-components";
import { colors } from "@theme/colors";
import colors from "@theme/colors";
import breakpoints from "@theme/breakpoints";
const Container = styled.div`
display: flex;
@@ -13,16 +14,18 @@ const Container = styled.div`
section {
padding: 2rem 6rem;
@media screen and (max-width: 800px) {
@media screen and (max-width: ${breakpoints.mobile}) {
padding: 1rem;
}
}
aside {
max-width: 50%;
padding: 3rem 6rem;
align-items: center;
@media screen and (max-width: 800px) {
@media screen and (max-width: ${breakpoints.mobile}) {
max-width: unset;
padding: 2rem 1rem;
}
}
@@ -31,7 +34,7 @@ const Container = styled.div`
flex: 8;
}
@media screen and (max-width: 800px) {
@media screen and (max-width: ${breakpoints.mobile}) {
flex-direction: column;
}
@@ -46,6 +49,6 @@ const Hero: React.FC = ({ children }) => (
<Container>
{children}
</Container>
)
);
export default Hero;
export default Hero;
+16 -16
View File
@@ -1,7 +1,7 @@
import React from "react";
import styled from "styled-components";
import { colors } from "@theme/colors";
import Anchor from "@components/Anchor";
import { Link } from "@components/index";
interface HeroAsideItemProps {
header: string;
@@ -14,19 +14,21 @@ const Article = styled.article`
margin-bottom: 1rem;
`;
export const HeroAsideItem: React.FC<HeroAsideItemProps> = ({ header, text, link, linkText }) => (
export const HeroAsideItem: React.FC<HeroAsideItemProps> = ({
header, text, link, linkText,
}) => (
<Article>
<h2>{header}</h2>
{text && (
<p>{text}</p>
)}
<Anchor to={link}>
<Link to={link}>
<h6>
{linkText}
</h6>
</Anchor>
</Link>
</Article>
)
);
type Colors = "darkBlue" | "lightTurquoise";
@@ -43,8 +45,6 @@ const Aside = styled.aside<{ colors: string }>`
justify-content: center;
& > div {
max-width: 350px;
h2 {
word-break: break-word;
hyphens: auto;
@@ -75,27 +75,27 @@ const Aside = styled.aside<{ colors: string }>`
`;
const textColors = (bgColor: Colors) => {
switch(bgColor) {
case "darkBlue":
return `
switch (bgColor) {
case "darkBlue":
return `
background-color: ${colors[bgColor]};
color: ${colors.lightBlue};
`;
case "lightTurquoise":
return `
case "lightTurquoise":
return `
background-color: ${colors[bgColor]};
color: ${colors.darkBlue};
`;
default: return ""
default: return "";
}
}
};
const HeroAside: React.FC<HeroAsideProps> = ({ bgColor, children}) => (
const HeroAside: React.FC<HeroAsideProps> = ({ bgColor, children }) => (
<Aside colors={textColors(bgColor)}>
<div>
{children}
</div>
</Aside>
)
);
export default HeroAside;
+2 -2
View File
@@ -6,7 +6,7 @@ const Buttons = styled.div<{row?: boolean}>`
max-width: fit-content;
margin: auto;
display: flex;
flex-flow: ${(p) => p.row ? "row" : "column"} wrap;
flex-flow: ${(p) => (p.row ? "row" : "column")} wrap;
a {
display: contents;
@@ -36,4 +36,4 @@ const Buttons = styled.div<{row?: boolean}>`
}
`;
export default Buttons;
export default Buttons;
+7 -8
View File
@@ -1,6 +1,7 @@
import React from "react";
import styled from "styled-components";
import { colors } from "@theme/colors";
import colors from "@theme/colors";
import breakpoints from "@theme/breakpoints";
interface HeroPrimarySectionProps {
header: string;
@@ -8,17 +9,15 @@ interface HeroPrimarySectionProps {
}
const Section = styled.section`
max-width: 50%;
margin: 10vh auto 0;
max-width: 800px;
text-align: center;
line-height: 1.5rem;
h1 {
line-height: 40px;
@media screen and (max-width: ${breakpoints.mobile}) {
max-width: unset;
}
p {
max-width: 400px;
margin: 1em auto;
font-weight: 200;
}
@@ -43,6 +42,6 @@ const HeroPrimarySection: React.FC<HeroPrimarySectionProps> = ({ header, text, c
)}
{children}
</Section>
)
);
export default HeroPrimarySection;
export default HeroPrimarySection;
+5 -10
View File
@@ -10,12 +10,7 @@ const Note = styled.span`
text-transform: uppercase;
font-size: 2.5rem;
font-weight: bold;
margin-right: 2rem;
margin-top: -0.5rem;
@media screen and (max-width: 800px) {
font-size: 1.25rem;
}
margin: -1rem 2rem 3rem;
`;
const Item = styled.div`
@@ -29,14 +24,14 @@ interface HeroSecondarySectionItemProps {
note?: string;
}
export const HeroSecondarySectionItem: React.FC<HeroSecondarySectionItemProps> = ({note, children}) => (
export const HeroSecondarySectionItem: React.FC<HeroSecondarySectionItemProps> = ({ note, children }) => (
<Item>
<Note>
{note}
</Note>
{children}
</Item>
)
);
const Section = styled.section`
background-color: ${colors.green1};
@@ -64,6 +59,6 @@ const HeroSecondarySection: React.FC<HeroSecondarySectionProps> = ({ heading, ch
{children}
</Items>
</Section>
)
);
export default HeroSecondarySection;
export default HeroSecondarySection;
+2 -2
View File
@@ -3,5 +3,5 @@ export { default as HeroPrimarySection } from "./HeroPrimarySection";
export { default as HeroSecondarySection } from "./HeroSecondarySection";
export { HeroSecondarySectionItem } from "./HeroSecondarySection";
export { default as HeroAside } from "./HeroAside";
export { HeroAsideItem as HeroAsideItem } from "./HeroAside";
export { default as HeroPrimaryButtons } from "./HeroPrimaryButtons";
export { HeroAsideItem } from "./HeroAside";
export { default as HeroPrimaryButtons } from "./HeroPrimaryButtons";
+21 -31
View File
@@ -1,5 +1,4 @@
import React from "react";
import styled from "styled-components";
export enum IconType {
Facebook,
@@ -19,9 +18,11 @@ interface IconProps {
const nameToIcon = (name: IconType): JSX.Element | string => {
if (name === IconType.Facebook) {
return (
<svg role="img"
<svg
role="img"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg">
xmlns="http://www.w3.org/2000/svg"
>
<title>Facebook icon</title>
<path d="M22.676 0H1.324C.593 0 0 .593 0 1.324v21.352C0 23.408.593 24 1.324 24h11.494v-9.294H9.689v-3.621h3.129V8.41c0-3.099 1.894-4.785 4.659-4.785 1.325 0 2.464.097 2.796.141v3.24h-1.921c-1.5 0-1.792.721-1.792 1.771v2.311h3.584l-.465 3.63H16.56V24h6.115c.733 0 1.325-.592 1.325-1.324V1.324C24 .593 23.408 0 22.676 0" />
</svg>
@@ -29,9 +30,11 @@ const nameToIcon = (name: IconType): JSX.Element | string => {
}
if (name === IconType.Instagram) {
return (
<svg role="img"
<svg
role="img"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg">
xmlns="http://www.w3.org/2000/svg"
>
<title>Instagram icon</title>
<path d="M12 0C8.74 0 8.333.015 7.053.072 5.775.132 4.905.333 4.14.63c-.789.306-1.459.717-2.126 1.384S.935 3.35.63 4.14C.333 4.905.131 5.775.072 7.053.012 8.333 0 8.74 0 12s.015 3.667.072 4.947c.06 1.277.261 2.148.558 2.913.306.788.717 1.459 1.384 2.126.667.666 1.336 1.079 2.126 1.384.766.296 1.636.499 2.913.558C8.333 23.988 8.74 24 12 24s3.667-.015 4.947-.072c1.277-.06 2.148-.262 2.913-.558.788-.306 1.459-.718 2.126-1.384.666-.667 1.079-1.335 1.384-2.126.296-.765.499-1.636.558-2.913.06-1.28.072-1.687.072-4.947s-.015-3.667-.072-4.947c-.06-1.277-.262-2.149-.558-2.913-.306-.789-.718-1.459-1.384-2.126C21.319 1.347 20.651.935 19.86.63c-.765-.297-1.636-.499-2.913-.558C15.667.012 15.26 0 12 0zm0 2.16c3.203 0 3.585.016 4.85.071 1.17.055 1.805.249 2.227.415.562.217.96.477 1.382.896.419.42.679.819.896 1.381.164.422.36 1.057.413 2.227.057 1.266.07 1.646.07 4.85s-.015 3.585-.074 4.85c-.061 1.17-.256 1.805-.421 2.227-.224.562-.479.96-.899 1.382-.419.419-.824.679-1.38.896-.42.164-1.065.36-2.235.413-1.274.057-1.649.07-4.859.07-3.211 0-3.586-.015-4.859-.074-1.171-.061-1.816-.256-2.236-.421-.569-.224-.96-.479-1.379-.899-.421-.419-.69-.824-.9-1.38-.165-.42-.359-1.065-.42-2.235-.045-1.26-.061-1.649-.061-4.844 0-3.196.016-3.586.061-4.861.061-1.17.255-1.814.42-2.234.21-.57.479-.96.9-1.381.419-.419.81-.689 1.379-.898.42-.166 1.051-.361 2.221-.421 1.275-.045 1.65-.06 4.859-.06l.045.03zm0 3.678c-3.405 0-6.162 2.76-6.162 6.162 0 3.405 2.76 6.162 6.162 6.162 3.405 0 6.162-2.76 6.162-6.162 0-3.405-2.76-6.162-6.162-6.162zM12 16c-2.21 0-4-1.79-4-4s1.79-4 4-4 4 1.79 4 4-1.79 4-4 4zm7.846-10.405c0 .795-.646 1.44-1.44 1.44-.795 0-1.44-.646-1.44-1.44 0-.794.646-1.439 1.44-1.439.793-.001 1.44.645 1.44 1.439z" />
</svg>
@@ -39,9 +42,11 @@ const nameToIcon = (name: IconType): JSX.Element | string => {
}
if (name === IconType.LinkedIn) {
return (
<svg role="img"
<svg
role="img"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg">
xmlns="http://www.w3.org/2000/svg"
>
<title>LinkedIn icon</title>
<path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z" />
</svg>
@@ -49,7 +54,8 @@ const nameToIcon = (name: IconType): JSX.Element | string => {
}
if (name === IconType.HamburgerMenu) {
return (
<svg role="img"
<svg
role="img"
viewBox="0 0 32 32"
xmlns="http://www.w3.org/2000/svg"
>
@@ -58,49 +64,33 @@ const nameToIcon = (name: IconType): JSX.Element | string => {
</svg>
);
}
if (name == IconType.FinlandFlag) {
if (name === IconType.FinlandFlag) {
return "🇫🇮";
}
if (name == IconType.GBFlag) {
if (name === IconType.GBFlag) {
return "🇬🇧";
}
return null;
};
const SomeIcon = styled.a`
display: flex;
flex-flow: row nowrap;
justify-content: center;
margin: 1em;
svg {
width: 20px;
height: 20px;
}
`;
const NormalIcon = styled.span`
/* stylelint-disable-next-line no-empty-source */
`;
const Icon: React.FC<IconProps> = ({ link, name, onClick }) => {
const elem = nameToIcon(name);
if (link) {
return (
<SomeIcon
<a
href={link}
onClick={onClick}
>
{elem}
</SomeIcon>
</a>
);
}
return (
<NormalIcon role="img" onClick={onClick}>
<span role="img" onClick={onClick}>
{elem}
</NormalIcon>
</span>
);
}
};
export default Icon;
+1 -1
View File
@@ -10,6 +10,6 @@ const InfoBox: React.FC = ({ children }) => (
<Box>
{children}
</Box>
)
);
export default InfoBox;
+39
View File
@@ -0,0 +1,39 @@
import React from "react";
import NextJSLink, { LinkProps } from "next/link";
interface Props extends Omit<LinkProps, "href" | "as"> {
to: string;
template?: string;
target?: string;
onClick?: (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => void;
onMouseEnter?: (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => void;
onMouseLeave?: (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => void;
}
const Link: React.FC<Props> = ({
to, template, passHref, onClick, onMouseEnter, onMouseLeave, ...props
}) => {
if (template) {
return (
<NextJSLink href={template} passHref={passHref} as={to} {...props}>
{/* eslint-disable-next-line jsx-a11y/anchor-has-content */}
<a onClick={onClick} onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave} {...props} />
</NextJSLink>
);
}
if (to.startsWith("/") || to.startsWith("#")) {
return (
<NextJSLink href={to} passHref={passHref} {...props}>
{/* eslint-disable-next-line jsx-a11y/anchor-has-content */}
<a onClick={onClick} onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave} {...props} />
</NextJSLink>
);
}
return (
// eslint-disable-next-line jsx-a11y/anchor-has-content
<a href={to} onClick={onClick} onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave} {...props} />
);
};
export default Link;
+46
View File
@@ -0,0 +1,46 @@
import React from "react";
import styled from "styled-components";
import { colors } from "@theme/colors";
const Loader = styled((props) => (
<div {...props}>
<div>
<div />
</div>
</div>
))<{ $color?: typeof colors }>`
overflow: hidden;
font-size: 200px;
width: 1em;
height: 1em;
@keyframes rotation {
0% { transform: rotate(0deg) }
50% { transform: rotate(180deg) }
100% { transform: rotate(360deg) }
}
& > div {
width: 100%;
height: 100%;
position: relative;
transform: translateZ(0) scale(1);
backface-visibility: hidden;
transform-origin: 0 0;
& > div {
box-sizing: content-box;
position: absolute;
animation: rotation 1s linear infinite;
width: 80%;
height: 80%;
top: 10%;
left: 10%;
border-radius: 50%;
box-shadow: 0 0.02em 0 0 ${({ $color }) => $color || colors.white};
transform-origin: 50% 51%;
}
}
`;
export default Loader;
+8 -7
View File
@@ -1,34 +1,35 @@
import React from "react";
import styled from "styled-components";
import Anchor from "./Anchor";
import { colors } from "@theme/colors";
import colors from "@theme/colors";
import breakpoints from "@theme/breakpoints";
import { Link } from "@components/index";
interface NavbarChildLinkProps {
to: string;
}
const StyledLink = styled(Anchor)`
const StyledLink = styled(Link)`
display: block;
padding: 1rem;
letter-spacing: 1.5px;
padding-right: 4rem;
font-weight: 400;
@media screen and (max-width: 1200px) {
@media screen and (max-width: ${breakpoints.medium}) {
border-bottom: 1px dotted ${colors.lightBlue};
margin-left: 2rem;
padding-left: 0;
}
&:hover {
@media screen and (min-width: 1200px) {
@media screen and (min-width: ${breakpoints.medium}) {
background-color: ${colors.lightBlue};
}
}
`;
const NavbarChildLink: React.FC<NavbarChildLinkProps> = (props) => (
<StyledLink {...props} />
)
<StyledLink passHref {...props} />
);
export default NavbarChildLink;
+12 -8
View File
@@ -1,8 +1,9 @@
import React, { useState } from "react";
import styled from "styled-components";
import DropDownBox from "./DropDownBox";
import Anchor from "./Anchor";
import { colors } from "@theme/colors";
import { Link } from "@components/index";
import colors from "@theme/colors";
import breakpoints from "@theme/breakpoints";
const Container = styled.div`
position: relative;
@@ -11,7 +12,7 @@ const Container = styled.div`
&::after {
content: "";
position: absolute;
bottom: 5px;
bottom: 0.4rem;
left: 0;
width: 100%;
border-bottom: 4px solid ${colors.lightBlue};
@@ -19,16 +20,16 @@ const Container = styled.div`
}
`;
const StyledLink = styled(Anchor)`
const StyledLink = styled(Link)`
display: flex;
flex-flow: row nowrap;
justify-content: flex-start;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 2px;
padding: 20px 0;
padding: 1.25rem 0;
@media screen and (max-width: 1200px) {
@media screen and (max-width: ${breakpoints.medium}) {
border-bottom: 1px solid ${colors.lightBlue};
}
`;
@@ -39,7 +40,9 @@ interface NavbarDropdownLinkProps {
exploded?: boolean; // if exploded, show items directly underneath without a dropdown menu
}
const NavbarDropdownLink: React.FC<NavbarDropdownLinkProps> = ({ to, text, exploded, children }) => {
const NavbarDropdownLink: React.FC<NavbarDropdownLinkProps> = ({
to, text, exploded, children,
}) => {
const [mouseOverLink, setMouseOverLink] = useState(false);
const [mouseOverBox, setMouseOverBox] = useState(false);
@@ -65,6 +68,7 @@ const NavbarDropdownLink: React.FC<NavbarDropdownLinkProps> = ({ to, text, explo
<Container>
<StyledLink
to={to}
passHref
onMouseEnter={handleMouseEnterLink}
onMouseLeave={handleMouseLeaveLink}
>
@@ -79,6 +83,6 @@ const NavbarDropdownLink: React.FC<NavbarDropdownLinkProps> = ({ to, text, explo
</DropDownBox>
</Container>
);
}
};
export default NavbarDropdownLink;
+38 -35
View File
@@ -1,28 +1,27 @@
import React from "react";
import styled from "styled-components";
import { colors } from "@theme/colors";
import colors from "@theme/colors";
import breakpoints from "@theme/breakpoints";
import Icon, { IconType } from "./Icon";
import NavbarDropdownLink from "./NavbarDropdownLink";
import NavbarChildLink from "./NavbarChildLink";
const renderNavigationDesktopItems = () => {
return (
<>
<NavbarDropdownLink to="/kilta" text="Kilta ">
<NavbarChildLink to="/kilta/toiminta">Toiminta</NavbarChildLink>
<NavbarChildLink to="/kilta/fuksi">Fuksi</NavbarChildLink>
<NavbarChildLink to="https://static.sika.sik.party">Arkisto</NavbarChildLink>
</NavbarDropdownLink>
<NavbarDropdownLink to="/opinnot_ja_ura" text="Opinnot ja ura"></NavbarDropdownLink>
<NavbarDropdownLink to="/yritysyhteistyo" text="Yritysyhteistyö"></NavbarDropdownLink>
<NavbarDropdownLink to="/yhteystiedot" text="Yhteystiedot">
{/* <NavbarChildLink to="https://en.wikipedia.org/wiki/Gay">Simo Höglund</NavbarChildLink> */}
</NavbarDropdownLink>
<NavbarDropdownLink to="/in_english" text="In English"></NavbarDropdownLink>
</>
);
}
const renderNavigationDesktopItems = () => (
<>
<NavbarDropdownLink to="/kilta" text="Kilta ">
<NavbarChildLink to="/kilta/toiminta">Toiminta</NavbarChildLink>
<NavbarChildLink to="/kilta/fuksi">Fuksi</NavbarChildLink>
<NavbarChildLink to="/kilta/kunnia">Kunnianosoitukset</NavbarChildLink>
<NavbarChildLink to="https://static.sahkoinsinoorikilta.fi">Arkisto</NavbarChildLink>
</NavbarDropdownLink>
<NavbarDropdownLink to="/opinnot_ja_ura" text="Opinnot ja ura" />
<NavbarDropdownLink to="/yritysyhteistyo" text="Yritysyhteistyö" />
<NavbarDropdownLink to="/yhteystiedot" text="Yhteystiedot">
{/* <NavbarChildLink to="https://en.wikipedia.org/wiki/Gay">Simo Höglund</NavbarChildLink> */}
</NavbarDropdownLink>
<NavbarDropdownLink to="/in_english" text="In English" />
</>
);
const Nav = styled.div`
flex: 1 0 auto;
@@ -31,7 +30,7 @@ const Nav = styled.div`
justify-content: space-between;
align-items: center;
font-size: 14px;
font-size: 0.8rem;
color: ${colors.lightBlue};
margin-left: 5rem;
@@ -41,14 +40,22 @@ const Nav = styled.div`
text-decoration: none;
}
@media screen and (min-width: 600px) and (max-width: 1200px) {
@media screen and (min-width: ${breakpoints.mobile}) and (max-width: ${breakpoints.medium}) {
justify-content: flex-end;
}
@media screen and (max-width: 600px) {
@media screen and (max-width: ${breakpoints.mobile}) {
justify-content: center;
margin-left: 0;
}
svg {
width: 1.5rem;
height: 1.5rem;
fill: ${colors.white};
color: ${colors.white};
}
`;
const DesktopContainer = styled.div`
@@ -57,7 +64,7 @@ const DesktopContainer = styled.div`
flex-flow: row nowrap;
justify-content: space-between;
@media screen and (max-width: 1200px) {
@media screen and (max-width: ${breakpoints.medium}) {
display: none;
}
`;
@@ -67,8 +74,10 @@ const SomeContainer = styled.div`
flex-flow: row nowrap;
a {
fill: ${colors.white};
color: ${colors.white};
display: flex;
flex-flow: row nowrap;
justify-content: center;
margin: 1rem;
}
`;
@@ -81,20 +90,13 @@ const MobileMenu = styled.div`
display: flex;
}
@media screen and (min-width: 1200px) {
@media screen and (min-width: ${breakpoints.medium}) {
display: none;
}
@media screen and (max-width: 600px) {
@media screen and (max-width: ${breakpoints.mobile}) {
margin-left: 3rem;
}
svg {
width: 26px;
height: 26px;
fill: ${colors.white};
color: ${colors.white};
}
`;
interface NavigationProps {
@@ -117,6 +119,7 @@ const Navigation: React.FC<NavigationProps> = ({ onMobileMenuOpen }) => {
<Icon name={IconType.HamburgerMenu} onClick={onMobileMenuOpen} />
</MobileMenu>
</Nav>
)};
);
};
export default Navigation;
+17 -18
View File
@@ -4,23 +4,22 @@ import { colors } from "@theme/colors";
import NavbarDropdownLink from "./NavbarDropdownLink";
import NavbarChildLink from "./NavbarChildLink";
const renderNavigationMobileItems = () => {
return (
<>
<NavbarDropdownLink to="/kilta" text="Kilta " exploded>
<NavbarChildLink to="/kilta/toiminta">Toiminta</NavbarChildLink>
<NavbarChildLink to="/kilta/fuksi">Fuksi</NavbarChildLink>
<NavbarChildLink to="https://static.sika.sik.party">Arkisto</NavbarChildLink>
</NavbarDropdownLink>
<NavbarDropdownLink to="/opinnot_ja_ura" text="Opinnot ja ura" exploded />
<NavbarDropdownLink to="/yritysyhteistyo" text="Yritysyhteistyö" exploded />
<NavbarDropdownLink to="/yhteystiedot" text="Yhteystiedot" exploded>
{/* <NavbarChildLink to="https://en.wikipedia.org/wiki/Gay">Simo Höglund</NavbarChildLink> */}
</NavbarDropdownLink>
<NavbarDropdownLink to="/in_english" text="In English" exploded />
</>
);
}
const renderNavigationMobileItems = () => (
<>
<NavbarDropdownLink to="/kilta" text="Kilta " exploded>
<NavbarChildLink to="/kilta/toiminta">Toiminta</NavbarChildLink>
<NavbarChildLink to="/kilta/fuksi">Fuksi</NavbarChildLink>
<NavbarChildLink to="/kilta/kunnia">Kunnianosoitukset</NavbarChildLink>
<NavbarChildLink to="https://static.sahkoinsinoorikilta.fi">Arkisto</NavbarChildLink>
</NavbarDropdownLink>
<NavbarDropdownLink to="/opinnot_ja_ura" text="Opinnot ja ura" exploded />
<NavbarDropdownLink to="/yritysyhteistyo" text="Yritysyhteistyö" exploded />
<NavbarDropdownLink to="/yhteystiedot" text="Yhteystiedot" exploded>
{/* <NavbarChildLink to="https://en.wikipedia.org/wiki/Gay">Simo Höglund</NavbarChildLink> */}
</NavbarDropdownLink>
<NavbarDropdownLink to="/in_english" text="In English" exploded />
</>
);
const Nav = styled.nav`
padding: 1rem 2rem;
@@ -40,6 +39,6 @@ const NavigationMobile: React.FC<NavigationMobileProps> = ({ mobileMenuOpen }) =
<Nav hidden={!mobileMenuOpen}>
{renderNavigationMobileItems()}
</Nav>
)
);
export default NavigationMobile;
+2 -2
View File
@@ -1,7 +1,7 @@
import React from "react";
import styled from "styled-components";
import { colors } from "@theme/colors";
import Anchor from "@components/Anchor";
import { Link } from "@components/index";
interface PageLinkProps {
to: string;
@@ -43,7 +43,7 @@ const StyledPageLink = styled.div`
const PageLink: React.FC<PageLinkProps> = ({ to, desc, children }) => (
<StyledPageLink>
<p>{children}</p>
<Anchor to={to}>{desc}</Anchor>
<Link to={to}>{desc}</Link>
</StyledPageLink>
);
+15 -14
View File
@@ -1,8 +1,7 @@
import React from "react";
import styled from "styled-components";
import { colors } from "@theme/colors";
import Anchor from "@components/Anchor";
import { Link } from "@components/index";
const Section = styled.section<{ colors: string }>`
${(p) => p.colors}
@@ -47,8 +46,8 @@ interface CTASectionProps extends React.HTMLAttributes<HTMLDivElement> {
}
const textColors = (bgColor: Colors) => {
switch(bgColor) {
case "orange1": return `
switch (bgColor) {
case "orange1": return `
color: ${colors.white};
background-color: ${colors[bgColor]};
a:hover {
@@ -56,12 +55,12 @@ a:hover {
}
`;
case "darkBlue": return `
case "darkBlue": return `
background-color: ${colors[bgColor]};
color: ${colors.white};
`;
case "lightBlue": return `
case "lightBlue": return `
background-color: ${colors[bgColor]};
color: ${colors.darkBlue};
a:hover {
@@ -69,33 +68,35 @@ a:hover {
}
`;
case "lightTurquoise": return `
case "lightTurquoise": return `
background-color: ${colors[bgColor]};
color: ${colors.darkBlue};
a:hover {
color: ${colors.white};
}
`;
case "blue1": return `
case "blue1": return `
background-color: ${colors[bgColor]};
color: ${colors.white};
a:hover {
color: ${colors.darkBlue};
}
`;
default: return ""
default: return "";
}
}
};
const CTASection: React.FC<CTASectionProps> = ({ bgColor = "orange1", link, linkText, children, ...props }) => (
const CTASection: React.FC<CTASectionProps> = ({
bgColor = "orange1", link, linkText, children, ...props
}) => (
<Section colors={textColors(bgColor)} {...props}>
<h1>{children}</h1>
{link && (
<Anchor to={link}>
<Link to={link}>
<h4>{linkText}</h4>
</Anchor>
</Link>
)}
</Section>
);
export default CTASection;
export default CTASection;
+5 -4
View File
@@ -1,5 +1,6 @@
import styled from "styled-components";
import { colors } from "@theme/colors";
import colors from "@theme/colors";
import breakpoints from "@theme/breakpoints";
const CardSection = styled.section`
@@ -11,7 +12,7 @@ const CardSection = styled.section`
flex-flow: row wrap;
padding: 2rem 1rem;
@media screen and (max-width: 800px) {
@media screen and (max-width: ${breakpoints.mobile}) {
flex-flow: column nowrap;
}
@@ -22,12 +23,12 @@ const CardSection = styled.section`
& > * {
width: calc(25% - 2rem);
@media screen and (min-width: 800px) and (max-width: 1200px) {
@media screen and (min-width: ${breakpoints.mobile}) and (max-width: ${breakpoints.medium}) {
width: calc(50% - 2rem);
margin-bottom: 2rem;
}
@media screen and (max-width: 800px) {
@media screen and (max-width: ${breakpoints.mobile}) {
width: 100%;
margin: 0 0 3rem 0;
}
+8 -2
View File
@@ -3,9 +3,10 @@ import styled from "styled-components";
const StyledSection = styled.section`
display: grid;
padding: 24px;
padding: 1.5rem;
grid-template-columns: 1fr auto;
grid-template-rows: auto 1fr;
grid-template-areas:
"title"
"content";
@@ -22,11 +23,16 @@ const StyledSection = styled.section`
& > h6 {
text-align: center;
grid-area: title;
margin: 1rem 0;
}
p {
margin-top: 0;
}
`;
const FullWidthSection: React.FC<React.HTMLAttributes<HTMLDivElement>> = (props) => (
<StyledSection {...props} />
)
);
export default FullWidthSection;
+16 -13
View File
@@ -1,10 +1,11 @@
import React from "react";
import styled from "styled-components";
import { colors } from "@theme/colors";
import colors from "@theme/colors";
import breakpoints from "@theme/breakpoints";
const StyledSection = styled.section`
display: grid;
padding: 24px;
padding: 1.5rem;
word-break: break-word;
hyphens: auto;
@@ -12,10 +13,10 @@ const StyledSection = styled.section`
grid-template-columns: 1fr 2fr 1fr;
grid-template-rows: 1fr auto;
grid-template-areas:
"title title title"
". title ."
"leftaside content rightaside";
@media screen and (max-width: 800px) {
@media screen and (max-width: ${breakpoints.mobile}) {
grid-template-columns: 1fr;
grid-template-rows: 1fr auto auto auto;
grid-template-areas:
@@ -37,13 +38,15 @@ const StyledSection = styled.section`
& > h6 {
text-align: center;
grid-area: title;
margin: 1rem 0;
}
p {
margin-top: 0;
}
& > div, p {
grid-area: content;
max-width: 1000px;
}
& > aside {
@@ -51,11 +54,11 @@ const StyledSection = styled.section`
flex-direction: column;
justify-content: space-between;
@media screen and (max-width: 800px) {
@media screen and (max-width: ${breakpoints.mobile}) {
align-items: center;
max-width: unset;
margin-left: unset;
margin-top: 48px;
margin-top: 3rem;
* {
flex: 1;
@@ -65,15 +68,15 @@ const StyledSection = styled.section`
& > aside:first-of-type {
grid-area: rightaside;
padding-left: 24px;
@media screen and (max-width: 800px) {
padding-left: 1.5rem;
@media screen and (max-width: ${breakpoints.mobile}) {
padding-left: 0;
}
}
& > aside:nth-of-type(2) {
grid-area: leftaside;
padding-right: 24px;
@media screen and (max-width: 800px) {
padding-right: 1.5rem;
@media screen and (max-width: ${breakpoints.mobile}) {
padding-left: 0;
}
}
@@ -81,6 +84,6 @@ const StyledSection = styled.section`
const TextSection: React.FC<React.HTMLAttributes<HTMLDivElement>> = (props) => (
<StyledSection {...props} />
)
);
export default TextSection;
+4 -4
View File
@@ -32,7 +32,7 @@ const CustomCBoxElement = styled.span<{checked?: boolean}>`
left: 0;
height: 1em;
width: 1em;
background-color: ${(props) => props.checked ? colors.blue1 : colors.grey2};
background-color: ${(props) => (props.checked ? colors.blue1 : colors.grey2)};
&:focus &:before {
transition: box-shadow 150ms ease;
@@ -64,7 +64,7 @@ type CheckboxProps = Omit<
"type"
>;
const Checkbox: React.FC<CheckboxProps> = ({children, checked, ...props}) => (
const Checkbox: React.FC<CheckboxProps> = ({ children, checked, ...props }) => (
<Container>
{children}
<HiddenDefaultElement
@@ -77,6 +77,6 @@ const Checkbox: React.FC<CheckboxProps> = ({children, checked, ...props}) => (
{checked && (<Checkmark />)}
</CustomCBoxElement>
</Container>
)
);
export default Checkbox;
export default Checkbox;
+12 -11
View File
@@ -14,7 +14,7 @@ function selectValue(value, selected, all) {
}
function deselectValue(value, selected) {
return selected.filter(v => v !== value);
return selected.filter((v) => v !== value);
}
type CheckboxesProps = Omit<WidgetProps, "options"> & {
@@ -25,14 +25,16 @@ const CheckboxContainer = styled.div`
margin-bottom: 0.5rem;
`;
const Checkboxes: React.FC<CheckboxesProps> = ({id, disabled, options, value, autofocus, readonly, onChange}) => {
const Checkboxes: React.FC<CheckboxesProps> = ({
id, disabled, options, value, autofocus, readonly, onChange,
}) => {
const { enumOptions, enumDisabled, inline } = options;
return (
<div className="checkboxes" id={id}>
{enumOptions.map((option, index) => {
const checked = value.indexOf(option.value) !== -1;
const itemDisabled =
enumDisabled && enumDisabled.indexOf(option.value) != -1;
enumDisabled && enumDisabled.indexOf(option.value) !== -1;
const disabledCls =
disabled || itemDisabled || readonly ? "disabled" : "";
const checkbox = (
@@ -41,8 +43,8 @@ const Checkboxes: React.FC<CheckboxesProps> = ({id, disabled, options, value, au
checked={checked}
disabled={disabled || itemDisabled || readonly}
autoFocus={autofocus && index === 0}
onChange={event => {
const all = enumOptions.map(({ value }) => value);
onChange={(event) => {
const all = enumOptions.map(({ val }) => val);
if (event.target.checked) {
onChange(selectValue(option.value, value, all));
} else {
@@ -64,15 +66,14 @@ const Checkboxes: React.FC<CheckboxesProps> = ({id, disabled, options, value, au
);
})}
</div>
)
}
);
};
Checkboxes.defaultProps = {
autofocus: false,
options: {
inline: false,
}
}
},
};
export default Checkboxes;
export default Checkboxes;
+8 -4
View File
@@ -22,7 +22,9 @@ interface DatetimeWidgetProps {
disabled: boolean;
}
const DatetimeWidget: React.FC<DatetimeWidgetProps> = ({ value, onChange, onFocus, onBlur, required, disabled }) => {
const DatetimeWidget: React.FC<DatetimeWidgetProps> = ({
value, onChange, onFocus, onBlur, required, disabled,
}) => {
let date;
let time;
if (value && value.length !== 0) {
@@ -44,14 +46,16 @@ const DatetimeWidget: React.FC<DatetimeWidgetProps> = ({ value, onChange, onFocu
type="date"
onChange={(event) => onChange(`${event.target.value}T${time}`)}
value={date}
{...commonProps} />
{...commonProps}
/>
<input
type="time"
onChange={(event) => onChange(`${date}T${event.target.value}:00`)}
value={time}
{...commonProps} />
{...commonProps}
/>
</Widget>
);
}
};
export default DatetimeWidget;

Some files were not shown because too many files have changed in this diff Show More