Detailed changes
@@ -5,13 +5,33 @@
# - Log in to the DigitalOcean docker registry
# doctl registry login
#
-# - Set the default K8s context to production
+# - Target the `zed-1` kubernetes cluster
# doctl kubernetes cluster kubeconfig save zed-1
-set -e
+set -eu
-IMAGE_ID=registry.digitalocean.com/zed/zed-server
+if [[ $# < 1 ]]; then
+ echo "Usage: $0 [production|staging|...]"
+ exit 1
+fi
-docker build . --tag $IMAGE_ID
-docker push $IMAGE_ID
-kubectl rollout restart deployment zed
+export ZED_KUBE_NAMESPACE=$1
+ENV_FILE="server/k8s/environments/${ZED_KUBE_NAMESPACE}.sh"
+if [[ ! -f $ENV_FILE ]]; then
+ echo "Invalid environment name '${ZED_KUBE_NAMESPACE}'"
+ exit 1
+fi
+
+if [[ $ZED_KUBE_NAMESPACE == "production" && -n $(git status --short) ]]; then
+ echo "Cannot deploy uncommited changes to production"
+ exit 1
+fi
+
+git_sha=$(git rev-parse HEAD)
+export ZED_IMAGE_ID="registry.digitalocean.com/zed/zed-server:${ZED_KUBE_NAMESPACE}-${git_sha}"
+export $(cat $ENV_FILE)
+
+docker build . --tag "$ZED_IMAGE_ID"
+docker push "$ZED_IMAGE_ID"
+
+envsubst < server/k8s/manifest.template.yml | kubectl apply -f -
@@ -1,11 +1,42 @@
#!/bin/bash
-set -e
+# Prerequisites:
+#
+# - Log in to the DigitalOcean docker registry
+# doctl registry login
+#
+# - Target the `zed-1` kubernetes cluster
+# doctl kubernetes cluster kubeconfig save zed-1
-IMAGE_ID=registry.digitalocean.com/zed/zed-migrator
+set -eu
+
+if [[ $# < 1 ]]; then
+ echo "Usage: $0 [production|staging|...]"
+ exit 1
+fi
+
+export ZED_KUBE_NAMESPACE=$1
+ENV_FILE="server/k8s/environments/${ZED_KUBE_NAMESPACE}.sh"
+if [[ ! -f $ENV_FILE ]]; then
+ echo "Invalid environment name '${ZED_KUBE_NAMESPACE}'"
+ exit 1
+fi
+
+if [[ -n $(git status --short) ]]; then
+ echo "Cannot deploy with uncommited changes"
+ exit 1
+fi
+
+git_sha=$(git rev-parse HEAD)
+export ZED_IMAGE_ID=registry.digitalocean.com/zed/zed-migrator:${ZED_KUBE_NAMESPACE}-${git_sha}
+export ZED_MIGRATE_JOB_NAME=zed-migrate-${git_sha}
docker build . \
--file ./Dockerfile.migrator \
- --tag $IMAGE_ID
-docker push $IMAGE_ID
-kubectl apply -f ./server/migrate.yml
+ --tag $ZED_IMAGE_ID
+docker push $ZED_IMAGE_ID
+
+envsubst < server/k8s/migrate.template.yml | kubectl apply -f -
+
+pod=$(kubectl --namespace=${ZED_KUBE_NAMESPACE} get pods --selector=job-name=${ZED_MIGRATE_JOB_NAME} --output=jsonpath='{.items[*].metadata.name}')
+echo "pod:" $pod
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+if [[ $# < 1 ]]; then
+ echo "Usage: $0 [production|staging|...]"
+ exit 1
+fi
+
+export ZED_KUBE_NAMESPACE=$1
+
+pod=$(kubectl --namespace=${ZED_KUBE_NAMESPACE} get pods --selector=app=zed --output=jsonpath='{.items[*].metadata.name}')
+exec kubectl --namespace $ZED_KUBE_NAMESPACE exec --tty --stdin $pod -- /bin/bash
@@ -1,44 +1,46 @@
+const colors = require('tailwindcss/colors')
+
module.exports = {
+ corePlugins: {
+ float: false,
+ tableLayout: false,
+ sepia: false,
+ saturate: false,
+ },
+
theme: {
fontFamily: {
display: [
- "Visby CF", "ui-sans-serif", "system-ui", "-apple-system", "BlinkMacSystemFont", "Segoe UI", "Roboto",
- "Helvetica Neue", "Arial", "Noto Sans", "sans-serif", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
+ "Spectral", "Constantia", "Lucida Bright", "Lucidabright", "Lucida Serif", "Lucida", "DejaVu Serif", "Bitstream Vera Serif",
+ "Liberation Serif", "Georgia", "serif", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
"Noto Color Emoji"
],
body: [
- "Open Sans", "ui-sans-serif", "system-ui", "-apple-system", "BlinkMacSystemFont", "Segoe UI", "Roboto",
- "Helvetica Neue", "Arial", "Noto Sans", "sans-serif", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
- "Noto Color Emoji"
+ "JetBrains Mono", "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono",
+ "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", "Courier New", "Apple Color Emoji", "Segoe UI Emoji",
+ "Segoe UI Symbol", "Noto Color Emoji"
+ ],
+ mono: [
+ "JetBrains Mono", "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono",
+ "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", "Courier New", "Apple Color Emoji", "Segoe UI Emoji",
+ "Segoe UI Symbol", "Noto Color Emoji"
],
},
- extend: {
- typography: (theme) => ({
- DEFAULT: {
- css: {
- h1: {
- fontFamily: theme("fontFamily.display").join(", ")
- },
- h2: {
- fontFamily: theme("fontFamily.display").join(", ")
- },
- h3: {
- fontFamily: theme("fontFamily.display").join(", ")
- },
- h4: {
- fontFamily: theme("fontFamily.display").join(", ")
- }
- }
- }
- })
- }
+ colors: {
+ transparent: 'transparent',
+ current: 'currentColor',
+ black: colors.black,
+ white: colors.white,
+ gray: colors.trueGray,
+ },
+ extend: {},
},
+
variants: {
},
- plugins: [
- require('@tailwindcss/typography'),
- ],
+ darkMode: false,
purge: [
- "../server/templates/**/*.hbs"
+ "../server/templates/**/*.hbs",
+ "../server/templates/*.hbs"
]
}
@@ -0,0 +1 @@
+ZED_LOAD_BALANCER_CERT_ID=6f857971-20fb-4c68-a7d6-35fef9e5ec4c
@@ -0,0 +1 @@
+ZED_LOAD_BALANCER_CERT_ID=b0d48941-4895-4d75-a966-fe5a571b1fff
@@ -1,11 +1,17 @@
---
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: ${ZED_KUBE_NAMESPACE}
+---
kind: Service
apiVersion: v1
metadata:
+ namespace: ${ZED_KUBE_NAMESPACE}
name: zed
annotations:
service.beta.kubernetes.io/do-loadbalancer-tls-ports: "443"
- service.beta.kubernetes.io/do-loadbalancer-certificate-id: "606e2db9-2b58-4ae7-b12c-a0c7d56af49b"
+ service.beta.kubernetes.io/do-loadbalancer-certificate-id: "${ZED_LOAD_BALANCER_CERT_ID}"
spec:
type: LoadBalancer
selector:
@@ -19,6 +25,7 @@ spec:
apiVersion: apps/v1
kind: Deployment
metadata:
+ namespace: ${ZED_KUBE_NAMESPACE}
name: zed
spec:
replicas: 1
@@ -32,7 +39,7 @@ spec:
spec:
containers:
- name: zed
- image: registry.digitalocean.com/zed/zed-server
+ image: "${ZED_IMAGE_ID}"
ports:
- containerPort: 8080
protocol: TCP
@@ -69,3 +76,8 @@ spec:
secretKeyRef:
name: github
key: privateKey
+ securityContext:
+ capabilities:
+ # FIXME - Switch to the more restrictive `PERFMON` capability.
+ # This capability isn't yet available in a stable version of Debian.
+ add: ["SYS_ADMIN"]
@@ -0,0 +1,18 @@
+apiVersion: batch/v1
+kind: Job
+metadata:
+ namespace: ${ZED_KUBE_NAMESPACE}
+ name: ${ZED_MIGRATE_JOB_NAME}
+spec:
+ template:
+ spec:
+ restartPolicy: Never
+ containers:
+ - name: migrator
+ image: ${ZED_IMAGE_ID}
+ env:
+ - name: DATABASE_URL
+ valueFrom:
+ secretKeyRef:
+ name: database
+ key: url
@@ -1,17 +0,0 @@
-apiVersion: batch/v1
-kind: Job
-metadata:
- name: migrate
-spec:
- template:
- spec:
- restartPolicy: Never
- containers:
- - name: migrator
- image: registry.digitalocean.com/zed/zed-migrator
- env:
- - name: DATABASE_URL
- valueFrom:
- secretKeyRef:
- name: database
- key: url
@@ -0,0 +1,4 @@
+ALTER TABLE "signups"
+ ADD "wants_releases" BOOLEAN,
+ ADD "wants_updates" BOOLEAN,
+ ADD "wants_community" BOOLEAN;
@@ -1,18 +1,16 @@
-use crate::{AppState, Request};
use anyhow::anyhow;
use rust_embed::RustEmbed;
-use std::sync::Arc;
use tide::{http::mime, Server};
#[derive(RustEmbed)]
#[folder = "static"]
struct Static;
-pub fn add_routes(app: &mut Server<Arc<AppState>>) {
- app.at("/static/*path").get(get_static_asset);
+pub fn add_routes(app: &mut Server<()>) {
+ app.at("/*path").get(get_static_asset);
}
-async fn get_static_asset(request: Request) -> tide::Result {
+async fn get_static_asset(request: tide::Request<()>) -> tide::Result {
let path = request.param("path").unwrap();
let content = Static::get(path).ok_or_else(|| anyhow!("asset not found at {}", path))?;
@@ -0,0 +1,15 @@
+use crate::{AppState, Request, RequestExt};
+use std::sync::Arc;
+use tide::http::mime;
+
+pub fn add_routes(community: &mut tide::Server<Arc<AppState>>) {
+ community.at("/community").get(get_community);
+}
+
+async fn get_community(mut request: Request) -> tide::Result {
+ let data = request.layout_data().await?;
+ Ok(tide::Response::builder(200)
+ .body(request.state().render_template("community.hbs", &data)?)
+ .content_type(mime::HTML)
+ .build())
+}
@@ -47,17 +47,30 @@ impl Db {
github_login: &str,
email_address: &str,
about: &str,
+ wants_releases: bool,
+ wants_updates: bool,
+ wants_community: bool,
) -> Result<SignupId> {
test_support!(self, {
let query = "
- INSERT INTO signups (github_login, email_address, about)
- VALUES ($1, $2, $3)
+ INSERT INTO signups (
+ github_login,
+ email_address,
+ about,
+ wants_releases,
+ wants_updates,
+ wants_community
+ )
+ VALUES ($1, $2, $3, $4, $5, $6)
RETURNING id
";
sqlx::query_scalar(query)
.bind(github_login)
.bind(email_address)
.bind(about)
+ .bind(wants_releases)
+ .bind(wants_updates)
+ .bind(wants_community)
.fetch_one(&self.pool)
.await
.map(SignupId)
@@ -475,6 +488,9 @@ pub struct Signup {
pub github_login: String,
pub email_address: String,
pub about: String,
+ pub wants_releases: Option<bool>,
+ pub wants_updates: Option<bool>,
+ pub wants_community: Option<bool>,
}
id_type!(ChannelId);
@@ -1,8 +1,5 @@
-use crate::{
- auth::RequestExt as _, github::Release, AppState, LayoutData, Request, RequestExt as _,
-};
-use comrak::ComrakOptions;
-use serde::{Deserialize, Serialize};
+use crate::{AppState, Request, RequestExt as _};
+use serde::Deserialize;
use std::sync::Arc;
use tide::{http::mime, log, Server};
@@ -13,42 +10,7 @@ pub fn add_routes(app: &mut Server<Arc<AppState>>) {
}
async fn get_home(mut request: Request) -> tide::Result {
- #[derive(Serialize)]
- struct HomeData {
- #[serde(flatten)]
- layout: Arc<LayoutData>,
- releases: Option<Vec<Release>>,
- }
-
- let mut data = HomeData {
- layout: request.layout_data().await?,
- releases: None,
- };
-
- if let Some(user) = request.current_user().await? {
- if user.is_insider {
- data.releases = Some(
- request
- .state()
- .repo_client
- .releases()
- .await?
- .into_iter()
- .filter_map(|mut release| {
- if release.draft {
- None
- } else {
- let mut options = ComrakOptions::default();
- options.render.unsafe_ = true; // Allow raw HTML in the markup. We control these release notes anyway.
- release.body = comrak::markdown_to_html(&release.body, &options);
- Some(release)
- }
- })
- .collect(),
- );
- }
- }
-
+ let data = request.layout_data().await?;
Ok(tide::Response::builder(200)
.body(request.state().render_template("home.hbs", &data)?)
.content_type(mime::HTML)
@@ -61,6 +23,12 @@ async fn post_signup(mut request: Request) -> tide::Result {
github_login: String,
email_address: String,
about: String,
+ #[serde(default)]
+ wants_releases: bool,
+ #[serde(default)]
+ wants_updates: bool,
+ #[serde(default)]
+ wants_community: bool,
}
let mut form: Form = request.body_form().await?;
@@ -75,7 +43,14 @@ async fn post_signup(mut request: Request) -> tide::Result {
// Save signup in the database
request
.db()
- .create_signup(&form.github_login, &form.email_address, &form.about)
+ .create_signup(
+ &form.github_login,
+ &form.email_address,
+ &form.about,
+ form.wants_releases,
+ form.wants_updates,
+ form.wants_community,
+ )
.await?;
let layout_data = request.layout_data().await?;
@@ -1,12 +1,14 @@
mod admin;
mod assets;
mod auth;
+mod community;
mod db;
mod env;
mod errors;
mod expiring;
mod github;
mod home;
+mod releases;
mod rpc;
mod team;
@@ -173,13 +175,20 @@ pub async fn run_server(
web.with(errors::Middleware);
home::add_routes(&mut web);
team::add_routes(&mut web);
+ releases::add_routes(&mut web);
+ community::add_routes(&mut web);
admin::add_routes(&mut web);
auth::add_routes(&mut web);
- assets::add_routes(&mut web);
+
+ let mut assets = tide::new();
+ assets.with(CompressMiddleware::new());
+ assets::add_routes(&mut assets);
let mut app = tide::with_state(state.clone());
rpc::add_routes(&mut app, &rpc);
+
app.at("/").nest(web);
+ app.at("/static").nest(assets);
app.listen(listener).await?;
@@ -0,0 +1,55 @@
+use crate::{
+ auth::RequestExt as _, github::Release, AppState, LayoutData, Request, RequestExt as _,
+};
+use comrak::ComrakOptions;
+use serde::{Serialize};
+use std::sync::Arc;
+use tide::{http::mime};
+
+pub fn add_routes(releases: &mut tide::Server<Arc<AppState>>) {
+ releases.at("/releases").get(get_releases);
+}
+
+async fn get_releases(mut request: Request) -> tide::Result {
+
+ #[derive(Serialize)]
+ struct ReleasesData {
+ #[serde(flatten)]
+ layout: Arc<LayoutData>,
+ releases: Option<Vec<Release>>,
+ }
+
+ let mut data = ReleasesData {
+ layout: request.layout_data().await?,
+ releases: None,
+ };
+
+ if let Some(user) = request.current_user().await? {
+ if user.is_insider {
+ data.releases = Some(
+ request
+ .state()
+ .repo_client
+ .releases()
+ .await?
+ .into_iter()
+ .filter_map(|mut release| {
+ if release.draft {
+ None
+ } else {
+ let mut options = ComrakOptions::default();
+ options.render.unsafe_ = true; // Allow raw HTML in the markup. We control these release notes anyway.
+ release.body = comrak::markdown_to_html(&release.body, &options);
+ Some(release)
+ }
+ })
+ .collect(),
+ );
+ }
+ }
+
+ Ok(tide::Response::builder(200)
+ .body(request.state().render_template("releases.hbs", &data)?)
+ .content_type(mime::HTML)
+ .build())
+}
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<browserconfig>
+ <msapplication>
+ <tile>
+ <square150x150logo src="/static/images/mstile-150x150.png"/>
+ <TileColor>#000000</TileColor>
+ </tile>
+ </msapplication>
+</browserconfig>
@@ -0,0 +1,14 @@
+<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <style>
+ path {
+ fill: #000000;
+ }
+ @media ( prefers-color-scheme: dark ) {
+ path {
+ fill: #FFFFFF;
+ }
+ }
+ </style>
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M256 0C114.615 0 0 114.615 0 256C0 397.385 114.615 512 256 512C397.385 512 512 397.385 512 256C512 114.615 397.385 0 256 0ZM256 64C149.961 64 64 149.961 64 256C64 362.039 149.961 448 256 448C362.039 448 448 362.039 448 256C448 149.961 362.039 64 256 64Z"/>
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M160 160L376 160L238 304H304L352 352H136L274 208H208L160 160Z"/>
+</svg>
@@ -0,0 +1,19 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+ "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
+ width="512.000000pt" height="512.000000pt" viewBox="0 0 512.000000 512.000000"
+ preserveAspectRatio="xMidYMid meet">
+ <style>
+ path {
+ fill: #000000;
+ }
+ @media ( prefers-color-scheme: dark ) {
+ path {
+ fill: #FFFFFF;
+ }
+ }
+ </style>
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M256 0C114.615 0 0 114.615 0 256C0 397.385 114.615 512 256 512C397.385 512 512 397.385 512 256C512 114.615 397.385 0 256 0ZM256 64C149.961 64 64 149.961 64 256C64 362.039 149.961 448 256 448C362.039 448 448 362.039 448 256C448 149.961 362.039 64 256 64Z"/>
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M160 160L376 160L238 304H304L352 352H136L274 208H208L160 160Z"/>
+</svg>
@@ -0,0 +1,12 @@
+/* PrismJS 1.25.0
+https://prismjs.com/download.html#themes=prism-twilight&languages=markup+css+clike+javascript+bash+c+cpp+rust+scss */
@@ -0,0 +1,253 @@
+article.prose {
+ margin-bottom: 2.5rem;
+}
+
+article.prose,
+.type-prose {
+ font-family: "Spectral", "Constantia", "Lucida Bright", "Lucidabright", "Lucida Serif", "Lucida", "DejaVu Serif", "Bitstream Vera Serif", "Liberation Serif", "Georgia", "serif", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji", serif;
+ letter-spacing: -0.05rem;
+}
+
+article.prose h1,
+article.prose h2,
+article.prose h3,
+article.prose h4,
+.type-prose h1,
+.type-prose h2,
+.type-prose h3,
+.type-prose h4 {
+ margin: 3rem 0 1rem 0;
+}
+
+article.prose h1,
+.type-prose h1 {
+ font-size: 2.25rem;
+ line-height: 2.5rem;
+}
+
+article.prose h2,
+.type-prose h2 {
+ font-size: 1.875rem;
+ line-height: 2.25rem;
+}
+
+article.prose h3,
+.type-prose h3 {
+ font-size: 1.6rem;
+ line-height: 2rem;
+}
+
+article.prose h4,
+.type-prose h4 {
+ font-size: 1.4rem;
+ line-height: 1.75rem;
+}
+
+article.prose p,
+article.prose li,
+article.prose a,
+.type-prose p,
+.type-prose li,
+.type-prose a {
+ color: #eee;
+ font-size: 1.3rem;
+ line-height: 2.1rem;
+}
+
+article.prose a:not(img),
+.type-prose a:not(img) {
+ text-decoration: underline;
+ text-underline-offset: 4px;
+}
+
+article.prose strong,
+.type-prose strong {
+ font-weight: 600;
+}
+
+article.prose i,
+.type-prose i {
+ font-style: italic;
+}
+
+article.prose p:not(:last-of-type),
+.type-prose p:not(:last-of-type) {
+ margin-bottom: 1.5rem;
+}
+
+article.prose img,
+article.prose pre,
+.type-prose img,
+.type-prose pre {
+ margin: 1.5rem 0;
+}
+
+article.prose ul,
+.type-prose ul {
+ margin-left: 1.5rem;
+}
+
+article.prose ul li,
+.type-prose ul li {
+ list-style-type: disc;
+ list-style-position: outside;
+}
+
+article.prose ul li:not(:last-of-type),
+.type-prose ul li:not(:last-of-type) {
+ margin-bottom: 0.2rem;
+}
+
+article.prose code,
+.type-prose code {
+ font-family: "JetBrains Mono", "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", "Courier New", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji", monospace;
+ font-size: 0.96rem;
+ letter-spacing: 0rem;
+}
+
+article.prose :not(pre) > code,
+.type-prose :not(pre) > code {
+ padding: 0.2rem 0.4rem;
+}
+
+article.prose pre,
+.type-prose pre {
+ padding: 0.8rem;
+}
+
+article.prose pre,
+article.prose :not(pre) > code,
+.type-prose pre,
+.type-prose :not(pre) > code {
+ border-radius: 4px;
+ background-color: rgba(255, 255, 255, 0.1);
+}
+
+/* Code Highlighting Styles
+/* Based on PrismJS 1.25.0
+https://prismjs.com/download.html#themes=prism-twilight&languages=markup+css+clike+javascript+bash+c+cpp+rust+scss */
+code[class*="language-"],
+pre[class*="language-"] {
+ color: #ddd;
+ text-align: left;
+ white-space: pre;
+ word-spacing: normal;
+ word-break: normal;
+ word-wrap: normal;
+ -moz-tab-size: 4;
+ -o-tab-size: 4;
+ tab-size: 4;
+ -webkit-hyphens: none;
+ -ms-hyphens: none;
+ hyphens: none;
+}
+
+/* Code blocks */
+pre[class*="language-"]::-moz-selection {
+ /* Firefox */
+ background: #3b57bc33;
+}
+
+pre[class*="language-"]::selection {
+ /* Safari */
+ background: #3b57bc33;
+}
+
+/* Text Selection colour */
+pre[class*="language-"]::-moz-selection,
+pre[class*="language-"] ::-moz-selection,
+code[class*="language-"]::-moz-selection,
+code[class*="language-"] ::-moz-selection {
+ text-shadow: none;
+ background: #3b57bc33;
+}
+
+pre[class*="language-"]::selection,
+pre[class*="language-"] ::selection,
+code[class*="language-"]::selection,
+code[class*="language-"] ::selection {
+ text-shadow: none;
+ background: #3b57bc33;
+}
+
+.token.comment,
+.token.prolog,
+.token.doctype,
+.token.cdata {
+ color: #9cdcfe;
+}
+
+.token.punctuation {
+ opacity: 0.7;
+}
+
+.token.namespace {
+ opacity: 0.7;
+}
+
+.token.tag,
+.token.boolean,
+.token.number,
+.token.deleted {
+ color: #b5cea8;
+}
+
+.token.keyword,
+.token.property,
+.token.selector,
+.token.constant,
+.token.symbol,
+.token.builtin {
+ color: #0086c0;
+ /* #F9EE98 */
+}
+
+.token.attr-name,
+.token.attr-value,
+.token.string,
+.token.char,
+.token.operator,
+.token.entity,
+.token.url,
+.language-css .token.string,
+.style .token.string,
+.token.variable,
+.token.inserted {
+ color: #4e94ce;
+}
+
+.token.atrule {
+ color: #4ec9b0;
+}
+
+.token.regex,
+.token.important {
+ color: #dcdcaa;
+}
+
+.token.important,
+.token.bold {
+ font-weight: bold;
+}
+
+.token.italic {
+ font-style: italic;
+}
+
+.token.entity {
+ cursor: help;
+}
+
+/* Markup */
+.language-markup .token.tag,
+.language-markup .token.attr-name,
+.language-markup .token.punctuation {
+ color: #4e94ce;
+}
+
+/* Make the tokens sit above the line highlight so the colours don't look faded. */
+.token {
+ position: relative;
+ z-index: 1;
+}
+/*# sourceMappingURL=prose.css.map */
@@ -0,0 +1,9 @@
+{
+ "version": 3,
@@ -0,0 +1,260 @@
+// Style prose by hand
+// add .prose to any <article> to activate prose styles
+// or .type-prose to any element
+
+article.prose {
+ margin-bottom: 2.5rem;
+}
+
+article.prose,
+.type-prose {
+ font-family: "Spectral", "Constantia", "Lucida Bright", "Lucidabright",
+ "Lucida Serif", "Lucida", "DejaVu Serif", "Bitstream Vera Serif",
+ "Liberation Serif", "Georgia", "serif", "Apple Color Emoji",
+ "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji", serif;
+ letter-spacing: -0.05rem;
+
+ h1,
+ h2,
+ h3,
+ h4 {
+ margin: 3rem 0 1rem 0;
+ }
+
+ h1 {
+ font-size: 2.25rem;
+ line-height: 2.5rem;
+ }
+
+ h2 {
+ font-size: 1.875rem;
+ line-height: 2.25rem;
+ }
+
+ h3 {
+ font-size: 1.6rem;
+ line-height: 2rem;
+ }
+
+ h4 {
+ font-size: 1.4rem;
+ line-height: 1.75rem;
+ }
+
+ p,
+ li,
+ a {
+ color: #eee;
+ font-size: 1.3rem;
+ line-height: 2.1rem;
+ }
+
+ a:not(img) {
+ text-decoration: underline;
+ text-underline-offset: 4px;
+ }
+
+ strong {
+ font-weight: 600;
+ }
+
+ i {
+ font-style: italic;
+ }
+
+ p:not(:last-of-type) {
+ margin-bottom: 1.5rem;
+ }
+
+ img,
+ pre {
+ margin: 1.5rem 0;
+ }
+
+ ul {
+ margin-left: 1.5rem;
+ }
+
+ ul li {
+ list-style-type: disc;
+ list-style-position: outside;
+ &:not(:last-of-type) {
+ margin-bottom: 0.2rem;
+ }
+ }
+
+ code {
+ font-family: "JetBrains Mono", "Andale Mono WT", "Andale Mono",
+ "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono",
+ "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L",
+ "Courier New", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
+ "Noto Color Emoji", monospace;
+ font-size: 0.96rem;
+ letter-spacing: 0rem;
+ }
+
+ :not(pre) > code {
+ padding: 0.2rem 0.4rem;
+ }
+
+ pre {
+ padding: 0.8rem;
+ }
+
+ pre,
+ :not(pre) > code {
+ border-radius: 4px;
+ background-color: rgba(255, 255, 255, 0.1);
+ }
+}
+
+/* Code Highlighting Styles
+/* Based on PrismJS 1.25.0
+https://prismjs.com/download.html#themes=prism-twilight&languages=markup+css+clike+javascript+bash+c+cpp+rust+scss */
+
+code[class*="language-"],
+pre[class*="language-"] {
+ color: #ddd;
+ text-align: left;
+ white-space: pre;
+ word-spacing: normal;
+ word-break: normal;
+ word-wrap: normal;
+
+ -moz-tab-size: 4;
+ -o-tab-size: 4;
+ tab-size: 4;
+
+ -webkit-hyphens: none;
+ -moz-hyphens: none;
+ -ms-hyphens: none;
+ hyphens: none;
+}
+
+/* Code blocks */
+pre[class*="language-"] {
+ // Language specific code block styles
+}
+
+pre[class*="language-"]::-moz-selection {
+ /* Firefox */
+ background: #3b57bc33;
+}
+
+pre[class*="language-"]::selection {
+ /* Safari */
+ background: #3b57bc33;
+}
+
+/* Text Selection colour */
+pre[class*="language-"]::-moz-selection,
+pre[class*="language-"] ::-moz-selection,
+code[class*="language-"]::-moz-selection,
+code[class*="language-"] ::-moz-selection {
+ text-shadow: none;
+ background: #3b57bc33;
+}
+
+pre[class*="language-"]::selection,
+pre[class*="language-"] ::selection,
+code[class*="language-"]::selection,
+code[class*="language-"] ::selection {
+ text-shadow: none;
+ background: #3b57bc33;
+}
+
+.token.comment,
+.token.prolog,
+.token.doctype,
+.token.cdata {
+ color: #9cdcfe;
+}
+
+.token.punctuation {
+ opacity: 0.7;
+}
+
+.token.namespace {
+ opacity: 0.7;
+}
+
+.token.tag,
+.token.boolean,
+.token.number,
+.token.deleted {
+ color: #b5cea8;
+}
+
+.token.keyword,
+.token.property,
+.token.selector,
+.token.constant,
+.token.symbol,
+.token.builtin {
+ color: #0086c0; /* #F9EE98 */
+}
+
+.token.attr-name,
+.token.attr-value,
+.token.string,
+.token.char,
+.token.operator,
+.token.entity,
+.token.url,
+.language-css .token.string,
+.style .token.string,
+.token.variable,
+.token.inserted {
+ color: #4e94ce;
+}
+
+.token.atrule {
+ color: #4ec9b0;
+}
+
+.token.regex,
+.token.important {
+ color: #dcdcaa;
+}
+
+.token.important,
+.token.bold {
+ font-weight: bold;
+}
+.token.italic {
+ font-style: italic;
+}
+
+.token.entity {
+ cursor: help;
+}
+
+/* Markup */
+.language-markup .token.tag,
+.language-markup .token.attr-name,
+.language-markup .token.punctuation {
+ color: #4e94ce;
+}
+
+/* Make the tokens sit above the line highlight so the colours don't look faded. */
+.token {
+ position: relative;
+ z-index: 1;
+}
+
+// TODO: Style line highlights
+
+// .line-highlight.line-highlight {
+// background: hsla(0, 0%, 33%, 0.25); /* #545454 */
+// background: linear-gradient(to right, hsla(0, 0%, 33%, .1) 70%, hsla(0, 0%, 33%, 0)); /* #545454 */
+// border-bottom: 1px dashed hsl(0, 0%, 33%); /* #545454 */
+// border-top: 1px dashed hsl(0, 0%, 33%); /* #545454 */
+// margin-top: 0.75em; /* Same as .prismโs padding-top */
+// z-index: 0;
+// }
+
+// .line-highlight.line-highlight:before,
+// .line-highlight.line-highlight[data-end]:after {
+// background-color: hsl(215, 15%, 59%); /* #8794A6 */
+// color: hsl(24, 20%, 95%); /* #F5F2F0 */
+// }
@@ -0,0 +1,18 @@
+{
+ "name": "Zed โ a lightning fast, collaborative code editor written natively in Rust",
+ "short_name": "Zed",
+ "icons": [
+ {
+ "src": "/static/android-chrome-192x192.png",
+ "sizes": "192x192",
+ "type": "image/png"
+ },
+ {
+ "src": "/static/android-chrome-512x512.png",
+ "sizes": "512x512",
+ "type": "image/png"
+ }
+ ],
+ "theme_color": "#000",
+ "background_color": "#000"
+}
@@ -1,108 +1,136 @@
/* This file is compiled to /assets/styles/tailwind.css via script/tailwind */
-@import url('https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,400;0,700;1,400;1,700&display=swap');
-
-@font-face {
- font-family: 'Visby CF';
- src:
- url('/static/fonts/VisbyCF-Thin.woff2') format('woff2'),
- url('/static/fonts/VisbyCF-Thin.woff') format('woff');
- font-weight: 100;
- font-style: normal;
-}
+@import url("https://fonts.googleapis.com/css2?family=Spectral:ital,wght@0,200;0,300;1,200;1,300&display=swap");
+@import url("https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@0,100;0,300;0,600;1,100;1,300;1,600&display=swap");
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
-@font-face {
- font-family: 'Visby CF';
- src:
- url('/static/fonts/VisbyCF-Light.woff2') format('woff2'),
- url('/static/fonts/VisbyCF-Light.woff') format('woff');
- font-weight: 300;
- font-style: normal;
-}
-
-@font-face {
- font-family: 'Visby CF';
- src:
- url('/static/fonts/VisbyCF-Regular.woff2') format('woff2'),
- url('/static/fonts/VisbyCF-Regular.woff') format('woff');
- font-weight: 400;
- font-style: normal;
-}
+@layer base {
+ html {
+ font-size: 110%;
+ text-rendering: geometricPrecision;
+ }
-@font-face {
- font-family: 'Visby CF';
- src:
- url('/static/fonts/VisbyCF-Medium.woff2') format('woff2'),
- url('/static/fonts/VisbyCF-Medium.woff') format('woff');
- font-weight: 500;
- font-style: normal;
-}
+ @media screen and (min-width: 1024px) {
+ html {
+ font-size: 125%;
+ }
+ }
-@font-face {
- font-family: 'Visby CF';
- src:
- url('/static/fonts/VisbyCF-DemiBold.woff2') format('woff2'),
- url('/static/fonts/VisbyCF-DemiBold.woff') format('woff');
- font-weight: 600;
- font-style: normal;
-}
+ h1 {
+ @apply text-4xl;
+ @apply tracking-tighter;
+ }
+ h2 {
+ @apply text-3xl;
+ @apply tracking-tighter;
+ }
+ h3 {
+ @apply text-2xl;
+ @apply tracking-tighter;
+ }
+ h4 {
+ @apply text-xl;
+ }
-@font-face {
- font-family: 'Visby CF';
- src:
- url('/static/fonts/VisbyCF-Bold.woff2') format('woff2'),
- url('/static/fonts/VisbyCF-Bold.woff') format('woff');
- font-weight: 700;
- font-style: normal;
-}
+ .underline,
+ .hover\:underline:hover {
+ text-underline-offset: 6px;
+ }
-@font-face {
- font-family: 'Visby CF';
- src:
- url('/static/fonts/VisbyCF-ExtraBold.woff2') format('woff2'),
- url('/static/fonts/VisbyCF-ExtraBold.woff') format('woff');
- font-weight: 800;
- font-style: normal;
+ @media screen and (min-width: 1024px) {
+ .text-columns-2 {
+ column-count: 2;
+ column-gap: 3rem;
+ }
+
}
+ .site-nav a:not(.active) .nav-active-arrow {
+ display: none;
+ }
-@font-face {
- font-family: 'Visby CF';
- src:
- url('/static/fonts/VisbyCF-Heavy.woff2') format('woff2'),
- url('/static/fonts/VisbyCF-Heavy.woff') format('woff');
- font-weight: 900;
- font-style: normal;
-}
+ .site-nav a.active .nav-active-arrow {
+ display: flex;
+ }
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
+ .site-mobile-nav a.active {
+ font-weight: bold;
+ }
+
+ .text-columns-2 {
+ -webkit-column-break-inside: avoid;
+ page-break-inside: avoid;
+ break-inside: avoid;
+ }
-@layer utilities {
- @responsive {
- .bg-dotgrid-sm {
- background:
- linear-gradient(90deg, theme('colors.gray.50') 38px, transparent 1%) center,
- linear-gradient(theme('colors.gray.50') 38px, transparent 1%) center,
- theme('colors.gray.600');
- background-size: 40px 40px;
- }
-
- .bg-dotgrid-md {
- background:
- linear-gradient(90deg, theme('colors.gray.50') 58px, transparent 1%) center,
- linear-gradient(theme('colors.gray.50') 58px, transparent 1%) center,
- theme('colors.gray.600');
- background-size: 60px 60px;
- }
-
- .bg-dotgrid-lg {
- background:
- linear-gradient(90deg, theme('colors.gray.50') 88px, transparent 1%) center,
- linear-gradient(theme('colors.gray.50') 88px, transparent 1%) center,
- theme('colors.gray.600');
- background-size: 90px 90px;
- }
+ .text-columns-2 p {
+ break-inside: avoid;
+ }
+
+ .alternate-bg:nth-of-type(even) {
+ background-color: rgba(255,255,255,0.06);
+ }
+
+ /* div:not(.type-prose) code {
+ background-color: rgba(255,255,255,0.15);
+ padding: 0px 4px;
+ border-radius: 2px;
+ color: #eee;
+ } */
+
+ /* This fixes scrollbar jump */
+ @media screen and (min-width: 960px) {
+ html {
+ margin-left: calc(100vw - 100%);
+ margin-right: 0;
}
-}
+ }
+
+ :root {
+ --color: white;
+ --disabled: #959495;
+ }
+
+ .checkbox {
+ color: var(--color);
+ }
+
+ .checkbox--disabled {
+ color: var(--disabled);
+ }
+
+ .checkbox__control {
+ width: 30px;
+ height: 30px;
+ }
+
+ .checkbox__control svg {
+ transform: scale(0);
+ transform-origin: center center;
+ }
+
+ .checkbox__brackets {
+ left: -1px;
+ top: -1px;
+ }
+
+ .checkbox__input input {
+ opacity: 0;
+ width: 30px;
+ height: 30px;
+ }
+
+ .checkbox__input input:focus + .checkbox__control {
+ box-shadow: 0 0 0 2px #000, 0 0 0 4px #3b57bc99
+ }
+
+ .checkbox__input input:checked + .checkbox__control svg {
+ transform: scale(1);
+ }
+
+ .checkbox__input input:disabled + .checkbox__control {
+ color: var(--disabled);
+ }
+}
@@ -20,62 +20,80 @@
});
</script>
-<div class="bg-white">
- <div class="container py-4 px-8 md:px-12 mx-auto">
- <h1 class="text-xl font-bold border-b border-gray-300 mb-4">Users</h1>
- <table class="table" id="users">
- <tr>
- <th class="text-left pr-2">GitHub Login</th>
- <th class="text-left pr-2">Admin</th>
- <th></th>
- </tr>
- <form action="/users" method="post" class="m-0 mb-4">
- <tr>
- <td>
- <input name="github_login" type="text" class="border border-gray-300 p-1 mr-2 w-48"
- placeholder="@github_handle">
- </td>
- <td>
- <input type="checkbox" id="admin" name="admin" value="true">
- </td>
- <td class="text-right">
- <button class="p-1 w-20 text-white rounded-md bg-gray-600 hover:bg-black">Add</button>
- </td>
- </tr>
+<div class="h-screen text-white border-r border-white text-main font-extralight">
+ <div class="flex flex-row items-center justify-between p-5 border-b border-white pl-7 pr-7 admin-nav">
+ <h1 class="font-display font-extralight">Admin</h1>
+ <ul class="flex flex-row">
+ <li><a href="#userlist" class="mr-4 leading-relaxed no-underline lowercase text-main hover:underline">Users</a></li>
+ <li><a href="#signuplist" class="leading-relaxed no-underline lowercase text-main hover:underline">Signups</a></li>
+ </ul>
+ </div>
+
+ <h2 id="userlist" class="pt-10 mb-5 text-white pl-7 pr-7 font-display font-extralight">Users</h2>
+
+ <div class="flex flex-col w-full pb-5 font-mono text-xs" id="users">
+ <div class="flex flex-row pl-5 pr-10 font-bold">
+ <p class="w-1/3 p-2">Github Username</p>
+ <p class="w-32 p-2 text-center">Admin</p>
+ <p class="w-24 p-2"> </p>
+ </div>
+ <div class="flex flex-col pl-5 pr-10 text-gray-100">
+ <form action="/users" method="post" class="m-0">
+ <div class="flex flex-row items-center">
+ <p class="w-1/3 p-2"><input class="block w-full p-2 text-xs bg-transparent border border-white" type="text" name="github_login" required minlength="4" placeholder="@github_handle"></p>
+ <p class="w-32 p-2 text-center"><input type="checkbox" id="admin" name="admin" value="true"></p>
+ <p class="w-24 p-2"><button class="underline hover:no-underline">Add</button></p>
+ </div>
+ </form>
+ </div>
+ </div>
+
+ <div class="flex flex-col w-full pb-10 font-mono text-xs border-b border-white">
+ <div class="flex flex-row pl-5 pr-10 font-bold">
+ <p class="w-1/3 p-2">Github Username</p>
+ <p class="w-32 p-2 text-center">Admin</p>
+ <p class="w-24 p-2"> </p>
+ </div>
+ {{#each users}}
+ <div class="flex flex-col pl-5 pr-10 text-gray-100 alternate-bg">
+ <form action="/users/{{id}}/delete" method="post" class="m-0">
+ <div class="flex flex-row items-center">
+ <p class="w-1/3 p-2">{{github_login}}</p>
+ <p class="w-32 p-2 text-center"><input action="/users/{{id}}" type="checkbox" {{#if admin}}checked{{/if}}></p>
+ <p class="w-24 p-2"><button class="underline hover:no-underline">Remove</button></p>
+ </div>
</form>
+ </div>
+ {{/each}}
+ </div>
- {{#each users}}
- <tr>
- <form action="/users/{{id}}/delete" method="post">
- <td class="py-1">
- {{github_login}}
- </td>
- <td>
- <input action="/users/{{id}}" type="checkbox" {{#if admin}}checked{{/if}}>
- </td>
- <td class="text-right">
- <button class="p-1 w-20 rounded-md bg-gray-600 hover:bg-black text-white">Remove</button>
- </td>
- </form>
- </tr>
- {{/each}}
- </table>
+ <h2 class="pt-10 mb-5 text-white pl-7 pr-7 font-display font-extralight">Signups</h2>
- <h1 class="text-xl font-bold border-b border-gray-300 mb-4 mt-8">Signups</h1>
- <table class="table">
- {{#each signups}}
- <tr>
- <form action="/signups/{{id}}/delete" method="post">
- <td class="align-top">{{github_login}}</td>
- <td class="pl-4 align-top">{{email_address}}</td>
- <td class="pl-4 align-top">{{about}}</td>
- <td class="text-right">
- <button class="p-1 w-20 rounded-md bg-gray-600 hover:bg-black text-white">Remove</button>
- </td>
- </form>
- </tr>
- {{/each}}
- </table>
+ <div class="flex flex-col w-full pb-10 font-mono text-xs border-b border-white">
+
+ <div class="flex flex-row justify-between pl-5 pr-10 font-bold">
+ <p class="w-1/5 p-2">Email</p>
+ <p class="w-1/5 p-2">Github</p>
+ <p class="w-24 p-2 text-center">Releases</p>
+ <p class="w-24 p-2 text-center">Updates</p>
+ <p class="w-24 p-2 text-center">Community</p>
+ <p class="w-24 p-2 text-right">Remove</p>
+ </div>
+ {{#each signups}}
+ <div class="flex flex-col pb-1 pl-5 pr-10 text-gray-100 alternate-bg">
+ <form action="/signups/{{id}}/delete" method="post" class="m-0">
+ <div class="flex flex-row items-center justify-between">
+ <p class="w-1/5 p-2 pb-1">{{email_address}}</p>
+ <p class="w-1/5 p-2 pb-1">{{github_login}}</p>
+ <p class="w-24 p-2 pb-1 text-center">{{#if wants_releases}}[โ]{{else}}[ ]{{/if}}</p>
+ <p class="w-24 p-2 pb-1 text-center">{{#if wants_updates}}[โ]{{else}}[ ]{{/if}}</p>
+ <p class="w-24 p-2 pb-1 text-center">{{#if wants_community}}[โ]{{else}}[ ]{{/if}}</p>
+ <p class="w-24 p-2 pb-1 text-right"><button class="text-lg text-gray-500 hover:text-white">ร</button></p>
+ </div>
+ </form>
+ <p class="max-w-full p-2 pt-0 overflow-hidden leading-normal text-gray-400 max-h-5 whitespace-nowrap overflow-ellipsis" title="{{about}}">{{about}}</p>
+ </div>
+ {{/each}}
</div>
</div>
{{/layout}}
@@ -0,0 +1,107 @@
+{{#> layout }}
+
+<div class="max-w-screen-lg p-5 mx-auto font-extralight text-main lg:p-20">
+ <h1 class="mb-10 font-display font-extralight">Weโre building a community of passionate developers & advocates.</h1>
+
+ <p class="mt-5 leading-relaxed">If you would like to get involved early, sign up below and we will let you know when our developer community opens!</p>
+
+ <form action="/signups" method="post" class="max-w-screen-md mt-10">
+ <ul>
+ <li class="flex flex-row mt-5 text-lg">
+ <span class="relative w-6 mt-2 mr-5 checkbox__input">
+ <span class="absolute z-0 block checkbox__brackets">
+ <svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg" focusable="false">
+ <path d="M8 0H0V32H8V31H1V1H8V0Z" fill="white"/>
+ <path d="M24 31H31V1H24V0H32V32H24V31Z" fill="white"/>
+ </svg>
+ </span>
+ <input class="absolute z-10" type="checkbox" value=true name="wants_releases">
+ <span class="flex items-center justify-center checkbox__control">
+ <svg width="12" height="11" viewBox="0 0 12 11" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false">
+ <path d="M1 6.38905L4.33333 9.72239L11 0.833496" fill='none' stroke='currentColor' stroke-width="1" stroke-linecap="round"/>
+ </svg>
+ </span>
+ </span>
+
+ <div class="flex-1 mt-1">
+ <label for="wants_releases">
+ <span class="radio__label">Let me know when there is a beta release I can try.</span>
+ </label>
+ <p class="text-sm leading-6 text-gray-300">
+ We'll put you on the list to play with an early beta and let you know when Zed launches.
+ </p>
+ </div>
+ </li>
+ <li class="flex flex-row mt-5 text-lg">
+ <span class="relative w-6 mt-2 mr-5 checkbox__input">
+ <span class="absolute z-0 block checkbox__brackets">
+ <svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg" focusable="false">
+ <path d="M8 0H0V32H8V31H1V1H8V0Z" fill="white"/>
+ <path d="M24 31H31V1H24V0H32V32H24V31Z" fill="white"/>
+ </svg>
+ </span>
+
+ <input class="absolute z-10" type="checkbox" value=true name="wants_updates">
+ <span class="flex items-center justify-center checkbox__control">
+ <svg width="12" height="11" viewBox="0 0 12 11" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false">
+ <path d="M1 6.38905L4.33333 9.72239L11 0.833496" fill='none' stroke='currentColor' stroke-width="1" stroke-linecap="round"/>
+ </svg>
+ </span>
+ </span>
+
+ <div class="flex-1 mt-1">
+ <label for="wants_updates">
+ <span class="radio__label">Iโm interested in following Zed's development</span>
+ </label>
+ <p class="text-sm leading-6 text-gray-300">
+ We'll send you occasional updates about our progress and share what we're learning along the way.
+ </p>
+ </div>
+ </li>
+ <li class="flex flex-row mt-5 text-lg">
+ <span class="relative w-6 mt-2 mr-5 checkbox__input">
+ <span class="absolute z-0 block checkbox__brackets">
+ <svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg" focusable="false">
+ <path d="M8 0H0V32H8V31H1V1H8V0Z" fill="white"/>
+ <path d="M24 31H31V1H24V0H32V32H24V31Z" fill="white"/>
+ </svg>
+ </span>
+
+ <input class="absolute z-10" type="checkbox" value=true name="wants_community">
+
+ <span class="flex items-center justify-center checkbox__control">
+ <svg width="12" height="11" viewBox="0 0 12 11" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false">
+ <path d="M1 6.38905L4.33333 9.72239L11 0.833496" fill='none' stroke='currentColor' stroke-width="1" stroke-linecap="round"/>
+ </svg>
+ </span>
+ </span>
+
+ <div class="flex-1 mt-1">
+ <label for="wants_community">
+ <span class="radio__label">I want to test early releases & join the Zed community</span>
+ </label>
+ <p class="text-sm leading-6 text-gray-300">
+ We'll add you to the waitlist to receive early builds and ask you to help us by testing them out.
+ </p>
+ </div>
+ </li>
+ </ul>
+ <div class="lg:flex lg:flex-row lg:mt-10">
+ <input class="block w-full p-5 mt-10 bg-transparent border border-white font-extralight lg:mt-0 lg:mr-5" type="text" id="form-email" name="email_address" required minlength="4" placeholder="Your email">
+
+ <input class="block w-full p-5 mt-5 bg-transparent border border-white font-extralight lg:mt-0" type="text" id="form-gh" name="github_login" placeholder="Github Username">
+ </div>
+
+ <textarea class="block w-full h-40 p-5 mt-5 leading-relaxed bg-transparent border border-white font-extralight" type="text" name="about" placeholder="Tell us a bit about yourself and your interest in Zed. What does your dream code-editing experience look like? What do you love or hate about your current editor?"></textarea>
+
+ <button class="block mt-10 text-lg opacity-100 font-extralight hover:opacity-80">
+ Join the waitlist →
+ </button>
+
+ <p class="mt-10 text-sm leading-relaxed text-gray-500">
+ We're not gonna spam you—You can expect an email every 1 to 3 months from us if you sign up for updates, and occasional emails about beta releases.
+ </p>
+ </form>
+</div>
+
+{{/layout}}
@@ -1,7 +1,15 @@
{{#> layout }}
-<div class="bg-white py-8">
- <div class="container mx-auto my-16 px-8 md:px-12 text-2xl md:text-4xl">
- Sorry, we encountered a {{status}} error: {{reason}}.
- </div>
+
+<div class="max-w-screen-lg p-10 mx-auto text-main font-extralight lg:p-20">
+ <article class="max-w-xl">
+ <h1 class="mb-5 text-4xl text-white font-display font-extralight">Sorry!</h1>
+ <p class="mb-5 leading-relaxed">
+ Looks like we encountered a {{status}} error: {{reason}}
+ </p>
+ <p class="leading-relaxed">
+ Try refreshing or going <a class="underline hover:no-underline" href="/">home</a>.
+ </p>
+ </article>
</div>
+
{{/layout}}
@@ -1,69 +1,104 @@
{{#> layout }}
-{{#if releases}}
-
-<div class="bg-white">
- <div class="container mx-auto py-12 px-8 md:px-12">
- {{#each releases}}
- <div class="md:flex md:flex-row mb-32 md:mb-12">
- <div class="font-display mb-8 md:mb-0 md:text-right w-48">
- <div class="text-2xl font-bold whitespace-nowrap">
- VERSION {{name}}
- </div>
- <a class="text-md underline text-yellow-600 hover:text-yellow-700"
- href="/releases/{{tag_name}}/{{assets.0.name}}">
- DOWNLOAD
- </a>
- </div>
- <div
- class="prose prose-lg xl:prose-xl border-t md:border-t-0 pt-8 md:border-l border-gray-400 md:ml-8 md:pl-8 md:pt-0 xl:ml-16 xl:pl-16 max-w-5xl font-body">
- {{{body}}}
- </div>
- </div>
- {{/each}}
- </div>
-</div>
-{{else}}
+<div class="max-w-screen-lg p-5 mx-auto text-gray-200 font-extralight text-main lg:p-20">
+ <article class="">
+ <h1 class="mb-10 text-4xl leading-tight text-white font-display font-extralight">Introducing Zed—A lightning-fast, collaborative code editor written in Rust.</h1>
+ <p class="mt-5 leading-relaxed">
+ We think thereโs a better way to write code, and it starts with the following assumptions:
+ </p>
-<div class="bg-dotgrid-sm md:bg-dotgrid-md lg:bg-dotgrid-lg">
- <img src="/static/svg/hero.svg" class="container mx-auto px-8 md:px-12 py-16 md:py-24 lg:py-32" />
-</div>
+ <h3 class="mt-10 leading-tight text-white font-display font-extralight">Mission-critical tools should be hyper-responsive.</h3>
+
+ <p class="mt-3 leading-relaxed">
+ When you move the cursor or type a character, you should see pixels on the next refresh of your display—every time. Even sub-perceptual pauses add up over the course of a day to create unnecessary stress.
+ </p>
-<div class="container mx-auto py-24 lg:py-32 px-8 md:px-12 lg:flex lg:flex-row lg:items-center">
- <div class="prose prose-xl md:prose-2xl text-gray-50 prose-gray-50 w-full lg:w-1/2">
- <p>
- Weโre the team behind GitHubโs Atom text editor, and weโre building something new:
+ <p class="mt-5 leading-relaxed">
+ Joyful coding starts with an editor that stays out of your way.
</p>
+
+ <h3 class="mt-10 leading-tight text-white font-display font-extralight">Real-time collaboration produces better software.</h3>
- <p>
- <b>Zed</b> is a fully-native desktop code editor focused on high performance,
- clean design, and seamless collaboration.
+ <p class="mt-3 leading-relaxed">
+ Pull requests have their place, but sometimes you just want to code together. Itโs more fun than code review, builds trust between colleagues, and itโs one of the best ways to distribute knowledge through a team. But it has to be easy.
</p>
+
+ <p class="mt-5 leading-relaxed">
+ If you want someoneโs perspective on a piece of code, it should be as easy as sending a message to pull them into your working copy and start coding.
+ </p>
+
+ <h3 class="mt-10 leading-tight text-white font-display font-extralight">Conversations about software should happen close to the code.</h3>
- <p>
- Weโre in early development, but weโd like to build a small community of developers who care deeply about
- their tools and are willing to give us feedback. We'll be sharing alpha builds with community members and
- telling our story along the way.
+ <p class="mt-3 leading-relaxed">
+ If you want to talk about code on GitHub you have to commit and push it first, and pasting code into a chat application sucks.
</p>
- <p>
- If youโre interested in joining us, please let us know.
+ <p class="mt-5 leading-relaxed">
+ By treating keystrokes as the fundamental unit of change and integrating chat into the editor, we can make it easy to have a conversation about any line of code in any working copyโwhether it was committed last year or just typed ten seconds ago.
+ </p>
+
+ <h3 class="mt-10 leading-tight text-white font-display font-extralight">Our goal is to make you as efficient as possible.</h3>
+
+ <p class="mt-3 leading-relaxed">
+ If youโre living in a tool for hours every day, you want it to disappear. Every pixel must carry its weight, and the software youโre creating should always be the focus. So we constantly ask ourselves how we can maximize signal and minimize noise.
</p>
- </div>
-
- <form class="my-16 lg:my-0 lg:ml-16 flex-1 text-xl md:text-2xl" action="/signups" method="post">
- <input name="github_login" placeholder="@github_handle"
- class="w-3/5 xl:w-1/2 p-3 mb-8 block bg-gray-50 placeholder-gray-500">
- <input name="email_address" placeholder="email@addre.ss"
- class="w-4/5 xl:w-3/4 p-3 my-8 block bg-gray-50 placeholder-gray-500">
- <textarea name="about" class="block w-full xl:w-full h-48 p-3 my-8 bg-gray-50 placeholder-gray-500 my-6"
- placeholder="Please tell us a bit about you and why you're interested in Zed. What code editor do you use today? What do you love and hate about it?"></textarea>
- <button
- class="p-4 rounded-md text-gray-50 bg-gray-500 inline-block cursor-pointer hover:bg-gray-400 font-display">
- ENGAGE
- </button>
- </form>
+
+ <p class="mt-5 leading-relaxed">
+ Do we need an icon? Do we need a gradient? We all want to achieve mastery. Our goal is to find the most efficient way to accomplish each coding task and make it accessible. We will never dumb things down.
+ </p>
+
+ <p class="mt-10 mb-10 leading-relaxed">———</p>
+
+ <h2 class="mt-16 mb-5 leading-tight text-white font-display font-extralight">Under the hood</h2>
+
+ <article class="leading-relaxed">
+ <h3 class="mt-10 leading-tight text-white font-display font-extralight">Building in Rust</h3>
+ <p class="mt-3">Rust offers expressivity and developer productivity rivaling languages that depend on a VM, while simultaneously offering the control required to fully utilize the underlying hardware.</p>
+
+ <p class="mt-5">Rustโs unique ownership model is a challenge at the beginning, but once you internalize it, you can write extremely efficient multi-core code without fear of invoking undefined behavior.</p>
+
+ <p class="mt-5">It also makes it straightforward to call directly into the C-based APIs of the operating system. Rust makes it possible for a small team to build a complex product quickly, and Zed wouldnโt have been possible without it.</p>
+
+ <p class="mt-5">In the past, to write software with this performant you would need to use C++. Rust, for the first time, enables us to write software at that level as a very small team.</p>
+ </article>
+
+ <article class="leading-relaxed">
+ <h3 class="mt-10 mb-4 leading-tight text-white font-display font-extralight">A new GPU-powered UI framework</h3>
+ <p class="mt-3">We originally planned to use Electron as a convenient means of delivering a cross-platform GUI for Zed, while building the core of the application in Rust. But at every turn, we found that web technology was the bottleneck in achieving amazing performance. Finally, we decided to take full control and simply build a GPU-powered UI framework that met our needs.</p>
+
+ <p class="mt-5"></p>We call it GPUI.</p>
+
+ <p class="mt-5">We took a lot of inspiration from Mozillaโs Webrender project. The key insight was that modern graphics hardware can render complex 3D graphics at high frame rates, so why not use it to render relatively simple 2D user interfaces with an immediate mode architecture? </p>
+
+ <p class="mt-5">Rustโs ownership model required us to rethink much of what we learned in other UI programming paradigms, but the result is a framework thatโs productive to use and remarkably easy to reason about.</p>
+
+ <p class="mt-5">Itโs liberating to control every pixel, and itโs a rush to push those pixels at lightning speed.</p>
+ </article>
+
+ <article class="leading-relaxed">
+ <h3 class="mt-10 mb-4 leading-tight text-white font-display font-extralight">Conflict-free replicated data types</h3>
+
+ <p class="mt-3">Real-time collaborative editing presents the illusion that multiple people are editing the same buffer. In reality, each collaborator maintains their own personal replica of the buffer to which they can apply local edits immediately without network latency.</p>
+
+ <p class="mt-5">After being applied locally, edits are transmitted to collaborators over the network, whose copies may have also changed in the meantime. This means that as participants edit together, their replicas continuously diverge and reconverge. Turns out this is a tricky problem.</p>
+
+ <p class="mt-5">To solve it, weโre using conflict-free replicated data types, which have emerged in the last decade as a general framework for achieving eventual consistency in a variety of circumstances.</p>
+
+ <p class="mt-5">Making Zedโs buffers CRDTs allows for collaborative editing, but it also helps us reason about concurrent change so that we can push work into background threads and keep the UI thread responsive.</p>
+ </article>
+
+ <article class="leading-relaxed">
+ <h3 class="mt-10 mb-4 leading-tight text-white font-display font-extralight">Tree-sitter</h3>
+
+ <p class="mt-3">We plan to integrate with the Language Server Protocol to support advanced IDE features, but we also think itโs important for a code editor to have a rich, native understanding of syntax.</p>
+
+ <p class="mt-5">Thatโs why we built Tree-sitter, a fast, general, incremental parsing library that can provide Zed with syntax trees for over 50 languages. Tree-sitter already powers production functionality on GitHub, and weโll use it to deliver syntactically-precise syntax highlighting, tree-based selection and cursor navigation, robust auto-indent support, symbolic navigation, and more.</p>
+ </article>
+
+ <p class="mt-10 mb-10 leading-relaxed">———</p>
+
+ <p class="mt-5 leading-relaxed">Excited about what we are building? <a class="underline hover:no-underline" href="/community">Sign up for updates</a> to follow along in our development process.</p>
+ </article>
</div>
-{{/if}}
{{/layout}}
@@ -1,62 +1,193 @@
<html>
<head>
- <link rel="icon" href="/static/images/favicon.png">
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=0.86, maximum-scale=5.0, minimum-scale=0.86">
+
+ <link rel="mask-icon" href="/static/images/favicon.svg" color="#000000">
+ <link rel="alternate icon" type="image/png" href="/static/images/favicon.png">
+ <link rel="shortcut icon" href="/static/images/favicon.svg">
+ <link rel="apple-touch-icon" sizes="180x180" href="/static/images/apple-touch-icon.png">
+ <link rel="manifest" href="/static/site.webmanifest">
+
<link rel="stylesheet" href="/static/styles.css">
- <title>Zed Industries</title>
-
-
- <script>
- window.addEventListener("DOMContentLoaded", function () {
- let avatar = document.getElementById("avatar");
- let sign_out = document.getElementById("sign_out");
- if (avatar && sign_out) {
- avatar.addEventListener("click", function (event) {
- sign_out.classList.toggle("hidden");
- event.stopPropagation();
- });
- document.addEventListener("click", function (event) {
- sign_out.classList.add("hidden");
- });
- }
- });
- </script>
+ <link rel="stylesheet" href="/static/prose.css">
+
+ <link rel="mask-icon" href="/static/images/safari-pinned-tab.svg" color="#000000">
+ <meta name="msapplication-TileColor" content="#000000">
+ <meta name="msapplication-config" content="/static/browserconfig.xml">
+ <meta name="theme-color" content="#000">
+
+ <!-- Open Graph stuff -->
+ <meta name="twitter:card" content="summary" />
+ <meta property="twitter:image" content="/static/images/zed-twitter-image.png" />
+ <meta name="twitter:image:alt" content="An image of Zed's logo, sharp Z inside a circle, in white on a black background." />
+ <meta property="og:url" content="https://zed.dev/" />
+ <meta property="og:title" content="Introducing Zed" />
+ <meta property="og:description" content="A lightning-fast, collaborative code editor written in Rust." />
+ <meta property="og:image" content="/static/images/zed-og-image.png" />
+ <meta property="og:type" content="website" />
+
+ <title>Zed</title>
+
</head>
-<body class="font-body bg-black">
- <div class="text-lg text-gray-50">
- <div class="container mx-auto flex flex-row items-center py-4 px-8 md:px-12 font-display">
- <a href="/" class="font-display">
- <span class="font-black">ZED</span><span class="font-light" style="padding-left: 1px">INDUSTRIES</span>
- </a>
- <div class="flex-1"></div>
- <a href="/team" class="text-sm mr-4 hover:underline">
- Team
+<body class="box-border font-light bg-black font-body text-main">
+ <main class="container flex flex-col mx-auto lg:bg-white lg:flex-none lg:grid lg:min-h-full lg:grid-cols-4 max-w-screen-2xl lg:gap-x-px text-gray-50">
+ <nav id="mobile-nav" class="p-5 pt-10 pb-5 bg-black font-extralight lg:hidden site-mobile-nav">
+ <div class="flex flex-row justify-between">
+ <a href="/" class="block hover:opacity-80">
+ <svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M16 0C7.16344 0 0 7.16344 0 16C0 24.8366 7.16344 32 16 32C24.8366 32 32 24.8366 32 16C32 7.16344 24.8366 0 16 0ZM16 4C9.37258 4 4 9.37258 4 16C4 22.6274 9.37258 28 16 28C22.6274 28 28 22.6274 28 16C28 9.37258 22.6274 4 16 4Z" fill="white"/>
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M10 10L23.5 10L14.875 19H19L22 22H8.5L17.125 13H13L10 10Z" fill="white"/>
+ </svg>
+ </a>
+ <div class="flex flex-row">
+ {{#if current_user}}
+
+ <form id="sign_out" action="/sign_out" method="post" class="inline m-0 text-gray-500 font-extralight">
+ <button class="text-lg leading-relaxed โ no-underline font-extralight hover:underline">Log Out</button>
+ </form>
+
+ {{else}}
+
+ <!-- Otherwise let user log in -->
+ <a href=" /sign_in"
+ class="text-lg leading-relaxed text-gray-500">
+ Log in
+ </a>
+ {{/if}}
+ </div>
+ </div>
+
+ <div class="flex flex-row flex-wrap mt-10">
+ <a href="/" class="mr-2 text-lg leading-relaxed">
+ Meet Zed <span class="pt-1 mr-1 text-lg text-gray-500">ยท</span>
+ </a>
+ <a href="/team" class="mr-2 text-lg leading-relaxed">
+ The Team <span class="pt-1 mr-1 text-lg text-gray-500">ยท</span>
+ </a>
+
+ <a href="/community" class="mr-2 text-lg leading-relaxed">
+ Waitlist
+ </a>
+ {{#if current_user}}
+ <a href="/releases" class="mr-2 text-lg leading-relaxed">
+ <span class="pt-1 mr-1 text-lg text-gray-500">ยท</span> Releases
+ </a>
+
+ {{#if current_user.is_admin }}
+ <a href="/admin" class="inline-block mr-2 text-lg leading-relaxed">
+ <span class="pt-1 mr-1 text-lg text-gray-500">ยท</span> Manage Users
+ </a>
+ {{/if}}
+ {{/if}}
+ </div>
+
+ <!-- If user is logged in AND -->
+ <!-- If user is at least an insider -->
+ {{#if current_user}}
+
+ <!-- AND If user is an admin -->
+
+
+ {{/if}}
+ </nav>
+
+ <nav id="nav" class="hidden p-10 pt-20 bg-black lg:flex lg:flex-col font-extralight site-nav">
+ <a href="/" class="block hover:opacity-80">
+ <svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M16 0C7.16344 0 0 7.16344 0 16C0 24.8366 7.16344 32 16 32C24.8366 32 32 24.8366 32 16C32 7.16344 24.8366 0 16 0ZM16 4C9.37258 4 4 9.37258 4 16C4 22.6274 9.37258 28 16 28C22.6274 28 28 22.6274 28 16C28 9.37258 22.6274 4 16 4Z" fill="white"/>
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M10 10L23.5 10L14.875 19H19L22 22H8.5L17.125 13H13L10 10Z" fill="white"/>
+ </svg>
</a>
+ <div class="flex flex-col mt-10 font-mono">
+ <a href="/" class="relative mt-2 text-base no-underline lowercase hover:underline">
+ <span class="absolute items-center justify-center hidden h-full align-middle nav-active-arrow -left-7">
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M10.1594 12.1606C10.0309 12.0567 9.96803 11.8899 9.96803 11.7204C9.96803 11.5509 10.0321 11.3846 10.1603 11.2564L12.7596 8.65813H1.6562C1.29392 8.65813 1 8.36284 1 7.97732C1 7.63829 1.29392 7.34573 1.6562 7.34573H12.7596L10.1613 4.74747C9.90501 4.49114 9.90501 4.07596 10.1613 3.81949C10.4177 3.56303 10.8328 3.56317 11.0893 3.81949L14.8078 7.53794C15.0641 7.79427 15.0641 8.20945 14.8078 8.46592L11.0893 12.1844C10.832 12.4395 10.4164 12.4395 10.1594 12.1606Z" fill="white"/></svg>
+ </span>
+ Meet Zed
+ </a>
+ <a href="/team" class="relative mt-2 text-base no-underline lowercase hover:underline">
+ <span class="absolute items-center justify-center hidden h-full align-middle nav-active-arrow -left-7">
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M10.1594 12.1606C10.0309 12.0567 9.96803 11.8899 9.96803 11.7204C9.96803 11.5509 10.0321 11.3846 10.1603 11.2564L12.7596 8.65813H1.6562C1.29392 8.65813 1 8.36284 1 7.97732C1 7.63829 1.29392 7.34573 1.6562 7.34573H12.7596L10.1613 4.74747C9.90501 4.49114 9.90501 4.07596 10.1613 3.81949C10.4177 3.56303 10.8328 3.56317 11.0893 3.81949L14.8078 7.53794C15.0641 7.79427 15.0641 8.20945 14.8078 8.46592L11.0893 12.1844C10.832 12.4395 10.4164 12.4395 10.1594 12.1606Z" fill="white"/></svg>
+ </span>
+ The Team
+ </a>
+ <a href="/community" class="relative mt-2 text-base no-underline lowercase hover:underline">
+ <span class="absolute items-center justify-center hidden h-full align-middle nav-active-arrow -left-7">
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M10.1594 12.1606C10.0309 12.0567 9.96803 11.8899 9.96803 11.7204C9.96803 11.5509 10.0321 11.3846 10.1603 11.2564L12.7596 8.65813H1.6562C1.29392 8.65813 1 8.36284 1 7.97732C1 7.63829 1.29392 7.34573 1.6562 7.34573H12.7596L10.1613 4.74747C9.90501 4.49114 9.90501 4.07596 10.1613 3.81949C10.4177 3.56303 10.8328 3.56317 11.0893 3.81949L14.8078 7.53794C15.0641 7.79427 15.0641 8.20945 14.8078 8.46592L11.0893 12.1844C10.832 12.4395 10.4164 12.4395 10.1594 12.1606Z" fill="white"/></svg>
+ </span>
+ Waitlist
+ </a>
+ </div>
+
+ <!-- If user is logged in AND -->
+ <!-- If user is at least an insider -->
{{#if current_user}}
+ <div class="flex flex-col mt-10 font-mono">
+ <p class="text-xs tracking-widest uppercase opacity-50">Insiders</p>
+ <a href="/releases" class="relative mt-2 text-base no-underline lowercase hover:underline">
+ <span class="absolute items-center justify-center hidden h-full align-middle nav-active-arrow -left-7">
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M10.1594 12.1606C10.0309 12.0567 9.96803 11.8899 9.96803 11.7204C9.96803 11.5509 10.0321 11.3846 10.1603 11.2564L12.7596 8.65813H1.6562C1.29392 8.65813 1 8.36284 1 7.97732C1 7.63829 1.29392 7.34573 1.6562 7.34573H12.7596L10.1613 4.74747C9.90501 4.49114 9.90501 4.07596 10.1613 3.81949C10.4177 3.56303 10.8328 3.56317 11.0893 3.81949L14.8078 7.53794C15.0641 7.79427 15.0641 8.20945 14.8078 8.46592L11.0893 12.1844C10.832 12.4395 10.4164 12.4395 10.1594 12.1606Z" fill="white"/></svg>
+ </span>
+ Releases
+ </a>
+ </div>
+
+ <!-- AND If user is an admin -->
{{#if current_user.is_admin }}
- <a href="/admin" class="text-sm mr-4 hover:underline">
- Admin
- </a>
+ <div class="flex flex-col mt-10 font-mono">
+ <p class="text-xs tracking-widest uppercase opacity-50">Admin</p>
+ <a href="/admin" class="relative inline-block mt-2 text-base no-underline lowercase hover:underline">
+ <span class="absolute items-center justify-center hidden h-full align-middle nav-active-arrow -left-7">
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M10.1594 12.1606C10.0309 12.0567 9.96803 11.8899 9.96803 11.7204C9.96803 11.5509 10.0321 11.3846 10.1603 11.2564L12.7596 8.65813H1.6562C1.29392 8.65813 1 8.36284 1 7.97732C1 7.63829 1.29392 7.34573 1.6562 7.34573H12.7596L10.1613 4.74747C9.90501 4.49114 9.90501 4.07596 10.1613 3.81949C10.4177 3.56303 10.8328 3.56317 11.0893 3.81949L14.8078 7.53794C15.0641 7.79427 15.0641 8.20945 14.8078 8.46592L11.0893 12.1844C10.832 12.4395 10.4164 12.4395 10.1594 12.1606Z" fill="white"/></svg>
+ </span>
+ Manage
+ </a>
+ </div>
{{/if}}
- <div class="relative">
- <img id="avatar" src="{{current_user.avatar_url}}"
- class="w-8 rounded-full border-gray-400 border cursor-pointer" />
- <form id="sign_out" action="/sign_out" method="post"
- class="hidden absolute mt-1 right-0 bg-black rounded border border-gray-400 text-center text-sm p-2 px-4 whitespace-nowrap">
- <button class="hover:underline">Sign out</button>
+
+ <div class="mt-10">
+ <p class="text-base no-underline">@{{current_user.github_login}}</p>
+ <form id="sign_out" action="/sign_out" method="post">
+ <button class="mt-2 text-xs no-underline lowercase opacity-50 font-extralight hover:opacity-100">Sign out</button>
</form>
</div>
+
{{else}}
+ <!-- Otherwise let user log in -->
<a href=" /sign_in"
- class="text-sm align-middle p-1 px-2 rounded-md border border-gray-50 cursor-pointer hover:bg-gray-800">
+ class="mt-10 text-base text-gray-400 no-underline lowercase hover:underline">
Log in
</a>
{{/if}}
- </div>
- </div>
+ </nav>
- {{> @partial-block}}
+ <div class="col-span-3 pb-20 bg-black">
+ {{> @partial-block}}
+ </div>
+ </main>
+ <script src="/static/prism.js"></script>
</body>
+<script>
+ const nav = document.getElementById('nav');
+ const links = nav.getElementsByTagName('a');
+ const currentPath = window.location.pathname;
+ for (const link of links) {
+ if (link.getAttribute('href') === currentPath) {
+ link.classList.add('active');
+ }
+ }
+ const mnav = document.getElementById('mobile-nav');
+ const mlinks = mnav.getElementsByTagName('a');
+ const mcurrentPath = window.location.pathname;
+ for (const mlink of mlinks) {
+ if (mlink.getAttribute('href') === mcurrentPath) {
+ mlink.classList.add('active');
+ }
+ }
+</script>
+
</html>
@@ -0,0 +1,35 @@
+{{#> layout }}
+
+<div class="max-w-screen-lg p-5 mx-auto font-extralight text-main lg:p-20">
+ {{#if current_user}}
+ <h1 class="mb-10 font-display font-extralight">Releases</h1>
+ <p class="mt-5 leading-relaxed">Zed is currently only available on macOS.</p>
+ <p class="mt-5 mb-10 leading-relaxed">We are frequently shipping new versions, check back regularly to get the most recent version.</p>
+
+ {{#if releases}}
+
+ {{#each releases}}
+ <article id="{{name}}" class="mb-20">
+ <h3 class="mb-2 font-display font-extralight">{{name}}</h3>
+ <div>
+ <a class="text-sm underline opacity-80 hover:opacity-100" href="/releases/{{tag_name}}/{{assets.0.name}}">Download</a> ยท <a class="text-sm underline opacity-50 hover:opacity-100" href="https://github.com/zed-industries/zed/releases/tag/{{tag_name}}">Release Notes</a>
+ </p>
+ <div class="mt-10 type-prose">
+ {{{body}}}
+ </div>
+ <div class="mt-5">
+ <p>———</p>
+ </div>
+ </article>
+ {{/each}}
+ {{/if}}
+
+ {{else}}
+
+ <h1 class="mb-10 font-display font-extralight">Hold it!</h1>
+ <p class="mt-5 leading-relaxed">You can't access this without <a href=" /sign_in" class="mt-5 leading-relaxed underline">logging in</a>.</p>
+ <p class="mt-5 leading-relaxed">Try <a href="/community" class="mt-5 leading-relaxed underline">joining our community</a> to get access to updates & releases.</p>
+ {{/if}}
+</div>
+
+{{/layout}}
@@ -1,19 +1,18 @@
{{#> layout }}
-<div class="bg-gray-50 py-10 text-black">
- <div class="container mx-auto px-8 md:px-12">
- <div class=" text-6xl font-black mb-8">
- THANKS
- </div>
- <div class="text-xl max-w-md">
- <p class="mb-8">
- Thanks a ton for your interest! We'll add you to our list and let you know when we have something ready
- for you to try out.
- </p>
- <p>
- <a href="/" class="font-bold text-yellow-600 hover:text-yellow-700">Back to /</a>
- </p>
- </div>
- </div>
+<div class="max-w-screen-lg p-10 mx-auto font-extralight text-main lg:p-20">
+ <h1 class="mb-10 font-display font-extralight">Thanks for signing up!</h1>
+ <p class="mt-5 leading-relaxed">
+ We'll add you to our list and let you know when we have something ready for you to try out.
+ </p>
+
+ <p class="mt-5 leading-relaxed">
+ Thanks for your interest!
+ </p>
+
+ <a href="/" class="block mt-10 text-lg font-extralight underline opacity-100 hover:opacity-80">
+ Back to Home
+ </a>
</div>
-{{/layout}}
+
+{{/layout}}
@@ -1,62 +1,160 @@
{{#> layout }}
-<div class="bg-white">
- <div class="container mx-auto py-12 px-8 md:px-12 lg:flex lg:flex-row">
- <div class="mb-16 lg:mb-0 lg:flex-1 lg:mr-8 xl:mr-16">
- <img src="https://github.com/nathansobo.png?size=200" class="mx-auto mb-4 h-28 rounded-full">
- <div>
- <a href="https://github.com/nathansobo"
- class="block text-center mb-4 font-display text-2xl font-bold whitespace-nowrap hover:underline">
- NATHAN SOBO
- </a>
- <div class="prose md:prose-lg lg:prose xl:prose-lg">
- Nathan joined GitHub in late 2011 to build the <a href="https://atom.io">Atom text editor</a>, and
- he led the Atom team until 2018. He also co-led development of <a
- href="https://teletype.atom.io">Teletype for Atom</a>, pioneering one of the first production
- uses of conflict-free replicated data types for collaborative text editing. He's been dreaming about
- building the worldโs best text editor since he graduated from college, and is excited to finally
- have
- the knowledge, tools, and resources to achieve this vision.
+<div class="max-w-screen-lg p-5 mx-auto font-extralight text-main lg:p-20">
+ <h1 class="mb-10 text-4xl text-white font-display font-extralight">
+ We think thereโs a better way to write code—and we've been working for more than a decade to bring it into existence.
+ </h1>
+ <p class="mt-5 leading-relaxed">
+ Our first attempt was Atom, which we loved like a child but which ultimately fell short of our original vision. When we created Electron in 2012 to serve as Atom's runtime, there weren't a lot of great options for building cross-platform desktop apps.
+ </p>
+ <p class="mt-5 leading-relaxed">
+ Had we tried to write Atom in C or C++, it never would have shipped, and we loved the idea of developers extending their editor with the familiar tools of JavaScript, HTML, and CSS.
+ </p>
+ <p class="mt-5 leading-relaxed">
+ In the end, however, we reached the conclusion that the editor we wanted to use couldn't be built in a single-threaded scripting language. It was time to start over. Now we're back from the wilderness, this time with the knowledge and tools we need to execute without compromise.
+ </p>
+ <p class="mt-5 leading-relaxed">
+ We're leveraging Rust, conflict-free replicated data types, and every core of your CPU and GPU to deliver an editor that will make coding more productive, fun, and collaborative. We look forward to sharing our best with you!
+ </p>
+
+ <h1 class="mt-20 mb-5 text-4xl text-white font-display font-extralight">The Team</h1>
+ <div class="">
+ <article class="mb-10 bg-black">
+ <div class="content">
+ <h3 class="mb-2 font-display font-extralight">Nathan Sobo</h3>
+ <div class="">
+ <p class="mt-3 mb-3 leading-relaxed">Nathan joined GitHub in late 2011 to build the <a href="https://atom.io" class="underline hover:no-underline">Atom text editor</a>, and he led the Atom team until 2018.</p>
+
+ <p class="mt-3 mb-3 leading-relaxed">He also co-led development of <a href="https://teletype.atom.io" class="underline hover:no-underline">Teletype for Atom</a>, pioneering one of the first production uses of conflict-free replicated data types for collaborative text editing.</p>
+
+ <p class="mt-3 mb-3 leading-relaxed">He's been dreaming about building the worldโs best text editor since he graduated from college, and is excited to finally have the knowledge, tools, and resources to achieve this vision.</p>
+
+ <div class="flex flex-row mt-6 mb-3">
+ <a class="block mr-4 opacity-60 hover:opacity-100" href="https://github.com/nathansobo">
+ <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">