feat: new design for koodiklinikka.fi

This commit is contained in:
Petri Partio
2024-05-30 15:25:21 +03:00
parent 2791108118
commit 1b0cdd3708
106 changed files with 828 additions and 4874 deletions

View File

@@ -1,13 +0,0 @@
# http://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false

View File

@@ -1 +0,0 @@
out

View File

@@ -1,37 +0,0 @@
module.exports = {
extends: [
"plugin:@typescript-eslint/recommended",
"plugin:react-hooks/recommended",
"plugin:react/recommended",
"plugin:jsx-a11y/recommended",
"plugin:@next/next/recommended",
"prettier",
],
settings: {
react: {
version: "detect",
},
},
env: {
browser: true,
node: true,
},
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: 2020,
sourceType: "module",
ecmaFeatures: {
jsx: true,
},
},
rules: {
"@typescript-eslint/ban-types": "warn",
"no-use-before-define": 0,
"padded-blocks": 0,
"react/jsx-no-target-blank": 0,
"react/jsx-uses-react": 2,
"react/jsx-uses-vars": 2,
"react/prop-types": 0,
"react/react-in-jsx-scope": 2,
},
};

3
.eslintrc.json Normal file
View File

@@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}

View File

@@ -1,12 +0,0 @@
name: Scheduled build
on:
schedule:
- cron: "0 0 * * *"
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Trigger our build webhook on Netlify
run: curl -s -X POST "https://api.netlify.com/build_hooks/${TOKEN}"
env:
TOKEN: ${{ secrets.NETLIFY_CRON_BUILD_HOOK }}

41
.gitignore vendored
View File

@@ -1,7 +1,36 @@
*.log
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
.history
.next
node_modules
out
package-lock.json
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts

2
.nvmrc
View File

@@ -1 +1 @@
16
20

View File

@@ -1,2 +0,0 @@
.next
out

8
.prettierrc Normal file
View File

@@ -0,0 +1,8 @@
{
"printWidth": 120,
"singleQuote": true,
"trailingComma": "es5",
"tabWidth": 2,
"useTabs": false,
"plugins": ["prettier-plugin-tailwindcss"]
}

View File

