mirror of
https://github.com/koodiklinikka/koodiklinikka.fi.git
synced 2026-02-07 10:49:54 +00:00
Merge pull request #23 from Keksike/master
Add Yhdistys-page with membership-form
This commit is contained in:
@@ -8,6 +8,8 @@
|
||||
"scripts": {
|
||||
"start": "rm -rf public && gulp",
|
||||
"build": "rm -rf public && gulp build",
|
||||
"dev": "SERVER=http://localhost:9000/ ENV=development npm start",
|
||||
"prod": "ENV=production npm start",
|
||||
"lint": "eslint src",
|
||||
"test": "mocha src/**/__tests__/*.js --compilers js:babel-core/register --require test/test-helper"
|
||||
},
|
||||
@@ -22,8 +24,10 @@
|
||||
"http-server": "^0.8.0",
|
||||
"lodash": "^3.9.1",
|
||||
"parse-github-event": "^0.2.0",
|
||||
"prop-types": "^15.5.10",
|
||||
"react": "^0.14.3",
|
||||
"react-dom": "^0.14.3",
|
||||
"react-stripe-checkout": "^2.4.0",
|
||||
"timeago": "^0.2.0",
|
||||
"twitter-text": "^1.11.0"
|
||||
},
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.5 KiB |
BIN
src/assets/images/hp3_bw.jpg
Normal file
BIN
src/assets/images/hp3_bw.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 286 KiB |
16
src/config.js
Normal file
16
src/config.js
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
var development = {
|
||||
stripe: {
|
||||
publicKey: "pk_test_OmNve9H1OuORlmD4rblpjgzh"
|
||||
}
|
||||
}
|
||||
|
||||
var production = {
|
||||
stripe: {
|
||||
publicKey: "pk_live_xrnwdLNXbt20LMxpIDffJnnC"
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = function () {
|
||||
return process.env.ENV == 'development' ? development : production;
|
||||
}
|
||||
197
src/index.jade
197
src/index.jade
@@ -1,150 +1,79 @@
|
||||
doctype html
|
||||
html
|
||||
head
|
||||
title Koodiklinikka
|
||||
// inject:css
|
||||
// endinject
|
||||
meta(name='description', content='Koodiklinikka on suomalainen Slack-yhteisö ohjelmistoalan harrastajille ja ammattilaisille.')
|
||||
meta(name='keywords', content='ohjelmointi,frontend,open source,devaus,suomi,javascript,clojure,go,java,node.js,io.js,angular.js,web')
|
||||
meta(charset='utf-8')
|
||||
meta(name='viewport', content='width=device-width, initial-scale=1')
|
||||
meta(name='apple-mobile-web-app-capable', content='yes')
|
||||
extends templates/head
|
||||
|
||||
script.
|
||||
if(location.hostname === 'koodiklinikka.fi' && location.protocol !== 'https:') {
|
||||
location.protocol = 'https';
|
||||
}
|
||||
link(rel='apple-touch-icon', sizes='57x57', href='icons/apple-touch-icon-57x57.png')
|
||||
link(rel='apple-touch-icon', sizes='114x114', href='icons/apple-touch-icon-114x114.png')
|
||||
link(rel='apple-touch-icon', sizes='72x72', href='icons/apple-touch-icon-72x72.png')
|
||||
link(rel='apple-touch-icon', sizes='144x144', href='icons/apple-touch-icon-144x144.png')
|
||||
link(rel='apple-touch-icon', sizes='60x60', href='icons/apple-touch-icon-60x60.png')
|
||||
link(rel='apple-touch-icon', sizes='120x120', href='icons/apple-touch-icon-120x120.png')
|
||||
link(rel='apple-touch-icon', sizes='76x76', href='icons/apple-touch-icon-76x76.png')
|
||||
link(rel='apple-touch-icon', sizes='152x152', href='icons/apple-touch-icon-152x152.png')
|
||||
link(rel='apple-touch-icon', sizes='180x180', href='icons/apple-touch-icon-180x180.png')
|
||||
link(rel='icon', type='image/png', href='icons/favicon-192x192.png', sizes='192x192')
|
||||
link(rel='icon', type='image/png', href='icons/favicon-160x160.png', sizes='160x160')
|
||||
link(rel='icon', type='image/png', href='icons/favicon-96x96.png', sizes='96x96')
|
||||
link(rel='icon', type='image/png', href='icons/favicon-16x16.png', sizes='16x16')
|
||||
link(rel='icon', type='image/png', href='icons/favicon-32x32.png', sizes='32x32')
|
||||
link(rel='shortcut icon', href='icons/favicon.ico')
|
||||
link(rel='icon', href='icons/favicon.ico')
|
||||
meta(name='msapplication-TileColor', content='#10558c')
|
||||
meta(name='msapplication-TileImage', content='icons/mstile-144x144.png')
|
||||
meta(property='og:image', content='images/logo.png')
|
||||
script(src='//use.typekit.net/scb5xny.js')
|
||||
script.
|
||||
try{Typekit.load();}catch(e){};
|
||||
block title
|
||||
| Koodiklinikka
|
||||
|
||||
body
|
||||
.site
|
||||
.container
|
||||
.header
|
||||
video(autoplay, loop, poster='images/poster.jpg', class='header__video-bg')
|
||||
source(src='videos/jumbo.mp4', type='video/mp4')
|
||||
.header__container
|
||||
.header__headline
|
||||
.header__logo
|
||||
h1.header__title <a target="_blank" href="https://slack.com/">Slack</a>-yhteisö kaikille ohjelmoinnista ja ohjelmistoalasta kiinnostuneille harrastajille ja ammattilaisille.
|
||||
block header_content
|
||||
video(autoplay, loop, poster='images/poster.jpg', class='header__video-bg')
|
||||
source(src='videos/jumbo.mp4', type='video/mp4')
|
||||
.header__container
|
||||
.header__nav
|
||||
a(href='/') etusivu
|
||||
a(href='/yhdistys.html') yhdistys
|
||||
.header__headline
|
||||
.header__logo
|
||||
h1.header__title <a target="_blank" href="https://slack.com/">Slack</a>-yhteisö kaikille ohjelmoinnista ja ohjelmistoalasta kiinnostuneille harrastajille ja ammattilaisille.
|
||||
|
||||
.content
|
||||
section
|
||||
.row
|
||||
h3 Tule mukaan
|
||||
#invite-form
|
||||
block content
|
||||
.content.with-feed
|
||||
section
|
||||
.row
|
||||
h3 Tule mukaan
|
||||
#invite-form.form
|
||||
|
||||
section
|
||||
.row
|
||||
.bread
|
||||
.column.column1-2
|
||||
h3 Yhteisö ohjelmoinnista kiinnostuneille
|
||||
p.
|
||||
Koodiklinikka on Suomen suurin ohjelmistoalan yhteisö, joka kokoaa työntekijät, harrastajat ja vasta-alkajat yhteen.
|
||||
Tarkoituksenamme on yhdistää ja kasvattaa suomalaista ohjelmointiyhteisöä, sekä tarjota apua ja uusia kontakteja ohjelmoinnista innostuneille nuorille.
|
||||
p.
|
||||
Mukaan liittyminen on ilmaista ja helppoa. Jätä sähköpostiosoitteesi ylläolevaan kenttään ja lähetämme sinulle kutsun Slack-yhteisöömme.
|
||||
.column.column1-2
|
||||
a(href='images/slack.png', target='_blank')
|
||||
img(src='images/slack.png')
|
||||
section
|
||||
.row
|
||||
.bread
|
||||
.column.column1-2
|
||||
h3 Yhteisö ohjelmoinnista kiinnostuneille
|
||||
p.
|
||||
Koodiklinikka on Suomen suurin ohjelmistoalan yhteisö, joka kokoaa työntekijät, harrastajat ja vasta-alkajat yhteen.
|
||||
Tarkoituksenamme on yhdistää ja kasvattaa suomalaista ohjelmointiyhteisöä, sekä tarjota apua ja uusia kontakteja ohjelmoinnista innostuneille nuorille.
|
||||
p.
|
||||
Mukaan liittyminen on ilmaista ja helppoa. Jätä sähköpostiosoitteesi ylläolevaan kenttään ja lähetämme sinulle kutsun Slack-yhteisöömme.
|
||||
.column.column1-2
|
||||
a(href='images/slack.png', target='_blank')
|
||||
img(src='images/slack.png')
|
||||
|
||||
|
||||
.row
|
||||
.bread
|
||||
.column.column2-5
|
||||
img(src='images/octocat.png')
|
||||
.row
|
||||
.bread
|
||||
.column.column2-5
|
||||
img(src='images/octocat.png')
|
||||
|
||||
.column.column3-5
|
||||
h3 Avoin lähdekoodi
|
||||
p
|
||||
|Suosimme avointa lähdekoodia ja kaikki käyttämämme koodi on vapaasti saatavilla ja hyödynnettävissä <a href="https://github.com/koodiklinikka">Github-organisaatiomme sivulta</a>.
|
||||
|Organisaation jäseneksi otamme kaikki Slack-yhteisömme jäsenet ja kontribuutio projekteihimme otetaan lämpimästi vastaan.
|
||||
.column.column3-5
|
||||
h3 Avoin lähdekoodi
|
||||
p
|
||||
|Suosimme avointa lähdekoodia ja kaikki käyttämämme koodi on vapaasti saatavilla ja hyödynnettävissä <a href="https://github.com/koodiklinikka">Github-organisaatiomme sivulta</a>.
|
||||
|Organisaation jäseneksi otamme kaikki Slack-yhteisömme jäsenet ja kontribuutio projekteihimme otetaan lämpimästi vastaan.
|
||||
|
||||
#members
|
||||
#members
|
||||
|
||||
.row
|
||||
h2 Potilaiden projekteja
|
||||
.bread
|
||||
.column.column2-5
|
||||
a(href='https://redom.js.org', target='_blank')
|
||||
img(src='images/redom.svg')
|
||||
.row
|
||||
h2 Potilaiden projekteja
|
||||
.bread
|
||||
.column.column2-5
|
||||
a(href='https://redom.js.org', target='_blank')
|
||||
img(src='images/redom.svg')
|
||||
|
||||
.column.column3-5
|
||||
h4 RE:DOM
|
||||
.column.column3-5
|
||||
h4 RE:DOM
|
||||
|
||||
p.
|
||||
Tiny (2 KB) turboboosted JavaScript library for creating user interfaces.
|
||||
Develop web apps with 100 % JavaScript and web standards.
|
||||
p.
|
||||
Tiny (2 KB) turboboosted JavaScript library for creating user interfaces.
|
||||
Develop web apps with 100 % JavaScript and web standards.
|
||||
|
||||
.bread
|
||||
.column.column2-5
|
||||
a(href='https://codestats.net/', target='_blank')
|
||||
img.project-image__codestats(src='images/codestats.png')
|
||||
.bread
|
||||
.column.column2-5
|
||||
a(href='https://codestats.net/', target='_blank')
|
||||
img.project-image__codestats(src='images/codestats.png')
|
||||
|
||||
.column.column3-5
|
||||
h4 Code::Stats
|
||||
.column.column3-5
|
||||
h4 Code::Stats
|
||||
|
||||
p.
|
||||
Code::Stats is a free stats tracking service for programmers
|
||||
p.
|
||||
Code::Stats is a free stats tracking service for programmers
|
||||
|
||||
#members
|
||||
#members
|
||||
|
||||
#feed
|
||||
|
||||
|
||||
footer
|
||||
.sponsors
|
||||
.sponsors__label Yhteistyössä
|
||||
a(href='http://futurice.com/', target='_blank')
|
||||
img.sponsor.sponsor__futurice(src='images/futurice.svg')
|
||||
a(href='http://www.metosin.fi/', target='_blank')
|
||||
img.sponsor.sponsor__metosin(src='images/metosin.svg')
|
||||
a(href='https://www.solita.fi/', target='_blank')
|
||||
img.sponsor(src='images/solita.svg')
|
||||
a(href='http://leonidasoy.fi/', target='_blank')
|
||||
img.sponsor.sponsor__leonidas(src='images/leonidas.png')
|
||||
a(href='https://www.nordea.com/', target='_blank')
|
||||
img.sponsor.sponsor__nordea(src='images/nordea.png')
|
||||
|
||||
.contacts
|
||||
div
|
||||
a(href='https://koodiklinikka.slack.com')
|
||||
i.fa.fa-slack
|
||||
|
||||
a(href='https://github.com/koodiklinikka/koodiklinikka.fi')
|
||||
i.fa.fa-github
|
||||
|
||||
a(href='https://twitter.com/koodiklinikka')
|
||||
i.fa.fa-twitter
|
||||
|
||||
a(href='https://www.linkedin.com/groups/12025476')
|
||||
i.fa.fa-linkedin
|
||||
|
||||
a(href='https://www.facebook.com/koodiklinikka')
|
||||
i.fa.fa-facebook
|
||||
div#email
|
||||
|
||||
|
||||
#fader
|
||||
// inject:js
|
||||
// endinject
|
||||
#feed
|
||||
|
||||
@@ -5,7 +5,7 @@ var React = require('react');
|
||||
var classSet = require('classnames');
|
||||
|
||||
var api = require('../api');
|
||||
|
||||
var Loader = require('./loader');
|
||||
module.exports = React.createClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
@@ -48,6 +48,7 @@ module.exports = React.createClass({
|
||||
},
|
||||
render() {
|
||||
var formClasses = classSet({
|
||||
'form': true,
|
||||
'invite-form': true,
|
||||
'has-success': this.state.submitted,
|
||||
'has-error': this.state.error,
|
||||
@@ -76,7 +77,7 @@ module.exports = React.createClass({
|
||||
}
|
||||
|
||||
feedbackMessage = (
|
||||
<div className='invite-form--message'>
|
||||
<div className='form--message'>
|
||||
{messageText}
|
||||
</div>
|
||||
);
|
||||
@@ -98,11 +99,11 @@ module.exports = React.createClass({
|
||||
disabled={this.state.error || this.state.submitted}>
|
||||
⏎
|
||||
</button>
|
||||
<span
|
||||
className='loader'>
|
||||
</span>
|
||||
<div className='invite-form__loader'>
|
||||
<Loader />
|
||||
</div>
|
||||
{feedbackMessage}
|
||||
</form>
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
12
src/js/components/loader.js
Normal file
12
src/js/components/loader.js
Normal file
@@ -0,0 +1,12 @@
|
||||
const React = require('react');
|
||||
|
||||
module.exports = function Loader() {
|
||||
return (
|
||||
<div className='sk-folding-cube'>
|
||||
<div className='sk-cube1 sk-cube'></div>
|
||||
<div className='sk-cube2 sk-cube'></div>
|
||||
<div className='sk-cube4 sk-cube'></div>
|
||||
<div className='sk-cube3 sk-cube'></div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -7,7 +7,7 @@ var _ = require('lodash');
|
||||
var api = require('../api');
|
||||
|
||||
module.exports = React.createClass({
|
||||
getInitialState() {
|
||||
getInitialState() {
|
||||
return {
|
||||
members: []
|
||||
};
|
||||
|
||||
34
src/js/components/membershipForm.js
Normal file
34
src/js/components/membershipForm.js
Normal file
@@ -0,0 +1,34 @@
|
||||
import React from 'react';
|
||||
import MembershipInfoForm from './membershipInfoForm';
|
||||
|
||||
module.exports = React.createClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
paymentSuccess: false
|
||||
};
|
||||
},
|
||||
handlePaymentSuccess() {
|
||||
this.setState({ paymentSuccess: true });
|
||||
},
|
||||
render() {
|
||||
if(!this.state.paymentSuccess) {
|
||||
return (
|
||||
<MembershipInfoForm onPaymentSuccess={this.handlePaymentSuccess} />
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<svg height='50' width='50' viewBox='0 0 512 512' xmlns='http://www.w3.org/2000/svg'>
|
||||
<path
|
||||
fill='#349c4a'
|
||||
d='M256 6.998c-137.533 0-249 111.467-249 249 0 137.534 111.467 249 249 249s249-111.467 249-249c0-137.534-111.467-249-249-249zm0 478.08c-126.31 0-229.08-102.77-229.08-229.08 0-126.31 102.77-229.08 229.08-229.08 126.31 0 229.08 102.77 229.08 229.08 0 126.31-102.77 229.08-229.08 229.08z' />
|
||||
<path
|
||||
fill='#349c4a'
|
||||
d='M384.235 158.192L216.92 325.518 127.86 236.48l-14.142 14.144 103.2 103.18 181.36-181.47' />
|
||||
</svg>
|
||||
<p> Maksu ja rekisteröityminen onnistui.</p>
|
||||
<p> Tervetuloa Koodiklinikka ry:n jäseneksi!</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
199
src/js/components/membershipInfoForm.js
Normal file
199
src/js/components/membershipInfoForm.js
Normal file
@@ -0,0 +1,199 @@
|
||||
'use strict';
|
||||
|
||||
var _ = require('lodash');
|
||||
var request = require('axios');
|
||||
var React = require('react');
|
||||
var classSet = require('classnames');
|
||||
var StripeCheckout = require('react-stripe-checkout').default;
|
||||
|
||||
var api = require('../api');
|
||||
var Loader = require('./loader');
|
||||
var config = require('../../config.js')();
|
||||
|
||||
var fieldNameTranslations = {
|
||||
address: { fi: 'Osoite' },
|
||||
city: { fi: 'Paikkakunta' },
|
||||
email: { fi: 'Sähköpostiosoite' },
|
||||
handle: { fi: 'Slack-käyttäjätunnus ' },
|
||||
name: { fi: 'Koko nimi ' },
|
||||
postcode: { fi: 'Postinumero' }
|
||||
};
|
||||
|
||||
function validateEmail(email) {
|
||||
var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
||||
return re.test(email);
|
||||
}
|
||||
|
||||
const fieldNames = ['name', 'email', 'handle', 'address', 'city', 'postcode'];
|
||||
|
||||
function getUserInfo(state) {
|
||||
return _.pick(state, fieldNames);
|
||||
}
|
||||
|
||||
module.exports = React.createClass({
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
address: '',
|
||||
city: '',
|
||||
email: '',
|
||||
handle: '',
|
||||
name: '',
|
||||
postcode: '',
|
||||
sending: false,
|
||||
pristineFields: fieldNames
|
||||
};
|
||||
},
|
||||
onSubmit(token) {
|
||||
this.setState({
|
||||
sending: true,
|
||||
error: null
|
||||
});
|
||||
|
||||
request.post(api('membership'), {
|
||||
userInfo: getUserInfo(this.state),
|
||||
stripeToken: token.id
|
||||
})
|
||||
.then(() => {
|
||||
this.setState({ sending: false });
|
||||
this.props.onPaymentSuccess();
|
||||
})
|
||||
.catch((err) => {
|
||||
this.setState({ error: err, sending: false });
|
||||
});
|
||||
},
|
||||
onChange(e) {
|
||||
var name = e.target.name;
|
||||
if (e.target.value === this.state[name]) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
[e.target.name]: e.target.value,
|
||||
pristineFields: this.state.pristineFields.filter((fieldName) => fieldName !== name),
|
||||
errors: []
|
||||
});
|
||||
},
|
||||
|
||||
getDataErrors() {
|
||||
var foundErrors = [];
|
||||
|
||||
fieldNames.forEach((fieldName) => {
|
||||
if (!this.state[fieldName]) {
|
||||
foundErrors.push({ field: fieldName, type: 'missing' });
|
||||
}
|
||||
});
|
||||
|
||||
if (this.state.email && !validateEmail(this.state.email)) {
|
||||
foundErrors.push({ field: 'email', type: 'invalid' });
|
||||
}
|
||||
|
||||
return foundErrors;
|
||||
},
|
||||
|
||||
render() {
|
||||
const inputErrors = this.getDataErrors();
|
||||
|
||||
var formClasses = classSet({
|
||||
'form': true,
|
||||
'membership-form': true,
|
||||
'has-error': inputErrors.length !== 0 || this.state.error,
|
||||
'sending': this.state.sending
|
||||
});
|
||||
|
||||
function getErrorMessage(err) {
|
||||
var feedbackText;
|
||||
|
||||
if (err.type === 'missing') {
|
||||
feedbackText = `${fieldNameTranslations[err.field].fi} on pakollinen.`;
|
||||
} else if (err.type === 'invalid') {
|
||||
feedbackText = `${fieldNameTranslations[err.field].fi} on virheellinen.`;
|
||||
}
|
||||
|
||||
return <div key={err.field} className='form--message'>{feedbackText}</div>;
|
||||
}
|
||||
|
||||
/* generate error messages */
|
||||
var visibleErrors = inputErrors
|
||||
.filter((error) => this.state.pristineFields.indexOf(error.field) === -1);
|
||||
|
||||
var fieldsWithErrors = visibleErrors.map(({ field }) => field);
|
||||
|
||||
var inputFields = fieldNames.map((fieldName) => {
|
||||
var inputClasses = classSet({
|
||||
'input': true,
|
||||
'has-error': _.includes(fieldsWithErrors, fieldName),
|
||||
'half': fieldName === 'city' || fieldName === 'postcode',
|
||||
'left': fieldName === 'city'
|
||||
});
|
||||
|
||||
function showsErrorFor(field) {
|
||||
if (fieldName === 'city') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return field === fieldName || fieldName === 'postcode' && field === 'city';
|
||||
}
|
||||
|
||||
return (
|
||||
<span key={fieldName}>
|
||||
<input
|
||||
className={inputClasses}
|
||||
type={fieldName === 'email' ? 'email' : 'text'}
|
||||
name={fieldName}
|
||||
placeholder={fieldNameTranslations[fieldName].fi}
|
||||
value={this.state[fieldName]}
|
||||
onChange={this.onChange} />
|
||||
{
|
||||
visibleErrors
|
||||
.filter(({ field }) => showsErrorFor(field))
|
||||
.map(getErrorMessage)
|
||||
|
||||
}
|
||||
</span>
|
||||
);
|
||||
});
|
||||
if (this.state.sending) {
|
||||
return (
|
||||
<div className='membership-form__loader'>
|
||||
<Loader />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<h3>Liity jäseneksi</h3>
|
||||
<form className={formClasses}>
|
||||
{inputFields}
|
||||
{this.state.error && (
|
||||
<div className='form--message'>
|
||||
Jotain meni pieleen! Ota yhteyttä info@koodiklinikka.fi
|
||||
</div>
|
||||
)}
|
||||
<br />
|
||||
<StripeCheckout
|
||||
amount={1000}
|
||||
currency='EUR'
|
||||
description='Jäsenmaksu'
|
||||
email={this.state.email}
|
||||
image='https://avatars3.githubusercontent.com/u/10520119?v=3&s=200'
|
||||
locale='fi'
|
||||
name='Koodiklinikka ry'
|
||||
stripeKey={config.stripe.publicKey}
|
||||
token={this.onSubmit}
|
||||
>
|
||||
<button
|
||||
type='button'
|
||||
disabled={inputErrors.length !== 0}
|
||||
className='btn btn__submit'>
|
||||
Siirry maksamaan
|
||||
</button>
|
||||
</StripeCheckout>
|
||||
<p>
|
||||
<small>Seuraava vuosimaksu veloitetaan automaattisesti <br />kortiltasi vuoden kuluttua.</small>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -3,31 +3,49 @@ require('./ga');
|
||||
let ReactDOM = require('react-dom');
|
||||
var React = require('react');
|
||||
|
||||
|
||||
var inviteForm = React.createFactory(require('./components/inviteForm'));
|
||||
var fader = React.createFactory(require('./components/fader'));
|
||||
var members = React.createFactory(require('./components/members'));
|
||||
var feed = React.createFactory(require('./components/feed'));
|
||||
var email = React.createFactory(require('./components/email'));
|
||||
var membershipForm = React.createFactory(require('./components/membershipForm'));
|
||||
|
||||
ReactDOM.render(
|
||||
inviteForm(),
|
||||
document.getElementById('invite-form'));
|
||||
const pathName = window.location.pathname;
|
||||
|
||||
ReactDOM.render(
|
||||
fader(),
|
||||
document.getElementById('fader'));
|
||||
document.querySelectorAll('.email').forEach((element) =>
|
||||
ReactDOM.render(email(), element)
|
||||
);
|
||||
|
||||
if (pathName == '/') {
|
||||
ReactDOM.render(
|
||||
inviteForm(),
|
||||
document.getElementById('invite-form'));
|
||||
|
||||
ReactDOM.render(
|
||||
members(),
|
||||
document.getElementById('members'));
|
||||
ReactDOM.render(
|
||||
fader(),
|
||||
document.getElementById('fader'));
|
||||
|
||||
ReactDOM.render(
|
||||
members(),
|
||||
document.getElementById('members'));
|
||||
|
||||
ReactDOM.render(
|
||||
feed(),
|
||||
document.getElementById('feed'));
|
||||
ReactDOM.render(
|
||||
feed(),
|
||||
document.getElementById('feed'));
|
||||
|
||||
ReactDOM.render(
|
||||
email(),
|
||||
document.getElementById('email'));
|
||||
} else if (pathName == '/yhdistys.html') {
|
||||
ReactDOM.render(
|
||||
membershipForm(),
|
||||
document.getElementById('membership-form'));
|
||||
|
||||
ReactDOM.render(
|
||||
fader(),
|
||||
document.getElementById('fader'));
|
||||
|
||||
ReactDOM.render(
|
||||
React.createElement('div', {}, [
|
||||
members({ key: 0 }),
|
||||
members({ key: 1 })
|
||||
]),
|
||||
document.getElementById('members'));
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
headerHeight = 400px
|
||||
|
||||
.header
|
||||
background url('../images/jumbo.jpg')
|
||||
background-position bottom center
|
||||
background-size cover
|
||||
height 400px
|
||||
height headerHeight
|
||||
overflow hidden
|
||||
position relative
|
||||
width 100%
|
||||
@@ -23,6 +25,43 @@
|
||||
vertical-align middle
|
||||
width 100%
|
||||
|
||||
.header__nav
|
||||
position absolute
|
||||
right 60px
|
||||
top 32px
|
||||
|
||||
@media screen and (max-width: 1030px)
|
||||
right 40px
|
||||
top 20px
|
||||
a
|
||||
color white
|
||||
font-size 16px
|
||||
font-weight bold
|
||||
margin-left 16px
|
||||
text-shadow 0 2px 0 rgba(0,0,0,0.1)
|
||||
position relative
|
||||
@media screen and (max-width: 420px)
|
||||
display block
|
||||
margin-top 5px
|
||||
|
||||
&:last-child
|
||||
margin-left 1.5em
|
||||
&:before
|
||||
content '!'
|
||||
font-size 11px
|
||||
line-height 15px
|
||||
width 14px
|
||||
height 14px
|
||||
text-align center
|
||||
background #ec3d3d
|
||||
display inline-block
|
||||
margin-right 5px
|
||||
top -5px
|
||||
right -15px
|
||||
border-radius 100%
|
||||
position absolute
|
||||
text-shadow none
|
||||
|
||||
.header__headline
|
||||
display table-cell
|
||||
padding 0 1em
|
||||
@@ -85,3 +124,59 @@
|
||||
@media (min-aspect-ratio: 1/2)
|
||||
width 100%
|
||||
height auto
|
||||
|
||||
@keyframes spin
|
||||
0%
|
||||
top 0
|
||||
50%
|
||||
top -(headerHeight)
|
||||
50.0001%
|
||||
top headerHeight
|
||||
100%
|
||||
top 0
|
||||
|
||||
@keyframes spin2
|
||||
0%
|
||||
top (headerHeight)
|
||||
50%
|
||||
top 0
|
||||
99.99999%
|
||||
top -(headerHeight)
|
||||
100%
|
||||
top (headerHeight)
|
||||
|
||||
.header__members
|
||||
width 100%
|
||||
height 100%
|
||||
z-index -1
|
||||
position absolute
|
||||
top 0
|
||||
left 0
|
||||
|
||||
.member
|
||||
margin 0
|
||||
border-radius 0
|
||||
width (100/18)%
|
||||
|
||||
@media screen and (min-width: 2000px)
|
||||
width 5%
|
||||
@media screen and (max-width: 1200px)
|
||||
width (100/15)%
|
||||
@media screen and (max-width: 810px)
|
||||
width 10%
|
||||
@media screen and (max-width: 450px)
|
||||
width 20%
|
||||
|
||||
.members
|
||||
position absolute
|
||||
overflow hidden
|
||||
top 0
|
||||
left 0
|
||||
right 0
|
||||
height headerHeight
|
||||
animation spin 40s infinite linear
|
||||
&:first-child
|
||||
z-index 1
|
||||
&:last-child
|
||||
animation spin2 40s infinite linear
|
||||
|
||||
|
||||
@@ -30,3 +30,8 @@
|
||||
.input.has-error
|
||||
border-color rgba(226, 33, 112, 0.6)
|
||||
color rgb(226, 33, 112)
|
||||
|
||||
.input.half
|
||||
width 48%
|
||||
&.left
|
||||
margin-right 4%
|
||||
|
||||
55
src/styles/_loader.styl
Normal file
55
src/styles/_loader.styl
Normal file
@@ -0,0 +1,55 @@
|
||||
.sk-folding-cube
|
||||
margin auto
|
||||
width 100%
|
||||
height 100%
|
||||
position relative
|
||||
transform rotateZ(45deg)
|
||||
|
||||
.sk-folding-cube .sk-cube
|
||||
float left
|
||||
width 50%
|
||||
height 50%
|
||||
position relative
|
||||
transform scale(1.1)
|
||||
|
||||
.sk-folding-cube .sk-cube:before
|
||||
content ''
|
||||
position absolute
|
||||
top 0
|
||||
left 0
|
||||
width 100%
|
||||
height 100%
|
||||
background-color linkColor
|
||||
animation sk-foldCubeAngle 2.4s infinite linear both
|
||||
transform-origin 100% 100%
|
||||
|
||||
.sk-folding-cube .sk-cube2
|
||||
transform scale(1.1) rotateZ(90deg)
|
||||
|
||||
.sk-folding-cube .sk-cube3
|
||||
transform scale(1.1) rotateZ(180deg)
|
||||
|
||||
.sk-folding-cube .sk-cube4
|
||||
transform scale(1.1) rotateZ(270deg)
|
||||
|
||||
.sk-folding-cube .sk-cube2:before
|
||||
animation-delay 0.3s
|
||||
|
||||
.sk-folding-cube .sk-cube3:before
|
||||
animation-delay 0.6s
|
||||
|
||||
.sk-folding-cube .sk-cube4:before
|
||||
animation-delay 0.9s
|
||||
|
||||
@keyframes sk-foldCubeAngle
|
||||
0%, 10%
|
||||
transform perspective(140px) rotateX(-180deg)
|
||||
opacity 0
|
||||
25%, 75%
|
||||
transform perspective(140px) rotateX(0deg)
|
||||
opacity 1
|
||||
90%, 100%
|
||||
transform perspective(140px) rotateY(180deg)
|
||||
opacity 0
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ footerHeight = 50px
|
||||
@require '_input'
|
||||
@require '_button'
|
||||
@require '_header'
|
||||
@require '_loader'
|
||||
|
||||
body, html
|
||||
margin 0
|
||||
@@ -25,6 +26,9 @@ h1, h2, h3
|
||||
h2
|
||||
margin-bottom 1em
|
||||
|
||||
h3
|
||||
font-size 1.25em
|
||||
|
||||
p
|
||||
margin-top 1em
|
||||
line-height 1.5em
|
||||
@@ -51,13 +55,17 @@ section
|
||||
.content
|
||||
z-index 2
|
||||
position relative
|
||||
padding-right feedWidth
|
||||
min-height 50vh
|
||||
box-sizing border-box
|
||||
|
||||
@media screen and (max-width: 700px)
|
||||
h3
|
||||
margin-top 0
|
||||
|
||||
&.with-feed
|
||||
padding-right feedWidth
|
||||
|
||||
|
||||
section:first-child
|
||||
box-shadow -1px -1px 1px rgba(0, 0, 0, 0.05)
|
||||
border-bottom 1px solid #EEEEEE
|
||||
@@ -104,35 +112,55 @@ section:first-child
|
||||
padding 0
|
||||
&:first-child
|
||||
margin-top 0
|
||||
|
||||
.form
|
||||
.btn
|
||||
background linkColor
|
||||
border-bottom 2px solid #117280
|
||||
color rgba(255, 255, 255, 0.9)
|
||||
&.sending
|
||||
.btn
|
||||
display none
|
||||
.invite-form__loader
|
||||
display block
|
||||
.invite-form
|
||||
position relative
|
||||
.btn
|
||||
width 40px
|
||||
height 32px
|
||||
background linkColor
|
||||
padding 0
|
||||
position absolute
|
||||
right 8px
|
||||
top 7px
|
||||
|
||||
border-bottom 2px solid #117280
|
||||
color rgba(255, 255, 255, 0.5)
|
||||
&:active
|
||||
border-bottom 0
|
||||
.loader
|
||||
.invite-form__loader
|
||||
display none
|
||||
width 20px
|
||||
height 20px
|
||||
position absolute
|
||||
right 9px
|
||||
top 9px
|
||||
width 0px
|
||||
height 0px
|
||||
background transparent url('../images/ajax-loader.gif') no-repeat center center
|
||||
right 14px
|
||||
top 14px
|
||||
|
||||
.membership-form
|
||||
.input
|
||||
margin 8px 0px
|
||||
.btn
|
||||
margin-top 12px
|
||||
|
||||
.membership-form__loader
|
||||
width 70px
|
||||
height 70px
|
||||
margin auto
|
||||
|
||||
.stripe-form
|
||||
margin 20px 0px
|
||||
.name
|
||||
margin-top 20px
|
||||
text-align left
|
||||
display block
|
||||
&.sending
|
||||
.btn
|
||||
display none
|
||||
.loader
|
||||
width 28px
|
||||
height 28px
|
||||
color rgba(0, 0, 0, 0.4)
|
||||
|
||||
@keyframes drop
|
||||
0%
|
||||
@@ -146,7 +174,7 @@ section:first-child
|
||||
100%
|
||||
transform rotateX(0deg)
|
||||
|
||||
.invite-form--message
|
||||
.form--message
|
||||
background linkColor
|
||||
color #fff
|
||||
line-height 40px
|
||||
@@ -156,8 +184,8 @@ section:first-child
|
||||
transform-origin 100% 0
|
||||
animation drop 0.6s linear
|
||||
|
||||
.invite-form.has-error
|
||||
.invite-form--message
|
||||
.form.has-error
|
||||
.form--message
|
||||
background rgb(226, 33, 112)
|
||||
|
||||
.members
|
||||
@@ -182,7 +210,7 @@ footer
|
||||
justify-content space-between
|
||||
flex-wrap wrap
|
||||
text-align center
|
||||
@media screen and (max-width: 760px)
|
||||
@media screen and (max-width: 940px)
|
||||
display block
|
||||
i
|
||||
margin 0 0.30em
|
||||
@@ -194,7 +222,7 @@ footer
|
||||
display flex
|
||||
flex-direction column
|
||||
justify-content center
|
||||
@media screen and (max-width: 760px)
|
||||
@media screen and (max-width: 940px)
|
||||
margin-top 1em
|
||||
|
||||
.sponsors
|
||||
@@ -215,16 +243,17 @@ footer
|
||||
height 40px
|
||||
margin-right 1em
|
||||
vertical-align middle
|
||||
@media screen and (max-width: 760px)
|
||||
@media screen and (max-width: 940px)
|
||||
margin-top 1em
|
||||
|
||||
|
||||
.sponsor__futurice, .sponsor__metosin, .sponsor__leonidas
|
||||
height 30px
|
||||
|
||||
.sponsor__nordea
|
||||
height 25px
|
||||
margin-top: -3px
|
||||
margin-top -3px
|
||||
@media screen and (max-width: 940px)
|
||||
margin-top 1em
|
||||
|
||||
.feed
|
||||
width feedWidth
|
||||
@@ -242,7 +271,7 @@ footer
|
||||
@media screen and (max-width: 980px)
|
||||
.feed
|
||||
width 0
|
||||
.content
|
||||
.content.with-feed
|
||||
padding-right 0
|
||||
|
||||
.message
|
||||
@@ -314,3 +343,24 @@ footer
|
||||
display block
|
||||
.column
|
||||
display block
|
||||
|
||||
.bread-img
|
||||
background url('../images/hp3_bw.jpg')
|
||||
background-size cover
|
||||
border-radius 160px
|
||||
opacity 0.85
|
||||
width 320px
|
||||
height 320px
|
||||
margin auto
|
||||
|
||||
@media screen and (max-width: 700px)
|
||||
.bread-img
|
||||
display none
|
||||
|
||||
.organization
|
||||
padding-top 3em
|
||||
|
||||
.membership-information.column
|
||||
vertical-align initial
|
||||
p:first-child
|
||||
margin-top 37px
|
||||
|
||||
84
src/templates/head.jade
Normal file
84
src/templates/head.jade
Normal file
@@ -0,0 +1,84 @@
|
||||
doctype html
|
||||
html
|
||||
head
|
||||
title
|
||||
block title
|
||||
// inject:css
|
||||
// endinject
|
||||
meta(name='description', content='Koodiklinikka on suomalainen Slack-yhteisö ohjelmistoalan harrastajille ja ammattilaisille.')
|
||||
meta(name='keywords', content='ohjelmointi,frontend,open source,devaus,suomi,javascript,clojure,go,java,node.js,io.js,angular.js,web')
|
||||
meta(charset='utf-8')
|
||||
meta(name='viewport', content='width=device-width, initial-scale=1')
|
||||
meta(name='apple-mobile-web-app-capable', content='yes')
|
||||
|
||||
script.
|
||||
if(location.hostname === 'koodiklinikka.fi' && location.protocol !== 'https:') {
|
||||
location.protocol = 'https';
|
||||
}
|
||||
link(rel='apple-touch-icon', sizes='57x57', href='icons/apple-touch-icon-57x57.png')
|
||||
link(rel='apple-touch-icon', sizes='114x114', href='icons/apple-touch-icon-114x114.png')
|
||||
link(rel='apple-touch-icon', sizes='72x72', href='icons/apple-touch-icon-72x72.png')
|
||||
link(rel='apple-touch-icon', sizes='144x144', href='icons/apple-touch-icon-144x144.png')
|
||||
link(rel='apple-touch-icon', sizes='60x60', href='icons/apple-touch-icon-60x60.png')
|
||||
link(rel='apple-touch-icon', sizes='120x120', href='icons/apple-touch-icon-120x120.png')
|
||||
link(rel='apple-touch-icon', sizes='76x76', href='icons/apple-touch-icon-76x76.png')
|
||||
link(rel='apple-touch-icon', sizes='152x152', href='icons/apple-touch-icon-152x152.png')
|
||||
link(rel='apple-touch-icon', sizes='180x180', href='icons/apple-touch-icon-180x180.png')
|
||||
link(rel='icon', type='image/png', href='icons/favicon-192x192.png', sizes='192x192')
|
||||
link(rel='icon', type='image/png', href='icons/favicon-160x160.png', sizes='160x160')
|
||||
link(rel='icon', type='image/png', href='icons/favicon-96x96.png', sizes='96x96')
|
||||
link(rel='icon', type='image/png', href='icons/favicon-16x16.png', sizes='16x16')
|
||||
link(rel='icon', type='image/png', href='icons/favicon-32x32.png', sizes='32x32')
|
||||
link(rel='shortcut icon', href='icons/favicon.ico')
|
||||
link(rel='icon', href='icons/favicon.ico')
|
||||
meta(name='msapplication-TileColor', content='#10558c')
|
||||
meta(name='msapplication-TileImage', content='icons/mstile-144x144.png')
|
||||
meta(property='og:image', content='images/logo.png')
|
||||
script(src='https://js.stripe.com/v3/')
|
||||
script(src='//use.typekit.net/scb5xny.js')
|
||||
script.
|
||||
try{Typekit.load();}catch(e){};
|
||||
|
||||
body
|
||||
.site
|
||||
.container
|
||||
.header
|
||||
block header_content
|
||||
|
||||
block content
|
||||
|
||||
footer
|
||||
.sponsors
|
||||
.sponsors__label Yhteistyössä
|
||||
a(href='http://futurice.com/', target='_blank')
|
||||
img.sponsor.sponsor__futurice(src='images/futurice.svg')
|
||||
a(href='http://www.metosin.fi/', target='_blank')
|
||||
img.sponsor.sponsor__metosin(src='images/metosin.svg')
|
||||
a(href='https://www.solita.fi/', target='_blank')
|
||||
img.sponsor(src='images/solita.svg')
|
||||
a(href='http://leonidasoy.fi/', target='_blank')
|
||||
img.sponsor.sponsor__leonidas(src='images/leonidas.png')
|
||||
a(href='https://www.nordea.com/', target='_blank')
|
||||
img.sponsor.sponsor__nordea(src='images/nordea.png')
|
||||
|
||||
.contacts
|
||||
div
|
||||
a(href='https://koodiklinikka.slack.com')
|
||||
i.fa.fa-slack
|
||||
|
||||
a(href='https://github.com/koodiklinikka/koodiklinikka.fi')
|
||||
i.fa.fa-github
|
||||
|
||||
a(href='https://twitter.com/koodiklinikka')
|
||||
i.fa.fa-twitter
|
||||
|
||||
a(href='https://www.linkedin.com/groups/12025476')
|
||||
i.fa.fa-linkedin
|
||||
|
||||
a(href='https://www.facebook.com/koodiklinikka')
|
||||
i.fa.fa-facebook
|
||||
div#email.email
|
||||
|
||||
#fader
|
||||
// inject:js
|
||||
// endinject
|
||||
48
src/yhdistys.jade
Normal file
48
src/yhdistys.jade
Normal file
@@ -0,0 +1,48 @@
|
||||
extends templates/head
|
||||
|
||||
block title
|
||||
| Yhdistys
|
||||
|
||||
block header_content
|
||||
.header__container
|
||||
.header__nav
|
||||
a(href='/') etusivu
|
||||
a(href='/yhdistys.html') yhdistys
|
||||
.header__headline
|
||||
.header__logo
|
||||
h1.header__title Koodiklinikka ry
|
||||
.header__members
|
||||
#members
|
||||
|
||||
block content
|
||||
.content
|
||||
section.organization
|
||||
.row
|
||||
.bread
|
||||
.column.column1-2
|
||||
h3 Rekisteröity yhdistys
|
||||
p.
|
||||
Koodiklinikka on nyt rekisteröity yhdistys!
|
||||
p.
|
||||
Lähes nelivuotisen taipaleensa aikana Koodiklinikka on kasvanut lähes tuhannen rekisteröityneen jäsenen yhteisöiksi ja näin saavuttanut aseman Suomen suurimpana ohjelmointiaiheisena yhteisönä! Liittymällä Koodiklinikka ry:n jäseneksi tuet toimintaamme, ja tulevaisuudessa yhdistyksen jäsenyys oikeuttaa etuihin Koodiklinikan tapahtumissa.
|
||||
p.
|
||||
Yhdistyksen jäsenyys <b>ei ole</b>, eikä tule olemaan, <b>pakollinen</b> Koodiklinikan käyttäjille tai meetuppeihin osallistujille.
|
||||
.column.column1-2
|
||||
.bread-img
|
||||
.row
|
||||
.bread
|
||||
.column.column1-2
|
||||
#membership-form.form
|
||||
|
||||
.column.column1-2.membership-information
|
||||
p.
|
||||
Kuka tahansa Slack:iin rekisteröitynyt käyttäjä voi liittyä yhdistyksen jäseneksi maksamalla <b>10€</b> vuosittaisen jäsenmaksun.
|
||||
p.
|
||||
Jäsenmaksulla tulemme tekemään tapahtumistamme vieläkin mielenkiintoisempia ja kattamaan kustannuksia jäsenmäärämme kasvaessa.
|
||||
p.
|
||||
Jos tarvitset Slack-kutsun, siirry <a target="_blank" href="/">etusivulle</a>.
|
||||
p.
|
||||
Jäsenrekisterin rekisteriseloste luettavissa <a target="_blank" href="https://docs.google.com/document/d/1w-NZkf1EFYMC8a4LsoZouhpMVKORmPi8UFWRhurr0oM/edit?usp=sharing">Google Drivessä</a>.
|
||||
p.
|
||||
Lisätietoa yhdistyksen jäsenyydestä tai vuosimaksusta emaililla <span class="email"></span>
|
||||
|
||||
Reference in New Issue
Block a user