This commit is contained in:
Michael Zhang 2024-07-01 02:17:16 -05:00
parent 0466b64c5a
commit 633f544e75
33 changed files with 213 additions and 270 deletions

117
Cargo.lock generated
View file

@ -23,7 +23,7 @@ version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"getrandom 0.2.15",
"once_cell",
"version_check",
@ -239,7 +239,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964"
dependencies = [
"async-lock",
"cfg-if 1.0.0",
"cfg-if",
"concurrent-queue",
"futures-io",
"futures-lite",
@ -274,7 +274,7 @@ dependencies = [
"async-signal",
"async-task",
"blocking",
"cfg-if 1.0.0",
"cfg-if",
"event-listener 5.3.1",
"futures-lite",
"rustix",
@ -302,7 +302,7 @@ dependencies = [
"async-io",
"async-lock",
"atomic-waker",
"cfg-if 1.0.0",
"cfg-if",
"futures-core",
"futures-io",
"rustix",
@ -455,7 +455,7 @@ checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a"
dependencies = [
"addr2line",
"cc",
"cfg-if 1.0.0",
"cfg-if",
"libc",
"miniz_oxide",
"object",
@ -783,12 +783,6 @@ dependencies = [
"target-lexicon",
]
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "cfg-if"
version = "1.0.0"
@ -1137,7 +1131,7 @@ version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
]
[[package]]
@ -1379,7 +1373,7 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"dirs-sys-next",
]
@ -1544,7 +1538,7 @@ version = "0.8.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
]
[[package]]
@ -1596,7 +1590,7 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"home",
"windows-sys 0.48.0",
]
@ -1652,7 +1646,7 @@ version = "4.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e5768da2206272c81ef0b5e951a41862938a6070da63bcea197899942d3b947"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"rustix",
"windows-sys 0.52.0",
]
@ -2020,7 +2014,7 @@ version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"libc",
"wasi 0.9.0+wasi-snapshot-preview1",
]
@ -2031,7 +2025,7 @@ version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
]
@ -2551,7 +2545,7 @@ version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"js-sys",
"wasm-bindgen",
"web-sys",
@ -2664,7 +2658,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97"
dependencies = [
"cesu8",
"cfg-if 1.0.0",
"cfg-if",
"combine",
"jni-sys",
"log",
@ -2789,7 +2783,7 @@ version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"winapi",
]
@ -2799,7 +2793,7 @@ version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"windows-targets 0.52.5",
]
@ -2864,7 +2858,7 @@ version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"generator",
"scoped-tls",
"serde",
@ -2959,7 +2953,7 @@ version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"digest",
]
@ -3006,12 +3000,6 @@ dependencies = [
"autocfg",
]
[[package]]
name = "memory_units"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3"
[[package]]
name = "mime"
version = "0.3.17"
@ -3112,7 +3100,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
dependencies = [
"bitflags 2.5.0",
"cfg-if 1.0.0",
"cfg-if",
"libc",
"memoffset",
]
@ -3475,20 +3463,7 @@ dependencies = [
]
[[package]]
name = "panorama-abi"
version = "0.1.0"
[[package]]
name = "panorama-app-sdk"
version = "0.1.0"
dependencies = [
"chrono",
"panorama-app-sdk-macros",
"wee_alloc",
]
[[package]]
name = "panorama-app-sdk-macros"
name = "panorama-codetrack"
version = "0.1.0"
[[package]]
@ -3545,15 +3520,11 @@ dependencies = [
]
[[package]]
name = "panorama-journal"
name = "panorama-macros"
version = "0.1.0"
dependencies = [
"chrono",
"panorama-app-sdk",
]
[[package]]
name = "panorama-macros"
name = "panorama-sync"
version = "0.1.0"
[[package]]
@ -3578,7 +3549,7 @@ version = "0.9.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"libc",
"redox_syscall 0.5.2",
"smallvec",
@ -3849,7 +3820,7 @@ version = "3.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3ed00ed3fbf728b5816498ecd316d1716eecaced9c0c8d2c5a6740ca214985b"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"concurrent-queue",
"hermit-abi 0.4.0",
"pin-project-lite",
@ -4301,7 +4272,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
dependencies = [
"cc",
"cfg-if 1.0.0",
"cfg-if",
"getrandom 0.2.15",
"libc",
"spin 0.9.8",
@ -4715,7 +4686,7 @@ version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"cpufeatures",
"digest",
]
@ -4726,7 +4697,7 @@ version = "0.10.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"cpufeatures",
"digest",
]
@ -5158,7 +5129,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af91f480ee899ab2d9f8435bfdfc14d08a5754bd9d3fef1f1a1c23336aad6c8b"
dependencies = [
"async-channel 1.9.0",
"cfg-if 1.0.0",
"cfg-if",
"futures-core",
"pin-project-lite",
]
@ -5824,7 +5795,7 @@ version = "3.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"fastrand",
"rustix",
"windows-sys 0.52.0",
@ -5873,7 +5844,7 @@ version = "1.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"once_cell",
]
@ -6477,7 +6448,7 @@ version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"wasm-bindgen-macro",
]
@ -6502,7 +6473,7 @@ version = "0.4.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"js-sys",
"wasm-bindgen",
"web-sys",
@ -6593,7 +6564,7 @@ dependencies = [
"async-trait",
"bumpalo",
"cc",
"cfg-if 1.0.0",
"cfg-if",
"encoding_rs",
"hashbrown 0.14.5",
"indexmap 2.2.6",
@ -6635,7 +6606,7 @@ version = "22.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d697d99c341d4a9ffb72f3af7a02124d233eeb59aee010f36d88e97cca553d5e"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
]
[[package]]
@ -6666,7 +6637,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3975deafea000457ba84355c7c0fce0372937204f77026510b7b454f28a3a65"
dependencies = [
"anyhow",
"cfg-if 1.0.0",
"cfg-if",
"cranelift-codegen",
"cranelift-control",
"cranelift-entity",
@ -6714,7 +6685,7 @@ checksum = "4ded58eb2d1bf0dcd2182d0ccd7055c4b10b50d711514f1d73f61515d0fa829d"
dependencies = [
"anyhow",
"cc",
"cfg-if 1.0.0",
"cfg-if",
"rustix",
"wasmtime-asm-macros",
"wasmtime-versioned-export-macros",
@ -6728,7 +6699,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5afe2f0499542f9a4bcfa1b55bfdda803b6ade4e7c93c6b99e0f39dba44b0a91"
dependencies = [
"anyhow",
"cfg-if 1.0.0",
"cfg-if",
"libc",
"windows-sys 0.52.0",
]
@ -6948,18 +6919,6 @@ dependencies = [
"windows-core 0.56.0",
]
[[package]]
name = "wee_alloc"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e"
dependencies = [
"cfg-if 0.1.10",
"libc",
"memory_units",
"winapi",
]
[[package]]
name = "whoami"
version = "1.5.1"
@ -7417,7 +7376,7 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"windows-sys 0.48.0",
]

View file

@ -1,5 +1,5 @@
workspace.resolver = "2"
workspace.members = ["apps/journal", "crates/*", "ui/src-tauri"]
workspace.members = ["apps/*", "crates/*", "ui/src-tauri"]
[profile.wasm-debug]
inherits = "dev"

View file

@ -1 +0,0 @@
main.wasm

10
apps/codetrack/Cargo.toml Normal file
View file

@ -0,0 +1,10 @@
[package]
name = "panorama-codetrack"
version = "0.1.0"
edition = "2021"
[[bin]]
name = "panorama-codetrack"
path = "rust-src/main.rs"
[dependencies]

View file

@ -1,4 +0,0 @@
SOURCES := $(shell find -name "*.go")
main.wasm: $(SOURCES)
GOOS=js GOARCH=wasm go build -o main.wasm

View file

@ -1,3 +0,0 @@
module panorama/codetrack
go 1.21.6

View file

@ -1,7 +0,0 @@
package main
import "fmt"
func main() {
fmt.Println("Hello, WebAssembly!")
}

View file

@ -3,7 +3,7 @@ version: 0.1.0
panorama_version: 0.1.0
description: Code tracking app similar to WakaTime
module: ./main.wasm
command: cargo run -p panorama-codetrack
node_types:
- name: heartbeat

View file

@ -0,0 +1,3 @@
fn main() {
println!("Hello, world!");
}

View file

@ -0,0 +1,9 @@
{
"compilerOptions": {
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"allowJs": false,
"skipLibCheck": true,
"target": "ESNext",
"module": "ESNext"
}
}

View file

@ -0,0 +1,3 @@
export default {
nodeTypes: {},
};

View file

@ -1,11 +0,0 @@
[package]
name = "panorama-journal"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
chrono = "0.4.38"
panorama-app-sdk = { path = "../../crates/panorama-app-sdk" }

View file

@ -1,25 +0,0 @@
name: panorama/journal
version: 0.1.0
panorama_version: 0.1.0
description: Note taking app
# installer_path: ../../target/wasm32-unknown-unknown/wasm-release/panorama_journal.wasm
installer_path: ../../target/wasm32-unknown-unknown/wasm-debug/panorama_journal.wasm
node_types:
- name: page
- name: block
keys:
- name: page/content
type: text
- name: page/day
type: date
endpoints:
- url: /date/:date
method: GET
export_name: get_date_info
permissions:
- @panorama/current_time

View file

@ -1,9 +0,0 @@
#![no_std]
#[macro_use]
extern crate panorama_app_sdk;
#[no_mangle]
pub fn get_date_info() {
panorama_app_sdk::get_current_time();
}

View file

@ -1,5 +0,0 @@
#[repr(C)]
pub struct HttpRequest {}
#[repr(C)]
pub struct HttpResponse {}

View file

@ -1,9 +0,0 @@
[package]
name = "panorama-app-sdk-macros"
version = "0.1.0"
edition = "2021"
[lib]
proc-macro = true
[dependencies]

View file

@ -1,12 +0,0 @@
[package]
name = "panorama-app-sdk"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["rlib"]
[dependencies]
wee_alloc = "0.4.5"
panorama-app-sdk-macros = { path = "../panorama-app-sdk-macros" }
chrono = "0.4.38"

View file

@ -1,27 +0,0 @@
use core::{
fmt,
sync::atomic::{AtomicBool, Ordering},
};
use alloc::{
ffi::CString,
string::String,
vec::{self, Vec},
};
#[doc(hidden)]
pub fn _println(args: fmt::Arguments<'_>) {
_print(format_args!("{}\n", args))
}
#[doc(hidden)]
pub fn _print(args: fmt::Arguments<'_>) {
// print_to(args, stdout, "stdout");
// TODO: Lock prints?
let mut buf = String::new();
alloc::fmt::write(&mut buf, args);
let cs = CString::new(buf).unwrap();
let len = cs.as_bytes_with_nul().len() as u64;
let cptr = cs.into_raw();
unsafe { crate::sys::_print(len, cptr) };
}

View file

@ -1,24 +0,0 @@
#![no_std]
use chrono::{DateTime, Utc};
pub extern crate wee_alloc;
#[macro_use]
extern crate alloc;
// Reference for FFI closures
// https://adventures.michaelfbryan.com/posts/rust-closures-in-ffi/
#[macro_use]
pub mod macros;
pub mod internal;
pub mod sys;
pub mod prelude {}
/// Returns the current time
pub fn get_current_time() -> DateTime<Utc> {
let result = unsafe { sys::_get_current_time() };
DateTime::from_timestamp_nanos(result)
}

View file

@ -1,26 +0,0 @@
#[macro_export]
macro_rules! println {
() => { $crate::print!("\n") };
($($arg:tt)*) => {{ $crate::internal::_println(format_args!($($arg)*)); }};
}
#[macro_export]
macro_rules! print {
($($arg:tt)*) => {{ $crate::internal::_print(format_args!($($arg)*)); }};
}
#[macro_export]
macro_rules! init {
() => {
// Use `wee_alloc` as the global allocator.
#[global_allocator]
static ALLOC: panorama_app_sdk::wee_alloc::WeeAlloc =
panorama_app_sdk::wee_alloc::WeeAlloc::INIT;
#[cfg(no_std)]
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
loop {}
}
};
}