@@ -1,19 +0,0 @@
script: yarn build
language: node_js
node_js:
- "12.18"
install:
- yarn
test:
- yarn lint
- yarn build
deploy:
local_dir: out
provider: pages
fqdn: koodiklinikka.fi
skip_cleanup: true
github_token: "$GITHUB_TOKEN"
repo: koodiklinikka/koodiklinikka.github.io
target_branch: master
on:
branch: master

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2015 Riku Rouvila
Copyright (c) 2024 Petri Partio
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -1,57 +1,36 @@
# Koodiklinikka
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).
![Travis](https://travis-ci.org/koodiklinikka/koodiklinikka.fi.svg?branch=master)
## Getting Started
<img align="right" src="./public/static/images/logo-new-black.svg" alt="Koodiklinikka-logo" max-width="30%">
First, run the development server:
**Koodiklinikka.fi lähdekoodi**. [Issueita](https://github.com/koodiklinikka/koodiklinikka.fi/issues) ja [Pull Requestejä](https://github.com/koodiklinikka/koodiklinikka.fi/pulls) otetaan lämpimästi vastaan. Yritämme pitää kynnyksen kontribuoida projektiin alhaisena, jotta mahdollisimman moni pääsisi jättämään siihen jälkensä. Kaikki koodi katselmoidaan läpi ja mergetään projektiin kun näyttää hyvälle. Muutamasta mergetystä Pull Requestista oikeudet ylläpitää projektia.
[Issueita](https://github.com/koodiklinikka/koodiklinikka.fi/issues) voidaan käyttää myös sivun:
- toiminnallisuuteen
- designiin
- [HTTP-rajapintaan](https://github.com/koodiklinikka/koodiklinikka.fi-api)
- projektin hallintaan liittyviin asioihin
- tai koko Koodiklinikkaan yleisesti.
---
## Projektin asennus
### Vaaditut työkalut
- Asenna [Node.js](http://nodejs.org)
- Asenna [Yarn 1.x](https://classic.yarnpkg.com/en/)
- Asenna [Git](https://git-scm.com/) client lähdekoodin hallintaan
### Kloonaa projekti koneellesi
```sh
git clone https://github.com/koodiklinikka/koodiklinikka.fi.git
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
### Käynnistä kehitystila
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
```sh
cd koodiklinikka.fi
yarn
yarn start
```
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
### Avaa esikatselu selaimessa
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
Avaa selaimessasi: [`http://localhost:3000`](http://localhost:3000)
## Learn More
## Komennot
To learn more about Next.js, take a look at the following resources:
### `yarn`
- [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.
Asentaa projektin riippuvuudet
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
### `yarn start`
## Deploy on Vercel
Kääntää lähdetiedostot ja palvelee sovellusta porttiin `3000`
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
### `yarn build`
Kääntää lähdetiedostot -> `out/` -hakemistoon
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.

View File

@@ -1,6 +0,0 @@
- Stripe
- Test ID `pk_test_OmNve9H1OuORlmD4rblpjgzh`
- Prod ID `pk_live_xrnwdLNXbt20LMxpIDffJnnC`
- API integration (test backend `https://lit-plateau-4689.herokuapp.com/`)
- Hero video
- Deployment

99
app/globals.css Normal file
View File

@@ -0,0 +1,99 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer utilities {
.text-balance {
text-wrap: balance;
}
.text-shadow {
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
}
.title-highlight {
background: linear-gradient(200deg, #ff0098 20%, #0ef 80%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
filter: drop-shadow(0 0 20px rgba(255, 0, 234, 0.2));
}
@supports (color: color(display-p3 1 1 1)) {
.title-highlight {
background: linear-gradient(200deg, oklch(68% 0.5 340) 20%, oklch(90% 0.5 200) 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
filter: drop-shadow(0 0 20px oklch(80% 0.41 211 / 20%));
}
}
.bg-button {
background: linear-gradient(200deg, #f0f 20%, #ff00c4 100%);
}
@supports (color: color(display-p3 1 1 1)) {
.bg-button {
background: linear-gradient(200deg, oklch(100% 0.5 340) 20%, oklch(86% 0.5 360) 100%);
}
}
html {
background: #070b1e url('../public/background.webp');
background-size: 1024px auto;
background-position: top center;
background-repeat: no-repeat;
scroll-behavior: smooth;
}
@media (min-width: 1024px) {
html {
background-size: 100% auto;
}
}
h1,
h2,
h3 {
text-wrap: balance;
}
.checkbox svg {
display: none;
}
input[type='checkbox']:checked + .checkbox {
background-color: #ef008e;
border-color: #ff0099;
}
input[type='checkbox']:checked + .checkbox svg {
display: block;
align-items: center;
justify-items: center;
width: 80%;
height: auto;
}
input[type='checkbox']:focus + .checkbox {
outline: 2px solid var(--tw-color-red-800);
outline-offset: 2px;
}
@keyframes fadeInOut {
0% {
opacity: 20%;
}
50% {
opacity: 100%;
}
100% {
opacity: 20%;
}
}
.fade-in-out {
opacity: 20%;
animation: fadeInOut 4s ease-in-out infinite;
}

BIN
app/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

27
app/layout.tsx Normal file
View File

@@ -0,0 +1,27 @@
import type { Metadata } from 'next';
import { Inter } from 'next/font/google';
import './globals.css';
import BottomFade from '@/components/BottomFade';
const inter = Inter({ subsets: ['latin'] });
export const metadata: Metadata = {
title: 'Koodiklinikka',
description: 'Yhteisö kaikille ohjelmoinnista ja ohjelmistoalasta kiinnostuneille harrastajille ja ammattilaisille',
robots: 'noindex',
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="fi">
<body className={`${inter.className} pb-24 text-white`}>
{children}
<BottomFade />
</body>
</html>
);
}

View File

@@ -0,0 +1 @@
Koodiklinikka on Suomen suurin ohjelmistoalan yhteisö, joka tuo alan ammattilaiset ja harrastajat yhteen

BIN
app/opengraph-image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 497 KiB

105
app/page.tsx Normal file
View File

@@ -0,0 +1,105 @@
import shuffle from 'lodash.shuffle';
import ChannelGrid from '@/components/ChannelGrid';
import FeatureImage from '@/components/FeatureImage';
import Footer from '@/components/Footer';
import Hero from '@/components/Hero';
import Nav from '@/components/Nav';
import Wrapper from '@/components/Wrapper';
async function getChannels() {
const res = await fetch('https://stats.koodiklinikka.fi/api/channels', { next: { revalidate: 3600 } });
if (!res.ok) {
// This will activate the closest `error.js` Error Boundary
throw new Error('Failed to fetch data');
}
return res.json();
}
export default async function Home() {
let channels: Channel[] = await getChannels();
channels = channels.sort((a, b) => (a.messages_today > b.messages_today ? -1 : 1));
return (
<>
<Nav />
<main className="mt-20">
<Wrapper>
<Hero />
<div className="text-shadow py-16 lg:my-24">
<h2 className=" max-w-screen-xs mx-auto text-center text-2xl font-extrabold md:max-w-none md:text-3xl">
Suosituimmat keskustelunaiheet tänään
</h2>
<ChannelGrid channels={channels.splice(0, 12)} />
<div className="mx-auto max-w-md p-6 text-center font-mono text-sm leading-relaxed text-fuchsia-100/60 lg:max-w-3xl">
Ja paljon muuta:{' '}
{shuffle(channels.splice(0, 20))
.map<React.ReactNode>((channel) => (
<a
key={channel.id}
href={`https://app.slack.com/client/T03BQ3NU9/${channel.id}`}
target="_blank"
className="underline-offset-4 hover:underline"
>
#{channel.name}
</a>
))
.reduce((prev, curr) => [prev, ', ', curr])}
</div>
</div>
<div className="mx-auto max-w-lg space-y-14 p-6 md:p-12 lg:max-w-none lg:space-y-28">
<div className="text-shadow grid gap-10 lg:grid-cols-2 lg:gap-16">
<div className="lg:order-2">
<FeatureImage src="/meetup.webp" alt="" width="1792" height="1024" />
</div>
<div className="flex flex-col justify-center space-y-5 lg:order-1">
<h2 className="text-3xl font-extrabold">Yhteisö ohjelmoinnista kiinnostuneille</h2>
<div className="space-y-5 font-mono text-sm leading-relaxed text-pink-100">
<p>
Koodiklinikka on Suomen suurin ohjelmistoalan yhteisö, joka kokoaa yhteen ammattilaiset, harrastajat
ja vasta-alkajat. Tavoitteenamme on yhdistää ja kasvattaa suomalaista ohjelmointiyhteisöä sekä
tarjota apua ja uusia kontakteja kaikille ohjelmoinnista innostuneille.
</p>
<p>
Liittyminen on ilmaista ja helppoa. Jätä sähköpostiosoitteesi{' '}
<a href="#liity" className="underline underline-offset-4">
yllä olevaan kenttään
</a>
, niin lähetämme sinulle kutsun Slack-yhteisöömme.
</p>
</div>
</div>
</div>
<div className="text-shadow grid gap-10 lg:grid-cols-2 lg:gap-16">
<div>
<FeatureImage src="/opensource.webp" alt="" width="1792" height="1024" />
</div>
<div className="flex flex-col justify-center space-y-5">
<h2 className="text-3xl font-extrabold">Avoin lähdekoodi &lt;3</h2>
<div className="space-y-5 font-mono text-sm leading-relaxed text-pink-100">
<p>
Suosimme avointa lähdekoodia ja kaikki käyttämämme koodi on vapaasti saatavilla sekä
hyödynnettävissä Github-organisaatiomme sivulta. Organisaation jäseneksi otamme kaikki
Slack-yhteisömme jäsenet. Koodiklinikan projekteihin voi osallistua kuka tahansa ja muutosideat ovat
aina lämpimästi tervetulleita!
</p>
</div>
</div>
</div>
</div>
</Wrapper>
</main>
<Footer />
</>
);
}

View File

@@ -0,0 +1 @@
Koodiklinikka on Suomen suurin ohjelmistoalan yhteisö, joka tuo alan ammattilaiset ja harrastajat yhteen

BIN
app/twitter-image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 497 KiB

BIN
bun.lockb Executable file

Binary file not shown.

View File

@@ -0,0 +1,5 @@
export default function BottomFade() {
return (
<div className="pointer-events-none fixed bottom-0 left-0 right-0 z-50 h-32 bg-gradient-to-t from-[#070b1e] to-black/0"></div>
);
}

View File

@@ -0,0 +1,33 @@
import shuffle from 'lodash.shuffle';
export default function ChannelGrid({ channels }: { channels: Channel[] }) {
const DELAYS = shuffle([0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1]);
return (
<div className=" xs:grid-cols-2 mt-8 grid gap-3 rounded-3xl bg-gradient-to-b from-black/10 to-black/0 p-6 backdrop-blur-sm sm:grid-cols-3 md:grid-cols-4 md:p-12">
{channels.map((channel, i) => (
<div key={channel.id} className="relative h-[5.5rem]">
<div
className="fade-in-out absolute bottom-0 left-0 right-0 top-0 z-0 rounded-[9px] bg-fuchsia-200/40"
style={{
WebkitMask: 'linear-gradient(to bottom, rgba(0,0,0,1), rgba(0,0,0,0))',
animationDelay: `${DELAYS[i] * 2}s`,
}}
></div>
<div
className="absolute bottom-0 left-0 right-0 top-0 z-10 m-px rounded-[8px] bg-[#2c0c33]"
style={{ WebkitMask: 'linear-gradient(to bottom, rgba(0,0,0,.9), rgba(0,0,0,0))' }}
></div>
<div className="relative z-20 flex flex-col items-center justify-center gap-1 px-3 py-6 font-mono">
<a
href={`https://app.slack.com/client/T03BQ3NU9/${channel.id}`}
target="_blank"
className="text-sm font-semibold underline-offset-4 hover:underline"
>{`#${channel.name}`}</a>
<div className="text-xs opacity-70">{channel.num_members} jäsentä</div>
</div>
</div>
))}
</div>
);
}

View File

@@ -1,32 +0,0 @@
/* eslint-disable @typescript-eslint/ban-types */
import React from "react";
function renderStringWithChannelRefs(value: string) {
return (
<>
{value.split(/(<#[A-Z0-9]+\|[A-Za-z0-9]+>)/).map((str, i) => {
const matches = str.match(/<#([A-Z0-9]+)\|([A-Za-z0-9]+)>/);
if (matches) {
return (
<a
href={`https://app.slack.com/client/T03BQ3NU9/${matches[1]}`}
key={i}
>
#{matches[2]}
</a>
);
}
return <React.Fragment key={i}>{str}</React.Fragment>;
})}
</>
);
}
export const ChannelReferenceRenderer = ({
children,
}: React.PropsWithChildren<{}>) => {
// TODO: this should probably walk the tree
if (typeof children[0] === "string")
return renderStringWithChannelRefs(children[0]);
return <>{children}</>;
};

View File

@@ -1,5 +0,0 @@
import React from "react";
export default function EmailComponent() {
return <a href="mailto:info@koodiklinikka.fi">info@koodiklinikka.fi</a>;
}

View File

@@ -1,46 +0,0 @@
import React from "react";
type Props = {
threshold: number;
};
function clamp(min, max, value) {
return Math.min(Math.max(value, min), max);
}
export default class Fader extends React.Component<Props> {
static defaultProps = {
threshold: 100,
};
state = {
opacity: 0,
};
onScroll = () => {
const scrollableDistance = document.body.scrollHeight - window.innerHeight,
scrollTop = window.pageYOffset || document.documentElement.scrollTop,
distanceToBottom = scrollableDistance - scrollTop;
this.setState({
opacity: clamp(0, 1, distanceToBottom / this.props.threshold),
});
};
componentDidMount() {
window.addEventListener("scroll", this.onScroll);
this.onScroll();
}
componentWillUnmount() {
window.removeEventListener("scroll", this.onScroll);
}
render() {
const style = {
opacity: this.state.opacity,
};
return <div className="fader" style={style}></div>;
}
}

View File

@@ -0,0 +1,27 @@
import Image from 'next/image';
export default function FeatureImage({
src,
width,
height,
alt,
}: {
src: string;
width: number | `${number}`;
height: number | `${number}`;
alt: string;
}) {
return (
<div className="relative rounded-[18px] p-px shadow-2xl">
<div
className="fade-in-out absolute bottom-0 left-0 right-0 top-0 z-0 rounded-[17px] bg-gradient-to-tr from-[#4d094e] to-pink-500/70 p-[2px] "
style={{
WebkitMask: 'linear-gradient(to bottom, rgba(0,0,0,1), rgba(0,0,0,0))',
animationDelay: `${Math.floor(Math.random() * 5) + 1 * 0.5}s`,
}}
></div>
<Image className="relative z-10 block rounded-2xl " src={src} alt={alt} width={width} height={height} />
</div>
);
}

View File

@@ -1,80 +0,0 @@
import flatMap from "lodash/flatMap";
import sortBy from "lodash/sortBy";
import React from "react";
import request from "axios";
import api from "./api";
import transformers from "./feed-transformers";
import ReactTimeAgo from "react-time-ago";
import JavascriptTimeAgo from "javascript-time-ago";
import timeagoFi from "javascript-time-ago/locale/fi";
JavascriptTimeAgo.addLocale(timeagoFi);
export default class Feed extends React.Component {
state = {
messages: [],
};
componentDidMount() {
this.updateFeed();
}
async updateFeed() {
const res = await request.get(api("feeds"));
const messages = sortBy(
flatMap(res.data, (messages, type) => transformers[type](messages)),
"timestamp"
);
messages.reverse(); // In-place
this.setState({
messages: messages.slice(0, 40),
});
}
render() {
const messages = this.state.messages.map((message, i) => {
let image = <img src={message.image} alt="" loading="lazy" />;
if (message.imageLink) {
image = (
<a
target="_blank"
href={message.imageLink}
rel="noopener noreferrer"
tabIndex={-1}
>
{image}
</a>
);
}
return (
<div className="message" key={i}>
<div className="message__image" aria-hidden="true">
{image}
</div>
<div className="message__content">
<div className="message__user">
<a href={message.userLink}>{message.user}</a>
</div>
<div
className="message__body"
dangerouslySetInnerHTML={{ __html: message.body }}
/>
<div className="message__icon">
<i className={`fa fa-${message.type}`} aria-hidden="true" />
</div>
<div className="message__details">
<span className="message__timestamp">
<ReactTimeAgo date={message.timestamp} locale="fi" />
</span>
<span className="message__meta">{message.meta}</span>
</div>
</div>
</div>
);
});
return <div className="feed">{messages}</div>;
}
}

View File

@@ -1,76 +1,49 @@
import React from "react";
import EmailComponent from "./EmailComponent";
import sponsors from "../data/sponsors";
import Image from 'next/image';
type Props = {
href: string;
name: string;
title?: string;
};
const SponsorLink = ({ href, name }: Props) => (
<a href={href} target="_blank" rel="noopener noreferrer">
<img
src={`/static/images/sponsors/${name.toLowerCase()}.svg`}
alt={name}
className={`sponsor sponsor__${name.toLowerCase()}`}
loading="lazy"
/>
</a>
);
const SocialLink = ({ href, name, title }: Props) => (
<a href={href} target="_blank" rel="noopener noreferrer" aria-label={title}>
<img
src={`/static/images/social/${name.toLowerCase()}.svg`}
alt={title}
className={`social social__${name.toLowerCase()}`}
loading="lazy"
/>
</a>
);
export function Footer() {
export default function Footer() {
return (
<footer>
<div className="sponsors">
<div className="sponsors__label">Yhteistyössä</div>
{sponsors.map((sponsor) => (
<SponsorLink key={sponsor.name} {...sponsor} />
))}
<div className="space-y-10 pt-24 text-center">
<div className="flex items-center justify-center gap-10 ">
<a
href="https://koodiklinikka.slack.com/"
className="opacity-50 transition-opacity hover:opacity-100 focus-visible:opacity-100"
>
<Image className="size-8" width="800" height="800" src="/logos/slack.svg" alt="Koodiklinikka Slack" />
</a>
<a
href="https://github.com/koodiklinikka"
className="opacity-50 transition-opacity hover:opacity-100 focus-visible:opacity-100"
>
<Image className="size-8" width="98" height="96" src="/logos/github.svg" alt="Koodiklinikka GitHub" />
</a>
<a
href="https://x.com/koodiklinikka"
className="opacity-50 transition-opacity hover:opacity-100 focus-visible:opacity-100"
>
<Image className="size-8" width="300" height="300" src="/logos/x.svg" alt="Koodiklinikka X" />
</a>
<a
href="https://www.facebook.com/koodiklinikka"
className="opacity-50 transition-opacity hover:opacity-100 focus-visible:opacity-100"
>
<Image className="size-8" width="40" height="40" src="/logos/facebook.svg" alt="Koodiklinikka Facebook" />
</a>
<a
href="https://www.linkedin.com/groups/12025476"
className="opacity-50 transition-opacity hover:opacity-100 focus-visible:opacity-100"
>
<Image className="size-8" width="531" height="530" src="/logos/linkedin.svg" alt="Koodiklinikka LinkedIn" />
</a>
</div>
<div className="contacts">
<div>
<SocialLink
href="https://koodiklinikka.slack.com"
title="Koodiklinikka Slackissä"
name="slack"
/>
<SocialLink
href="https://github.com/koodiklinikka"
title="Koodiklinikka Githubissa"
name="github"
/>
<SocialLink
href="https://twitter.com/koodiklinikka"
title="Koodiklinikka Twitterissä"
name="twitter"
/>
<SocialLink
href="https://www.linkedin.com/groups/12025476"
title="Koodiklinikka Linkedinissä"
name="linkedin"
/>
<SocialLink
href="https://www.facebook.com/koodiklinikka"
title="Koodiklinikka Facebookissa"
name="facebook"
/>
<div id="email">
<EmailComponent />
</div>
</div>
<div>
<a
href="mailto:info@koodiklinikka.fi"
className="font-mono text-xs opacity-50 transition-opacity hover:opacity-100 focus-visible:opacity-100"
>
info@koodiklinikka.fi
</a>
</div>
</footer>
</div>
);
}

138
components/Form.tsx Normal file
View File

@@ -0,0 +1,138 @@
'use client';
import { FormEvent, ReactNode, useState } from 'react';
const API_URL = 'https://koodiklinikka-api.fly.dev/invites';
export default function Form() {
const [message, setMessage] = useState<ReactNode | null>(null);
const [isSubmitting, setIsSubmitting] = useState(false);
async function handleSubmit(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
if (isSubmitting) return;
setIsSubmitting(true);
const formData = new FormData(event.currentTarget);
const response = await fetch(API_URL, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(Object.fromEntries(formData)),
});
const data = await response.text();
setIsSubmitting(false);
if (response.status === 200) {
setMessage('✅ Kutsu lähetetty antamaasi sähköpostiosoitteeseen.');
return;
}
if (response.status === 400 && data === 'invalid_email') {
setMessage('⚠️ Tarkasta syöttämäsi sähköpostiosoite');
return;
}
if (response.status === 400 && data === 'already_invited') {
setMessage('♻️ Sähköpostiosoitteeseen on jo lähetetty kutsu');
return;
}
if (response.status === 400 && data === 'already_in_team') {
setMessage(
<span>
🤔 Tällä sähköpostilla on jo luotu tunnus.{' '}
<a href="https://koodiklinikka.slack.com/forgot" className="underline underline-offset-4">
Nollaa unohtunut salasana
</a>
.
</span>
);
return;
}
setMessage('⚡ Jotain meni pieleen. Yritä hetken päästä uudelleen.');
}
return (
<div className="mx-auto w-full max-w-sm text-center md:max-w-xl">
{message === null && (
<form onSubmit={handleSubmit}>
<h2 className="font-mono text-sm font-semibold">
Syötä sähköpostiosoitteesi alle ja saat kutsun Slack-yhteisöömme:
</h2>
<div className="my-5 grid grid-cols-4 gap-2">
<input
type="email"
name="email"
required
className="col-span-3 grow rounded px-3 py-2 text-sm text-fuchsia-950 sm:text-base md:rounded-lg md:px-4 md:py-4 lg:rounded-lg lg:px-5 lg:py-5 lg:text-lg"
placeholder="minna.meikalainen@example.org"
tabIndex={1}
/>
<button
tabIndex={3}
type="submit"
className="text-shadow bg-button rounded border border-pink-400 px-3 py-2 text-sm font-extrabold sm:text-base md:rounded-lg md:px-4 md:py-4 lg:px-5 lg:py-5 lg:text-lg"
>
{isSubmitting ? 'Liitytään' : 'Liity'}
</button>
</div>
<label className="text-xxs flex flex-wrap items-center justify-center gap-2 font-mono sm:text-xs">
<div className="relative h-5 w-5">
<input
type="checkbox"
name="terms"
required
className="h-3 w-3 opacity-5 focus:outline-none"
tabIndex={2}
/>
<div className="checkbox absolute left-0 top-0 flex h-full w-full items-center justify-center rounded border border-white bg-transparent transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" className="h-5 w-5">
<path
fillRule="evenodd"
d="M16.704 4.153a.75.75 0 0 1 .143 1.052l-8 10.5a.75.75 0 0 1-1.127.075l-4.5-4.5a.75.75 0 0 1 1.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 0 1 1.05-.143Z"
clipRule="evenodd"
/>
</svg>
</div>
</div>
Sitoudun yhteisön
<a
className="inline-flex items-center gap-1 underline underline-offset-4"
href="https://github.com/koodiklinikka/code-of-conduct/blob/master/README.md"
target="_blank"
>
<span>käyttäytymissääntöihin</span>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" className="h-3 w-3">
<path
fillRule="evenodd"
d="M4.25 5.5a.75.75 0 0 0-.75.75v8.5c0 .414.336.75.75.75h8.5a.75.75 0 0 0 .75-.75v-4a.75.75 0 0 1 1.5 0v4A2.25 2.25 0 0 1 12.75 17h-8.5A2.25 2.25 0 0 1 2 14.75v-8.5A2.25 2.25 0 0 1 4.25 4h5a.75.75 0 0 1 0 1.5h-5Z"
clipRule="evenodd"
/>
<path
fillRule="evenodd"
d="M6.194 12.753a.75.75 0 0 0 1.06.053L16.5 4.44v2.81a.75.75 0 0 0 1.5 0v-4.5a.75.75 0 0 0-.75-.75h-4.5a.75.75 0 0 0 0 1.5h2.553l-9.056 8.194a.75.75 0 0 0-.053 1.06Z"
clipRule="evenodd"
/>
</svg>
</a>
</label>
</form>
)}
{message && (
<div className="text-balance rounded-3xl bg-black/20 p-10 text-center font-mono text-sm backdrop-blur-sm">
{message}
</div>
)}
</div>
);
}

14
components/Hero.tsx Normal file
View File

@@ -0,0 +1,14 @@
import Form from './Form';
export default function Hero() {
return (
<div className="text-shadow mx-auto flex flex-col items-center justify-center" id="liity">
<h1 className="my-14 text-center text-2xl font-extrabold leading-tight sm:max-w-[80%] sm:text-3xl md:my-24 md:text-4xl lg:my-32 lg:text-5xl">
Koodiklinikka on Suomen suurin <span className="title-highlight">ohjelmistoalan yhteisö</span>, joka tuo alan
ammattilaiset ja harrastajat yhteen
</h1>
<Form />
</div>
);
}

View File

@@ -1,141 +0,0 @@
import request from "axios";
import React from "react";
import classSet from "classnames";
import api from "./api";
import Loader from "./Loader";
export default class InviteForm extends React.Component {
state = {
email: "",
submitted: false,
sending: false,
error: null,
};
onSubmit = async (e) => {
e.preventDefault();
this.setState({
submitted: false,
sending: true,
error: null,
});
try {
await request.post(api("invites"), {
email: this.state.email.trim(),
});
this.handleSuccess();
} catch (error) {
this.handleError(error);
}
};
handleSuccess = () => {
this.setState({ submitted: true, sending: false });
};
handleError = (err) => {
this.setState({ error: err, sending: false });
};
onChange = (e) => {
if (e.target.value === this.state.email) {
return;
}
this.setState({
email: e.target.value,
error: null,
submitted: false,
});
};
render() {
const formClasses = classSet({
form: true,
"invite-form": true,
"has-success": this.state.submitted,
"has-error": this.state.error,
sending: this.state.sending,
});
const inputClasses = classSet({
input: true,
"invite-form__input": true,
"has-success": this.state.submitted,
"has-error": this.state.error,
});
let feedbackMessage;
if (this.state.error || this.state.submitted) {
let messageText;
if (this.state.submitted) {
messageText = "Kutsu lähetetty antamaasi sähköpostiosoitteeseen.";
} else if (
this.state.error.response.status === 400 &&
this.state.error.response.data === "invalid_email"
) {
messageText = "Tarkasta syöttämäsi sähköpostiosoite";
} else if (
this.state.error.response.status === 400 &&
this.state.error.response.data === "already_invited"
) {
messageText = "Sähköpostiosoitteeseen on jo lähetetty kutsu";
} else if (
this.state.error.response.status === 400 &&
this.state.error.response.data === "already_in_team"
) {
messageText = (
<span>
Tällä sähköpostilla on jo luotu tunnus. <br /> Voit vaihtaa
unohtuneen salasanasi{" "}
<a href="https://koodiklinikka.slack.com/forgot">täältä</a>.
</span>
);
} else {
messageText = "Jotain meni pieleen. Yritä hetken päästä uudelleen.";
}
feedbackMessage = <div className="form--message">{messageText}</div>;
}
return (
<form className={formClasses} onSubmit={this.onSubmit}>
<div className="form__field">
<label className="label" htmlFor="email-field">
Sähköpostiosoite:
</label>
<div className="controls-wrapper">
<span className="input-wrapper">
<input
className={inputClasses}
type="text"
name="email"
id="email-field"
// Placeholder is not accessible way to provide information
// Used here for :placeholder-shown -styles
placeholder=""
value={this.state.email}
onChange={this.onChange}
/>
<div className="invite-form__loader">
<Loader />
</div>
</span>
<button
className="btn btn__submit"
type="submit"
title="Lähetä"
disabled={this.state.error || this.state.submitted}
>
Lähetä
</button>
</div>
</div>
{feedbackMessage}
</form>
);
}
}

View File

@@ -1,12 +0,0 @@
import React from "react";
export default function Loader() {
return (
<div className="sk-folding-cube">
<div className="sk-cube1 sk-cube" />
<div className="sk-cube2 sk-cube" />
<div className="sk-cube4 sk-cube" />
<div className="sk-cube3 sk-cube" />
</div>
);
}

View File

@@ -1,51 +0,0 @@
import React from "react";
import request from "axios";
import shuffle from "lodash/shuffle";
import api from "./api";
export default class Members extends React.Component {
state = {
members: [],
};
componentDidMount() {
this.refreshMembers();
}
async refreshMembers() {
const res = await request.get(api("members"));
this.setState({
members: shuffle(res.data),
});
}
render() {
const members = this.state.members.map((member) => {
const src = `${member.avatar_url}&s=120`;
return (
<img
className="member"
key={member.avatar_url}
src={src}
alt=""
width={30}
height={30}
loading="lazy"
/>
);
});
return (
<div className="members" aria-hidden="true">
<a
href="https://github.com/koodiklinikka"
target="_blank"
rel="noopener noreferrer"
tabIndex={-1}
>
{members}
</a>
</div>
);
}
}

82
components/Nav.tsx Normal file
View File

@@ -0,0 +1,82 @@
'use client';
import Image from 'next/image';
import Link from 'next/link';
import Wrapper from './Wrapper';
import { useEffect, useRef, useState } from 'react';
export default function Nav() {
const [navOpen, setNavOpen] = useState(false);
const navRef = useRef<HTMLDivElement | null>(null);
const handleClickOutside = (event: MouseEvent) => {
if (navRef.current && !navRef.current.contains(event.target as Node)) {
setNavOpen(false);
}
};
useEffect(() => {
document.addEventListener('click', handleClickOutside, true);
return () => {
document.removeEventListener('click', handleClickOutside, true);
};
}, []);
return (
<nav className="fixed left-0 top-0 z-50 h-32 w-full bg-gradient-to-b from-black/40 to-fuchsia-950/0">
<Wrapper>
<div className="relative flex items-center justify-between px-6 py-5 md:px-12">
<div className="shrink-0">
<Image src="/koodiklinikka.svg" alt="Koodiklinikka" width="179" height="34" className="w-40" priority />
</div>
<div ref={navRef}>
<button
type="button"
className="-mr-2 rounded bg-black/0 p-2 hover:bg-black/20 lg:hidden"
onMouseDown={() => setNavOpen(!navOpen)}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth="1.5"
stroke="currentColor"
className="size-6"
>
<path strokeLinecap="round" strokeLinejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
</svg>
</button>
<div
className={`${navOpen ? 'flex' : 'hidden'} text-shadow absolute right-6 top-16 flex-col gap-5 rounded-lg bg-black/80 p-5 text-xs uppercase tracking-widest text-pink-100 backdrop-blur-md lg:static lg:flex lg:flex-row lg:bg-transparent lg:backdrop-blur-none`}
>
<Link className="underline-offset-4 hover:underline" href="https://github.com/koodiklinikka">
GitHub
</Link>
<NavSeparator />
<Link className="underline-offset-4 hover:underline" href="https://koodiklinikka.slack.com">
Slack
</Link>
<NavSeparator />
<Link className="underline-offset-4 hover:underline" href="https://resources.koodiklinikka.fi">
Resources
</Link>
<NavSeparator />
<Link className="underline-offset-4 hover:underline" href="https://koodiklinikka.myspreadshop.fi/">
Shop
</Link>
<NavSeparator />
<Link
className="underline-offset-4 hover:underline"
href="https://github.com/koodiklinikka/code-of-conduct"
>
Code of Conduct
</Link>
</div>
</div>
</div>
</Wrapper>
</nav>
);
}
const NavSeparator = () => <div className="hidden opacity-20 lg:block">|</div>;

5
components/Wrapper.tsx Normal file
View File

@@ -0,0 +1,5 @@
import { ReactNode } from 'react';
export default function Wrapper({ children }: { children: ReactNode }) {
return <div className="mx-auto max-w-6xl px-5">{children}</div>;
}

View File

@@ -1,5 +0,0 @@
const host = process.env.SERVER || "https://koodiklinikka-api.fly.dev/";
export default function getApiURL(path) {
return host + path;
}

View File

@@ -1,70 +0,0 @@
import lodashTemplate from "lodash/template";
import defaultTemplateSettings from "lodash/templateSettings";
import githubEvent from "parse-github-event";
import twitterText from "twitter-text";
const isVisibleGithubEvent = ({ type }) =>
type !== "PushEvent" && type !== "DeleteEvent";
const templateSettings = {
...defaultTemplateSettings,
interpolate: /{{([\s\S]+?)}}/g,
};
export default {
github(items) {
return items.filter(isVisibleGithubEvent).map((item) => {
const template = lodashTemplate(
githubEvent.parse(item).text,
templateSettings,
false
);
const repository = `https://github.com/${item.repo.name}`;
let branch;
if (item.payload.ref) {
branch = item.payload.ref.replace("refs/heads/", "");
}
const message = template({
repository: `<a target="_blank" href="${repository}">${item.repo.name}</a>`,
branch: branch,
number: item.payload.number,
ref_type: item.payload.ref_type,
ref: item.payload.ref,
});
const url = `https://github.com/${item.actor.login}`;
return {
user: item.actor.login,
userLink: url,
image: item.actor.avatar_url,
imageLink: url,
body: message,
timestamp: new Date(item.created_at),
url: message.url,
type: "github",
};
});
},
twitter(items) {
return items.map((item) => {
if (item.retweeted) {
item = item.retweeted_status;
}
const url = `https://twitter.com/${item.user.screen_name}`;
return {
user: `@${item.user.screen_name}`,
userLink: url,
image: item.user.profile_image_url_https,
imageLink: url,
body: twitterText.autoLink(item.text),
timestamp: new Date(item.created_at),
type: "twitter",
};
});
},
};

View File

@@ -1,39 +0,0 @@
import React from "react";
import MembershipInfoForm from "./MembershipInfoForm";
export default class MembershipForm extends React.Component {
state = {
signupSuccess: false,
};
handleSignupSuccess = () => {
this.setState({ signupSuccess: true });
};
render() {
if (!this.state.signupSuccess) {
return <MembershipInfoForm onSignupSuccess={this.handleSignupSuccess} />;
}
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> Rekisteröityminen onnistui. Tervetuloa jäseneksi!</p>
<p> Tervetuloa Koodiklinikka ry:n jäseneksi!</p>
</div>
);
}
}

View File

@@ -1,212 +0,0 @@
import request from "axios";
import React from "react";
import classSet from "classnames";
import api from "../api";
import Loader from "../Loader";
type Props = {
onSignupSuccess: () => void;
};
type State = {
error: boolean;
errors: string[];
fields: {
name: string;
email: string;
handle: string;
address: string;
postcode: string;
city: string;
};
sending: boolean;
pristineFields: string[];
};
const 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" },
};
const mailValidateRe =
/^(([^<>()[\]\\.,;:\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,}))$/;
function validateEmail(email) {
return mailValidateRe.test(email);
}
function getUserInfo(state) {
return state.fields;
}
export default class MembershipInfoForm extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.setState({
fields: {
address: "",
city: "",
email: "",
handle: "",
name: "",
postcode: "",
},
sending: false,
pristineFields: Object.keys(this.state.fields),
});
}
onSubmit = async () => {
this.setState({
sending: true,
error: null,
});
try {
await request.post(api("membership"), {
userInfo: getUserInfo(this.state),
});
this.setState({ sending: false });
this.props.onSignupSuccess();
} catch (err) {
this.setState({ error: err, sending: false });
}
};
onChange = (e) => {
const name = e.target.name;
if (e.target.value === this.state[name]) {
return;
}
this.setState({
fields: {
...this.state.fields,
[name]: e.target.value,
},
pristineFields: this.state.pristineFields.filter(
(fieldName) => fieldName !== name
),
errors: [],
});
};
getDataErrors = () => {
const foundErrors = [];
Object.keys(this.state.fields).forEach((fieldName) => {
if (!this.state[fieldName]) {
foundErrors.push({ field: fieldName, type: "missing" });
}
});
if (this.state.fields.email && !validateEmail(this.state.fields.email)) {
foundErrors.push({ field: "email", type: "invalid" });
}
return foundErrors;
};
render() {
const inputErrors = this.getDataErrors();
const formClasses = classSet({
form: true,
"membership-form": true,
"has-error": inputErrors.length !== 0 || this.state.error,
sending: this.state.sending,
});
function getErrorMessage(err) {
let feedbackText;
const fieldName = fieldNameTranslations[err.field].fi;
if (err.type === "missing") {
feedbackText = `${fieldName} on pakollinen.`;
} else if (err.type === "invalid") {
feedbackText = `${fieldName} on virheellinen.`;
}
return (
<div key={err.field} className="form--message">
{feedbackText}
</div>
);
}
/* generate error messages */
const visibleErrors = inputErrors.filter(
(error) => this.state.pristineFields.indexOf(error.field) === -1
);
const fieldsWithErrors = visibleErrors.map(({ field }) => field);
const inputFields = Object.keys(this.state.fields).map((fieldName) => {
const inputClasses = classSet({
input: true,
"has-error": fieldsWithErrors.includes(fieldName),
half: fieldName === "city" || fieldName === "postcode",
left: fieldName === "postcode",
});
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 />
<button
type="button"
disabled={inputErrors.length !== 0}
className="btn btn__submit"
onClick={this.onSubmit}
>
Liity jäseneksi
</button>
</form>
</div>
);
}
}

View File

@@ -1,22 +0,0 @@
import axios from "axios";
export interface Channel {
id: string;
name: string;
topic: string;
num_members: number;
purpose: {
value: string;
creator: string;
last_set: number;
};
messages_today: number;
unique_members_today: number;
}
export async function getChannels() {
const response = await axios.get<Channel[]>(
"http://stats.koodiklinikka.fi/api/channels"
);
return response.data;
}

View File

@@ -1,31 +0,0 @@
const sponsors = [
{
name: "Futurice",
href: "https://futurice.com/",
},
{
name: "Metosin",
href: "https://www.metosin.fi/",
},
{
name: "Solita",
href: "https://www.solita.fi/",
},
{
name: "Wakeone",
href: "https://wakeone.co/",
},
{
name: "Nordea",
href: "https://www.nordea.fi/",
},
{
name: "Idean",
href: "https://www.idean.com/",
},
{
name: "Rare",
href: "https://rare.fi/",
},
];
export default sponsors;

BIN
logo.psd

Binary file not shown.

4
next.config.mjs Normal file
View File

@@ -0,0 +1,4 @@
/** @type {import('next').NextConfig} */
const nextConfig = {};
export default nextConfig;

View File

@@ -1,49 +1,30 @@
{
"name": "koodiklinikka",
"version": "1.0.0",
"description": "Koodiklinikka homepage",
"author": "Riku Rouvila <riku@rare.fi>",
"license": "MIT",
"name": "koodiklinikka-fi",
"version": "0.1.0",
"private": true,
"scripts": {
"start": "next",
"build": "next build && next export",
"dev": "SERVER=http://localhost:9000/ NODE_ENV=development next",
"prod": "NODE_ENV=production next build && next export",
"lint": "eslint --ext .tsx --ext .ts .",
"prettify": "prettier --write ."
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"axios": "^0.27.2",
"classnames": "^2.3.1",
"javascript-time-ago": "^2.3.13",
"less": "^4.1.2",
"lodash": "^4.17.21",
"next": "^12.1.6",
"parse-github-event": "^1.1.3",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"react-ga": "^3.3.0",
"react-markdown": "^8.0.3",
"react-time-ago": "^7.1.9",
"sass": "^1.51.0",
"twitter-text": "^3.0.0",
"utility-types": "^3.10.0"
"lodash.shuffle": "^4.2.0",
"next": "14.2.3",
"react": "^18",
"react-dom": "^18"
},
"devDependencies": {
"@next/eslint-plugin-next": "^12.1.6",
"@types/node": "17.0.31",
"@types/react": "18.0.8",
"@typescript-eslint/eslint-plugin": "^5.22.0",
"@typescript-eslint/parser": "^5.22.0",
"eslint": "^8.14.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-jsx-a11y": "^6.5.1",
"eslint-plugin-react": "^7.29.4",
"eslint-plugin-react-hooks": "^4.5.0",
"prettier": "^2.6.2",
"typescript": "4.6.4"
},
"prettier": {
"trailingComma": "es5"
"@types/lodash.shuffle": "^4.2.9",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"eslint": "^8",
"eslint-config-next": "14.2.3",
"postcss": "^8",
"prettier": "^3.2.5",
"prettier-plugin-tailwindcss": "^0.5.14",
"tailwindcss": "^3.4.1",
"typescript": "^5"
}
}

View File

@@ -1,60 +0,0 @@
import React from "react";
import Head from "next/head";
import "../styles/style.scss";
const metaImage = "/static/images/meta.jpg";
const metaDescription =
"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.";
const metaShortDescription =
"Koodiklinikka on suomalainen yhteisö ohjelmistoalan harrastajille ja ammattilaisille.";
const metaTitle = "Koodiklinikka Suomen suurin ohjelmistoalan yhteisö";
const metaKeywords =
"ohjelmointi,frontend,open source,devaus,suomi,javascript,clojure,go,java,node.js,io.js,angular.js,web";
const metaUrl = "https://koodiklinikka.fi/";
function MyApp({ Component, pageProps }) {
return (
<>
<Head>
<meta name="title" content={metaTitle} />
<meta name="description" content={metaShortDescription} />
<meta name="keywords" content={metaKeywords} />
<meta property="og:type" content="website" />
<meta property="og:url" content={metaUrl} />
<meta property="og:title" content={metaTitle} />
<meta property="og:description" content={metaDescription} />
<meta property="og:image" content={metaImage} />
<meta property="twitter:card" content="summary_large_image" />
<meta property="twitter:url" content={metaUrl} />
<meta property="twitter:title" content={metaTitle} />
<meta property="twitter:description" content={metaDescription} />
<meta property="twitter:image" content={metaImage} />
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<link
rel="apple-touch-icon"
sizes="180x180"
href="/static/icons/apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="/static/icons/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="/static/icons/favicon-16x16.png"
/>
<link rel="manifest" href="/static/icons/site.webmanifest" />
</Head>
<Component {...pageProps} />
</>
);
}
export default MyApp;

View File

@@ -1,48 +0,0 @@
import React from "react";
import Document, { Html, Head, Main, NextScript } from "next/document";
import { Footer } from "../components/Footer";
import Fader from "../components/Fader";
import ReactGA from "react-ga";
function trackPageView() {
if (location.hostname === "localhost" || location.hostname === "127.0.0.1") {
return;
}
if (!window.GA_INITIALIZED) {
ReactGA.initialize("UA-58806132-1");
window.GA_INITIALIZED = true;
}
ReactGA.set({ page: window.location.pathname });
ReactGA.pageview(window.location.pathname);
}
class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx);
return { ...initialProps };
}
componentDidMount() {
trackPageView();
}
render() {
return (
<Html lang="fi">
<Head />
<body>
<div className="site">
<div className="container">
<Main />
</div>
<Footer />
</div>
<Fader />
<NextScript />
</body>
</Html>
);
}
}
export default MyDocument;

View File

@@ -1,196 +0,0 @@
import React from "react";
import Head from "next/head";
import { PromiseType } from "utility-types";
import InviteForm from "../components/InviteForm";
import Members from "../components/Members";
import Feed from "../components/Feed";
import { getChannels } from "../data/channels";
import ReactMarkdown from "react-markdown";
import { ChannelReferenceRenderer } from "../components/ChannelReferenceRenderer";
export async function getStaticProps() {
const allChannels = await getChannels();
const channels = allChannels
.sort((a, b) => b.num_members - a.num_members)
.sort((a, b) => b.unique_members_today - a.unique_members_today);
return {
props: {
channels: channels,
},
revalidate: 3600,
};
}
type IndexProps = PromiseType<ReturnType<typeof getStaticProps>>["props"];
const Hero = () => (
<div className="header">
<video
autoPlay
loop
muted
poster="/static/images/poster.jpg"
className="header__video-bg"
>
<source src="/static/videos/jumbo.mp4" type="video/mp4" />
</video>
<div className="header__container">
<div className="header__nav">
<a href="/">
<img src="/static/images/logo-new.svg" alt="Etusivu" />
</a>
</div>
<div className="header__headline">
<h1 className="header__title">
Yhteisö kaikille ohjelmoinnista ja ohjelmistoalasta kiinnostuneille
harrastajille ja ammattilaisille.
</h1>
</div>
</div>
</div>
);
const IndexContent = (props: IndexProps) => (
<>
<div className="content with-feed">
<section>
<div className="row">
<h3>
Tule mukaan{" "}
<a
target="_blank"
href="https://slack.com/"
rel="noopener noreferrer"
>
Slack
</a>
-yhteisöömme
</h3>
<div className="form">
<InviteForm />
</div>
<p className="code-of-conduct">
Ennen liittymistä yhteisöömme varmista, että olet lukenut yhteisön{" "}
<a
target="_blank"
rel="noopener noreferrer"
href="https://github.com/koodiklinikka/code-of-conduct/blob/master/README.md"
>
käyttäytymissäännöt
</a>
.
</p>
</div>
</section>
<section>
<div className="row">
<div className="bread">
<div className="column column1-2">
<h3>Yhteisö ohjelmoinnista kiinnostuneille</h3>
<p>
Koodiklinikka on Suomen suurin ohjelmistoalan yhteisö, joka
kokoaa työntekijät, harrastajat ja vasta-alkajat yhteen.{"\n"}
Tarkoituksenamme on yhdistää ja kasvattaa suomalaista
ohjelmointiyhteisöä, sekä tarjota apua ja uusia kontakteja
ohjelmoinnista innostuneille nuorille.
</p>
<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.
</p>
</div>
<div className="column column1-2">
<a href="/static/images/slack.png" target="_blank">
<img
src="/static/images/slack.png"
alt="Slack app at Koodiklinikka"
loading="lazy"
/>
</a>
</div>
</div>
</div>
<div className="row">
<div className="bread">
<div className="column column5-5">
<h3>Suosituimmat keskustelunaiheet tänään</h3>
<table className="channels">
<tbody>
{props.channels.slice(0, 10).map((channel) => (
<tr key={channel.id}>
<td>
<div>
<a
href={`https://app.slack.com/client/T03BQ3NU9/${channel.id}`}
target="_blank"
className="channel"
>
#{channel.name}
</a>
</div>
</td>
<td>
<span className="channel-members">
{channel.num_members} jäsentä
</span>
</td>
</tr>
))}
</tbody>
</table>
<p>
<strong>Ja paljon muuta:</strong>{" "}
{props.channels.slice(10, 30).map((channel, i) => (
<React.Fragment key={channel.id}>
<a
href={`https://app.slack.com/client/T03BQ3NU9/${channel.id}`}
target="_blank"
>
#{channel.name}
</a>
{i !== 19 ? ", " : "..."}
</React.Fragment>
))}
</p>
</div>
</div>
</div>
<div className="row">
<div className="bread">
<h3>Avoin lähdekoodi</h3>
<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.
Koodiklinikan projekteihin voi osallistua kuka tahansa ja
muutosideat ovat aina lämpimästi tervetulleita.
</p>
<div id="members">
<Members />
</div>
</div>
</div>
</section>
<div id="feed">
<Feed />
</div>
</div>
</>
);
const Index = (props: IndexProps) => (
<React.Fragment>
<Head>
<title>Koodiklinikka</title>
</Head>
<Hero />
<IndexContent {...props} />
</React.Fragment>
);
export default Index;

8
postcss.config.mjs Normal file
View File

@@ -0,0 +1,8 @@
/** @type {import('postcss-load-config').Config} */
const config = {
plugins: {
tailwindcss: {},
},
};
export default config;

View File

@@ -1 +0,0 @@

BIN
public/background.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 499 KiB

55
public/koodiklinikka.svg Normal file
View File

@@ -0,0 +1,55 @@
<svg width="179" height="34" viewBox="0 0 179 34" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M53.1438 21.7387C53.405 22.0137 53.5356 22.323 53.5356 22.6668C53.5356 23.0105 53.3981 23.2993 53.1231 23.533C52.8619 23.7668 52.58 23.8837 52.2775 23.8837C51.92 23.8837 51.6175 23.7462 51.37 23.4712L47.6575 19.5524L46.6469 20.4805V22.6462C46.6469 23.0037 46.53 23.3062 46.2963 23.5537C46.0625 23.7874 45.7669 23.9043 45.4094 23.9043C45.0519 23.9043 44.7563 23.7874 44.5225 23.5537C44.2888 23.3062 44.1719 23.0037 44.1719 22.6462V9.89991C44.1719 9.54241 44.2888 9.24678 44.5225 9.01303C44.7563 8.76553 45.0519 8.64178 45.4094 8.64178C45.7669 8.64178 46.0625 8.76553 46.2963 9.01303C46.53 9.24678 46.6469 9.54241 46.6469 9.89991V17.5312L51.0606 13.2618C51.3219 13.0005 51.6244 12.8699 51.9681 12.8699C52.2706 12.8699 52.5387 13.0005 52.7725 13.2618C53.02 13.5093 53.1438 13.7637 53.1438 14.0249C53.1438 14.3549 52.9788 14.6643 52.6488 14.953L49.5344 17.8199L53.1438 21.7387Z" fill="white"/>
<path d="M66.4649 18.3974C66.4649 19.4974 66.2174 20.4874 65.7224 21.3674C65.2274 22.2337 64.5468 22.9074 63.6805 23.3887C62.828 23.8699 61.8862 24.1105 60.8549 24.1105C59.8099 24.1105 58.8612 23.8699 58.0087 23.3887C57.1562 22.9074 56.4824 22.2337 55.9874 21.3674C55.4924 20.4874 55.2449 19.4974 55.2449 18.3974C55.2449 17.2974 55.4924 16.3143 55.9874 15.448C56.4824 14.568 57.1562 13.8874 58.0087 13.4062C58.8612 12.9112 59.8099 12.6637 60.8549 12.6637C61.8862 12.6637 62.828 12.9112 63.6805 13.4062C64.5468 13.8874 65.2274 14.568 65.7224 15.448C66.2174 16.3143 66.4649 17.2974 66.4649 18.3974ZM63.9899 18.3974C63.9899 17.7237 63.8455 17.1255 63.5568 16.603C63.2818 16.0668 62.9037 15.6543 62.4224 15.3655C61.9549 15.0768 61.4324 14.9324 60.8549 14.9324C60.2774 14.9324 59.748 15.0768 59.2668 15.3655C58.7993 15.6543 58.4212 16.0668 58.1324 16.603C57.8574 17.1255 57.7199 17.7237 57.7199 18.3974C57.7199 19.0712 57.8574 19.6693 58.1324 20.1918C58.4212 20.7143 58.7993 21.1199 59.2668 21.4087C59.748 21.6974 60.2774 21.8418 60.8549 21.8418C61.4324 21.8418 61.9549 21.6974 62.4224 21.4087C62.9037 21.1199 63.2818 20.7143 63.5568 20.1918C63.8455 19.6693 63.9899 19.0712 63.9899 18.3974Z" fill="white"/>
<path d="M79.7527 18.3974C79.7527 19.4974 79.5052 20.4874 79.0102 21.3674C78.5152 22.2337 77.8346 22.9074 76.9684 23.3887C76.1159 23.8699 75.174 24.1105 74.1427 24.1105C73.0977 24.1105 72.149 23.8699 71.2965 23.3887C70.444 22.9074 69.7702 22.2337 69.2752 21.3674C68.7802 20.4874 68.5327 19.4974 68.5327 18.3974C68.5327 17.2974 68.7802 16.3143 69.2752 15.448C69.7702 14.568 70.444 13.8874 71.2965 13.4062C72.149 12.9112 73.0977 12.6637 74.1427 12.6637C75.174 12.6637 76.1159 12.9112 76.9684 13.4062C77.8346 13.8874 78.5152 14.568 79.0102 15.448C79.5052 16.3143 79.7527 17.2974 79.7527 18.3974ZM77.2777 18.3974C77.2777 17.7237 77.1334 17.1255 76.8446 16.603C76.5696 16.0668 76.1915 15.6543 75.7102 15.3655C75.2427 15.0768 74.7202 14.9324 74.1427 14.9324C73.5652 14.9324 73.0359 15.0768 72.5546 15.3655C72.0871 15.6543 71.709 16.0668 71.4202 16.603C71.1452 17.1255 71.0077 17.7237 71.0077 18.3974C71.0077 19.0712 71.1452 19.6693 71.4202 20.1918C71.709 20.7143 72.0871 21.1199 72.5546 21.4087C73.0359 21.6974 73.5652 21.8418 74.1427 21.8418C74.7202 21.8418 75.2427 21.6974 75.7102 21.4087C76.1915 21.1199 76.5696 20.7143 76.8446 20.1918C77.1334 19.6693 77.2777 19.0712 77.2777 18.3974Z" fill="white"/>
<path d="M91.3699 8.64178C91.7274 8.64178 92.0231 8.75866 92.2568 8.99241C92.4906 9.22616 92.6074 9.52866 92.6074 9.89991V22.6462C92.6074 23.0037 92.4906 23.3062 92.2568 23.5537C92.0231 23.7874 91.7274 23.9043 91.3699 23.9043C91.0124 23.9043 90.7168 23.7874 90.4831 23.5537C90.2631 23.3199 90.1462 23.0243 90.1324 22.6668C89.7887 23.0655 89.3212 23.4093 88.7299 23.698C88.1524 23.973 87.5406 24.1105 86.8943 24.1105C85.9456 24.1105 85.0862 23.8699 84.3162 23.3887C83.5462 22.8937 82.9343 22.213 82.4806 21.3468C82.0406 20.4805 81.8206 19.4974 81.8206 18.3974C81.8206 17.2974 82.0406 16.3143 82.4806 15.448C82.9206 14.568 83.5187 13.8874 84.2749 13.4062C85.0449 12.9112 85.8906 12.6637 86.8118 12.6637C87.4718 12.6637 88.0906 12.7874 88.6681 13.0349C89.2456 13.2687 89.7337 13.5712 90.1324 13.9424V9.89991C90.1324 9.54241 90.2493 9.24678 90.4831 9.01303C90.7168 8.76553 91.0124 8.64178 91.3699 8.64178ZM87.2037 21.8418C88.0974 21.8418 88.8262 21.5187 89.3899 20.8724C89.9537 20.2124 90.2356 19.3874 90.2356 18.3974C90.2356 17.4074 89.9537 16.5824 89.3899 15.9224C88.8262 15.2624 88.0974 14.9324 87.2037 14.9324C86.3237 14.9324 85.6018 15.2624 85.0381 15.9224C84.4743 16.5824 84.1924 17.4074 84.1924 18.3974C84.1924 19.3874 84.4674 20.2124 85.0174 20.8724C85.5812 21.5187 86.3099 21.8418 87.2037 21.8418Z" fill="white"/>
<path d="M98.239 22.6462C98.239 23.0037 98.1221 23.3062 97.8884 23.5537C97.6546 23.7874 97.359 23.9043 97.0015 23.9043C96.644 23.9043 96.3484 23.7874 96.1146 23.5537C95.8809 23.3062 95.764 23.0037 95.764 22.6462V14.128C95.764 13.7705 95.8809 13.4749 96.1146 13.2412C96.3484 12.9937 96.644 12.8699 97.0015 12.8699C97.359 12.8699 97.6546 12.9937 97.8884 13.2412C98.1221 13.4749 98.239 13.7705 98.239 14.128V22.6462ZM96.9809 11.5293C96.5134 11.5293 96.1834 11.4537 95.9909 11.3024C95.7984 11.1512 95.7021 10.883 95.7021 10.498V10.1062C95.7021 9.72116 95.8053 9.45303 96.0115 9.30178C96.2178 9.15053 96.5478 9.07491 97.0015 9.07491C97.4828 9.07491 97.8196 9.15053 98.0121 9.30178C98.2047 9.45303 98.3009 9.72116 98.3009 10.1062V10.498C98.3009 10.8968 98.1978 11.1718 97.9915 11.323C97.799 11.4605 97.4622 11.5293 96.9809 11.5293Z" fill="white"/>
<path d="M110.58 21.7387C110.841 22.0137 110.971 22.323 110.971 22.6668C110.971 23.0105 110.834 23.2993 110.559 23.533C110.298 23.7668 110.016 23.8837 109.713 23.8837C109.356 23.8837 109.053 23.7462 108.806 23.4712L105.093 19.5524L104.083 20.4805V22.6462C104.083 23.0037 103.966 23.3062 103.732 23.5537C103.498 23.7874 103.203 23.9043 102.845 23.9043C102.488 23.9043 102.192 23.7874 101.958 23.5537C101.725 23.3062 101.608 23.0037 101.608 22.6462V9.89991C101.608 9.54241 101.725 9.24678 101.958 9.01303C102.192 8.76553 102.488 8.64178 102.845 8.64178C103.203 8.64178 103.498 8.76553 103.732 9.01303C103.966 9.24678 104.083 9.54241 104.083 9.89991V17.5312L108.496 13.2618C108.758 13.0005 109.06 12.8699 109.404 12.8699C109.706 12.8699 109.975 13.0005 110.208 13.2618C110.456 13.5093 110.58 13.7637 110.58 14.0249C110.58 14.3549 110.415 14.6643 110.085 14.953L106.97 17.8199L110.58 21.7387Z" fill="white"/>
<path d="M116.343 22.6462C116.343 23.0037 116.22 23.3062 115.972 23.5537C115.738 23.7874 115.443 23.9043 115.085 23.9043C114.741 23.9043 114.453 23.7874 114.219 23.5537C113.985 23.3062 113.868 23.0037 113.868 22.6462V9.89991C113.868 9.54241 113.985 9.24678 114.219 9.01303C114.466 8.76553 114.769 8.64178 115.126 8.64178C115.47 8.64178 115.759 8.76553 115.993 9.01303C116.226 9.24678 116.343 9.54241 116.343 9.89991V22.6462Z" fill="white"/>
<path d="M122.17 22.6462C122.17 23.0037 122.054 23.3062 121.82 23.5537C121.586 23.7874 121.29 23.9043 120.933 23.9043C120.575 23.9043 120.28 23.7874 120.046 23.5537C119.812 23.3062 119.695 23.0037 119.695 22.6462V14.128C119.695 13.7705 119.812 13.4749 120.046 13.2412C120.28 12.9937 120.575 12.8699 120.933 12.8699C121.29 12.8699 121.586 12.9937 121.82 13.2412C122.054 13.4749 122.17 13.7705 122.17 14.128V22.6462ZM120.912 11.5293C120.445 11.5293 120.115 11.4537 119.922 11.3024C119.73 11.1512 119.634 10.883 119.634 10.498V10.1062C119.634 9.72116 119.737 9.45303 119.943 9.30178C120.149 9.15053 120.479 9.07491 120.933 9.07491C121.414 9.07491 121.751 9.15053 121.944 9.30178C122.136 9.45303 122.232 9.72116 122.232 10.1062V10.498C122.232 10.8968 122.129 11.1718 121.923 11.323C121.73 11.4605 121.394 11.5293 120.912 11.5293Z" fill="white"/>
<path d="M131.232 12.6637C132.634 12.6637 133.603 13.083 134.14 13.9218C134.676 14.7468 134.944 15.8949 134.944 17.3662V22.6462C134.944 23.0037 134.827 23.3062 134.593 23.5537C134.36 23.7874 134.064 23.9043 133.707 23.9043C133.349 23.9043 133.053 23.7874 132.82 23.5537C132.586 23.3062 132.469 23.0037 132.469 22.6462V17.3662C132.469 16.6099 132.311 16.0187 131.995 15.5924C131.678 15.1524 131.135 14.9324 130.365 14.9324C129.568 14.9324 128.942 15.1662 128.488 15.6337C128.035 16.0874 127.808 16.6649 127.808 17.3662V22.6462C127.808 23.0037 127.691 23.3062 127.457 23.5537C127.223 23.7874 126.928 23.9043 126.57 23.9043C126.213 23.9043 125.917 23.7874 125.683 23.5537C125.45 23.3062 125.333 23.0037 125.333 22.6462V14.128C125.333 13.7705 125.45 13.4749 125.683 13.2412C125.917 12.9937 126.213 12.8699 126.57 12.8699C126.928 12.8699 127.223 12.9937 127.457 13.2412C127.691 13.4749 127.808 13.7705 127.808 14.128V14.4787C128.179 13.9837 128.66 13.5574 129.252 13.1999C129.857 12.8424 130.517 12.6637 131.232 12.6637Z" fill="white"/>
<path d="M140.569 22.6462C140.569 23.0037 140.452 23.3062 140.218 23.5537C139.984 23.7874 139.689 23.9043 139.331 23.9043C138.974 23.9043 138.678 23.7874 138.444 23.5537C138.21 23.3062 138.094 23.0037 138.094 22.6462V14.128C138.094 13.7705 138.21 13.4749 138.444 13.2412C138.678 12.9937 138.974 12.8699 139.331 12.8699C139.689 12.8699 139.984 12.9937 140.218 13.2412C140.452 13.4749 140.569 13.7705 140.569 14.128V22.6462ZM139.31 11.5293C138.843 11.5293 138.513 11.4537 138.32 11.3024C138.128 11.1512 138.032 10.883 138.032 10.498V10.1062C138.032 9.72116 138.135 9.45303 138.341 9.30178C138.547 9.15053 138.877 9.07491 139.331 9.07491C139.812 9.07491 140.149 9.15053 140.342 9.30178C140.534 9.45303 140.63 9.72116 140.63 10.1062V10.498C140.63 10.8968 140.527 11.1718 140.321 11.323C140.129 11.4605 139.792 11.5293 139.31 11.5293Z" fill="white"/>
<path d="M152.909 21.7387C153.17 22.0137 153.301 22.323 153.301 22.6668C153.301 23.0105 153.164 23.2993 152.889 23.533C152.627 23.7668 152.345 23.8837 152.043 23.8837C151.685 23.8837 151.383 23.7462 151.135 23.4712L147.423 19.5524L146.412 20.4805V22.6462C146.412 23.0037 146.295 23.3062 146.062 23.5537C145.828 23.7874 145.532 23.9043 145.175 23.9043C144.817 23.9043 144.522 23.7874 144.288 23.5537C144.054 23.3062 143.937 23.0037 143.937 22.6462V9.89991C143.937 9.54241 144.054 9.24678 144.288 9.01303C144.522 8.76553 144.817 8.64178 145.175 8.64178C145.532 8.64178 145.828 8.76553 146.062 9.01303C146.295 9.24678 146.412 9.54241 146.412 9.89991V17.5312L150.826 13.2618C151.087 13.0005 151.39 12.8699 151.734 12.8699C152.036 12.8699 152.304 13.0005 152.538 13.2618C152.785 13.5093 152.909 13.7637 152.909 14.0249C152.909 14.3549 152.744 14.6643 152.414 14.953L149.3 17.8199L152.909 21.7387Z" fill="white"/>
<path d="M165.17 21.7387C165.431 22.0137 165.562 22.323 165.562 22.6668C165.562 23.0105 165.424 23.2993 165.149 23.533C164.888 23.7668 164.606 23.8837 164.303 23.8837C163.946 23.8837 163.643 23.7462 163.396 23.4712L159.683 19.5524L158.673 20.4805V22.6462C158.673 23.0037 158.556 23.3062 158.322 23.5537C158.088 23.7874 157.793 23.9043 157.435 23.9043C157.078 23.9043 156.782 23.7874 156.548 23.5537C156.315 23.3062 156.198 23.0037 156.198 22.6462V9.89991C156.198 9.54241 156.315 9.24678 156.548 9.01303C156.782 8.76553 157.078 8.64178 157.435 8.64178C157.793 8.64178 158.088 8.76553 158.322 9.01303C158.556 9.24678 158.673 9.54241 158.673 9.89991V17.5312L163.087 13.2618C163.348 13.0005 163.65 12.8699 163.994 12.8699C164.297 12.8699 164.565 13.0005 164.798 13.2618C165.046 13.5093 165.17 13.7637 165.17 14.0249C165.17 14.3549 165.005 14.6643 164.675 14.953L161.56 17.8199L165.17 21.7387Z" fill="white"/>
<path d="M177.203 12.6637C177.56 12.6637 177.856 12.7805 178.09 13.0143C178.324 13.248 178.44 13.5505 178.44 13.9218V22.6462C178.44 23.0037 178.324 23.3062 178.09 23.5537C177.856 23.7874 177.56 23.9043 177.203 23.9043C176.845 23.9043 176.55 23.7874 176.316 23.5537C176.096 23.3199 175.979 23.0243 175.965 22.6668C175.622 23.0655 175.154 23.4093 174.563 23.698C173.985 23.973 173.374 24.1105 172.727 24.1105C171.779 24.1105 170.919 23.8699 170.149 23.3887C169.379 22.8937 168.767 22.213 168.314 21.3468C167.874 20.4805 167.654 19.4974 167.654 18.3974C167.654 17.2974 167.874 16.3143 168.314 15.448C168.754 14.568 169.352 13.8874 170.108 13.4062C170.878 12.9112 171.724 12.6637 172.645 12.6637C173.305 12.6637 173.924 12.7874 174.501 13.0349C175.079 13.2687 175.567 13.5712 175.965 13.9424V13.9218C175.965 13.5643 176.082 13.2687 176.316 13.0349C176.55 12.7874 176.845 12.6637 177.203 12.6637ZM173.037 21.8418C173.93 21.8418 174.659 21.5187 175.223 20.8724C175.787 20.2124 176.069 19.3874 176.069 18.3974C176.069 17.4074 175.787 16.5824 175.223 15.9224C174.659 15.2624 173.93 14.9324 173.037 14.9324C172.157 14.9324 171.435 15.2624 170.871 15.9224C170.307 16.5824 170.025 17.4074 170.025 18.3974C170.025 19.3874 170.3 20.2124 170.85 20.8724C171.414 21.5187 172.143 21.8418 173.037 21.8418Z" fill="white"/>
<g clip-path="url(#clip0_1_8)">
<rect width="33" height="33.2515" fill="url(#paint0_radial_1_8)"/>
<mask id="mask0_1_8" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="33" height="34">
<rect width="33" height="33.2515" fill="#C4C4C4"/>
</mask>
<g mask="url(#mask0_1_8)">
<rect width="68.3757" height="28.5985" transform="matrix(0.914908 -0.403661 0.39855 0.917147 -11.4583 -3.34177)" fill="url(#paint1_linear_1_8)" fill-opacity="0.07"/>
<rect width="68.3757" height="28.5985" transform="matrix(0.914908 -0.403661 0.39855 0.917146 5.95831 4.50931)" fill="url(#paint2_linear_1_8)" fill-opacity="0.2"/>
<g filter="url(#filter0_d_1_8)">
<path d="M14.287 8.31287L22.6996 16.6258L14.287 24.9386L11.6996 22.3808L17.5247 16.6258L11.6996 10.8707L14.287 8.31287Z" fill="white"/>
</g>
</g>
</g>
<defs>
<filter id="filter0_d_1_8" x="9.69958" y="6.31287" width="15" height="20.6258" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1_8"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1_8" result="shape"/>
</filter>
<radialGradient id="paint0_radial_1_8" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(16.5) rotate(90) scale(38.0642 37.7763)">
<stop stop-color="#545454"/>
<stop offset="0.9999"/>
<stop offset="1" stop-color="#C4C4C4" stop-opacity="0"/>
</radialGradient>
<linearGradient id="paint1_linear_1_8" x1="17.8868" y1="11.2643" x2="9.52799" y2="21.6658" gradientUnits="userSpaceOnUse">
<stop stop-color="white" stop-opacity="0"/>
<stop offset="1" stop-color="white" stop-opacity="0.63"/>
</linearGradient>
<linearGradient id="paint2_linear_1_8" x1="7.19234" y1="11.0894" x2="25.6513" y2="25.1338" gradientUnits="userSpaceOnUse">
<stop stop-color="white" stop-opacity="0"/>
<stop offset="1" stop-color="white" stop-opacity="0.63"/>
</linearGradient>
<clipPath id="clip0_1_8">
<rect width="33" height="33.2515" rx="6" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 15 KiB

11
public/logos/facebook.svg Normal file
View File

@@ -0,0 +1,11 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none"
xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_3_5)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 20C0 29.9 7.2 38.1 16.7 39.8L16.8182 39.7033C16.8121 39.7022 16.8061 39.7011 16.8 39.7V25.6H11.8V20H16.8V15.6C16.8 10.6 20 7.79999 24.6 7.79999C26 7.79999 27.6 7.99999 29 8.19999V13.3H26.4C24 13.3 23.4 14.5 23.4 16.1V20H28.7L27.8 25.6H23.4V39.7C23.3391 39.7111 23.2782 39.7218 23.2172 39.7323L23.3 39.8C32.8 38.1 40 29.9 40 20C40 9 31 0 20 0C9 0 0 9 0 20Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_3_5">
<rect width="40" height="40" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 689 B

4
public/logos/github.svg Normal file
View File

@@ -0,0 +1,4 @@
<svg width="98" height="96"
xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 967 B

View File

@@ -0,0 +1,4 @@
<svg width="531" height="530" viewBox="0 0 531 530" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path d="M452.082 451.576H373.611V328.688C373.611 299.384 373.088 261.661 332.798 261.661C291.928 261.661 285.675 293.589 285.675 326.555V451.568H207.204V198.86H282.536V233.395H283.591C291.129 220.505 302.023 209.901 315.112 202.712C328.201 195.524 342.994 192.02 357.917 192.574C437.451 192.574 452.115 244.888 452.115 312.945L452.082 451.576ZM118.663 164.316C109.656 164.318 100.852 161.649 93.3622 156.646C85.8727 151.644 80.0347 144.533 76.5866 136.213C73.1385 127.892 72.235 118.736 73.9905 109.903C75.746 101.069 80.0816 92.9541 86.449 86.5844C92.8164 80.2147 100.93 75.8762 109.763 74.1176C118.596 72.3589 127.752 73.259 136.074 76.7042C144.395 80.1493 151.508 85.9847 156.513 93.4724C161.518 100.96 164.191 109.764 164.192 118.77C164.193 124.75 163.017 130.672 160.729 136.197C158.442 141.723 155.088 146.743 150.86 150.973C146.633 155.202 141.613 158.557 136.089 160.847C130.564 163.136 124.643 164.315 118.663 164.316ZM157.898 451.576H79.3457V198.86H157.898V451.576ZM491.203 0.369381H39.9142C29.6712 0.253789 19.8013 4.2095 12.4734 11.3673C5.14551 18.5251 0.959086 28.2993 0.834076 38.5422V491.703C0.954807 501.951 5.13855 511.732 12.4662 518.897C19.7939 526.062 29.6661 530.026 39.9142 529.917H491.203C501.471 530.045 511.371 526.093 518.728 518.928C526.084 511.763 530.296 501.971 530.438 491.703V38.5095C530.292 28.2463 526.077 18.4609 518.721 11.3033C511.364 4.14574 501.466 0.201326 491.203 0.336685" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

12
public/logos/slack.svg Normal file
View File

@@ -0,0 +1,12 @@
<svg fill="#fff" width="800px" height="800px" viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg">
<title>ionicons-v5_logos</title>
<path d="M126.12,315.1A47.06,47.06,0,1,1,79.06,268h47.06Z"/>
<path d="M149.84,315.1a47.06,47.06,0,0,1,94.12,0V432.94a47.06,47.06,0,1,1-94.12,0Z"/>
<path d="M196.9,126.12A47.06,47.06,0,1,1,244,79.06v47.06Z"/>
<path d="M196.9,149.84a47.06,47.06,0,0,1,0,94.12H79.06a47.06,47.06,0,0,1,0-94.12Z"/>
<path d="M385.88,196.9A47.06,47.06,0,1,1,432.94,244H385.88Z"/>
<path d="M362.16,196.9a47.06,47.06,0,0,1-94.12,0V79.06a47.06,47.06,0,1,1,94.12,0Z"/>
<path d="M315.1,385.88A47.06,47.06,0,1,1,268,432.94V385.88Z"/>
<path d="M315.1,362.16a47.06,47.06,0,0,1,0-94.12H432.94a47.06,47.06,0,1,1,0,94.12Z"/>
</svg>

After

Width:  |  Height:  |  Size: 754 B

4
public/logos/x.svg Normal file
View File

@@ -0,0 +1,4 @@
<svg width="300" height="300.251" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<path d="M178.57 127.15 290.27 0h-26.46l-97.03 110.38L89.34 0H0l117.13 166.93L0 300.25h26.46l102.4-116.59 81.8 116.59h89.34M36.01 19.54H76.66l187.13 262.13h-40.66" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 274 B

BIN
public/meetup.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

BIN
public/opensource.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 340 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -1,19 +0,0 @@
{
"name": "",
"short_name": "",
"icons": [
{
"src": "/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
}

View File

@@ -1 +0,0 @@
<svg height="512" viewBox="0 0 512 512" width="512" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path d="m.5.5h511v511h-511z" fill="#f50" stroke="#979797"/><path d="m416 206.000625c0 60.75125-49.24875 109.999375-110 109.999375-7.0125 0-13.86875-.66375-20.516875-1.918125l-15.0075 16.88375c-2.846519 3.202358-6.926653 5.034529-11.21125 5.034375h-23.264375v25c0 8.284375-6.715625 15-15 15h-25v25c0 8.284375-6.715625 15-15 15h-70c-8.284375 0-15-6.715625-15-15v-48.786875c0-3.978125 1.580625-7.79375 4.393125-10.606875l101.12625-101.12625c-3.576875-10.84625-5.519375-22.435625-5.519375-34.48 0-60.75125 49.248125-109.999375 109.999375-110 60.930625-.000625 110.000625 49.069375 110.000625 110.000625zm-110-30.000625c0 16.56875 13.43125 30 30 30s30-13.43125 30-30-13.43125-30-30-30-30 13.43125-30 30z" fill="#fff" fill-rule="nonzero"/></g></svg>

Before

Width:  |  Height:  |  Size: 866 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 268 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 293 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 9.5 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

View File

@@ -1 +0,0 @@
<svg height="129" viewBox="0 0 143 129" width="143" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path d="m125 75 12.5 25h-25zm0-50 12.5 25h-25zm-25 50 12.5 25h-25zm12.5-25 12.5 25h-25zm-100 0 12.5 25h-25zm25-50 12.5 25h-25zm-25 0 12.5 25h-25zm12.5 25 12.5 25h-25zm25 50 12.5 25h-25zm12.5-25 12.5 25h-25zm12.5-25 12.5 25h-25zm12.5 25 12.5 25h-25z" fill="#e8dc64"/><path d="m25 75 12.5-25h-25zm25-50 12.5-25h-25zm-25 0 12.5-25h-25zm12.5 25 12.5-25h-25zm-25 0 12.5-25h-25zm50 50 12.5-25h-25zm37.5-25 12.5-25h-25zm12.5 25 12.5-25h-25zm12.5-25 12.5-25h-25zm0-50 12.5-25h-25zm-112.5 75 12.5-25h-25zm75-50 12.5-25h-25z" fill="#fdf06f"/><path d="m25 75 12.5 25h-25zm50 0 12.5 25h-25zm-37.5-25 12.5 25h-25zm12.5-25 12.5 25h-25zm37.5-25 12.5 25h-25zm25 0 12.5 25h-25zm-12.5 25 12.5 25h-25zm-37.5-25 12.5 25h-25zm25 50 12.5 25h-25z" fill="#ba152b"/><path d="m100 25 12.5-25h-25zm-62.5 75 12.5-25h-25zm12.5-25 12.5-25h-25zm25-50 12.5-25h-25zm12.5 75 12.5-25h-25zm25-50 12.5-25h-25zm-37.5 25 12.5-25h-25zm-12.5-25 12.5-25h-25z" fill="#d31b33"/><path d="m21.78 104.67c1.76 0 3.218.186 4.373.56 1.156.374 2.074.902 2.756 1.584.68.682 1.16 1.485 1.434 2.41.276.923.413 1.946.413 3.068 0 1.54-.324 2.915-.974 4.125s-1.765 2.123-3.35 2.74l4.82 8.843h-5.644l-4.324-8.085h-3.828v8.085h-5.214v-23.33h9.537zm-4.322 11.12h3.762c.858 0 1.562-.077 2.112-.23.55-.155.99-.38 1.32-.678.33-.297.56-.66.693-1.09.132-.428.198-.917.198-1.467 0-.528-.066-1.006-.198-1.436s-.363-.787-.693-1.073-.77-.506-1.32-.66-1.254-.23-2.112-.23h-3.762v6.863zm17.457 12.21v-23.33h16.565v4.29h-11.35v5.114h9.833v4.323h-9.833v5.28h11.35v4.323h-16.564zm26.532-2.41c0 .793-.225 1.453-.677 1.98-.45.53-1.193.793-2.227.793s-1.77-.258-2.21-.775c-.44-.518-.66-1.183-.66-1.997 0-.77.22-1.412.66-1.93.44-.517 1.176-.775 2.21-.775s1.776.258 2.227.775c.452.518.677 1.16.677 1.93zm0-11.714c0 .792-.225 1.452-.677 1.98-.45.528-1.193.792-2.227.792s-1.77-.253-2.21-.76c-.44-.505-.66-1.176-.66-2.012 0-.77.22-1.413.66-1.93.44-.518 1.176-.776 2.21-.776s1.776.258 2.227.775c.452.518.677 1.16.677 1.93zm4.52-9.207h8.482c2.22 0 4.07.3 5.543.906 1.474.606 2.65 1.436 3.53 2.492s1.508 2.293 1.882 3.713.56 2.954.56 4.604c0 1.606-.19 3.113-.577 4.52-.385 1.41-1.022 2.64-1.913 3.697-.892 1.057-2.074 1.887-3.548 2.493-1.474.605-3.3.907-5.478.907h-8.482v-23.33zm9.24 19.007c.99 0 1.838-.18 2.542-.545.703-.363 1.275-.874 1.715-1.534s.764-1.435.974-2.326c.208-.892.312-1.865.312-2.92 0-1.057-.1-2.036-.297-2.938-.198-.902-.517-1.683-.957-2.343s-1.017-1.176-1.733-1.55c-.715-.374-1.59-.56-2.623-.56h-3.96v14.717h4.026zm24.685 4.686c-1.804 0-3.388-.286-4.752-.858s-2.508-1.375-3.432-2.41c-.924-1.033-1.622-2.28-2.096-3.745-.473-1.463-.71-3.096-.71-4.9 0-1.848.243-3.52.727-5.016.483-1.496 1.198-2.772 2.144-3.828s2.117-1.87 3.514-2.442c1.398-.572 2.998-.858 4.802-.858s3.393.28 4.77.84c1.374.563 2.528 1.365 3.463 2.41.936 1.046 1.645 2.3 2.13 3.763.483 1.462.725 3.095.725 4.9 0 1.803-.242 3.453-.726 4.95-.484 1.495-1.204 2.776-2.162 3.843-.957 1.068-2.133 1.892-3.53 2.475-1.398.584-3.02.875-4.868.875zm.198-4.29c1.848 0 3.29-.65 4.323-1.947 1.034-1.298 1.55-3.245 1.55-5.84 0-2.553-.51-4.472-1.533-5.76-1.024-1.287-2.47-1.93-4.34-1.93-1.914 0-3.388.654-4.422 1.963-1.034 1.31-1.55 3.228-1.55 5.758 0 2.574.527 4.51 1.583 5.808 1.057 1.298 2.52 1.947 4.39 1.947zm21.846-19.404 5.445 13.265 5.446-13.266h5.907l1.815 23.33h-5.249l-1.055-13.464-.033-2.442-5.016 11.748h-3.63l-4.983-11.715-.066 2.376-1.023 13.5h-5.28l1.815-23.33h5.906z" fill="#222"/></g></svg>

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 237 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path d="M504 256C504 119 393 8 256 8S8 119 8 256c0 123.78 90.69 226.38 209.25 245V327.69h-63V256h63v-54.64c0-62.15 37-96.48 93.67-96.48 27.14 0 55.52 4.84 55.52 4.84v61h-31.28c-30.8 0-40.41 19.12-40.41 38.73V256h68.78l-11 71.69h-57.78V501C413.31 482.38 504 379.78 504 256z"/></svg>

Before

Width:  |  Height:  |  Size: 524 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path d="M416 32H31.9C14.3 32 0 46.5 0 64.3v383.4C0 465.5 14.3 480 31.9 480H416c17.6 0 32-14.5 32-32.3V64.3c0-17.8-14.4-32.3-32-32.3zM135.4 416H69V202.2h66.5V416zm-33.2-243c-21.3 0-38.5-17.3-38.5-38.5S80.9 96 102.2 96c21.2 0 38.5 17.3 38.5 38.5 0 21.3-17.2 38.5-38.5 38.5zm282.1 243h-66.4V312c0-24.8-.5-56.7-34.5-56.7-34.6 0-39.9 27-39.9 54.9V416h-66.4V202.2h63.7v29.2h.9c8.9-16.8 30.6-34.5 62.9-34.5 67.2 0 79.7 44.3 79.7 101.9V416z"/></svg>

Before

Width:  |  Height:  |  Size: 684 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path d="M94.12 315.1c0 25.9-21.16 47.06-47.06 47.06S0 341 0 315.1c0-25.9 21.16-47.06 47.06-47.06h47.06v47.06zm23.72 0c0-25.9 21.16-47.06 47.06-47.06s47.06 21.16 47.06 47.06v117.84c0 25.9-21.16 47.06-47.06 47.06s-47.06-21.16-47.06-47.06V315.1zm47.06-188.98c-25.9 0-47.06-21.16-47.06-47.06S139 32 164.9 32s47.06 21.16 47.06 47.06v47.06H164.9zm0 23.72c25.9 0 47.06 21.16 47.06 47.06s-21.16 47.06-47.06 47.06H47.06C21.16 243.96 0 222.8 0 196.9s21.16-47.06 47.06-47.06H164.9zm188.98 47.06c0-25.9 21.16-47.06 47.06-47.06 25.9 0 47.06 21.16 47.06 47.06s-21.16 47.06-47.06 47.06h-47.06V196.9zm-23.72 0c0 25.9-21.16 47.06-47.06 47.06-25.9 0-47.06-21.16-47.06-47.06V79.06c0-25.9 21.16-47.06 47.06-47.06 25.9 0 47.06 21.16 47.06 47.06V196.9zM283.1 385.88c25.9 0 47.06 21.16 47.06 47.06 0 25.9-21.16 47.06-47.06 47.06-25.9 0-47.06-21.16-47.06-47.06v-47.06h47.06zm0-23.72c-25.9 0-47.06-21.16-47.06-47.06 0-25.9 21.16-47.06 47.06-47.06h117.84c25.9 0 47.06 21.16 47.06 47.06 0 25.9-21.16 47.06-47.06 47.06H283.1z"/></svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"/></svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -1,7 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="288" height="113" viewBox="0 0 288 113">
<g fill-rule="evenodd" transform="translate(28 24)">
<path d="M154.289688,15.9951456 L163.366979,15.9951456 L163.366979,49.1019417 L154.289688,49.1019417 L154.289688,15.9951456 Z M48.1533333,15.9951456 L48.1533333,33.8834951 C48.1533333,38.276699 46.1388542,40.8495146 42.1098958,40.8495146 C38.0809375,40.8495146 36.0664583,38.276699 36.0664583,33.8834951 L36.0664583,15.9951456 L26.8920833,15.9951456 L26.8920833,36.1650485 C26.8920833,44.684466 33.2267708,49.7330097 42.2069792,49.7330097 C51.1871875,49.7330097 57.521875,44.6601942 57.521875,36.1650485 L57.521875,15.9951456 L48.1533333,15.9951456 Z M111.912813,15.9951456 L111.912813,33.8834951 C111.912813,38.276699 109.898333,40.8495146 105.869375,40.8495146 C101.840417,40.8495146 99.8259375,38.276699 99.8259375,33.8834951 L99.8259375,15.9951456 L90.6515625,15.9951456 L90.6515625,36.1650485 C90.6515625,44.684466 96.98625,49.7330097 105.966458,49.7330097 C114.946667,49.7330097 121.281354,44.684466 121.281354,36.1650485 L121.281354,15.9951456 L111.912813,15.9951456 Z"/>
<ellipse cx="158.683" cy="5.777" rx="5.776" ry="5.777"/>
<path d="M126.766562,15.9951456 L126.766562,49.1019417 L135.843854,49.1019417 L135.843854,24.1504854 L148.513229,24.1504854 L148.513229,15.9951456 L126.766562,15.9951456 Z M223.000417,38.7621359 C221.35,40.6067961 219.044271,41.7961165 216.39875,41.7961165 L216.301667,41.7961165 C211.520312,41.7961165 208.607812,39.4174757 207.491354,35.7524272 L233,35.7524272 L233,32.4271845 C233,22.8883495 226.034271,15.2669903 215.937604,15.2669903 C206.399167,15.2669903 198.681042,22.961165 198.681042,32.5242718 C198.681042,42.0873786 205.840937,49.7815534 216.1075,49.7815534 L216.301667,49.7815534 C221.616979,49.7815534 225.840104,47.7669903 228.776875,44.7330097 L223.000417,38.7621359 Z M216.034687,23.2524272 C219.89375,23.2524272 222.733437,25 223.922708,28.4708738 L207.879687,28.4708738 C209.238854,25.3640777 212.175625,23.2524272 216.034687,23.2524272 Z M191.084271,38.7621359 C189.530937,40.2184466 187.516458,41.1407767 185.210729,41.1407767 L185.016562,41.1407767 C180.332292,41.0436893 176.764479,37.2815534 176.764479,32.5242718 C176.764479,27.8398058 180.332292,24.0048544 185.016562,23.907767 L185.210729,23.907767 C187.686354,23.907767 189.797917,25 191.35125,26.6504854 L197.588854,20.4126214 C194.555,17.2087379 190.259062,15.2669903 185.113646,15.2669903 L185.016562,15.2669903 C175.575208,15.3640777 168.05125,22.961165 168.05125,32.4271845 C168.05125,41.8932039 175.575208,49.5873786 185.016562,49.5873786 L185.113646,49.5873786 C189.967812,49.5873786 194.190937,47.7427184 197.224792,44.8058252 L191.084271,38.7621359 Z M72.1086458,15.9951456 L72.1086458,3.61650485 L63.0313542,3.61650485 L63.0313542,34.6359223 C63.0313542,45.461165 66.5263542,49.0291262 76.9628125,49.0291262 L84.75375,49.0291262 L84.75375,40.5825243 L78.2491667,40.5825243 C72.6426042,40.5825243 72.0115625,39.7572816 72.0115625,34.6116505 L72.0115625,24.1747573 L84.75375,24.1747573 L84.75375,16.0194175 C84.75375,15.9951456 72.1086458,15.9951456 72.1086458,15.9951456 Z M9.07729167,13.8106796 C9.07729167,10.6796117 10.9946875,8.8592233 13.5673958,8.8592233 C15.2178125,8.8592233 16.5041667,9.7815534 17.1352083,10.776699 L22.6446875,5.26699029 C19.805,1.31067961 16.0430208,0.0485436893 12.378125,0.0485436893 C5.679375,0.0485436893 0.169895833,5.9223301 0,13.7135922 L0,49.1262136 L9.07729167,49.1262136 L9.07729167,23.8834951 L20.824375,23.8834951 L20.824375,15.9951456 L9.07729167,15.9951456 L9.07729167,13.8106796 Z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.5 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 21 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 8.7 KiB

View File

@@ -1 +0,0 @@
<svg height="113" viewBox="0 0 256 113" width="256" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd" transform="translate(25 30)"><path d="m188.414599 9.40689655c-8.350365.60689655-15.030657 7.43448275-15.637957 15.77931035-.607299 9.862069 7.135767 18.0551724 16.852555 18.0551724 3.491971 0 8.19854-1.8206896 10.324088-5.462069v5.0068966h6.528467v-16.0827586c.303649-10.6206897-8.19854-18.05517244-18.067153-17.29655175zm11.083211 17.29655175c-.303649 5.6137931-5.162044 9.8620689-10.931387 9.1034483-4.402919-.6068966-7.89489-4.0965518-8.502189-8.4965518-.6073-5.9172414 3.947445-10.9241379 9.716788-10.9241379 5.162044 0 9.413139 4.0965517 9.716788 9.2551724z" fill-rule="nonzero"/><path d="m152.583942 9.40689655c-8.957665.30344828-16.548906 7.13103445-16.548906 17.14482755 0 9.1034483 7.439417 16.8413793 17.00438 16.8413793 6.680292 0 13.208759-3.9448275 15.789781-10.4689655l-6.528467-1.9724138c-1.214599 2.7310345-4.09927 5.0068966-7.287591 5.6137931-4.554745.9103449-8.80584-1.9724138-10.475913-5.0068965l25.354745-6.9793104c-.759124-6.675862-6.528467-15.47586202-17.308029-15.17241375zm-9.413139 16.08275865c0-3.4896552 2.125547-7.5862069 6.680292-9.2551724 5.162044-1.9724138 9.716788.6068965 11.690511 4.2482758z" fill-rule="nonzero"/><path d="m96.8642336 16.2344828v-6.97931039c-6.3766424 0-8.5021898 3.18620689-9.5649635 4.85517239v-3.7931034h-7.2875913v15.475862 16.8413794h7.4394161c0-10.0137931 0-9.862069 0-15.9310345 0-7.2827586 4.2510949-10.1655173 9.4131387-10.4689655z"/><path d="m29.9094891 29.737931-22.16642341-26.09655169h-7.59124087v38.99310349h7.89489051v-26.0965518l22.47007297 26.2482759h6.8321168v-39.14482759h-7.439416z"/><g fill-rule="nonzero"><path d="m131.632117.15172414h-6.983942v12.74482756c-1.670073-2.1241379-6.832117-3.94482756-11.235036-3.48965515-8.350365.60689655-15.0306572 7.43448275-15.6379565 15.77931035-.6072993 9.862069 7.1357665 18.0551724 16.8525545 18.0551724 3.643796 0 8.654015-1.6689655 10.324088-4.8551724v4.2482759h6.528467v-16.0827587c0-.1517241 0-.1517241 0-.3034482 0-.1517242 0-.1517242 0-.3034483zm-7.287591 26.55172416c-.30365 5.6137931-5.162044 9.8620689-10.931387 9.1034483-4.40292-.6068966-7.894891-4.0965518-8.50219-8.4965518-.607299-5.9172414 3.947445-10.9241379 9.716788-10.9241379 5.162044 0 9.413139 4.0965517 9.716789 9.2551724z"/><path d="m58.7562044 9.25517241c-9.4131387 0-17.0043796 7.58620689-17.0043796 16.99310349 0 9.4068965 7.5912409 16.9931034 17.0043796 16.9931034s17.0043795-7.5862069 17.0043795-16.9931034c-.1518248-9.4068966-7.7430657-16.99310349-17.0043795-16.99310349zm0 26.70344829c-5.3138686 0-9.7167883-4.4-9.7167883-9.7103448 0-5.3103449 4.4029197-9.7103449 9.7167883-9.7103449s9.7167883 4.4 9.7167883 9.7103449c0 5.4620689-4.4029197 9.7103448-9.7167883 9.7103448z"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -1,3 +0,0 @@
<svg width="256" height="113" viewBox="0 0 256 113" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M39.0615 75H49.2664V63.3449H53.0262H53.1336L60.7604 75H72.4693L63.1237 61.1427C66.9908 59.3703 69.5152 55.2883 69.5152 50.4544C69.5152 43.2572 63.4997 37.5639 56.0876 37.5639H39.0615V75ZM49.2664 55.1809V46.8021H55.8191C57.7527 46.8021 59.364 48.3597 59.364 50.7767C59.364 53.5696 57.6452 55.1809 54.9597 55.1809H49.2664ZM83.7317 75H94.3663L96.7833 70.1124H112.144L114.561 75H125.196L104.464 35.0396L83.7317 75ZM100.221 62.217L104.464 53.5696L108.707 62.217H100.221ZM136.772 75H146.977V63.3449H150.737H150.844L158.471 75H170.18L160.834 61.1427C164.702 59.3703 167.226 55.2883 167.226 50.4544C167.226 43.2572 161.21 37.5639 153.798 37.5639H136.772V75ZM146.977 55.1809V46.8021H153.53C155.463 46.8021 157.075 48.3597 157.075 50.7767C157.075 53.5696 155.356 55.1809 152.67 55.1809H146.977ZM181.872 75H209.909V65.9767H192.077V60.2834H208.298V51.9046H192.077V46.7484H209.479V37.5639H181.872V75Z" fill="black"/>
</svg>

Before

Width:  |  Height:  |  Size: 1020 B

View File

@@ -1 +0,0 @@
<svg height="113" viewBox="0 0 268 113" width="268" xmlns="http://www.w3.org/2000/svg"><g fill="#282828" fill-rule="evenodd" transform="translate(24 22)"><path d="m.9 25.4h12.7v25.4h-12.7z"/><path d="m30.1 0h12.7v25.4h-12.7z"/><path d="m15.5 0h12.7v50.8h-12.7z"/><path d="m85.8 35.5c0-8.7 7-15.8 15.8-15.8 8.7 0 15.8 7 15.8 15.8v.1c0 8.8-6.9 15.8-15.8 15.8-8.8 0-15.8-7.1-15.8-15.9zm24.2 0c0-4.7-3.6-8.6-8.4-8.6s-8.3 3.9-8.3 8.6 3.5 8.6 8.3 8.6c4.9 0 8.4-3.9 8.4-8.6z" fill-rule="nonzero"/><path d="m123.8 20.1h7.4v23.8h13.4v7.1h-20.8z"/><path d="m152 20.1h7.4v30.8h-7.4z"/><path d="m175.1 27.2h-8.8v-7.1h24.9v7.1h-8.8v23.8h-7.4v-23.8z"/><path d="m202.4 20.1h7.1l11.4 30.8h-7.5l-1.6-4.6h-11.8l-1.6 4.6h-7.4zm-.1 19.8h7.3l-3.6-10.4z" fill-rule="nonzero"/><path d="m55.5 45.2 4.9-4.9c2.5 3 5 4.1 9.2 4.1 2.5 0 3.8-1.2 3.8-2.9 0-2.1-2-2.5-6.4-3.6-4.5-1-9.7-2.7-9.7-9 0-5.4 4.7-9.5 11.3-9.5 5.7 0 9 1.9 12.3 5.5l-4.5 4.5c-2.2-2.5-4.3-3.5-8-3.5-2.5 0-3.7 1.4-3.7 2.7 0 1.9 2.5 2.3 6.3 3.2 4.6 1.1 10.1 2.7 10.1 9.3 0 5.8-4.9 10.1-11.7 10.1-6.9.2-11-2.5-13.9-6z"/></g></svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -1 +0,0 @@
<svg height="113" viewBox="0 0 349 113" width="349" xmlns="http://www.w3.org/2000/svg"><g fill="#231f20" fill-rule="evenodd" transform="translate(25 41)"><path d="m128.36964 32.3683594h9.092624l-15.437393-20.5321875 13.258148-11.26640627h-5.102058l-19.651801 16.69593747v-16.69593747h-7.253002v31.79859377h7.253002v-10.76625l5.948542-5.053125z"/><path d="m57.7667238.56976563-12.5789022 24.23953127-12.3576329-24.23953127h-8.060892l4.1114923 8.06695312-8.4288164 16.23960935-12.39108066-24.30656247h-8.06089194l16.2092624 31.79859377h3.915952l10.5180103-20.2717969 10.3353345 20.2717969h3.8464837l16.5-31.79859377z"/><path d="m152.56518 29.4086719v-12.2409375h18.401372v-2.9596875h-18.401372v-10.67859378h20.302745l2.315608-2.95968749h-29.868782v31.79859377h29.868782l-2.315608-2.9596875z"/><path d="m277.754717 29.4086719v-12.2409375h18.403945v-2.9596875h-18.403945v-10.67859378h22.106346v-2.95968749h-29.356775v31.79859377h29.356775v-2.9596875z"/><path d="m88.0523156 32.3683594h8.0608919l-16.2092624-31.79601565h-4.3867924l-16.5 31.79601565h3.558319l3.3010292-6.3602344h18.9339622zm-20.6372213-9.3199219 8.0145798-15.44554687 7.8730703 15.44554687z" fill-rule="nonzero"/><path d="m256.196398.56976563v21.80062497l-20.814751-21.80062497h-8.68868v31.79859377h3.246999v-26.89757815l25.682676 26.89757815h3.820754v-31.79859377z"/><path d="m218.091767 15.9044531c-.295884-11.27671873-8.88422-15.9044531-19.443397-15.9044531h-.002572c-10.744426 0-19.456261 4.78757813-19.456261 16.5 0 11.7124219 8.711835 16.5 19.456261 16.5h.002572c10.456261 0 18.985421-4.5375 19.435678-15.5796094.012865-.2990625.020583-.6032812.020583-.9203906 0-.20625-.005146-.4047656-.012864-.5955469m-19.443397 14.2028907c-7.510291 0-11.536878-2.26875-11.536878-13.6073438 0-11.33859375 4.02916-13.60992188 11.536878-13.60992188 7.510292 0 11.536879 2.26875 11.536879 13.60992188 0 11.3411719-4.02916 13.6073438-11.536879 13.6073438" fill-rule="nonzero"/></g></svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -1,4 +0,0 @@
<svg width="72" height="72" viewBox="0 0 72 72" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15 6C10.0294 6 6 10.0294 6 15V57C6 61.9706 10.0294 66 15 66H57C61.9706 66 66 61.9706 66 57V15C66 10.0294 61.9706 6 57 6H15ZM15 0H57C65.2843 0 72 6.71573 72 15V57C72 65.2843 65.2843 72 57 72H15C6.71573 72 0 65.2843 0 57V15C0 6.71573 6.71573 0 15 0Z" fill="white"/>
<path d="M31.792 18.2812L49.723 36.0077L31.792 53.734L26.277 48.2796L38.693 36.0077L26.277 23.7355L31.792 18.2812Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 508 B

View File

@@ -1,4 +0,0 @@
<svg width="72" height="72" viewBox="0 0 72 72" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15 6C10.0294 6 6 10.0294 6 15V57C6 61.9706 10.0294 66 15 66H57C61.9706 66 66 61.9706 66 57V15C66 10.0294 61.9706 6 57 6H15ZM15 0H57C65.2843 0 72 6.71573 72 15V57C72 65.2843 65.2843 72 57 72H15C6.71573 72 0 65.2843 0 57V15C0 6.71573 6.71573 0 15 0Z" fill="black"/>
<path d="M31.792 18.2812L49.723 36.0077L31.792 53.734L26.277 48.2796L38.693 36.0077L26.277 23.7355L31.792 18.2812Z" fill="black"/>
</svg>

Before

Width:  |  Height:  |  Size: 508 B

Binary file not shown.

View File

@@ -1,10 +0,0 @@
.btn {
border-radius: 3px;
padding: 1em;
border: 0;
font-size: 14px;
cursor: pointer;
&:disabled {
opacity: 0.6;
}
}

View File

@@ -1,299 +0,0 @@
$headerHeight: 400px;
.header {
background: url("/static/images/jumbo.jpg");
background-position: bottom center;
background-size: cover;
height: $headerHeight;
overflow: hidden;
position: relative;
width: 100%;
transform: translateZ(0);
@media screen and (max-width: 1030px) {
height: 300px;
video {
display: none;
}
}
}
.header__container {
background: #3e7394;
background: linear-gradient(
120deg,
rgba(#085078, 0.8) 10%,
rgba(#85d8ce, 0.7) 90%
);
display: table;
height: 100%;
text-align: center;
vertical-align: middle;
width: 100%;
}
.header__nav {
position: absolute;
left: 90px;
top: 40px;
@media screen and (max-width: 810px) {
left: auto;
right: auto;
width: 100%;
}
a {
display: block;
max-width: 180px;
@media screen and (max-width: 810px) {
margin-left: auto;
margin-right: auto;
}
img {
width: 100%;
}
}
}
.header__headline {
display: table-cell;
padding: 0 1em;
vertical-align: middle;
}
.header__title {
color: #fff;
display: inline-block;
font-size: 2.75em;
letter-spacing: -1px;
line-height: 1.4em;
margin: auto;
max-width: 780px;
font-family: "Lato", sans-serif;
font-weight: 900;
text-align: center;
text-shadow: 0 2px 0 rgba(#000, 0.1);
vertical-align: middle;
@media screen and (max-width: 1030px) {
font-size: 2em;
max-width: 640px;
}
@media screen and (max-width: 810px) {
display: block;
font-size: 1.6em;
max-width: 440px;
text-align: center;
}
@media screen and (max-width: 410px) {
font-size: 1.4em;
}
a {
color: inherit;
text-decoration: underline;
}
}
.header__video-bg {
height: 100%;
position: absolute;
bottom: 0;
z-index: -2;
@media (min-aspect-ratio: 1 / 2) {
width: 100%;
height: auto;
}
}
@-webkit-keyframes spin {
0% {
top: 0;
}
50% {
top: -($headerHeight);
}
50.0001% {
top: $headerHeight;
}
100% {
top: 0;
}
}
@-moz-keyframes spin {
0% {
top: 0;
}
50% {
top: -($headerHeight);
}
50.0001% {
top: $headerHeight;
}
100% {
top: 0;
}
}
@-ms-keyframes spin {
0% {
top: 0;
}
50% {
top: -($headerHeight);
}
50.0001% {
top: $headerHeight;
}
100% {
top: 0;
}
}
@-o-keyframes spin {
0% {
top: 0;
}
50% {
top: -($headerHeight);
}
50.0001% {
top: $headerHeight;
}
100% {
top: 0;
}
}
@keyframes spin {
0% {
top: 0;
}
50% {
top: -($headerHeight);
}
50.0001% {
top: $headerHeight;
}
100% {
top: 0;
}
}
@-webkit-keyframes spin2 {
0% {
top: $headerHeight;
}
50% {
top: 0;
}
99.99999% {
top: -($headerHeight);
}
100% {
top: $headerHeight;
}
}
@-moz-keyframes spin2 {
0% {
top: $headerHeight;
}
50% {
top: 0;
}
99.99999% {
top: -($headerHeight);
}
100% {
top: $headerHeight;
}
}
@-ms-keyframes spin2 {
0% {
top: $headerHeight;
}
50% {
top: 0;
}
99.99999% {
top: -($headerHeight);
}
100% {
top: $headerHeight;
}
}
@-o-keyframes spin2 {
0% {
top: $headerHeight;
}
50% {
top: 0;
}
99.99999% {
top: -($headerHeight);
}
100% {
top: $headerHeight;
}
}
@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: calc(100% / 18);
@media screen and (min-width: 2000px) {
width: 5%;
}
@media screen and (max-width: 1200px) {
width: calc(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;
}
}
}

View File

@@ -1,39 +0,0 @@
.input {
height: 45px;
padding: 0.5em 1em;
box-sizing: border-box;
font-size: inherit;
border: 1px solid rgba(0, 0, 0, 0.3);
border-radius: 5px;
background: #fff;
outline: 0;
color: rgba(0, 0, 0, 0.5);
&:focus {
border: 2px solid #3090de;
color: rgba(0, 0, 0, 0.6);
}
}
.input::-webkit-input-placeholder {
color: rgba(0, 0, 0, 0.3);
}
.input:-moz-placeholder {
color: rgba(0, 0, 0, 0.3);
opacity: 1;
}
.input::-moz-placeholder {
color: rgba(0, 0, 0, 0.3);
opacity: 1;
}
.input:-ms-input-placeholder {
color: rgba(0, 0, 0, 0.3);
}
.input.has-error {
border-color: rgba(226, 33, 112, 0.6);
color: rgb(226, 33, 112);
}
.input.half {
width: 48%;
&.left {
margin-right: 4%;
}
}

View File

@@ -1,133 +0,0 @@
.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;
}
@-webkit-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;
}
}
@-moz-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;
}
}
@-ms-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;
}
}
@-o-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;
}
}
@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;
}
}

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