mirror of https://github.com/AMT-Cheif/drift.git
Add web example served under docs website
This commit is contained in:
parent
1e74aae972
commit
b976e6f7ef
|
@ -0,0 +1,74 @@
|
|||
<script>
|
||||
import 'database.dart';
|
||||
|
||||
import 'entry.zap';
|
||||
import 'toolbar.zap';
|
||||
|
||||
var filter = TodoListFilter.all;
|
||||
var uncompleted = 0;
|
||||
|
||||
final connFuture = connect();
|
||||
final dbFuture = connFuture.then((r) => Database(r.resolvedExecutor));
|
||||
</script>
|
||||
<style>
|
||||
.ok {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.bad {
|
||||
color: red;
|
||||
}
|
||||
|
||||
small {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
||||
<hgroup>
|
||||
<h1>Todo list</h1>
|
||||
<h2>This offline todo-list app is implemented with drift on the web.</h2>
|
||||
</hgroup>
|
||||
|
||||
<article>
|
||||
{#await database from dbFuture}
|
||||
{#if database.hasData}
|
||||
<header>
|
||||
<toolbar database={database.data} />
|
||||
</header>
|
||||
{#await each snapshot from database.data.items}
|
||||
{#if snapshot.hasData}
|
||||
{#for entry, i in snapshot.data}
|
||||
<entry entry={entry} database={database.data} />
|
||||
{#if i != snapshot.data.length - 1}
|
||||
<hr>
|
||||
{/if}
|
||||
{/for}
|
||||
{/if}
|
||||
{/await}
|
||||
{:else if database.hasError}
|
||||
Sorry, we could not open the database on this browser!
|
||||
{:else}
|
||||
<progress></progress>
|
||||
{/if}
|
||||
{/await}
|
||||
<footer>
|
||||
{#await connection from connFuture}
|
||||
{#if connection.hasData}
|
||||
Using implementation <span class={ connection.data.chosenImplementation.fullySupported ? 'ok' : 'bad' }>{ connection.data.chosenImplementation.name }</span>.
|
||||
|
||||
{#if connection.data.chosenImplementation.fullySupported}
|
||||
Updates are synchronized across tabs thanks to drift.
|
||||
<small>Want to try it out? Go ahead and open this website in <a href="#" target="_blank">a new tab</a>.</small>
|
||||
{:else}
|
||||
This implementation has known caveats and shouldn't be selected on recent browsers.
|
||||
More information is in the console and in <a href="https://drift.simonbinder.eu/web">the documentation</a>.
|
||||
<small>Please consider <a href="https://github.com/simolus3/drift/issues/new/choose">filing an issue</a>.</small>
|
||||
{/if}
|
||||
{/if}
|
||||
{/await}
|
||||
</footer>
|
||||
</article>
|
||||
|
||||
<footer>
|
||||
<small><a href="https://github.com/simolus3/drift/tree/develop/docs/lib/sample">Source code</a></small>
|
||||
</footer>
|
|
@ -0,0 +1,105 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:drift/wasm.dart';
|
||||
import 'package:rxdart/rxdart.dart';
|
||||
|
||||
part 'database.g.dart';
|
||||
|
||||
enum TodoListFilter { all, active, completed }
|
||||
|
||||
class TodoItems extends Table {
|
||||
IntColumn get id => integer().autoIncrement()();
|
||||
TextColumn get description => text()();
|
||||
BoolColumn get completed => boolean().withDefault(const Constant(false))();
|
||||
}
|
||||
|
||||
@DriftDatabase(tables: [TodoItems])
|
||||
class Database extends _$Database {
|
||||
final BehaviorSubject<TodoListFilter> _filterChanges =
|
||||
BehaviorSubject.seeded(TodoListFilter.all);
|
||||
|
||||
Database(super.e);
|
||||
|
||||
@override
|
||||
int get schemaVersion => 1;
|
||||
|
||||
@override
|
||||
MigrationStrategy get migration {
|
||||
return MigrationStrategy(
|
||||
onCreate: (m) async {
|
||||
await m.createAll();
|
||||
|
||||
// Create some entries by default
|
||||
await batch((b) {
|
||||
b.insertAll(todoItems, [
|
||||
TodoItemsCompanion.insert(description: 'Migrate to drift'),
|
||||
TodoItemsCompanion.insert(description: 'Support all platforms'),
|
||||
TodoItemsCompanion.insert(
|
||||
description: 'Solve local persistence issues'),
|
||||
]);
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
TodoListFilter get currentFilter => _filterChanges.value;
|
||||
|
||||
set currentFilter(TodoListFilter value) {
|
||||
_filterChanges.add(value);
|
||||
}
|
||||
|
||||
Stream<List<TodoItem>> get items => _filterChanges.stream.switchMap(_items);
|
||||
|
||||
Stream<int> get uncompletedItems {
|
||||
final all = countAll();
|
||||
final query = selectOnly(todoItems)
|
||||
..addColumns([all])
|
||||
..where(todoItems.completed.not());
|
||||
|
||||
return query.map((row) => row.read(all)!).watchSingle();
|
||||
}
|
||||
|
||||
Stream<List<TodoItem>> _items(TodoListFilter filter) {
|
||||
final query = todoItems.select();
|
||||
|
||||
switch (filter) {
|
||||
case TodoListFilter.completed:
|
||||
query.where((row) => row.completed);
|
||||
case TodoListFilter.active:
|
||||
query.where((row) => row.completed.not());
|
||||
case TodoListFilter.all:
|
||||
break;
|
||||
}
|
||||
|
||||
return query.watch();
|
||||
}
|
||||
|
||||
Future<void> toggleCompleted(TodoItem item) async {
|
||||
final statement = update(todoItems)..whereSamePrimaryKey(item);
|
||||
await statement.write(TodoItemsCompanion.custom(
|
||||
completed: todoItems.completed.not(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Future<WasmDatabaseResult> connect() async {
|
||||
final result = await WasmDatabase.open(
|
||||
databaseName: 'todo_example',
|
||||
sqlite3Uri: Uri.parse('/sqlite3.wasm'),
|
||||
driftWorkerUri: Uri.parse('/drift_worker.dart.js'),
|
||||
);
|
||||
|
||||
if (!result.chosenImplementation.fullySupported) {
|
||||
print('Using ${result.chosenImplementation} due to unsupported browser '
|
||||
'features: ${result.missingFeatures}');
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
extension CompatibilityUI on WasmStorageImplementation {
|
||||
bool get fullySupported =>
|
||||
this != WasmStorageImplementation.inMemory &&
|
||||
this != WasmStorageImplementation.unsafeIndexedDb;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
<script>
|
||||
import 'database.dart';
|
||||
|
||||
@prop
|
||||
Database database;
|
||||
|
||||
@prop
|
||||
TodoItem entry;
|
||||
|
||||
void toggle() {
|
||||
database.toggleCompleted(entry);
|
||||
}
|
||||
</script>
|
||||
|
||||
<label for="entry-{entry.id}">
|
||||
<input type="checkbox" id="entry-{entry.id}" checked={entry.completed} on:change={toggle}>
|
||||
{entry.description}
|
||||
</label>
|
|
@ -0,0 +1,41 @@
|
|||
<script>
|
||||
import 'database.dart';
|
||||
|
||||
@prop
|
||||
Database database;
|
||||
|
||||
TextInputElement? text;
|
||||
|
||||
var currentFilter = database.currentFilter;
|
||||
|
||||
void select(TodoListFilter filter) {
|
||||
currentFilter = filter;
|
||||
database.currentFilter = filter;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
div {
|
||||
float: right;
|
||||
}
|
||||
|
||||
a {
|
||||
margin: 0px 2px;
|
||||
}
|
||||
|
||||
label {
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
{#await each entry from database.uncompletedItems}
|
||||
{#if entry.hasData}
|
||||
<strong>{entry.data} {entry.data == 1 ? 'item' : 'items'} left</strong>
|
||||
{/if}
|
||||
{/await}
|
||||
|
||||
<div>
|
||||
<a class={currentFilter == TodoListFilter.all ? '' : 'secondary'} on:click={() => select(TodoListFilter.all)}>All</a>
|
||||
<a class={currentFilter == TodoListFilter.active ? '' : 'secondary'} on:click={() => select(TodoListFilter.active)}>Active</a>
|
||||
<a class={currentFilter == TodoListFilter.completed ? '' : 'secondary'} on:click={() => select(TodoListFilter.completed)}>Completed</a>
|
||||
</div>
|
|
@ -25,6 +25,10 @@ dependencies:
|
|||
rxdart: ^0.27.3
|
||||
yaml: ^3.1.1
|
||||
drift_dev: any
|
||||
zap: ^0.2.0
|
||||
picocss:
|
||||
hosted: https://simonbinder.eu
|
||||
version: ^1.5.10
|
||||
|
||||
dev_dependencies:
|
||||
lints: ^2.0.0
|
||||
|
@ -42,6 +46,7 @@ dev_dependencies:
|
|||
source_span: ^1.9.1
|
||||
test: ^1.18.0
|
||||
sqlparser:
|
||||
zap_dev: ^0.2.2
|
||||
|
||||
|
||||
dependency_overrides:
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
import 'dart:html';
|
||||
|
||||
import 'package:drift/wasm.dart';
|
||||
import 'package:drift_docs/site.dart' as i0;
|
||||
import 'package:docsy/main.dart' as i1;
|
||||
|
||||
void main() async {
|
||||
i0.built_site_main();
|
||||
i1.built_site_main();
|
||||
|
||||
final btn = querySelector('#drift-compat-btn')!;
|
||||
final results = querySelector('#drift-compat-results')!;
|
||||
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Drift web example</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<script defer src="main.dart.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<main class="container">
|
||||
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,9 @@
|
|||
import 'dart:html';
|
||||
|
||||
import 'package:drift_docs/sample/app.zap.dart';
|
||||
|
||||
void main() {
|
||||
final main = document.querySelector('main.container')!;
|
||||
|
||||
App().create(main);
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
@use "package:picocss/pico";
|
||||
@use "package:drift_docs/sample/app.zap";
|
|
@ -21,6 +21,12 @@
|
|||
status = 301
|
||||
force = true
|
||||
|
||||
[[headers]]
|
||||
for = "/*"
|
||||
[headers.values]
|
||||
Cross-Origin-Opener-Policy = "same-origin"
|
||||
Cross-Origin-Embedder-Policy = "require-corp"
|
||||
|
||||
[context.production]
|
||||
environment = { BUILD_RELEASE="release" }
|
||||
|
||||
|
|
Loading…
Reference in New Issue