diff --git a/site/index.html b/site/index.html
new file mode 100644
index 0000000..abd26b8
--- /dev/null
+++ b/site/index.html
@@ -0,0 +1,89 @@
+
+
+
+
+
+ Blowfish
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Latest release:
+
+ ...
+
+ ...
+
+
+
+
+
+
+
+
+
+
+
diff --git a/site/screens.png b/site/screens.png
new file mode 100644
index 0000000..fe2cac0
Binary files /dev/null and b/site/screens.png differ
diff --git a/site/scripts.js b/site/scripts.js
new file mode 100644
index 0000000..b3be969
--- /dev/null
+++ b/site/scripts.js
@@ -0,0 +1,65 @@
+async function getLatestRelease() {
+ const response = await fetch(
+ 'https://api.github.com/repos/kremalicious/blowfish/releases/latest'
+ )
+
+ if (response.status !== 200) {
+ console.error(`Non-200 response code from GitHub: ${response.status}`)
+ return null
+ }
+
+ const json = await response.json()
+ return json
+}
+
+function getDownloads(release) {
+ const downloads = release.assets
+ .filter(
+ asset =>
+ asset.name.includes('mac.zip') |
+ (asset.name.includes('.exe') && !asset.name.includes('.exe.blockmap')) |
+ asset.name.includes('.deb')
+ )
+ .map(asset => {
+ const isMac = asset.name.includes('mac.zip')
+ const isWin = asset.name.includes('.exe')
+
+ return {
+ name: `Download (${isMac ? 'macOS' : isWin ? 'Windows' : 'Linux'})`,
+ url: asset.browser_download_url
+ }
+ })
+
+ return downloads
+}
+
+function replaceDom(release) {
+ if (!release) return
+
+ const releaseTagElement = document.querySelector('.release__tag')
+ const releaseDateElement = document.querySelector('.release__date')
+ const downloadsElement = document.querySelector('.downloads')
+ const dateFormatted = new Date(release.published_at).toLocaleDateString()
+
+ releaseTagElement.innerHTML = release.tag_name
+ releaseDateElement.innerHTML = dateFormatted
+
+ const downloads = getDownloads(release)
+ downloadsElement.innerHTML = ''
+
+ downloads.map(download => {
+ const li = document.createElement('li')
+ const a = document.createElement('a')
+ a.href = download.url
+ a.className = 'button'
+ a.appendChild(document.createTextNode(download.name))
+ downloadsElement.appendChild(li).appendChild(a)
+ })
+}
+
+async function init() {
+ const release = await getLatestRelease()
+ replaceDom(release)
+}
+
+init()
diff --git a/site/styles.css b/site/styles.css
new file mode 100644
index 0000000..0f38b7e
--- /dev/null
+++ b/site/styles.css
@@ -0,0 +1,130 @@
+:root {
+ --color-primary: #f7b737;
+ --color-secondary: #725418;
+ --color-signal: #049985;
+ --border-radius: 0.2rem;
+}
+
+*,
+*::before,
+*::after {
+ box-sizing: border-box;
+}
+
+html,
+body {
+ margin: 0;
+ padding: 0;
+}
+
+body {
+ text-rendering: optimizeLegibility;
+ font-feature-settings: 'liga', 'kern';
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ min-height: 100vh;
+ background: var(--color-primary);
+ color: var(--color-secondary);
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
+ Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;
+ font-size: 1rem;
+ font-weight: 400;
+ font-style: normal;
+ line-height: 1.5;
+}
+
+h1,
+h2,
+h3,
+.button {
+ font-family: josefin-sans, sans-serif;
+ font-weight: 700;
+ font-style: normal;
+}
+
+img,
+video,
+svg {
+ max-width: 100%;
+ height: auto;
+ margin: 0;
+}
+
+a {
+ color: var(--color-signal);
+ text-decoration: none;
+}
+
+.layout {
+ max-width: 35rem;
+ margin: auto;
+ padding: 1rem;
+}
+
+.header {
+ margin-bottom: 2rem;
+}
+
+.screen {
+ margin-left: calc(50% - 50vw);
+ margin-right: calc(50% - 50vw);
+ text-align: center;
+}
+
+.button {
+ display: inline-block;
+ background: var(--color-signal);
+ color: var(--color-primary);
+ padding: 0.5rem 1rem;
+ margin-bottom: 1rem;
+ border-radius: var(--border-radius);
+ transition: 0.2s ease-out;
+ min-width: 15rem;
+}
+
+.button:hover {
+ background: var(--color-secondary);
+}
+
+.downloads {
+ margin-top: 2rem;
+ padding: 0;
+ text-align: center;
+}
+
+.downloads li {
+ display: block;
+}
+
+.release {
+ text-align: center;
+ font-size: 0.8rem;
+}
+
+.footer {
+ margin-top: 4rem;
+ font-size: 0.8rem;
+}
+
+code {
+ background: rgba(255, 255, 255, 0.15);
+ padding: 0.1rem 0.3rem;
+ border-radius: var(--border-radius);
+ display: inline-block;
+}
+
+.credit {
+ margin-bottom: 1rem;
+}
+
+.thanks span {
+ display: block;
+}
+
+@media (min-width: 40rem) {
+ .thanks {
+ margin: 0;
+ display: flex;
+ justify-content: space-between;
+ }
+}