View file

@ -1,17 +0,0 @@
// use crate::RegisterCallback;
use core::ffi::{c_char, c_void};
extern "C" {
pub fn _print(len: u64, ptr: *const c_char);
pub fn register_endpoint(
url_len: u64,
url: *const c_char,
// callback: *mut RegisterCallback,
callback_data: *mut c_void,
);
/// Returns the current time in nanoseconds
pub fn _get_current_time() -> i64;
}

View file

@ -0,0 +1,7 @@
use anyhow::Result;
pub struct Memory {
pub memory: wasmtime::Memory,
}
impl Memory {}

View file

@ -2,6 +2,7 @@
pub mod macros;
pub mod internal;
pub mod manifest;
pub mod memory;
use std::{
collections::HashMap,

View file

@ -0,0 +1,74 @@
pub mod manifest;
use std::{
collections::HashMap,
fs::{self, File},
path::{Path, PathBuf},
};
use anyhow::{Context as _, Result};
use crate::AppState;
use self::manifest::AppManifest;
impl AppState {
pub async fn install_apps_from_search_paths(&self) -> Result<()> {
let search_paths = vec![
PathBuf::from("/Users/michael/Projects/panorama/apps"),
PathBuf::from("/home/michael/Projects/panorama/apps"),
];
let mut found = Vec::new();
for path in search_paths {
if !path.exists() {
continue;
}
let read_dir = fs::read_dir(&path)
.with_context(|| format!("could not read {}", path.display()))?;
for dir_entry in read_dir {
let dir_entry = dir_entry?;
let path = dir_entry.path();
let manifest_path = path.join("manifest.yml");
if manifest_path.exists() {
found.push(path);
}
}
}
// let mut all_app_data = HashMap::new();
// for path in found {
// let app_data = self.install_app_from_path(&path).await?;
// println!("App data: {:?}", app_data);
// all_app_data.insert(
// path.display().to_string(),
// AppData {
// name: "hello".to_string(),
// },
// );
// }
Ok(())
}
async fn install_app_from_path(&self, path: impl AsRef<Path>) -> Result<()> {
let app_path = path.as_ref();
let manifest_path = app_path.join("manifest.yml");
let manifest: AppManifest = {
let file = File::open(&manifest_path)?;
serde_yaml::from_reader(file).with_context(|| {
format!(
"Could not parse config file from {}",
manifest_path.display()
)
})?
};
println!("Manifest: {:?}", manifest);
todo!()
}
}

View file

@ -1,8 +1,9 @@
pub mod apps;
// pub mod apps;
// pub mod codetrack;
// pub mod export;
// pub mod journal;
// pub mod mail;
pub mod appsv0;
pub mod node;
pub mod node_raw;
// pub mod utils;
@ -109,10 +110,6 @@ impl AppState {
.await
.context("Could not migrate database")?;
// let state = self.clone();
// let mail_worker = MailWorker::new(state);
// tokio::spawn(mail_worker.mail_loop());
Ok(())
}

View file

@ -1,6 +1,6 @@
use anyhow::Result;
use clap::{Parser, Subcommand};
use panorama_core::state::apps::manifest::AppManifest;
use panorama_core::state::appsv0::manifest::AppManifest;
use schemars::schema_for;
#[derive(Debug, Parser)]

View file

@ -1,5 +1,5 @@
[package]
name = "panorama-abi"
name = "panorama-sync"
version = "0.1.0"
edition = "2021"

View file

@ -4,3 +4,5 @@
- [Nodes](./nodes.md)
- [Custom Apps](./custom_apps.md)
- [Sync](./sync.md)
- [Dream](./dream.md)
- [Comparison](./comparison.md)

8
docs/src/comparison.md Normal file
View file

@ -0,0 +1,8 @@
# Comparison
From anytype:
- Knowledgeable about clients
- Custom apps by third parties
From logseq:

50
docs/src/dream.md Normal file
View file

@ -0,0 +1,50 @@
# Dream
## Custom Apps List
- File Backup
- Object storage
- Archivebox like system, bookmarking
- Journal
- Block-based editor
- Embed any node type into journal
- Food
- Recipe tracker
- Grocery list (adds to my todo list)
- Meal planner
- Food blogging
- Health+Fitness
- Running progress (incl. saving GPS waypoints)
- Workout log for various workouts
- Weight tracking
- Connect to smartwatch?
- Pictures
- Face recognition
- Map view
- Coding
- Code tracking like Wakatime
- Git forge???
- Calendar
- Calendly-like appointment booking system
- Social
- Store people into people app
- Email+matrix chat
- Video conferencing?
- Feed readers / RSS
- Media
- Music and video hosting / streaming i.e Navidrome
- Money tracking
- Education
- Anki flashcards
- Canvas???
- Dashboards
# Features
- Graph view
- Instantly publish anything
- Notifications
- Full text+OCR search
- IFTTT workflows
- Multiuser
- Google docs like interface for docs / typst

View file

@ -1,6 +1,6 @@
# Panorama
Panorama is a personal information manager. It relies on [Cozo](https://cozodb.org) as its primary data backend.
Panorama is a personal information manager.
- [Repository](https://git.mzhang.io/michael/panorama)
- [Issues](https://git.mzhang.io/michael/panorama/issues)