diff --git a/docs/api.md b/docs/api.md deleted file mode 100644 index 936674c8..00000000 --- a/docs/api.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -sidebar_position: 1000 ---- -# API Docs - -* [`@automerge/automerge`](https://automerge.org/automerge/api-docs/js) -* [`@automerge/automerge-repo`](https://automerge.org/automerge-repo/) - -# Other Languages - -Here you can find links to the APIs for each implementation. - - * [C](https://github.com/automerge/automerge/tree/main/rust/automerge-c) - * [Rust](https://github.com/automerge/automerge-rs) - * [Python](https://github.com/automerge/automerge-py) - * [Swift (macOS, iOS)](https://automerge.org/automerge-swift/documentation/automerge/) - diff --git a/docs/concepts.md b/docs/concepts.md index 7c086158..9cd53065 100644 --- a/docs/concepts.md +++ b/docs/concepts.md @@ -10,14 +10,11 @@ This documentation is mostly focused on the javascript implementation of automer ::: - -## Core concepts - Using automerge means storing your data in automerge [documents](#Documents). Documents have a [URL](#Document-URLs)s which you can use to share or request documents with/from other peers using a [repository](#Repositories). Repositories give you [`DocHandle`](#dochandles)s which you use to make changes to the document and listen for changes from other peers. Automerge as used in javascript applications is actually a composition of two libraries. [`automerge-repo`](https://www.npmjs.com/package/@automerge/automerge-repo) which provides the networking and storage plumbing, and [`automerge`](https://www.npmjs.com/package/@automerge/automerge) which provides the CRDT implementation, a transport agnostic [sync protocol](#sync-protocol), and a compressed [storage format](#storage-format) which `automerge-repo` uses to implement various networking and storage plugins. -### Documents +## Documents A document is the "unit of change" in automerge. It's like a combination of a JSON object and a git repository. What does that mean? @@ -25,17 +22,17 @@ Like a JSON object an automerge document is a map from strings to values, where Like a git repository an automerge document has a history made up of commits. Every time you make a change to a document you are adding to the history of the document. The combination of this history and some rules about how to handle conflicts means that any two automerge documents can always be merged. See [merging](/docs/under-the-hood/merge_rules.md) for the gory details. -### Repositories +## Repositories A repository manages connections to remote peers and access to some kind of local storage. Typically you create a repository at application startup and then inject it into the parts of your application which need it. The repository gives out `DocHandle`s, which allow you to access the current state of a document and make changes to it without thinking about how to store those changes, transmit them to others, or fetch changes from others. Networking and storage for a repository is pluggable. There are various ready made network transports and storage implementations but it is also easy to build your own. -### DocHandles +## DocHandles A `DocHandle` is an object returned from the various methods on a repository which create or request a document. The `DocHandle` has methods on it to access the underlying automerge document and to create new changes which are stored locally and transmitted to connected peers. -### Document URLs +## Document URLs Documents in a repository have a URL. An automerge URL looks like this: @@ -45,10 +42,10 @@ automerge:2akvofn6L1o4RMUEMQi7qzwRjKWZ That is, a string of the form `automerge:`. This URL can be passed to a repository which will use it to check if the document is in any local storage or available from any connected peers. -### Sync Protocol +## Sync Protocol Repositories communicate with each other using an efficient sync protocol which is implemented in `automerge`. This protocol is transport agnostic and works on a per-document basis, a lot of the work `automerge-repo` does is handling running this sync protocol for multiple documents over different kinds of network. -### Storage Format +## Storage Format `automerge` implements a compact binary storage format which makes it feasible to store all the editing history of a document (for example, storing every keystroke in a large text document). `automerge-repo` implements the common logic of figuring out when to compress documents and doing so in a way which is safe for concurrent reads and writes. diff --git a/docs/cookbook/modeling-data.md b/docs/cookbook.md similarity index 97% rename from docs/cookbook/modeling-data.md rename to docs/cookbook.md index c5587344..2cd9d06f 100644 --- a/docs/cookbook/modeling-data.md +++ b/docs/cookbook.md @@ -1,12 +1,12 @@ --- -sidebar_position: 1 +sidebar_position: 999 --- -# Modeling Data +# Cookbook -All data in Automerge must be stored in a document. A document can be modeled in a variety of ways, and there are many design patterns that can be used. An application could have many documents, typically identified by a UUID. +## Modeling Data -In this section, we will discuss how to model data within a particular document, including how to version and manage data with Automerge in production scenarios. +All data in Automerge must be stored in a document. A document can be modeled in a variety of ways, and there are many design patterns that can be used. An application could have many documents, typically identified by a UUID. ## How many documents? diff --git a/docs/cookbook/_category_.json b/docs/cookbook/_category_.json deleted file mode 100644 index 44de5aae..00000000 --- a/docs/cookbook/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Cookbook", - "position": 5 -} \ No newline at end of file diff --git a/docs/documents/types.md b/docs/documents/types.md new file mode 100644 index 00000000..1e401ede --- /dev/null +++ b/docs/documents/types.md @@ -0,0 +1,124 @@ +--- +sidebar_position: -1 +--- + +# Types + +Automerge documents are quite similar to JSON objects. A document always consists of a root map which is a map from strings to other automerge values, which can themselves be composite types. + +The types in automerge are: + +* Composite types + * Maps + * [List](lists) + * [Text](./text) +* Scalar (non-composite) types: + * IEEE 754 64 bit floating point numbers + * Unsigned integers + * Signed integers + * Booleans Strings + * Timestamps + * Counters + * Byte arrays + +See [below](#javascript-language-mapping) for how these types map to JavaScript types. + +## Maps + +Maps have string keys and any automerge type as a value. "string" here means a unicode string. The underlying representation in automerge is as UTF-8 byte sequences but they are exposed as utf-16 strings in javascript. + +## Lists + +A list is an ordered sequence of automerge values. The underlying data structure is an RGA sequence, which means that concurrent insertions and deletions can be merged in a manner which attempts to preserve user intent. + +## Text + +Text is an implementation of the [peritext](https://www.inkandswitch.com/peritext/) CRDT. This is conceptually similar to a [list](#lists) where each element is a single unicode scalar value representing a single character. In addition to the characters `Text` also supports "marks". Marks are tuples of the form `(start, end, name, value)` which have the following meanings: + +* `start` - the index of the beginning of the mark +* `end` - the index of the end of the mark +* `name` - the name of the mark +* `value` - any scalar (as in automerge scalar) value + +For example, a bold mark from charaters 1 to 5 might be represented as `(1, 5, "bold", true)`. + +Note that the restriction to scalar values for the value of a mark will be lifted in future, although mark values will never be mutable - instead you should always create a new mark when updating a value. For now, if you need complex values in a mark you should serialize the value to a string. + +## Timestamps + +Timestamps are the integer number of milliseconds since the unix epoch (midnight 1970, UTC). + +## Counter + +Counters are a simple CRDT which just merges by adding all concurrent operations. They can be incremented and decremented. + +## Javascript language mapping + +The mapping to javascript is accomplished with the use of proxies. This means that in the javascript library maps appear as `object`s and lists appear as `Array`s. There is only one numeric type in javascript - `number` - so the javascript library guesses a bit. If you insert a javascript `number` for which [`Number.isInteger`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger) returns `true` then the number will be inserted as an integer, otherwise it will be a floating point value. + +How `Text` and `String` are represented will depend on whether you are using [the `next` API](/docs/the_js_packages#the-next-api) + +Timestamps are represented as javascript `Date`s. + +Counters are represented as instances of the `Counter` class. + +Putting it all together, here's an example of an automerge document containing all the value types: + +```typescript +import * as A from "@automerge/automerge/next" + +let doc = A.from({ + map: { + key: "value", + nested_map: {key: "value"}, + nested_list: [1] + }, + list: ["a", "b", "c", {nested: "map"}, ["nested list"]], + // Note we are using the `next` API for text, so text sequences are strings + text: "some text", + // In the `next` API non mergable strings are instances of `RawString`. + // You should generally not need to use these. They are retained for backwards + // compatibility + raw_string: new A.RawString("rawstring"), + integer: 1, + float: 2.3, + boolean: true, + bytes: new Uint8Array([1, 2, 3]), + date: new Date(), + counter: new A.Counter(1), + none: null, +}) + +doc = A.change(doc, d => { + // Insert 'Hello' at the begnning of the string + A.splice(d, ["text"], 0, 0, "Hello ") + d.counter.increment(20) + d.map.key = "new value" + d.map.nested_map.key = "new nested value" + d.list[0] = "A" + d.list.insertAt(0, "Z") + d.list[4].nested = "MAP" + d.list[5][0] = "NESTED LIST" +}) + +console.log(doc) + +// Prints +// { +// map: { +// key: 'new value', +// nested_map: { key: 'new nested value' }, +// nested_list: [ 1 ] +// }, +// list: [ 'Z', 'A', 'b', 'c', { nested: 'MAP' }, [ 'NESTED LIST' ] ], +// text: 'Hello world', +// raw_string: RawString { val: 'rawstring' }, +// integer: 1, +// float: 2.3, +// boolean: true, +// bytes: Uint8Array(3) [ 1, 2, 3 ], +// date: 2023-09-11T13:35:12.229Z, +// counter: Counter { value: 21 }, +// none: null +// } +``` diff --git a/docs/documents/values.md b/docs/documents/values.md index 1f6bf299..9ccfeba9 100644 --- a/docs/documents/values.md +++ b/docs/documents/values.md @@ -2,7 +2,7 @@ sidebar_position: 2 --- -# Simple Values +# Primitives All JSON primitive datatypes are supported in an Automerge document. In addition, JavaScript [Date objects](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) are supported. diff --git a/docs/quickstart.md b/docs/getting-started.md similarity index 86% rename from docs/quickstart.md rename to docs/getting-started.md index 83638680..8982a3ac 100644 --- a/docs/quickstart.md +++ b/docs/getting-started.md @@ -2,15 +2,11 @@ sidebar_position: 1 --- -# 5-Minute Quick Start +# Getting started -It's easy to build a local-first web application with real-time synchronization using Automerge. In this quickstart, we'll start with the standard `yarn create vite` example Typescript application and use Automerge to turn it into a simple local-first application. +It's easy to build a local-first app with real-time synchronization using Automerge. In this guide, we'll turn a standard `yarn create vite` into a simple local-first app. All the code shown here can be found in [this repo](https://github.com/automerge/automerge-repo-quickstart). -All the code here can be found at the [automerge-repo-quickstart](https://github.com/automerge/automerge-repo-quickstart) repo. - -Let's begin. - -## Setup +## Installation First, let's initialize an off-the-shelf React app using Vite as our bundler. We're not going to remind you along the way, but we recommend you initialize a git repo and check in the code at whatever interval feels comfortable. @@ -57,6 +53,44 @@ export default defineConfig({ With that out of the way, we're ready to build the application. +# Usage + +If you just want to know how to use Automerge in greenfield applications, here's how the library is intended to be used: + +Install both the `@automerge/automerge` and `@automerge/automerge-repo` packages. Then install the networking and storage plugins you need (typically `@automerge/automerge-repo-network-*` and `@automerge/automerge-repo-storage-*`) packages. Take a look at the cookbook for examples of different ways of using these. + +When you're making changes to an automerge document you should use [the `next` API](#the-next-api) + +### Using the next API + +There are two ways to use the next API + +#### Subpath Exports + +If you are either using JavaScript in a modern browser or on node > 16 then you can do the following: + +```javascript +import {default as A} from "@automerge/automerge/next" +``` + +Note that for this to work in typescript you will need to have the following in your `tsconfig.json` + +```json + ... + "module": "NodeNext", + "moduleResolution": "Node16", + ... +``` + +#### The `{ next }` module + +If for whatever reason you can't use `@automerge/automerge/next` then you can do this: + +```javascript +import {next as A} from "@automerge/automerge" +``` + + # Using Automerge The central concept of Automerge is one of documents. An Automerge document is a JSON-like data structure that is kept synchronized between all communicating peers with the same document ID. @@ -271,6 +305,13 @@ const repo = new AutomergeRepo.Repo({ Documents will be stored in `IndexedDB` and methods like `Repo.find` will consult storage when loading. The upshot is that if you had a document locally, it will continue to be available regardless of whether you are connected to any peers. +## React + +If you are using React, modify the above by: +1. Choosing React as your framework during the `yarn create vite` setup +2. Installing `@automerge/automerge-repo-react-hooks` in addition to the other packages +3 + ## More If you're hungry for more, look in the [Cookbook](/docs/cookbook/modeling-data/) section. diff --git a/docs/hello.md b/docs/hello.md deleted file mode 100644 index 8d9c691f..00000000 --- a/docs/hello.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -sidebar_position: 1 ---- - -# Welcome to Automerge - -Automerge is a library of data structures for building collaborative -applications. You can have a copy of the application state locally on several -devices which may belong to the same user, or to different users. Each user can -independently update the application state on their local device, even while -offline, and save the state to local disk. This is similar to Git, which allows -you to edit files and commit changes offline. - -* When a network connection is available, Automerge figures out which changes need -to be synced from one device to another, and brings them into the same state. - - (Similar to Git, which lets you push your own changes, and pull changes from other developers, when you are online.) - -* If the state was changed concurrently on different devices, Automerge automatically merges the changes together cleanly, so that everybody ends up in the same state, and no changes are lost. - - (Git only supports merging of plain text; Automerge allows complex file formats to be merged automatically.) - -* Automerge keeps track of the changes you make to the state, so that you can view old versions, compare versions, create branches, and choose when to merge them. - - (Similar to Git, which allows diffing, branching, merging, and pull request workflows.) - -## Design principles - -- **Network-agnostic**. Automerge is a pure data structure library that does not care about what - kind of network you use. It works with any connection-oriented network protocol, which could be - client/server (e.g. WebSocket), peer-to-peer (e.g. WebRTC), or entirely local (e.g. Bluetooth). - Bindings to particular networking technologies are handled by separate libraries; - Automerge provides [automerge-repo](https://automerge.org/automerge-repo/index.html) for a common collection of these libraries. - It also works with unidirectional messaging: you can send an Automerge file as email attachment, - or on a USB drive in the mail, and the recipient will be able to merge it with their version. -- **Immutable state**. An Automerge object is an immutable snapshot of the application state at one - point in time. Whenever you make a change, or merge in a change that came from the network, you - get back a new state object reflecting that change. This fact makes Automerge compatible with the - functional reactive programming style of [React](https://reactjs.org) and - [Redux](http://redux.js.org/), for example. -- **Automatic merging**. Automerge is a _Conflict-Free Replicated Data Type_ ([CRDT](https://crdt.tech/)), - which allows concurrent changes on different devices to be merged automatically without requiring any - central server. The conflict resolution approach is described - [in the documentation](/docs/documents/conflicts/). -- **Portable**. The [JavaScript implementation](https://github.com/automerge/automerge) of - Automerge is compatible with Node.js, [Electron](https://electron.atom.io/), and modern browsers. - The [Rust implementation](https://github.com/automerge/automerge-rs) compiles to WebAssembly - for use in browsers, and it exposes a C API through which it can be used on iOS and other - platforms without requiring a JavaScript engine. For TypeScript users, Automerge comes with - [type definitions](https://github.com/automerge/automerge/blob/main/@types/automerge/index.d.ts) - that allow you to use Automerge in a type-safe way. - -Automerge is designed for creating [local-first software](https://www.inkandswitch.com/local-first/), -i.e. software that treats a user's local copy of their data (on their own device) as primary, rather -than centralising data in a cloud service. The local-first approach enables offline working while -still allowing several users to collaborate in real-time and sync their data across multiple -devices. By reducing the dependency on cloud services (which may disappear if someone stops paying -for the servers), local-first software can have greater longevity, stronger privacy, and better -performance, and it gives users more control over their data. -The [essay on local-first software](https://www.inkandswitch.com/local-first/) goes into more -detail on the philosophy behind Automerge, and the pros and cons of this approach. - -However, if you want to use Automerge with a centralised server, that works fine too! You still get -useful benefits, such as allowing several clients to concurrently update the data, easy sync between -clients and server, being able to inspect the change history of your app's data, and support for -branching and merging workflows. diff --git a/docs/intro.md b/docs/intro.md new file mode 100644 index 00000000..48a449f1 --- /dev/null +++ b/docs/intro.md @@ -0,0 +1,73 @@ +--- +sidebar_position: 0 +--- + +# Overview + +Automerge is a library for building collaborative, local-first apps. Different +copies of your app state can exist on different devices. These copies can be +independently updated, even when the device is offline. Divergent versions +of state can then be merged together automatically and synced. + +Automerge will automatically: + +* **Sync state** when the app is online + +* **Merge divergent** state without losing conflicts + +* **Version state**, enabling Git-like workflows + +Automerge is [local-first](#local-first) but [server-friendly](#server-friendly) software. + +# API + +The primary API for Automerge is the Javascript API, consisting of a few modules: + +* [`@automerge/automerge`](https://automerge.org/automerge/api-docs/js) +* [`@automerge/automerge-repo`](https://automerge.org/automerge-repo/) + +In addition to the Javascript API, we provide bindings in several other languages: + + * [C](https://github.com/automerge/automerge/tree/main/rust/automerge-c) + * [Rust](https://github.com/automerge/automerge-rs) + * [Python](https://github.com/automerge/automerge-py) + * [Swift (macOS, iOS)](https://automerge.org/automerge-swift/documentation/automerge/) + +## Design principles + +Automerge is a data structure library implementing a _Conflict-Free Replicated Data Type_ ([CRDT](https://crdt.tech/)). +While plenty of CRDT libraries exist, our design has some distinguishing principles: + +- **Automatic merging** - enables [decentralized automatic merging](/docs/documents/conflicts/) of concurrent changes. +- **Local-first** - the user's local copy is a first-class citizen, enabling decentralized and privacy-preserving + data architectures. +- **Network-agnostic** - works with any connection-oriented network protocol and topology, with network + connectors seperately available. +- **Immutable state** - makes immutable snapshots of app state while efficiently storing full + state version history and Git-like branching workflows. +- **Portability** - the [JS API](https://github.com/automerge/automerge) isomorphic, and + the [Rust API](https://github.com/automerge/automerge-rs) compiles to WASM, enabling native APIs + for other platforms. +- **Typesafe** - ships with [type definitions](https://github.com/automerge/automerge/blob/main/@types/automerge/index.d.ts) for TypeScript. + +### Local-first + +Automerge is designed for creating [local-first software](https://www.inkandswitch.com/local-first/), +i.e. software that treats a user's local copy of their data (on their own device) as primary, rather +than centralising data in a cloud service. + +The local-first approach enables working offline while still enabling real-time online collaboration. +By reducing the dependency on cloud services - which can be discontinued abruptly - local-first software +can have greater longevity, enhanced privacy and improved performance. + +More importantly, local-first software it gives users control over their data. +The [essay on local-first software](https://www.inkandswitch.com/local-first/) goes into more +detail on the philosophy behind Automerge, and the pros and cons of this approach. + +### Server-friendly + +While we built Automerge to be local-first, it still works great in a classic client-server architecture. + +You still get useful benefits, such as allowing several clients to concurrently update the data, +easily sync between clients and server, version controlled app state, and support for Git-like +branching and merging workflows. diff --git a/docs/more/_category_.json b/docs/more/_category_.json new file mode 100644 index 00000000..d2d70fcc --- /dev/null +++ b/docs/more/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "More", + "position": 5 +} \ No newline at end of file diff --git a/docs/the_js_packages.md b/docs/more/api-history.md similarity index 57% rename from docs/the_js_packages.md rename to docs/more/api-history.md index 9a42041e..11e01f10 100644 --- a/docs/the_js_packages.md +++ b/docs/more/api-history.md @@ -1,17 +1,20 @@ --- -sidebar_position: 2 +sidebar_position: 4 --- -# The JavaScript packages -The javascript API has been through several iterations and is currently split over a few libraries. This page describes how all these pieces fit together. +# API History -## Recommended Usage +## Automerge Classic -If you just want to know how to use Automerge in greenfield applications, here's how the library is intended to be used: +The first version of automerge was implemented in pure javascript and is what we now call automerge Classic. You can find it [on NPM](https://www.npmjs.com/package/automerge) and [GitHub](https://github.com/automerge/automerge-classic). This project went through several iterations which changed quite dramatically. + +## `@automerge/automerge-wasm` and `@automerge/automerge` -Install both the `@automerge/automerge` and `@automerge/automerge-repo` packages. Then install the networking and storage plugins you need (typically `@automerge/automerge-repo-network-*` and `@automerge/automerge-repo-storage-*`) packages. Take a look at the cookbook for examples of different ways of using these. +More recently we rewrote automerge in Rust and deployed it to javascript by compiling to a wasm package at [`@automerge/automerge-wasm`](https://www.npmjs.com/package/@automerge/automerge-wasm). This wasm package is something we currently consider to be an implementation detail and should not be depended on by third parties. The `@automerge/automerge` package offers a very similar API to the original `automerge` package but implemented by forwarding logic to `@automerge/automerge-wasm`. It is consequently much faster. -When you're making changes to an automerge document you should use [the `next` API](#the-next-api) +## `@automerge/automerge-repo` + +The core automerge libraries (both the original classic library and the WASM implementation) offer a compact storage format and a network agnostic sync protocol, but they don't actually do the work of wiring these things up to real storage engines (such as filesystems) or transports (such as websockets). `automerge-repo` implements all of this plumbing and is how we recommend using automerge going forward. ## The `next` API @@ -20,48 +23,4 @@ Over time we have made a number of changes to the automerge API which are not ba ### Differences from stable * In the old API javascript strings are represented as scalar strings (see the [data model](/docs/documents/) for details) whilst in "next" javascript strings are `Text` sequences (i.e. they support concurrent insertions and deletions). This means that you should use `next.splice` to modify strings in the `next` API. Scalar strings in the `next` API are represented as instances of the `RawString` class. -* The next API exposes the `diff` and `changeAt` methods - -### Using the next API - -There are two ways to use the next API - -#### Subpath Exports - -If you are either using JavaScript in a modern browser or on node > 16 then you can do the following: - -```javascript -import {default as A} from "@automerge/automerge/next" -``` - -Note that for this to work in typescript you will need to have the following in your `tsconfig.json` - -```json - ... - "module": "NodeNext", - "moduleResolution": "Node16", - ... -``` - -#### The `{ next }` module - -If for whatever reason you can't use `@automerge/automerge/next` then you can do this: - -```javascript -import {next as A} from "@automerge/automerge" -``` - -## How we got here - -### Automerge Classic - -The first version of automerge was implemented in pure javascript and is what we now call automerge Classic. You can find it [on NPM](https://www.npmjs.com/package/automerge) and [GitHub](https://github.com/automerge/automerge-classic). This project went through several iterations which changed quite dramatically. - -### `@automerge/automerge-wasm` and `@automerge/automerge` - -More recently we rewrote automerge in Rust and deployed it to javascript by compiling to a wasm package at [`@automerge/automerge-wasm`](https://www.npmjs.com/package/@automerge/automerge-wasm). This wasm package is something we currently consider to be an implementation detail and should not be depended on by third parties. The `@automerge/automerge` package offers a very similar API to the original `automerge` package but implemented by forwarding logic to `@automerge/automerge-wasm`. It is consequently much faster. - -### `@automerge/automerge-repo` - -The core automerge libraries (both the original classic library and the WASM implementation) offer a compact storage format and a network agnostic sync protocol, but they don't actually do the work of wiring these things up to real storage engines (such as filesystems) or transports (such as websockets). `automerge-repo` implements all of this plumbing and is how we recommend using automerge going forward. - +* The next API exposes the `diff` and `changeAt` methods \ No newline at end of file diff --git a/docs/under-the-hood/indexedb-screenshot-detailed.png b/docs/more/indexedb-screenshot-detailed.png similarity index 100% rename from docs/under-the-hood/indexedb-screenshot-detailed.png rename to docs/more/indexedb-screenshot-detailed.png diff --git a/docs/under-the-hood/indexeddb-screenshot-manykeys.png b/docs/more/indexeddb-screenshot-manykeys.png similarity index 100% rename from docs/under-the-hood/indexeddb-screenshot-manykeys.png rename to docs/more/indexeddb-screenshot-manykeys.png diff --git a/docs/under-the-hood/indexeddb-screenshot-snapshot.png b/docs/more/indexeddb-screenshot-snapshot.png similarity index 100% rename from docs/under-the-hood/indexeddb-screenshot-snapshot.png rename to docs/more/indexeddb-screenshot-snapshot.png diff --git a/docs/under-the-hood/indexeddb-screenshot.png b/docs/more/indexeddb-screenshot.png similarity index 100% rename from docs/under-the-hood/indexeddb-screenshot.png rename to docs/more/indexeddb-screenshot.png diff --git a/docs/under-the-hood/merge_rules.md b/docs/more/merge_rules.md similarity index 100% rename from docs/under-the-hood/merge_rules.md rename to docs/more/merge_rules.md diff --git a/docs/under-the-hood/storage.md b/docs/more/storage.md similarity index 99% rename from docs/under-the-hood/storage.md rename to docs/more/storage.md index 76e07fa4..a0ea9e6f 100644 --- a/docs/under-the-hood/storage.md +++ b/docs/more/storage.md @@ -2,7 +2,7 @@ sidebar_position: 1 --- -# Storage +# Storage Mechanisms In the [getting started](../quickstart.md) section we introduced a simple application which synchronized the value of a counter between any number of tabs. If you close all the tabs and open a new one you will see that the value of the counter is persisted. How is this working? What's going on? diff --git a/docs/under-the-hood/_category_.json b/docs/under-the-hood/_category_.json deleted file mode 100644 index 8c148733..00000000 --- a/docs/under-the-hood/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Under the hood", - "position": 5 -} diff --git a/docusaurus.config.js b/docusaurus.config.js index f756e3f9..ff9b1420 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -47,13 +47,13 @@ const config = { ], stylesheets: [ - { - href: 'https://cdn.jsdelivr.net/npm/katex@0.13.24/dist/katex.min.css', - type: 'text/css', - integrity: - 'sha384-odtC+0UGzzFL/6PNoE8rX/SPcQDXBJ+uRepguP4QkPCm2LBxH3FA3y+fKSiJ+AmM', - crossorigin: 'anonymous', - }, + { + href: 'https://cdn.jsdelivr.net/npm/katex@0.13.24/dist/katex.min.css', + type: 'text/css', + integrity: + 'sha384-odtC+0UGzzFL/6PNoE8rX/SPcQDXBJ+uRepguP4QkPCm2LBxH3FA3y+fKSiJ+AmM', + crossorigin: 'anonymous', + }, ], @@ -69,7 +69,7 @@ const config = { items: [ { type: 'doc', - docId: 'hello', + docId: 'intro', position: 'left', label: 'Docs', }, @@ -141,7 +141,7 @@ const config = { copyright: `Copyright © ${new Date().getFullYear()} Automerge contributors. Built with Docusaurus.` }, metadata: [ - { name: 'title', content: 'Automerge'}, + { name: 'title', content: 'Automerge' }, { name: 'keywords', content: 'documentation, local-first, crdt, offline-first, automerge' }, { name: 'description', content: 'Automerge is a library for building collaborative, local-first applications.' } ], diff --git a/src/css/custom.css b/src/css/custom.css index d40e3b5a..af6813c7 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -5,42 +5,68 @@ */ /* You can override the default Infima variables here. */ -p, li, ul { - font-family: "Merriweather", serif; - font-size: 1.2rem; - line-height: 1.7rem; - } - -:root { - --ifm-color-primary:#ba7402; ---ifm-color-primary-dark: #ef9603; ---ifm-color-primary-darker: #e28d03; ---ifm-color-primary-darkest: #ba7402; ---ifm-color-primary-light: #fcad2c; ---ifm-color-primary-lighter: #fdb239; ---ifm-color-primary-lightest: #fdc261; +:root { + --ifm-color-primary: #ba7402; + --ifm-color-primary-dark: #ef9603; + --ifm-color-primary-darker: #e28d03; + --ifm-color-primary-darkest: #ba7402; + --ifm-color-primary-light: #fcad2c; + --ifm-color-primary-lighter: #fdb239; + --ifm-color-primary-lightest: #fdc261; --ifm-color-white: #fcfcfc; --ifm-background-color: #fcfcfc; + --automerge-yellow: #fecb32; + --automerge-black: #131313; + + --ifm-menu-color-background-active: var(--automerge-yellow); + --ifm-menu-color-active: var(--automerge-black); } .docusaurus-highlight-code-line { - background-color: rgba(0, 0, 0, 0.1); - display: block; - margin: 0 calc(-1 * var(--ifm-pre-padding)); - padding: 0 var(--ifm-pre-padding); + background-color: rgba(0, 0, 0, 0.1); + display: block; + margin: 0 calc(-1 * var(--ifm-pre-padding)); + padding: 0 var(--ifm-pre-padding); } html[data-theme='dark'] .docusaurus-highlight-code-line { - background-color: rgba(0, 0, 0, 0.3); + background-color: rgba(0, 0, 0, 0.3); } html[data-theme='dark'] { --ifm-color-primary: #fbcc34; ---ifm-color-primary-dark: #fac516; ---ifm-color-primary-darker: #fac107; ---ifm-color-primary-darkest: #d0a004; ---ifm-color-primary-light: #fcd352; ---ifm-color-primary-lighter: #fcd761; ---ifm-color-primary-lightest: #fde28d; + --ifm-color-primary-dark: #fac516; + --ifm-color-primary-darker: #fac107; + --ifm-color-primary-darkest: #d0a004; + --ifm-color-primary-light: #fcd352; + --ifm-color-primary-lighter: #fcd761; + --ifm-color-primary-lightest: #fde28d; +} + +.button--primary { + background-color: var(--automerge-yellow); + color: var(--automerge-black); + border: 0; + outline: 2px black solid; + outline-offset: -5px; +} + +.footer { + background-color: #222; +} + +.hero .container { + display: flex; + flex-flow: column; + align-items: center; +} + +.hero__title { + text-transform: uppercase; + font-size: 2rem; +} + +.hero__subtitle { + max-width: 600px; } \ No newline at end of file