feat: replace Starlight docs with simple HTML product website
- Removed docs/ (Starlight) - Added www/ with pure HTML/CSS/JS landing page - Product website with features, how it works, get started - Basic HTML documentation pages (installation, quick start, AI providers) - Dockerfile.docs now serves static files from www/ - Updated README and AGENTS.md
This commit is contained in:
@@ -1,17 +1,6 @@
|
|||||||
FROM node:20-alpine AS builder
|
|
||||||
|
|
||||||
WORKDIR /app/docs
|
|
||||||
|
|
||||||
COPY docs/package*.json ./
|
|
||||||
RUN npm install
|
|
||||||
|
|
||||||
COPY docs ./
|
|
||||||
RUN npm run build
|
|
||||||
|
|
||||||
FROM nginx:alpine
|
FROM nginx:alpine
|
||||||
|
|
||||||
COPY --from=builder /app/docs/dist /usr/share/nginx/html
|
COPY www/ /usr/share/nginx/html/
|
||||||
COPY docs/nginx.conf /etc/nginx/http.d/default.conf
|
|
||||||
|
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|
||||||
|
|||||||
29
README.md
29
README.md
@@ -3,7 +3,6 @@
|
|||||||
Self-hosted AI-powered daily journaling application. Capture events throughout the day and let AI generate thoughtful diary pages from your entries.
|
Self-hosted AI-powered daily journaling application. Capture events throughout the day and let AI generate thoughtful diary pages from your entries.
|
||||||
|
|
||||||
[](https://github.com/lotherk/deardiary)
|
[](https://github.com/lotherk/deardiary)
|
||||||
[](https://lotherk.github.io/deardiary)
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
@@ -33,21 +32,19 @@ cd deardiary
|
|||||||
docker compose up -d
|
docker compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
Access the app at `http://localhost:8080`
|
Access the app at `http://localhost:5173`
|
||||||
|
|
||||||
Default credentials: `admin@localhost` / `changeme123`
|
Default credentials: `admin@localhost` / `changeme123`
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
Full documentation is available at [https://lotherk.github.io/deardiary](https://lotherk.github.io/deardiary)
|
Documentation is included in the `www/` directory. Run the website container:
|
||||||
|
|
||||||
Topics covered:
|
```bash
|
||||||
- [Installation](https://lotherk.github.io/deardiary/getting-started/installation/)
|
docker compose up -d docs
|
||||||
- [Quick Start](https://lotherk.github.io/deardiary/getting-started/quick-start/)
|
```
|
||||||
- [Configuration](https://lotherk.github.io/deardiary/getting-started/configuration/)
|
|
||||||
- [Features](https://lotherk.github.io/deardiary/features/events/)
|
Access at `http://localhost:4000`
|
||||||
- [API Reference](https://lotherk.github.io/deardiary/api/authentication/)
|
|
||||||
- [Deployment](https://lotherk.github.io/deardiary/deployment/docker/)
|
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
@@ -81,14 +78,6 @@ npm install
|
|||||||
npm run dev
|
npm run dev
|
||||||
```
|
```
|
||||||
|
|
||||||
### Build Docs Locally
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd docs
|
|
||||||
npm install
|
|
||||||
npm run dev
|
|
||||||
```
|
|
||||||
|
|
||||||
### Docker Build
|
### Docker Build
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -106,7 +95,9 @@ docker compose build && docker compose up -d
|
|||||||
│ ├── pages/ # Page components
|
│ ├── pages/ # Page components
|
||||||
│ ├── components/
|
│ ├── components/
|
||||||
│ └── lib/ # API client, geolocation
|
│ └── lib/ # API client, geolocation
|
||||||
├── docs/ # Starlight documentation site
|
├── www/ # Product website with docs
|
||||||
|
├── Dockerfile # App container
|
||||||
|
├── Dockerfile.docs # Website container
|
||||||
└── docker-compose.yml
|
└── docker-compose.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -1,643 +0,0 @@
|
|||||||
{
|
|
||||||
"$ref": "#/definitions/docs",
|
|
||||||
"definitions": {
|
|
||||||
"docs": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"title": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"description": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"editUrl": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"format": "uri"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "boolean"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"default": true
|
|
||||||
},
|
|
||||||
"head": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"tag": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": [
|
|
||||||
"title",
|
|
||||||
"base",
|
|
||||||
"link",
|
|
||||||
"style",
|
|
||||||
"meta",
|
|
||||||
"script",
|
|
||||||
"noscript",
|
|
||||||
"template"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"attrs": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"not": {}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"content": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"tag"
|
|
||||||
],
|
|
||||||
"additionalProperties": false
|
|
||||||
},
|
|
||||||
"default": []
|
|
||||||
},
|
|
||||||
"tableOfContents": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"minHeadingLevel": {
|
|
||||||
"type": "integer",
|
|
||||||
"minimum": 1,
|
|
||||||
"maximum": 6,
|
|
||||||
"default": 2
|
|
||||||
},
|
|
||||||
"maxHeadingLevel": {
|
|
||||||
"type": "integer",
|
|
||||||
"minimum": 1,
|
|
||||||
"maximum": 6,
|
|
||||||
"default": 3
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"additionalProperties": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "boolean"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"default": {
|
|
||||||
"minHeadingLevel": 2,
|
|
||||||
"maxHeadingLevel": 3
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"template": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": [
|
|
||||||
"doc",
|
|
||||||
"splash"
|
|
||||||
],
|
|
||||||
"default": "doc"
|
|
||||||
},
|
|
||||||
"hero": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"title": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"tagline": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"image": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"alt": {
|
|
||||||
"type": "string",
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
"file": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"file"
|
|
||||||
],
|
|
||||||
"additionalProperties": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"alt": {
|
|
||||||
"type": "string",
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
"dark": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"light": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"dark",
|
|
||||||
"light"
|
|
||||||
],
|
|
||||||
"additionalProperties": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"html": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"html"
|
|
||||||
],
|
|
||||||
"additionalProperties": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"actions": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"text": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"link": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"variant": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": [
|
|
||||||
"primary",
|
|
||||||
"secondary",
|
|
||||||
"minimal"
|
|
||||||
],
|
|
||||||
"default": "primary"
|
|
||||||
},
|
|
||||||
"icon": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"enum": [
|
|
||||||
"up-caret",
|
|
||||||
"down-caret",
|
|
||||||
"right-caret",
|
|
||||||
"left-caret",
|
|
||||||
"up-arrow",
|
|
||||||
"down-arrow",
|
|
||||||
"right-arrow",
|
|
||||||
"left-arrow",
|
|
||||||
"bars",
|
|
||||||
"translate",
|
|
||||||
"pencil",
|
|
||||||
"pen",
|
|
||||||
"document",
|
|
||||||
"add-document",
|
|
||||||
"setting",
|
|
||||||
"external",
|
|
||||||
"download",
|
|
||||||
"cloud-download",
|
|
||||||
"moon",
|
|
||||||
"sun",
|
|
||||||
"laptop",
|
|
||||||
"open-book",
|
|
||||||
"information",
|
|
||||||
"magnifier",
|
|
||||||
"forward-slash",
|
|
||||||
"close",
|
|
||||||
"error",
|
|
||||||
"warning",
|
|
||||||
"approve-check-circle",
|
|
||||||
"approve-check",
|
|
||||||
"rocket",
|
|
||||||
"star",
|
|
||||||
"puzzle",
|
|
||||||
"list-format",
|
|
||||||
"random",
|
|
||||||
"comment",
|
|
||||||
"comment-alt",
|
|
||||||
"heart",
|
|
||||||
"github",
|
|
||||||
"gitlab",
|
|
||||||
"bitbucket",
|
|
||||||
"codePen",
|
|
||||||
"farcaster",
|
|
||||||
"discord",
|
|
||||||
"gitter",
|
|
||||||
"twitter",
|
|
||||||
"x.com",
|
|
||||||
"mastodon",
|
|
||||||
"codeberg",
|
|
||||||
"youtube",
|
|
||||||
"threads",
|
|
||||||
"linkedin",
|
|
||||||
"twitch",
|
|
||||||
"azureDevOps",
|
|
||||||
"microsoftTeams",
|
|
||||||
"instagram",
|
|
||||||
"stackOverflow",
|
|
||||||
"telegram",
|
|
||||||
"rss",
|
|
||||||
"facebook",
|
|
||||||
"email",
|
|
||||||
"phone",
|
|
||||||
"reddit",
|
|
||||||
"patreon",
|
|
||||||
"signal",
|
|
||||||
"slack",
|
|
||||||
"matrix",
|
|
||||||
"hackerOne",
|
|
||||||
"openCollective",
|
|
||||||
"blueSky",
|
|
||||||
"discourse",
|
|
||||||
"zulip",
|
|
||||||
"pinterest",
|
|
||||||
"tiktok",
|
|
||||||
"astro",
|
|
||||||
"alpine",
|
|
||||||
"pnpm",
|
|
||||||
"biome",
|
|
||||||
"bun",
|
|
||||||
"mdx",
|
|
||||||
"apple",
|
|
||||||
"linux",
|
|
||||||
"homebrew",
|
|
||||||
"nix",
|
|
||||||
"starlight",
|
|
||||||
"pkl",
|
|
||||||
"node",
|
|
||||||
"cloudflare",
|
|
||||||
"vercel",
|
|
||||||
"netlify",
|
|
||||||
"deno",
|
|
||||||
"jsr",
|
|
||||||
"nostr",
|
|
||||||
"backstage",
|
|
||||||
"confluence",
|
|
||||||
"jira",
|
|
||||||
"storybook",
|
|
||||||
"vscode",
|
|
||||||
"jetbrains",
|
|
||||||
"zed",
|
|
||||||
"vim",
|
|
||||||
"figma",
|
|
||||||
"sketch",
|
|
||||||
"npm",
|
|
||||||
"sourcehut",
|
|
||||||
"substack",
|
|
||||||
"seti:folder",
|
|
||||||
"seti:bsl",
|
|
||||||
"seti:mdo",
|
|
||||||
"seti:salesforce",
|
|
||||||
"seti:asm",
|
|
||||||
"seti:bicep",
|
|
||||||
"seti:bazel",
|
|
||||||
"seti:c",
|
|
||||||
"seti:c-sharp",
|
|
||||||
"seti:html",
|
|
||||||
"seti:cpp",
|
|
||||||
"seti:clojure",
|
|
||||||
"seti:coldfusion",
|
|
||||||
"seti:config",
|
|
||||||
"seti:crystal",
|
|
||||||
"seti:crystal_embedded",
|
|
||||||
"seti:json",
|
|
||||||
"seti:css",
|
|
||||||
"seti:csv",
|
|
||||||
"seti:xls",
|
|
||||||
"seti:cu",
|
|
||||||
"seti:cake",
|
|
||||||
"seti:cake_php",
|
|
||||||
"seti:d",
|
|
||||||
"seti:word",
|
|
||||||
"seti:elixir",
|
|
||||||
"seti:elixir_script",
|
|
||||||
"seti:hex",
|
|
||||||
"seti:elm",
|
|
||||||
"seti:favicon",
|
|
||||||
"seti:f-sharp",
|
|
||||||
"seti:git",
|
|
||||||
"seti:go",
|
|
||||||
"seti:godot",
|
|
||||||
"seti:gradle",
|
|
||||||
"seti:grails",
|
|
||||||
"seti:graphql",
|
|
||||||
"seti:hacklang",
|
|
||||||
"seti:haml",
|
|
||||||
"seti:mustache",
|
|
||||||
"seti:haskell",
|
|
||||||
"seti:haxe",
|
|
||||||
"seti:jade",
|
|
||||||
"seti:java",
|
|
||||||
"seti:javascript",
|
|
||||||
"seti:jinja",
|
|
||||||
"seti:julia",
|
|
||||||
"seti:karma",
|
|
||||||
"seti:kotlin",
|
|
||||||
"seti:dart",
|
|
||||||
"seti:liquid",
|
|
||||||
"seti:livescript",
|
|
||||||
"seti:lua",
|
|
||||||
"seti:markdown",
|
|
||||||
"seti:argdown",
|
|
||||||
"seti:info",
|
|
||||||
"seti:clock",
|
|
||||||
"seti:maven",
|
|
||||||
"seti:nim",
|
|
||||||
"seti:github",
|
|
||||||
"seti:notebook",
|
|
||||||
"seti:nunjucks",
|
|
||||||
"seti:npm",
|
|
||||||
"seti:ocaml",
|
|
||||||
"seti:odata",
|
|
||||||
"seti:perl",
|
|
||||||
"seti:php",
|
|
||||||
"seti:pipeline",
|
|
||||||
"seti:pddl",
|
|
||||||
"seti:plan",
|
|
||||||
"seti:happenings",
|
|
||||||
"seti:powershell",
|
|
||||||
"seti:prisma",
|
|
||||||
"seti:pug",
|
|
||||||
"seti:puppet",
|
|
||||||
"seti:purescript",
|
|
||||||
"seti:python",
|
|
||||||
"seti:react",
|
|
||||||
"seti:rescript",
|
|
||||||
"seti:R",
|
|
||||||
"seti:ruby",
|
|
||||||
"seti:rust",
|
|
||||||
"seti:sass",
|
|
||||||
"seti:spring",
|
|
||||||
"seti:slim",
|
|
||||||
"seti:smarty",
|
|
||||||
"seti:sbt",
|
|
||||||
"seti:scala",
|
|
||||||
"seti:ethereum",
|
|
||||||
"seti:stylus",
|
|
||||||
"seti:svelte",
|
|
||||||
"seti:swift",
|
|
||||||
"seti:db",
|
|
||||||
"seti:terraform",
|
|
||||||
"seti:tex",
|
|
||||||
"seti:default",
|
|
||||||
"seti:twig",
|
|
||||||
"seti:typescript",
|
|
||||||
"seti:tsconfig",
|
|
||||||
"seti:vala",
|
|
||||||
"seti:vite",
|
|
||||||
"seti:vue",
|
|
||||||
"seti:wasm",
|
|
||||||
"seti:wat",
|
|
||||||
"seti:xml",
|
|
||||||
"seti:yml",
|
|
||||||
"seti:prolog",
|
|
||||||
"seti:zig",
|
|
||||||
"seti:zip",
|
|
||||||
"seti:wgt",
|
|
||||||
"seti:illustrator",
|
|
||||||
"seti:photoshop",
|
|
||||||
"seti:pdf",
|
|
||||||
"seti:font",
|
|
||||||
"seti:image",
|
|
||||||
"seti:svg",
|
|
||||||
"seti:sublime",
|
|
||||||
"seti:code-search",
|
|
||||||
"seti:shell",
|
|
||||||
"seti:video",
|
|
||||||
"seti:audio",
|
|
||||||
"seti:windows",
|
|
||||||
"seti:jenkins",
|
|
||||||
"seti:babel",
|
|
||||||
"seti:bower",
|
|
||||||
"seti:docker",
|
|
||||||
"seti:code-climate",
|
|
||||||
"seti:eslint",
|
|
||||||
"seti:firebase",
|
|
||||||
"seti:firefox",
|
|
||||||
"seti:gitlab",
|
|
||||||
"seti:grunt",
|
|
||||||
"seti:gulp",
|
|
||||||
"seti:ionic",
|
|
||||||
"seti:platformio",
|
|
||||||
"seti:rollup",
|
|
||||||
"seti:stylelint",
|
|
||||||
"seti:yarn",
|
|
||||||
"seti:webpack",
|
|
||||||
"seti:lock",
|
|
||||||
"seti:license",
|
|
||||||
"seti:makefile",
|
|
||||||
"seti:heroku",
|
|
||||||
"seti:todo",
|
|
||||||
"seti:ignored"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"pattern": "^\\<svg"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"attrs": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": [
|
|
||||||
"string",
|
|
||||||
"number",
|
|
||||||
"boolean"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"text",
|
|
||||||
"link"
|
|
||||||
],
|
|
||||||
"additionalProperties": false
|
|
||||||
},
|
|
||||||
"default": []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"additionalProperties": false
|
|
||||||
},
|
|
||||||
"lastUpdated": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"format": "date-time"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"format": "date"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "integer",
|
|
||||||
"format": "unix-time"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "boolean"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"prev": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"link": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"label": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"additionalProperties": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"next": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"link": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"label": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"additionalProperties": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"sidebar": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"order": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"label": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"hidden": {
|
|
||||||
"type": "boolean",
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
"badge": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"variant": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": [
|
|
||||||
"note",
|
|
||||||
"danger",
|
|
||||||
"success",
|
|
||||||
"caution",
|
|
||||||
"tip",
|
|
||||||
"default"
|
|
||||||
],
|
|
||||||
"default": "default"
|
|
||||||
},
|
|
||||||
"class": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"text": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"text"
|
|
||||||
],
|
|
||||||
"additionalProperties": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"attrs": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"not": {}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"default": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"additionalProperties": false,
|
|
||||||
"default": {}
|
|
||||||
},
|
|
||||||
"banner": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"content": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"content"
|
|
||||||
],
|
|
||||||
"additionalProperties": false
|
|
||||||
},
|
|
||||||
"pagefind": {
|
|
||||||
"type": "boolean",
|
|
||||||
"default": true
|
|
||||||
},
|
|
||||||
"draft": {
|
|
||||||
"type": "boolean",
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
"$schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"title"
|
|
||||||
],
|
|
||||||
"additionalProperties": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#"
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export default new Map();
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
|
|
||||||
export default new Map([
|
|
||||||
["src/content/docs/index.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Findex.mdx&astroContentModuleFlag=true")],
|
|
||||||
["src/content/docs/api/authentication.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fapi%2Fauthentication.mdx&astroContentModuleFlag=true")],
|
|
||||||
["src/content/docs/api/events.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fapi%2Fevents.mdx&astroContentModuleFlag=true")],
|
|
||||||
["src/content/docs/api/journals.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fapi%2Fjournals.mdx&astroContentModuleFlag=true")],
|
|
||||||
["src/content/docs/api/settings.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fapi%2Fsettings.mdx&astroContentModuleFlag=true")],
|
|
||||||
["src/content/docs/deployment/docker.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdeployment%2Fdocker.mdx&astroContentModuleFlag=true")],
|
|
||||||
["src/content/docs/deployment/environment.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdeployment%2Fenvironment.mdx&astroContentModuleFlag=true")],
|
|
||||||
["src/content/docs/features/ai-providers.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Ffeatures%2Fai-providers.mdx&astroContentModuleFlag=true")],
|
|
||||||
["src/content/docs/features/calendar.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Ffeatures%2Fcalendar.mdx&astroContentModuleFlag=true")],
|
|
||||||
["src/content/docs/features/diary-pages.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Ffeatures%2Fdiary-pages.mdx&astroContentModuleFlag=true")],
|
|
||||||
["src/content/docs/features/export-import.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Ffeatures%2Fexport-import.mdx&astroContentModuleFlag=true")],
|
|
||||||
["src/content/docs/features/media.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Ffeatures%2Fmedia.mdx&astroContentModuleFlag=true")],
|
|
||||||
["src/content/docs/features/search.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Ffeatures%2Fsearch.mdx&astroContentModuleFlag=true")],
|
|
||||||
["src/content/docs/getting-started/configuration.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fgetting-started%2Fconfiguration.mdx&astroContentModuleFlag=true")],
|
|
||||||
["src/content/docs/getting-started/installation.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fgetting-started%2Finstallation.mdx&astroContentModuleFlag=true")],
|
|
||||||
["src/content/docs/getting-started/quick-start.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fgetting-started%2Fquick-start.mdx&astroContentModuleFlag=true")],
|
|
||||||
["src/content/docs/features/events.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Ffeatures%2Fevents.mdx&astroContentModuleFlag=true")]]);
|
|
||||||
|
|
||||||
218
docs/.astro/content.d.ts
vendored
218
docs/.astro/content.d.ts
vendored
@@ -1,218 +0,0 @@
|
|||||||
declare module 'astro:content' {
|
|
||||||
interface Render {
|
|
||||||
'.mdx': Promise<{
|
|
||||||
Content: import('astro').MDXContent;
|
|
||||||
headings: import('astro').MarkdownHeading[];
|
|
||||||
remarkPluginFrontmatter: Record<string, any>;
|
|
||||||
components: import('astro').MDXInstance<{}>['components'];
|
|
||||||
}>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'astro:content' {
|
|
||||||
export interface RenderResult {
|
|
||||||
Content: import('astro/runtime/server/index.js').AstroComponentFactory;
|
|
||||||
headings: import('astro').MarkdownHeading[];
|
|
||||||
remarkPluginFrontmatter: Record<string, any>;
|
|
||||||
}
|
|
||||||
interface Render {
|
|
||||||
'.md': Promise<RenderResult>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RenderedContent {
|
|
||||||
html: string;
|
|
||||||
metadata?: {
|
|
||||||
imagePaths: Array<string>;
|
|
||||||
[key: string]: unknown;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'astro:content' {
|
|
||||||
type Flatten<T> = T extends { [K: string]: infer U } ? U : never;
|
|
||||||
|
|
||||||
export type CollectionKey = keyof AnyEntryMap;
|
|
||||||
export type CollectionEntry<C extends CollectionKey> = Flatten<AnyEntryMap[C]>;
|
|
||||||
|
|
||||||
export type ContentCollectionKey = keyof ContentEntryMap;
|
|
||||||
export type DataCollectionKey = keyof DataEntryMap;
|
|
||||||
|
|
||||||
type AllValuesOf<T> = T extends any ? T[keyof T] : never;
|
|
||||||
type ValidContentEntrySlug<C extends keyof ContentEntryMap> = AllValuesOf<
|
|
||||||
ContentEntryMap[C]
|
|
||||||
>['slug'];
|
|
||||||
|
|
||||||
export type ReferenceDataEntry<
|
|
||||||
C extends CollectionKey,
|
|
||||||
E extends keyof DataEntryMap[C] = string,
|
|
||||||
> = {
|
|
||||||
collection: C;
|
|
||||||
id: E;
|
|
||||||
};
|
|
||||||
export type ReferenceContentEntry<
|
|
||||||
C extends keyof ContentEntryMap,
|
|
||||||
E extends ValidContentEntrySlug<C> | (string & {}) = string,
|
|
||||||
> = {
|
|
||||||
collection: C;
|
|
||||||
slug: E;
|
|
||||||
};
|
|
||||||
export type ReferenceLiveEntry<C extends keyof LiveContentConfig['collections']> = {
|
|
||||||
collection: C;
|
|
||||||
id: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @deprecated Use `getEntry` instead. */
|
|
||||||
export function getEntryBySlug<
|
|
||||||
C extends keyof ContentEntryMap,
|
|
||||||
E extends ValidContentEntrySlug<C> | (string & {}),
|
|
||||||
>(
|
|
||||||
collection: C,
|
|
||||||
// Note that this has to accept a regular string too, for SSR
|
|
||||||
entrySlug: E,
|
|
||||||
): E extends ValidContentEntrySlug<C>
|
|
||||||
? Promise<CollectionEntry<C>>
|
|
||||||
: Promise<CollectionEntry<C> | undefined>;
|
|
||||||
|
|
||||||
/** @deprecated Use `getEntry` instead. */
|
|
||||||
export function getDataEntryById<C extends keyof DataEntryMap, E extends keyof DataEntryMap[C]>(
|
|
||||||
collection: C,
|
|
||||||
entryId: E,
|
|
||||||
): Promise<CollectionEntry<C>>;
|
|
||||||
|
|
||||||
export function getCollection<C extends keyof AnyEntryMap, E extends CollectionEntry<C>>(
|
|
||||||
collection: C,
|
|
||||||
filter?: (entry: CollectionEntry<C>) => entry is E,
|
|
||||||
): Promise<E[]>;
|
|
||||||
export function getCollection<C extends keyof AnyEntryMap>(
|
|
||||||
collection: C,
|
|
||||||
filter?: (entry: CollectionEntry<C>) => unknown,
|
|
||||||
): Promise<CollectionEntry<C>[]>;
|
|
||||||
|
|
||||||
export function getLiveCollection<C extends keyof LiveContentConfig['collections']>(
|
|
||||||
collection: C,
|
|
||||||
filter?: LiveLoaderCollectionFilterType<C>,
|
|
||||||
): Promise<
|
|
||||||
import('astro').LiveDataCollectionResult<LiveLoaderDataType<C>, LiveLoaderErrorType<C>>
|
|
||||||
>;
|
|
||||||
|
|
||||||
export function getEntry<
|
|
||||||
C extends keyof ContentEntryMap,
|
|
||||||
E extends ValidContentEntrySlug<C> | (string & {}),
|
|
||||||
>(
|
|
||||||
entry: ReferenceContentEntry<C, E>,
|
|
||||||
): E extends ValidContentEntrySlug<C>
|
|
||||||
? Promise<CollectionEntry<C>>
|
|
||||||
: Promise<CollectionEntry<C> | undefined>;
|
|
||||||
export function getEntry<
|
|
||||||
C extends keyof DataEntryMap,
|
|
||||||
E extends keyof DataEntryMap[C] | (string & {}),
|
|
||||||
>(
|
|
||||||
entry: ReferenceDataEntry<C, E>,
|
|
||||||
): E extends keyof DataEntryMap[C]
|
|
||||||
? Promise<DataEntryMap[C][E]>
|
|
||||||
: Promise<CollectionEntry<C> | undefined>;
|
|
||||||
export function getEntry<
|
|
||||||
C extends keyof ContentEntryMap,
|
|
||||||
E extends ValidContentEntrySlug<C> | (string & {}),
|
|
||||||
>(
|
|
||||||
collection: C,
|
|
||||||
slug: E,
|
|
||||||
): E extends ValidContentEntrySlug<C>
|
|
||||||
? Promise<CollectionEntry<C>>
|
|
||||||
: Promise<CollectionEntry<C> | undefined>;
|
|
||||||
export function getEntry<
|
|
||||||
C extends keyof DataEntryMap,
|
|
||||||
E extends keyof DataEntryMap[C] | (string & {}),
|
|
||||||
>(
|
|
||||||
collection: C,
|
|
||||||
id: E,
|
|
||||||
): E extends keyof DataEntryMap[C]
|
|
||||||
? string extends keyof DataEntryMap[C]
|
|
||||||
? Promise<DataEntryMap[C][E]> | undefined
|
|
||||||
: Promise<DataEntryMap[C][E]>
|
|
||||||
: Promise<CollectionEntry<C> | undefined>;
|
|
||||||
export function getLiveEntry<C extends keyof LiveContentConfig['collections']>(
|
|
||||||
collection: C,
|
|
||||||
filter: string | LiveLoaderEntryFilterType<C>,
|
|
||||||
): Promise<import('astro').LiveDataEntryResult<LiveLoaderDataType<C>, LiveLoaderErrorType<C>>>;
|
|
||||||
|
|
||||||
/** Resolve an array of entry references from the same collection */
|
|
||||||
export function getEntries<C extends keyof ContentEntryMap>(
|
|
||||||
entries: ReferenceContentEntry<C, ValidContentEntrySlug<C>>[],
|
|
||||||
): Promise<CollectionEntry<C>[]>;
|
|
||||||
export function getEntries<C extends keyof DataEntryMap>(
|
|
||||||
entries: ReferenceDataEntry<C, keyof DataEntryMap[C]>[],
|
|
||||||
): Promise<CollectionEntry<C>[]>;
|
|
||||||
|
|
||||||
export function render<C extends keyof AnyEntryMap>(
|
|
||||||
entry: AnyEntryMap[C][string],
|
|
||||||
): Promise<RenderResult>;
|
|
||||||
|
|
||||||
export function reference<C extends keyof AnyEntryMap>(
|
|
||||||
collection: C,
|
|
||||||
): import('astro/zod').ZodEffects<
|
|
||||||
import('astro/zod').ZodString,
|
|
||||||
C extends keyof ContentEntryMap
|
|
||||||
? ReferenceContentEntry<C, ValidContentEntrySlug<C>>
|
|
||||||
: ReferenceDataEntry<C, keyof DataEntryMap[C]>
|
|
||||||
>;
|
|
||||||
// Allow generic `string` to avoid excessive type errors in the config
|
|
||||||
// if `dev` is not running to update as you edit.
|
|
||||||
// Invalid collection names will be caught at build time.
|
|
||||||
export function reference<C extends string>(
|
|
||||||
collection: C,
|
|
||||||
): import('astro/zod').ZodEffects<import('astro/zod').ZodString, never>;
|
|
||||||
|
|
||||||
type ReturnTypeOrOriginal<T> = T extends (...args: any[]) => infer R ? R : T;
|
|
||||||
type InferEntrySchema<C extends keyof AnyEntryMap> = import('astro/zod').infer<
|
|
||||||
ReturnTypeOrOriginal<Required<ContentConfig['collections'][C]>['schema']>
|
|
||||||
>;
|
|
||||||
|
|
||||||
type ContentEntryMap = {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
type DataEntryMap = {
|
|
||||||
"docs": Record<string, {
|
|
||||||
id: string;
|
|
||||||
body?: string;
|
|
||||||
collection: "docs";
|
|
||||||
data: any;
|
|
||||||
rendered?: RenderedContent;
|
|
||||||
filePath?: string;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
type AnyEntryMap = ContentEntryMap & DataEntryMap;
|
|
||||||
|
|
||||||
type ExtractLoaderTypes<T> = T extends import('astro/loaders').LiveLoader<
|
|
||||||
infer TData,
|
|
||||||
infer TEntryFilter,
|
|
||||||
infer TCollectionFilter,
|
|
||||||
infer TError
|
|
||||||
>
|
|
||||||
? { data: TData; entryFilter: TEntryFilter; collectionFilter: TCollectionFilter; error: TError }
|
|
||||||
: { data: never; entryFilter: never; collectionFilter: never; error: never };
|
|
||||||
type ExtractDataType<T> = ExtractLoaderTypes<T>['data'];
|
|
||||||
type ExtractEntryFilterType<T> = ExtractLoaderTypes<T>['entryFilter'];
|
|
||||||
type ExtractCollectionFilterType<T> = ExtractLoaderTypes<T>['collectionFilter'];
|
|
||||||
type ExtractErrorType<T> = ExtractLoaderTypes<T>['error'];
|
|
||||||
|
|
||||||
type LiveLoaderDataType<C extends keyof LiveContentConfig['collections']> =
|
|
||||||
LiveContentConfig['collections'][C]['schema'] extends undefined
|
|
||||||
? ExtractDataType<LiveContentConfig['collections'][C]['loader']>
|
|
||||||
: import('astro/zod').infer<
|
|
||||||
Exclude<LiveContentConfig['collections'][C]['schema'], undefined>
|
|
||||||
>;
|
|
||||||
type LiveLoaderEntryFilterType<C extends keyof LiveContentConfig['collections']> =
|
|
||||||
ExtractEntryFilterType<LiveContentConfig['collections'][C]['loader']>;
|
|
||||||
type LiveLoaderCollectionFilterType<C extends keyof LiveContentConfig['collections']> =
|
|
||||||
ExtractCollectionFilterType<LiveContentConfig['collections'][C]['loader']>;
|
|
||||||
type LiveLoaderErrorType<C extends keyof LiveContentConfig['collections']> = ExtractErrorType<
|
|
||||||
LiveContentConfig['collections'][C]['loader']
|
|
||||||
>;
|
|
||||||
|
|
||||||
export type ContentConfig = typeof import("../src/content.config.mjs");
|
|
||||||
export type LiveContentConfig = never;
|
|
||||||
}
|
|
||||||
2
docs/.astro/types.d.ts
vendored
2
docs/.astro/types.d.ts
vendored
@@ -1,2 +0,0 @@
|
|||||||
/// <reference types="astro/client" />
|
|
||||||
/// <reference path="content.d.ts" />
|
|
||||||
254
docs/api.md
254
docs/api.md
@@ -1,254 +0,0 @@
|
|||||||
# API Reference
|
|
||||||
|
|
||||||
Base URL: `/api/v1`
|
|
||||||
|
|
||||||
Authentication: All requests require an API key in the `Authorization` header:
|
|
||||||
```
|
|
||||||
Authorization: Bearer <api_key>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Authentication
|
|
||||||
|
|
||||||
### Register User
|
|
||||||
```bash
|
|
||||||
curl -X POST http://localhost:3000/api/v1/auth/register \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{"email": "user@example.com", "password": "password123"}'
|
|
||||||
```
|
|
||||||
|
|
||||||
### Login
|
|
||||||
```bash
|
|
||||||
curl -X POST http://localhost:3000/api/v1/auth/login \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{"email": "user@example.com", "password": "password123"}'
|
|
||||||
```
|
|
||||||
|
|
||||||
Response:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"token": "jwt_token",
|
|
||||||
"userId": "user_id"
|
|
||||||
},
|
|
||||||
"error": null
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Create API Key
|
|
||||||
```bash
|
|
||||||
curl -X POST http://localhost:3000/api/v1/auth/api-key \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-H "Authorization: Bearer <token>" \
|
|
||||||
-d '{"name": "my-app"}'
|
|
||||||
```
|
|
||||||
|
|
||||||
## Events
|
|
||||||
|
|
||||||
### Create Event
|
|
||||||
```bash
|
|
||||||
curl -X POST http://localhost:3000/api/v1/events \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-H "Authorization: Bearer <api_key>" \
|
|
||||||
-d '{
|
|
||||||
"date": "2026-03-27",
|
|
||||||
"type": "event",
|
|
||||||
"content": "Had a great meeting about the new project"
|
|
||||||
}'
|
|
||||||
```
|
|
||||||
|
|
||||||
Valid types: `event`, `text`, `photo`, `voice`, `health`
|
|
||||||
|
|
||||||
### Get Event
|
|
||||||
```bash
|
|
||||||
curl http://localhost:3000/api/v1/events/<event_id> \
|
|
||||||
-H "Authorization: Bearer <api_key>"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Update Event
|
|
||||||
```bash
|
|
||||||
curl -X PUT http://localhost:3000/api/v1/events/<event_id> \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-H "Authorization: Bearer <api_key>" \
|
|
||||||
-d '{"content": "Updated content"}'
|
|
||||||
```
|
|
||||||
|
|
||||||
Note: Events cannot be updated if a diary page has been generated for that date.
|
|
||||||
|
|
||||||
### Delete Event
|
|
||||||
```bash
|
|
||||||
curl -X DELETE http://localhost:3000/api/v1/events/<event_id> \
|
|
||||||
-H "Authorization: Bearer <api_key>"
|
|
||||||
```
|
|
||||||
|
|
||||||
Note: Events cannot be deleted if a diary page has been generated for that date.
|
|
||||||
|
|
||||||
## Days
|
|
||||||
|
|
||||||
### List Days
|
|
||||||
```bash
|
|
||||||
curl http://localhost:3000/api/v1/days \
|
|
||||||
-H "Authorization: Bearer <api_key>"
|
|
||||||
```
|
|
||||||
|
|
||||||
Response:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"data": [
|
|
||||||
{
|
|
||||||
"date": "2026-03-27",
|
|
||||||
"eventCount": 5,
|
|
||||||
"hasJournal": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"error": null
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Get Day Details
|
|
||||||
```bash
|
|
||||||
curl http://localhost:3000/api/v1/days/2026-03-27 \
|
|
||||||
-H "Authorization: Bearer <api_key>"
|
|
||||||
```
|
|
||||||
|
|
||||||
Response:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"date": "2026-03-27",
|
|
||||||
"events": [...],
|
|
||||||
"journal": {...}
|
|
||||||
},
|
|
||||||
"error": null
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Delete Day (and journal)
|
|
||||||
```bash
|
|
||||||
curl -X DELETE http://localhost:3000/api/v1/days/2026-03-27 \
|
|
||||||
-H "Authorization: Bearer <api_key>"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Journal
|
|
||||||
|
|
||||||
### Generate Diary Page
|
|
||||||
```bash
|
|
||||||
curl -X POST http://localhost:3000/api/v1/journal/generate/2026-03-27 \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-H "Authorization: Bearer <api_key>" \
|
|
||||||
-d '{"instructions": "Focus more on the technical aspects"}'
|
|
||||||
```
|
|
||||||
|
|
||||||
The `instructions` field is optional. If provided, it will be appended to the prompt for regeneration.
|
|
||||||
|
|
||||||
Response:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"journal": {
|
|
||||||
"id": "...",
|
|
||||||
"date": "2026-03-27",
|
|
||||||
"content": "Generated diary content...",
|
|
||||||
"eventCount": 5,
|
|
||||||
"generatedAt": "2026-03-27T10:30:00Z"
|
|
||||||
},
|
|
||||||
"task": {
|
|
||||||
"id": "...",
|
|
||||||
"type": "journal_generate",
|
|
||||||
"status": "completed",
|
|
||||||
"provider": "groq",
|
|
||||||
"model": "llama-3.3-70b-versatile"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"error": null
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Get Journal
|
|
||||||
```bash
|
|
||||||
curl http://localhost:3000/api/v1/journal/2026-03-27 \
|
|
||||||
-H "Authorization: Bearer <api_key>"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Delete Journal
|
|
||||||
```bash
|
|
||||||
curl -X DELETE http://localhost:3000/api/v1/journal/2026-03-27 \
|
|
||||||
-H "Authorization: Bearer <api_key>"
|
|
||||||
```
|
|
||||||
|
|
||||||
Deleting the journal unlocks events for editing.
|
|
||||||
|
|
||||||
### Get Journal Tasks
|
|
||||||
```bash
|
|
||||||
curl http://localhost:3000/api/v1/journal/2026-03-27/tasks \
|
|
||||||
-H "Authorization: Bearer <api_key>"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Tasks
|
|
||||||
|
|
||||||
### Get Task
|
|
||||||
```bash
|
|
||||||
curl http://localhost:3000/api/v1/tasks/<task_id> \
|
|
||||||
-H "Authorization: Bearer <api_key>"
|
|
||||||
```
|
|
||||||
|
|
||||||
Response includes full request/response JSON for debugging.
|
|
||||||
|
|
||||||
## Settings
|
|
||||||
|
|
||||||
### Get Settings
|
|
||||||
```bash
|
|
||||||
curl http://localhost:3000/api/v1/settings \
|
|
||||||
-H "Authorization: Bearer <api_key>"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Update Settings
|
|
||||||
```bash
|
|
||||||
curl -X PUT http://localhost:3000/api/v1/settings \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-H "Authorization: Bearer <api_key>" \
|
|
||||||
-d '{
|
|
||||||
"aiProvider": "groq",
|
|
||||||
"providerSettings": {
|
|
||||||
"groq": {
|
|
||||||
"apiKey": "your-api-key",
|
|
||||||
"model": "llama-3.3-70b-versatile"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}'
|
|
||||||
```
|
|
||||||
|
|
||||||
## AI Providers
|
|
||||||
|
|
||||||
### Test Connection
|
|
||||||
```bash
|
|
||||||
curl -X POST http://localhost:3000/api/v1/ai/test \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-H "Authorization: Bearer <api_key>" \
|
|
||||||
-d '{
|
|
||||||
"provider": "groq",
|
|
||||||
"apiKey": "your-api-key",
|
|
||||||
"model": "llama-3.3-70b-versatile"
|
|
||||||
}'
|
|
||||||
```
|
|
||||||
|
|
||||||
Supported providers: `groq`, `openai`, `anthropic`, `ollama`, `lmstudio`
|
|
||||||
|
|
||||||
## Error Responses
|
|
||||||
|
|
||||||
All endpoints return errors in this format:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"data": null,
|
|
||||||
"error": {
|
|
||||||
"code": "ERROR_CODE",
|
|
||||||
"message": "Human readable message"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Common error codes:
|
|
||||||
- `UNAUTHORIZED` - Invalid or missing API key
|
|
||||||
- `NOT_FOUND` - Resource not found
|
|
||||||
- `NO_EVENTS` - No events for diary generation
|
|
||||||
- `NO_AI_CONFIG` - AI provider not configured
|
|
||||||
- `EVENT_IMMUTABLE` - Cannot modify event (diary exists)
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
import { defineConfig } from 'astro/config';
|
|
||||||
import starlight from '@astrojs/starlight';
|
|
||||||
|
|
||||||
export default defineConfig({
|
|
||||||
integrations: [
|
|
||||||
starlight({
|
|
||||||
title: 'DearDiary',
|
|
||||||
description: 'AI-Powered Daily Journal - Self-hosted journaling app where users capture events throughout the day and AI generates diary pages.',
|
|
||||||
logo: {
|
|
||||||
light: './src/assets/logo-light.svg',
|
|
||||||
dark: './src/assets/logo-dark.svg',
|
|
||||||
replacesTitle: true,
|
|
||||||
},
|
|
||||||
social: [
|
|
||||||
{ icon: 'github', label: 'GitHub', href: 'https://github.com/lotherk/deardiary' },
|
|
||||||
],
|
|
||||||
editLink: {
|
|
||||||
baseUrl: 'https://github.com/lotherk/deardiary/edit/main/',
|
|
||||||
},
|
|
||||||
sidebar: [
|
|
||||||
{
|
|
||||||
label: 'Getting Started',
|
|
||||||
autogenerate: { directory: 'getting-started' },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Features',
|
|
||||||
autogenerate: { directory: 'features' },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'API Reference',
|
|
||||||
autogenerate: { directory: 'api' },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Deployment',
|
|
||||||
autogenerate: { directory: 'deployment' },
|
|
||||||
},
|
|
||||||
],
|
|
||||||
customCss: ['./src/styles/custom.css'],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name _;
|
|
||||||
|
|
||||||
root /usr/share/nginx/html;
|
|
||||||
index index.html;
|
|
||||||
|
|
||||||
# Starlight static site
|
|
||||||
location / {
|
|
||||||
try_files $uri $uri/ $uri.html =404;
|
|
||||||
}
|
|
||||||
|
|
||||||
# SPA fallback for client-side routing
|
|
||||||
location ~ ^/[^.]+$ {
|
|
||||||
try_files $uri $uri.html =404;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Cache static assets
|
|
||||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
|
|
||||||
expires 1y;
|
|
||||||
add_header Cache-Control "public, immutable";
|
|
||||||
}
|
|
||||||
|
|
||||||
# Security headers
|
|
||||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
|
||||||
add_header X-Content-Type-Options "nosniff" always;
|
|
||||||
add_header X-XSS-Protection "1; mode=block" always;
|
|
||||||
}
|
|
||||||
7311
docs/package-lock.json
generated
7311
docs/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "deardiary-docs",
|
|
||||||
"version": "0.1.0",
|
|
||||||
"private": true,
|
|
||||||
"scripts": {
|
|
||||||
"dev": "astro dev",
|
|
||||||
"start": "astro dev",
|
|
||||||
"build": "astro build",
|
|
||||||
"preview": "astro preview"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@astrojs/starlight": "^0.34.2",
|
|
||||||
"astro": "^5.6.1",
|
|
||||||
"sharp": "^0.33.5",
|
|
||||||
"zod": "^3.23.8"
|
|
||||||
},
|
|
||||||
"overrides": {
|
|
||||||
"zod": "^3.23.8"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
|
||||||
<defs>
|
|
||||||
<linearGradient id="grad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
||||||
<stop offset="0%" style="stop-color:#a78bfa;stop-opacity:1" />
|
|
||||||
<stop offset="100%" style="stop-color:#818cf8;stop-opacity:1" />
|
|
||||||
</linearGradient>
|
|
||||||
</defs>
|
|
||||||
<rect width="100" height="100" rx="20" fill="url(#grad)"/>
|
|
||||||
<path d="M25 25 L75 25 L75 80 L25 80 Z" fill="none" stroke="white" stroke-width="3" stroke-linecap="round"/>
|
|
||||||
<path d="M35 40 L65 40" stroke="white" stroke-width="2" stroke-linecap="round"/>
|
|
||||||
<path d="M35 50 L65 50" stroke="white" stroke-width="2" stroke-linecap="round"/>
|
|
||||||
<path d="M35 60 L55 60" stroke="white" stroke-width="2" stroke-linecap="round"/>
|
|
||||||
<circle cx="70" cy="60" r="8" fill="white" opacity="0.3"/>
|
|
||||||
<path d="M70 55 L70 65 M65 60 L75 60" stroke="white" stroke-width="2" stroke-linecap="round"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 897 B |
@@ -1,15 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
|
||||||
<defs>
|
|
||||||
<linearGradient id="grad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
||||||
<stop offset="0%" style="stop-color:#8b5cf6;stop-opacity:1" />
|
|
||||||
<stop offset="100%" style="stop-color:#6366f1;stop-opacity:1" />
|
|
||||||
</linearGradient>
|
|
||||||
</defs>
|
|
||||||
<rect width="100" height="100" rx="20" fill="url(#grad)"/>
|
|
||||||
<path d="M25 25 L75 25 L75 80 L25 80 Z" fill="none" stroke="white" stroke-width="3" stroke-linecap="round"/>
|
|
||||||
<path d="M35 40 L65 40" stroke="white" stroke-width="2" stroke-linecap="round"/>
|
|
||||||
<path d="M35 50 L65 50" stroke="white" stroke-width="2" stroke-linecap="round"/>
|
|
||||||
<path d="M35 60 L55 60" stroke="white" stroke-width="2" stroke-linecap="round"/>
|
|
||||||
<circle cx="70" cy="60" r="8" fill="white" opacity="0.3"/>
|
|
||||||
<path d="M70 55 L70 65 M65 60 L75 60" stroke="white" stroke-width="2" stroke-linecap="round"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 897 B |
@@ -1,47 +0,0 @@
|
|||||||
---
|
|
||||||
title: Authentication
|
|
||||||
description: API authentication methods
|
|
||||||
sidebar:
|
|
||||||
order: 1
|
|
||||||
---
|
|
||||||
|
|
||||||
## API Key Authentication
|
|
||||||
|
|
||||||
All API requests require authentication using a Bearer token:
|
|
||||||
|
|
||||||
```http
|
|
||||||
Authorization: Bearer your-api-key-here
|
|
||||||
```
|
|
||||||
|
|
||||||
## Getting an API Key
|
|
||||||
|
|
||||||
### Via Login
|
|
||||||
|
|
||||||
1. POST to `/api/v1/auth/login` with email/password
|
|
||||||
2. Receive JWT token
|
|
||||||
3. Create API key via POST to `/api/v1/auth/api-key`
|
|
||||||
|
|
||||||
### Via Registration
|
|
||||||
|
|
||||||
1. POST to `/api/v1/auth/register` with email/password
|
|
||||||
2. Receive API key directly
|
|
||||||
|
|
||||||
## Response Format
|
|
||||||
|
|
||||||
All endpoints return:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"data": { ... } | null,
|
|
||||||
"error": { "code": "ERROR_CODE", "message": "Error description" } | null
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Error Codes
|
|
||||||
|
|
||||||
| Code | HTTP Status | Description |
|
|
||||||
|------|-------------|-------------|
|
|
||||||
| `UNAUTHORIZED` | 401 | Invalid or missing API key |
|
|
||||||
| `NOT_FOUND` | 404 | Resource not found |
|
|
||||||
| `VALIDATION_ERROR` | 400 | Invalid request data |
|
|
||||||
| `EVENT_IMMUTABLE` | 400 | Cannot modify locked events |
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
---
|
|
||||||
title: Events API
|
|
||||||
description: Events endpoints reference
|
|
||||||
sidebar:
|
|
||||||
order: 2
|
|
||||||
---
|
|
||||||
|
|
||||||
## Create Event
|
|
||||||
|
|
||||||
```http
|
|
||||||
POST /api/v1/events
|
|
||||||
```
|
|
||||||
|
|
||||||
### Request Body
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"date": "2024-01-15",
|
|
||||||
"type": "text",
|
|
||||||
"content": "Had coffee with Sarah",
|
|
||||||
"latitude": 40.7128,
|
|
||||||
"longitude": -74.0060,
|
|
||||||
"placeName": "New York, NY"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
| Field | Type | Required | Description |
|
|
||||||
|-------|------|----------|-------------|
|
|
||||||
| `date` | string | Yes | Date in YYYY-MM-DD format |
|
|
||||||
| `type` | string | Yes | One of: event, text, photo, voice, health |
|
|
||||||
| `content` | string | Yes | Event content |
|
|
||||||
| `latitude` | number | No | GPS latitude |
|
|
||||||
| `longitude` | number | No | GPS longitude |
|
|
||||||
| `placeName` | string | No | Reverse-geocoded place name |
|
|
||||||
| `metadata` | object | No | Additional metadata |
|
|
||||||
|
|
||||||
### Response
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"id": "uuid",
|
|
||||||
"date": "2024-01-15",
|
|
||||||
"type": "text",
|
|
||||||
"content": "Had coffee with Sarah",
|
|
||||||
"latitude": 40.7128,
|
|
||||||
"longitude": -74.0060,
|
|
||||||
"placeName": "New York, NY",
|
|
||||||
"createdAt": "2024-01-15T10:30:00Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Get Day
|
|
||||||
|
|
||||||
```http
|
|
||||||
GET /api/v1/days/:date
|
|
||||||
```
|
|
||||||
|
|
||||||
Returns all events and journal for a specific date.
|
|
||||||
|
|
||||||
## Delete Event
|
|
||||||
|
|
||||||
```http
|
|
||||||
DELETE /api/v1/events/:id
|
|
||||||
```
|
|
||||||
|
|
||||||
:::caution
|
|
||||||
Cannot delete events from days with generated journals.
|
|
||||||
:::
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
---
|
|
||||||
title: Journals API
|
|
||||||
description: Journals endpoints reference
|
|
||||||
sidebar:
|
|
||||||
order: 3
|
|
||||||
---
|
|
||||||
|
|
||||||
## Generate Diary
|
|
||||||
|
|
||||||
```http
|
|
||||||
POST /api/v1/journal/generate/:date
|
|
||||||
```
|
|
||||||
|
|
||||||
### Request Body
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"instructions": "Make it more detailed and poetic"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Response
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"journal": {
|
|
||||||
"id": "uuid",
|
|
||||||
"date": "2024-01-15",
|
|
||||||
"title": "A Productive Tuesday",
|
|
||||||
"content": "Full diary content...",
|
|
||||||
"eventCount": 8,
|
|
||||||
"generatedAt": "2024-01-15T22:00:00Z"
|
|
||||||
},
|
|
||||||
"task": {
|
|
||||||
"id": "uuid",
|
|
||||||
"status": "completed",
|
|
||||||
"provider": "groq",
|
|
||||||
"model": "llama-3.3-70b-versatile"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Get Journal
|
|
||||||
|
|
||||||
```http
|
|
||||||
GET /api/v1/journal/:date
|
|
||||||
```
|
|
||||||
|
|
||||||
Returns the diary page for a specific date.
|
|
||||||
|
|
||||||
## List Journals
|
|
||||||
|
|
||||||
```http
|
|
||||||
GET /api/v1/journals?page=1&limit=10
|
|
||||||
```
|
|
||||||
|
|
||||||
### Query Parameters
|
|
||||||
|
|
||||||
| Parameter | Default | Description |
|
|
||||||
|-----------|---------|-------------|
|
|
||||||
| `page` | 1 | Page number |
|
|
||||||
| `limit` | 10 | Items per page (10, 50, or 100) |
|
|
||||||
|
|
||||||
## Get Generation Tasks
|
|
||||||
|
|
||||||
```http
|
|
||||||
GET /api/v1/journal/:date/tasks
|
|
||||||
```
|
|
||||||
|
|
||||||
Returns all generation attempts for a journal with request/response JSON.
|
|
||||||
|
|
||||||
## Delete Journal
|
|
||||||
|
|
||||||
```http
|
|
||||||
DELETE /api/v1/journal/:date
|
|
||||||
```
|
|
||||||
|
|
||||||
Deleting a journal **unlocks** all events for that day, allowing edits and new entries.
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
---
|
|
||||||
title: Settings API
|
|
||||||
description: Settings endpoints reference
|
|
||||||
sidebar:
|
|
||||||
order: 4
|
|
||||||
---
|
|
||||||
|
|
||||||
## Get Settings
|
|
||||||
|
|
||||||
```http
|
|
||||||
GET /api/v1/settings
|
|
||||||
```
|
|
||||||
|
|
||||||
### Response
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"aiProvider": "groq",
|
|
||||||
"aiApiKey": null,
|
|
||||||
"aiModel": "llama-3.3-70b-versatile",
|
|
||||||
"journalPrompt": "Custom instructions...",
|
|
||||||
"language": "en",
|
|
||||||
"timezone": "UTC",
|
|
||||||
"journalContextDays": 10,
|
|
||||||
"providerSettings": {
|
|
||||||
"groq": { "apiKey": "...", "model": "..." }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Update Settings
|
|
||||||
|
|
||||||
```http
|
|
||||||
PUT /api/v1/settings
|
|
||||||
```
|
|
||||||
|
|
||||||
### Request Body
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"aiProvider": "openai",
|
|
||||||
"aiApiKey": "sk-...",
|
|
||||||
"journalPrompt": "Write in a reflective tone"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Fields
|
|
||||||
|
|
||||||
| Field | Type | Description |
|
|
||||||
|-------|------|-------------|
|
|
||||||
| `aiProvider` | string | groq, openai, anthropic, ollama, lmstudio |
|
|
||||||
| `aiApiKey` | string | API key for selected provider |
|
|
||||||
| `aiModel` | string | Model identifier |
|
|
||||||
| `journalPrompt` | string | Custom instructions (null to clear) |
|
|
||||||
| `journalContextDays` | number | Days of previous journals to include (0-30) |
|
|
||||||
|
|
||||||
## Change Password
|
|
||||||
|
|
||||||
```http
|
|
||||||
POST /api/v1/account/password
|
|
||||||
```
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"currentPassword": "old-password",
|
|
||||||
"newPassword": "new-secure-password"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Delete Account
|
|
||||||
|
|
||||||
```http
|
|
||||||
DELETE /api/v1/account
|
|
||||||
```
|
|
||||||
|
|
||||||
:::danger
|
|
||||||
This permanently deletes your account and all data. This cannot be undone.
|
|
||||||
:::
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
---
|
|
||||||
title: Docker Deployment
|
|
||||||
description: Deploy DearDiary with Docker
|
|
||||||
sidebar:
|
|
||||||
order: 1
|
|
||||||
---
|
|
||||||
|
|
||||||
## Docker Compose
|
|
||||||
|
|
||||||
The recommended way to run DearDiary:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
services:
|
|
||||||
app:
|
|
||||||
build: .
|
|
||||||
ports:
|
|
||||||
- "8080:8080"
|
|
||||||
volumes:
|
|
||||||
- ./data:/data
|
|
||||||
env_file:
|
|
||||||
- backend/.env
|
|
||||||
restart: unless-stopped
|
|
||||||
```
|
|
||||||
|
|
||||||
## Running
|
|
||||||
|
|
||||||
### Start
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
### Stop
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose down
|
|
||||||
```
|
|
||||||
|
|
||||||
### Rebuild
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose build && docker compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
## Volumes
|
|
||||||
|
|
||||||
Data persists in `./data/`:
|
|
||||||
|
|
||||||
| Directory | Contents |
|
|
||||||
|-----------|----------|
|
|
||||||
| `data/db/` | SQLite database |
|
|
||||||
| `data/media/` | Uploaded files |
|
|
||||||
|
|
||||||
## Health Check
|
|
||||||
|
|
||||||
The app exposes a health endpoint:
|
|
||||||
|
|
||||||
```http
|
|
||||||
GET http://localhost:8080/health
|
|
||||||
```
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"status": "ok",
|
|
||||||
"timestamp": "2024-01-15T10:30:00Z"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Production Considerations
|
|
||||||
|
|
||||||
### Reverse Proxy
|
|
||||||
|
|
||||||
For production, use a reverse proxy (nginx, Caddy, Traefik) with:
|
|
||||||
|
|
||||||
- HTTPS/TLS termination
|
|
||||||
- Security headers
|
|
||||||
- Rate limiting
|
|
||||||
|
|
||||||
### Database
|
|
||||||
|
|
||||||
Default SQLite is fine for single-user or small deployments.
|
|
||||||
|
|
||||||
For multi-user or high traffic, consider PostgreSQL:
|
|
||||||
|
|
||||||
```env
|
|
||||||
DATABASE_URL="postgresql://user:pass@host:5432/deardiary"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Backup
|
|
||||||
|
|
||||||
Regularly backup `./data/` directory.
|
|
||||||
|
|
||||||
## Documentation Site
|
|
||||||
|
|
||||||
The documentation site is included in the stack and starts automatically with `docker compose up`.
|
|
||||||
|
|
||||||
Access at `http://localhost:4000`
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
---
|
|
||||||
title: Environment Variables
|
|
||||||
description: Complete environment variable reference
|
|
||||||
sidebar:
|
|
||||||
order: 2
|
|
||||||
---
|
|
||||||
|
|
||||||
## Configuration File
|
|
||||||
|
|
||||||
Copy `.env.example` to `.env`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cp backend/.env.example backend/.env
|
|
||||||
```
|
|
||||||
|
|
||||||
## Variables
|
|
||||||
|
|
||||||
### Application
|
|
||||||
|
|
||||||
| Variable | Default | Description |
|
|
||||||
|----------|---------|-------------|
|
|
||||||
| `APP_NAME` | DearDiary | App name displayed in UI |
|
|
||||||
| `VERSION` | 0.1.0 | App version |
|
|
||||||
| `PORT` | 3000 | Internal API port |
|
|
||||||
|
|
||||||
### Database
|
|
||||||
|
|
||||||
| Variable | Default | Description |
|
|
||||||
|----------|---------|-------------|
|
|
||||||
| `DATABASE_URL` | file:./data/deardiary.db | SQLite by default |
|
|
||||||
| `DATABASE_URL` | postgresql://... | PostgreSQL connection |
|
|
||||||
| `DATABASE_URL` | mysql://... | MySQL connection |
|
|
||||||
|
|
||||||
### Security
|
|
||||||
|
|
||||||
| Variable | Default | Description |
|
|
||||||
|----------|---------|-------------|
|
|
||||||
| `JWT_SECRET` | development-secret... | **Required in production!** |
|
|
||||||
| `CORS_ORIGIN` | * | CORS allowed origins |
|
|
||||||
|
|
||||||
### User Management
|
|
||||||
|
|
||||||
| Variable | Default | Description |
|
|
||||||
|----------|---------|-------------|
|
|
||||||
| `REGISTRATION_ENABLED` | false | Enable/disable registration |
|
|
||||||
| `DEFAULT_USER_EMAIL` | admin@localhost | Default admin email |
|
|
||||||
| `DEFAULT_USER_PASSWORD` | changeme123 | Default admin password |
|
|
||||||
|
|
||||||
### Storage
|
|
||||||
|
|
||||||
| Variable | Default | Description |
|
|
||||||
|----------|---------|-------------|
|
|
||||||
| `MEDIA_DIR` | ./data/media | Media files directory |
|
|
||||||
|
|
||||||
## Production Checklist
|
|
||||||
|
|
||||||
:::caution
|
|
||||||
Before going to production:
|
|
||||||
|
|
||||||
1. Set a strong `JWT_SECRET`
|
|
||||||
2. Set `CORS_ORIGIN` to your domain
|
|
||||||
3. Change default admin credentials
|
|
||||||
4. Set `REGISTRATION_ENABLED=false` if not needed
|
|
||||||
5. Use HTTPS/TLS
|
|
||||||
6. Set up regular backups
|
|
||||||
:::
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
---
|
|
||||||
title: AI Providers
|
|
||||||
description: Configure AI providers for diary generation
|
|
||||||
sidebar:
|
|
||||||
order: 3
|
|
||||||
---
|
|
||||||
|
|
||||||
## Supported Providers
|
|
||||||
|
|
||||||
DearDiary supports multiple AI providers:
|
|
||||||
|
|
||||||
| Provider | Default Model | Type |
|
|
||||||
|----------|---------------|------|
|
|
||||||
| **Groq** | llama-3.3-70b-versatile | Cloud |
|
|
||||||
| OpenAI | gpt-4o | Cloud |
|
|
||||||
| Anthropic | claude-3.5-sonnet | Cloud |
|
|
||||||
| Ollama | varies | Local |
|
|
||||||
| LM Studio | varies | Local |
|
|
||||||
|
|
||||||
## Groq (Recommended)
|
|
||||||
|
|
||||||
Free tier available. Fast inference.
|
|
||||||
|
|
||||||
1. Get an API key from [console.groq.com](https://console.groq.com)
|
|
||||||
2. Enter the API key in Settings
|
|
||||||
3. Select Groq as your provider
|
|
||||||
|
|
||||||
## OpenAI
|
|
||||||
|
|
||||||
1. Get an API key from [platform.openai.com](https://platform.openai.com)
|
|
||||||
2. Optionally select a specific model:
|
|
||||||
- `gpt-4o` - Most capable
|
|
||||||
- `gpt-4o-mini` - Faster, cheaper
|
|
||||||
|
|
||||||
## Anthropic
|
|
||||||
|
|
||||||
1. Get an API key from [console.anthropic.com](https://console.anthropic.com)
|
|
||||||
2. Select Claude model:
|
|
||||||
- `claude-3-5-sonnet-latest` - Recommended
|
|
||||||
- `claude-3-opus-latest` - Most capable
|
|
||||||
|
|
||||||
## Ollama (Local)
|
|
||||||
|
|
||||||
Run models locally on your machine.
|
|
||||||
|
|
||||||
1. Install [Ollama](https://ollama.ai)
|
|
||||||
2. Pull a model: `ollama pull llama3.2`
|
|
||||||
3. Set base URL: `http://localhost:11434/v1`
|
|
||||||
4. Select model name
|
|
||||||
|
|
||||||
## LM Studio (Local)
|
|
||||||
|
|
||||||
Alternative local option with GUI.
|
|
||||||
|
|
||||||
1. Download [LM Studio](https://lmstudio.ai)
|
|
||||||
2. Download a model
|
|
||||||
3. Start local server (click "Start Server")
|
|
||||||
4. Set base URL: `http://localhost:1234/v1`
|
|
||||||
|
|
||||||
## Testing Connection
|
|
||||||
|
|
||||||
Use the **Test Connection** button in Settings to verify your AI provider is working before generating diaries.
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
---
|
|
||||||
title: Calendar
|
|
||||||
description: Visual calendar view of your journals
|
|
||||||
sidebar:
|
|
||||||
order: 5
|
|
||||||
---
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
The Calendar view provides a monthly overview of your journal activity.
|
|
||||||
|
|
||||||
Access it via the navigation menu: **Calendar**
|
|
||||||
|
|
||||||
## Calendar Indicators
|
|
||||||
|
|
||||||
Each day shows:
|
|
||||||
|
|
||||||
| Indicator | Meaning |
|
|
||||||
|-----------|---------|
|
|
||||||
| **Number** | Day of month |
|
|
||||||
| **Filled circle** | Has events |
|
|
||||||
| **Purple border** | Has generated diary page |
|
|
||||||
| **Today** | Highlighted border |
|
|
||||||
|
|
||||||
## Navigation
|
|
||||||
|
|
||||||
- **Previous/Next Month** - Arrow buttons
|
|
||||||
- **Month/Year Picker** - Click month name
|
|
||||||
- **Today Button** - Jump to current date
|
|
||||||
|
|
||||||
## Clicking a Day
|
|
||||||
|
|
||||||
Click any day to view:
|
|
||||||
|
|
||||||
- All events for that day
|
|
||||||
- Diary page if generated
|
|
||||||
- Option to add new events (if unlocked)
|
|
||||||
|
|
||||||
## Use Cases
|
|
||||||
|
|
||||||
- Quickly see activity patterns
|
|
||||||
- Identify gaps in journaling
|
|
||||||
- Navigate to specific past dates
|
|
||||||
- Plan when to catch up on entries
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
---
|
|
||||||
title: Diary Pages
|
|
||||||
description: AI-generated diary entries
|
|
||||||
sidebar:
|
|
||||||
order: 2
|
|
||||||
---
|
|
||||||
|
|
||||||
## What is a Diary Page?
|
|
||||||
|
|
||||||
A **Diary Page** is an AI-generated narrative summary of your day's events. Unlike events, diary pages:
|
|
||||||
|
|
||||||
- Can be regenerated (rewritten)
|
|
||||||
- Include a generated title
|
|
||||||
- Are narrative, not just data points
|
|
||||||
|
|
||||||
## Generating a Diary
|
|
||||||
|
|
||||||
1. Navigate to **Today** (`/today`)
|
|
||||||
2. Ensure you have at least one event
|
|
||||||
3. Click **Generate Diary Page**
|
|
||||||
4. Wait for AI processing
|
|
||||||
|
|
||||||
## Viewing Diary Pages
|
|
||||||
|
|
||||||
Access diary pages via:
|
|
||||||
|
|
||||||
- **Dashboard** - Recent diary excerpts
|
|
||||||
- **Diary** - Paginated list of all diaries
|
|
||||||
- **Calendar** - Visual overview with indicators
|
|
||||||
- **Day View** - Click any date to see its diary
|
|
||||||
|
|
||||||
## Rewriting
|
|
||||||
|
|
||||||
Click **Rewrite** to regenerate with additional instructions:
|
|
||||||
|
|
||||||
### Default Rewrite
|
|
||||||
|
|
||||||
Regenerates with the same events and default prompt.
|
|
||||||
|
|
||||||
### Custom Instructions
|
|
||||||
|
|
||||||
Add specific guidance:
|
|
||||||
|
|
||||||
```
|
|
||||||
Make it more poetic and reflective.
|
|
||||||
Focus on the conversations I had.
|
|
||||||
```
|
|
||||||
|
|
||||||
## Title Generation
|
|
||||||
|
|
||||||
Each diary page includes an AI-generated title (max 50 characters) that summarizes the day.
|
|
||||||
|
|
||||||
## Task History
|
|
||||||
|
|
||||||
Every generation attempt is logged as a **Task**, including:
|
|
||||||
|
|
||||||
- Request/response JSON for debugging
|
|
||||||
- Provider and model used
|
|
||||||
- Success/failure status
|
|
||||||
- Processing time
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
---
|
|
||||||
title: Events
|
|
||||||
description: Capturing and managing events
|
|
||||||
sidebar:
|
|
||||||
order: 1
|
|
||||||
---
|
|
||||||
|
|
||||||
## What is an Event?
|
|
||||||
|
|
||||||
An **Event** is a single log entry in your journal. Events can be:
|
|
||||||
|
|
||||||
- **Text** - Simple text notes
|
|
||||||
- **Photo** - Captured moments with images
|
|
||||||
- **Voice** - Voice memos
|
|
||||||
- **Health** - Health-related observations
|
|
||||||
- **Event** - General activity logs
|
|
||||||
|
|
||||||
## Creating Events
|
|
||||||
|
|
||||||
### Via Today Page
|
|
||||||
|
|
||||||
1. Navigate to **Today** (`/today`)
|
|
||||||
2. Type your event in the input field
|
|
||||||
3. Select the event type
|
|
||||||
4. Press Enter or click Add
|
|
||||||
|
|
||||||
### Via Quick Add
|
|
||||||
|
|
||||||
Press `Ctrl + J` from anywhere to open the quick add widget.
|
|
||||||
|
|
||||||
## Location
|
|
||||||
|
|
||||||
Events automatically capture:
|
|
||||||
|
|
||||||
- GPS coordinates (if browser permits)
|
|
||||||
- Reverse-geocoded place names
|
|
||||||
|
|
||||||
This helps you remember where things happened.
|
|
||||||
|
|
||||||
## Immutability
|
|
||||||
|
|
||||||
Once a **Diary Page** is generated for a day, all events for that day become **locked**:
|
|
||||||
|
|
||||||
- Cannot be deleted
|
|
||||||
- Cannot be edited
|
|
||||||
- Cannot have new events added
|
|
||||||
|
|
||||||
To unlock, you must delete the diary page.
|
|
||||||
|
|
||||||
## Media
|
|
||||||
|
|
||||||
### Photos
|
|
||||||
|
|
||||||
Upload photos directly or attach them to existing events.
|
|
||||||
|
|
||||||
### Voice Memos
|
|
||||||
|
|
||||||
Record voice memos using your browser's microphone.
|
|
||||||
|
|
||||||
Media files are stored in `./data/media/{userId}/{date}/`
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
---
|
|
||||||
title: Export & Import
|
|
||||||
description: Backup and restore your data
|
|
||||||
sidebar:
|
|
||||||
order: 6
|
|
||||||
---
|
|
||||||
|
|
||||||
## Why Export?
|
|
||||||
|
|
||||||
Regular exports ensure you never lose your data:
|
|
||||||
|
|
||||||
- Backup to external storage
|
|
||||||
- Migrate to new server
|
|
||||||
- Keep offline archive
|
|
||||||
|
|
||||||
## Export Format
|
|
||||||
|
|
||||||
Exports are JSON files containing:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"version": "0.0.6",
|
|
||||||
"exportedAt": "2024-01-15T10:30:00Z",
|
|
||||||
"settings": { ... },
|
|
||||||
"events": [ ... ],
|
|
||||||
"journals": [ ... ],
|
|
||||||
"tasks": [ ... ]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Included Data
|
|
||||||
|
|
||||||
- **Settings** - AI provider, model, custom prompts
|
|
||||||
- **Events** - All event data including location
|
|
||||||
- **Journals** - All generated diary pages
|
|
||||||
- **Tasks** - Generation history for debugging
|
|
||||||
|
|
||||||
## How to Export
|
|
||||||
|
|
||||||
1. Go to **Settings**
|
|
||||||
2. Scroll to **Data Management**
|
|
||||||
3. Click **Export Data**
|
|
||||||
4. Save the JSON file
|
|
||||||
|
|
||||||
## Import
|
|
||||||
|
|
||||||
### Version Compatibility
|
|
||||||
|
|
||||||
- Minimum supported: 0.0.3
|
|
||||||
- Current version: 0.0.6
|
|
||||||
|
|
||||||
Older exports may lose some data or fail to import.
|
|
||||||
|
|
||||||
### Import Steps
|
|
||||||
|
|
||||||
1. Go to **Settings** → **Data Management**
|
|
||||||
2. Click **Import Data**
|
|
||||||
3. Select your JSON export file
|
|
||||||
4. Review the preview (imported/skipped counts)
|
|
||||||
5. Click **Confirm Import**
|
|
||||||
|
|
||||||
### Duplicate Handling
|
|
||||||
|
|
||||||
- **Events**: Skipped if identical (date + content + timestamp)
|
|
||||||
- **Journals**: Skipped by date
|
|
||||||
- **Tasks**: Linked to existing journals
|
|
||||||
|
|
||||||
## Danger Zone
|
|
||||||
|
|
||||||
:::caution
|
|
||||||
The **Reset Account** option in Danger Zone deletes ALL your data except settings. Use with extreme caution!
|
|
||||||
:::
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
---
|
|
||||||
title: Media Uploads
|
|
||||||
description: Photos and voice memos
|
|
||||||
sidebar:
|
|
||||||
order: 7
|
|
||||||
---
|
|
||||||
|
|
||||||
## Supported Media Types
|
|
||||||
|
|
||||||
### Photos
|
|
||||||
|
|
||||||
- Upload photos to accompany events
|
|
||||||
- JPEG, PNG, GIF, WebP supported
|
|
||||||
- Displayed inline in event list
|
|
||||||
|
|
||||||
### Voice Memos
|
|
||||||
|
|
||||||
- Record voice notes
|
|
||||||
- WebM audio format
|
|
||||||
- Playback controls in event list
|
|
||||||
|
|
||||||
## How to Add Media
|
|
||||||
|
|
||||||
### Photo Type Events
|
|
||||||
|
|
||||||
1. Select **Photo** type when creating event
|
|
||||||
2. Add description in text field
|
|
||||||
3. Upload photo
|
|
||||||
|
|
||||||
### Voice Type Events
|
|
||||||
|
|
||||||
1. Select **Voice** type
|
|
||||||
2. Click microphone button
|
|
||||||
3. Start recording
|
|
||||||
4. Stop when finished
|
|
||||||
5. Add optional text note
|
|
||||||
|
|
||||||
## Storage
|
|
||||||
|
|
||||||
Media files are stored at:
|
|
||||||
|
|
||||||
```
|
|
||||||
./data/media/{userId}/{date}/
|
|
||||||
```
|
|
||||||
|
|
||||||
For example:
|
|
||||||
```
|
|
||||||
./data/media/user123abc/2024-01-15/photo.jpg
|
|
||||||
./data/media/user123abc/2024-01-15/voice.webm
|
|
||||||
```
|
|
||||||
|
|
||||||
## Serving
|
|
||||||
|
|
||||||
Media is served via nginx at `/media/` route:
|
|
||||||
|
|
||||||
```
|
|
||||||
/media/{userId}/{date}/{filename}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Privacy
|
|
||||||
|
|
||||||
Media files are:
|
|
||||||
- Stored locally only
|
|
||||||
- Associated with your user account
|
|
||||||
- Not shared between users
|
|
||||||
- Deleted when you delete events
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
---
|
|
||||||
title: Search
|
|
||||||
description: Finding events and diary pages
|
|
||||||
sidebar:
|
|
||||||
order: 4
|
|
||||||
---
|
|
||||||
|
|
||||||
## Using Search
|
|
||||||
|
|
||||||
Press `Ctrl + K` from anywhere to open the search modal.
|
|
||||||
|
|
||||||
## What You Can Search
|
|
||||||
|
|
||||||
### Diary Pages
|
|
||||||
|
|
||||||
Search across all generated diary pages:
|
|
||||||
|
|
||||||
- Titles
|
|
||||||
- Full content
|
|
||||||
- Dates
|
|
||||||
|
|
||||||
### Events
|
|
||||||
|
|
||||||
Search across all events:
|
|
||||||
|
|
||||||
- Event content
|
|
||||||
- Event type
|
|
||||||
- Date
|
|
||||||
|
|
||||||
## How It Works
|
|
||||||
|
|
||||||
DearDiary uses **SQLite FTS5** (Full-Text Search) for fast, indexed searching:
|
|
||||||
|
|
||||||
1. Automatic indexing on content creation
|
|
||||||
2. Porter stemming for better matches
|
|
||||||
3. Fallback to LIKE queries if FTS fails
|
|
||||||
|
|
||||||
## Tips
|
|
||||||
|
|
||||||
- Use specific keywords for better results
|
|
||||||
- Search works across all dates
|
|
||||||
- Results are grouped by type (diaries vs events)
|
|
||||||
- Click any result to navigate directly to that item
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
---
|
|
||||||
title: Configuration
|
|
||||||
description: Configure DearDiary for your needs
|
|
||||||
sidebar:
|
|
||||||
order: 3
|
|
||||||
---
|
|
||||||
|
|
||||||
## Settings Page
|
|
||||||
|
|
||||||
Access settings via the navigation menu. Settings are organized into sections:
|
|
||||||
|
|
||||||
### AI Provider
|
|
||||||
|
|
||||||
Choose your AI provider for diary generation:
|
|
||||||
|
|
||||||
| Provider | Model | Notes |
|
|
||||||
|----------|-------|-------|
|
|
||||||
| **Groq** (default) | llama-3.3-70b-versatile | Fast, free tier available |
|
|
||||||
| OpenAI | gpt-4o, gpt-4o-mini | Requires API key |
|
|
||||||
| Anthropic | claude-3.5-sonnet | Requires API key |
|
|
||||||
| Ollama | Various | Local models |
|
|
||||||
| LM Studio | Various | Local models |
|
|
||||||
|
|
||||||
### Custom Instructions
|
|
||||||
|
|
||||||
Add custom instructions that are prepended to the default AI prompt:
|
|
||||||
|
|
||||||
```
|
|
||||||
Write in a poetic style.
|
|
||||||
Focus on health and wellness aspects.
|
|
||||||
```
|
|
||||||
|
|
||||||
### Journal Context
|
|
||||||
|
|
||||||
Set how many previous days of diaries the AI considers when generating new entries (0-30 days).
|
|
||||||
|
|
||||||
## Environment Variables
|
|
||||||
|
|
||||||
See [Environment Variables](/deployment/environment) for server-side configuration.
|
|
||||||
|
|
||||||
## Multi-User Setup
|
|
||||||
|
|
||||||
Enable user registration:
|
|
||||||
|
|
||||||
```env
|
|
||||||
REGISTRATION_ENABLED=true
|
|
||||||
```
|
|
||||||
|
|
||||||
Or create a default admin user:
|
|
||||||
|
|
||||||
```env
|
|
||||||
DEFAULT_USER_EMAIL=admin@example.com
|
|
||||||
DEFAULT_USER_PASSWORD=your-secure-password
|
|
||||||
```
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
---
|
|
||||||
title: Installation
|
|
||||||
description: How to install and set up DearDiary
|
|
||||||
sidebar:
|
|
||||||
order: 1
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
- [Docker](https://docs.docker.com/get-docker/) and Docker Compose
|
|
||||||
- Git
|
|
||||||
|
|
||||||
## Quick Install
|
|
||||||
|
|
||||||
1. Clone the repository:
|
|
||||||
```bash
|
|
||||||
git clone https://github.com/lotherk/deardiary.git
|
|
||||||
cd deardiary
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Copy the environment file:
|
|
||||||
```bash
|
|
||||||
cp backend/.env.example backend/.env
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Start with Docker:
|
|
||||||
```bash
|
|
||||||
docker compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Access the app at `http://localhost:8080`
|
|
||||||
|
|
||||||
## Default Credentials
|
|
||||||
|
|
||||||
On first start, a default user is created if configured:
|
|
||||||
|
|
||||||
- **Email**: `admin@localhost` (configurable via `DEFAULT_USER_EMAIL`)
|
|
||||||
- **Password**: `changeme123` (configurable via `DEFAULT_USER_PASSWORD`)
|
|
||||||
|
|
||||||
:::tip
|
|
||||||
Change these credentials immediately after first login!
|
|
||||||
:::
|
|
||||||
|
|
||||||
## Ports
|
|
||||||
|
|
||||||
| Service | Port | Description |
|
|
||||||
|---------|------|-------------|
|
|
||||||
| App | 8080 | Main application (nginx) |
|
|
||||||
| API | 3000 | Backend API (internal) |
|
|
||||||
| Docs | 4000 | Documentation site (optional, run with `--profile docs`) |
|
|
||||||
|
|
||||||
## Documentation Site
|
|
||||||
|
|
||||||
The documentation site is included and starts automatically:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
Access at `http://localhost:4000`
|
|
||||||
|
|
||||||
## Data Storage
|
|
||||||
|
|
||||||
All data is stored in Docker volumes:
|
|
||||||
|
|
||||||
- `./data/db/` - SQLite database
|
|
||||||
- `./data/media/` - Uploaded photos and voice memos
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
---
|
|
||||||
title: Quick Start
|
|
||||||
description: Get started with DearDiary in 5 minutes
|
|
||||||
sidebar:
|
|
||||||
order: 2
|
|
||||||
---
|
|
||||||
|
|
||||||
## First Steps
|
|
||||||
|
|
||||||
### 1. Log an Event
|
|
||||||
|
|
||||||
Navigate to **Today** and start logging events:
|
|
||||||
|
|
||||||
- Type your event and press Enter
|
|
||||||
- Use the type buttons to change event category (Event, Health, Photo, Voice)
|
|
||||||
- Events are timestamped automatically
|
|
||||||
|
|
||||||
### 2. Add Your Location
|
|
||||||
|
|
||||||
When you log an event, DearDiary automatically captures:
|
|
||||||
|
|
||||||
- **Latitude/Longitude** from your browser
|
|
||||||
- **Place Name** via reverse geocoding (OpenStreetMap)
|
|
||||||
|
|
||||||
:::note
|
|
||||||
Location access requires browser permission. Grant it when prompted for automatic geolocation.
|
|
||||||
:::
|
|
||||||
|
|
||||||
### 3. Generate Your Diary
|
|
||||||
|
|
||||||
When you're ready to lock in your day:
|
|
||||||
|
|
||||||
1. Click **Generate Diary Page**
|
|
||||||
2. AI analyzes all your events
|
|
||||||
3. Creates a narrative diary entry with title
|
|
||||||
|
|
||||||
Once generated, events become **locked** (immutable).
|
|
||||||
|
|
||||||
### 4. Rewrite if Needed
|
|
||||||
|
|
||||||
Click **Rewrite** to regenerate with additional instructions:
|
|
||||||
|
|
||||||
- Add context like "Make it more detailed"
|
|
||||||
- Include specific topics to emphasize
|
|
||||||
- Adjust the tone or style
|
|
||||||
|
|
||||||
## Keyboard Shortcuts
|
|
||||||
|
|
||||||
| Shortcut | Action |
|
|
||||||
|----------|--------|
|
|
||||||
| `Ctrl + J` | Quick add event |
|
|
||||||
| `Ctrl + K` | Search |
|
|
||||||
|
|
||||||
## Tips
|
|
||||||
|
|
||||||
- Log events throughout the day for richer diaries
|
|
||||||
- Use the calendar view to browse past days
|
|
||||||
- Export your data regularly for backup
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
---
|
|
||||||
title: DearDiary
|
|
||||||
description: AI-Powered Daily Journal
|
|
||||||
template: splash
|
|
||||||
hero:
|
|
||||||
title: DearDiary
|
|
||||||
tagline: Your AI-powered daily journal. Capture events throughout the day and let AI transform them into beautiful diary pages.
|
|
||||||
image:
|
|
||||||
file: ../../assets/logo-light.svg
|
|
||||||
actions:
|
|
||||||
- theme: brand
|
|
||||||
text: Get Started
|
|
||||||
link: /getting-started/installation/
|
|
||||||
- theme: alt
|
|
||||||
text: View on GitHub
|
|
||||||
link: https://github.com/lotherk/deardiary
|
|
||||||
---
|
|
||||||
|
|
||||||
import { Card, CardGrid } from '@astrojs/starlight/components';
|
|
||||||
|
|
||||||
<CardGrid stagger>
|
|
||||||
<Card title="Capture Events">
|
|
||||||
Log events throughout your day - text, photos, voice memos, and health data.
|
|
||||||
</Card>
|
|
||||||
<Card title="AI-Generated Diary">
|
|
||||||
Let AI transform your events into beautiful, narrative diary pages.
|
|
||||||
</Card>
|
|
||||||
<Card title="Privacy First">
|
|
||||||
Self-hosted. Your data stays on your server.
|
|
||||||
</Card>
|
|
||||||
<Card title="Geolocation">
|
|
||||||
Events are automatically tagged with your location.
|
|
||||||
</Card>
|
|
||||||
</CardGrid>
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
/* Custom DearDiary styling */
|
|
||||||
:root[data-theme='light'] {
|
|
||||||
--sl-color-accent-low: #e9e3ff;
|
|
||||||
--sl-color-accent: #7c3aed;
|
|
||||||
--sl-color-accent-high: #4c1d95;
|
|
||||||
--sl-color-white: #1e1b4b;
|
|
||||||
--sl-color-gray-1: #3730a3;
|
|
||||||
--sl-color-gray-2: #4338ca;
|
|
||||||
--sl-color-gray-3: #4f46e5;
|
|
||||||
--sl-color-gray-4: #6366f1;
|
|
||||||
--sl-color-gray-5: #818cf8;
|
|
||||||
--sl-color-gray-6: #a5b4fc;
|
|
||||||
--sl-color-gray-7: #c7d2fe;
|
|
||||||
--sl-color-black: #e0e7ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
:root[data-theme='dark'] {
|
|
||||||
--sl-color-accent-low: #4c1d95;
|
|
||||||
--sl-color-accent: #a78bfa;
|
|
||||||
--sl-color-accent-high: #c4b5fd;
|
|
||||||
}
|
|
||||||
178
www/css/docs.css
Normal file
178
www/css/docs.css
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
.docs-layout {
|
||||||
|
display: flex;
|
||||||
|
padding-top: 72px;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.docs-sidebar {
|
||||||
|
width: 260px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
border-right: 1px solid var(--border);
|
||||||
|
padding: 32px 24px;
|
||||||
|
position: fixed;
|
||||||
|
top: 72px;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-section {
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-section h3 {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
color: var(--text-muted);
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-section a {
|
||||||
|
display: block;
|
||||||
|
padding: 8px 12px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
transition: all 0.2s;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-section a:hover {
|
||||||
|
color: var(--text-primary);
|
||||||
|
background: rgba(109, 40, 217, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-section a.active {
|
||||||
|
color: var(--accent-light);
|
||||||
|
background: rgba(109, 40, 217, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.docs-content {
|
||||||
|
flex: 1;
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 48px 48px 100px;
|
||||||
|
margin-left: 260px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.docs-content h1 {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.docs-content h2 {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
margin-top: 48px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.docs-content h3 {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
margin-top: 32px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.docs-content p {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
margin-bottom: 16px;
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.docs-content ul,
|
||||||
|
.docs-content ol {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
margin-bottom: 16px;
|
||||||
|
padding-left: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.docs-content li {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.docs-content pre {
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
padding: 16px 20px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.docs-content code {
|
||||||
|
font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: var(--accent-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.docs-content table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.docs-content th,
|
||||||
|
.docs-content td {
|
||||||
|
padding: 12px 16px;
|
||||||
|
text-align: left;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.docs-content th {
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-size: 0.85rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.docs-content td {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.docs-content .tip {
|
||||||
|
background: rgba(109, 40, 217, 0.15);
|
||||||
|
border: 1px solid var(--accent);
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
padding: 16px 20px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.docs-content .tip strong {
|
||||||
|
color: var(--accent-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.docs-content .next-steps {
|
||||||
|
margin-top: 48px;
|
||||||
|
padding-top: 32px;
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.docs-content .btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 12px 24px;
|
||||||
|
background: linear-gradient(135deg, var(--accent), var(--accent-dark));
|
||||||
|
color: white;
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
font-weight: 600;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.docs-content .btn:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 4px 20px rgba(109, 40, 217, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.docs-sidebar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.docs-content {
|
||||||
|
margin-left: 0;
|
||||||
|
padding: 32px 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
367
www/css/styles.css
Normal file
367
www/css/styles.css
Normal file
@@ -0,0 +1,367 @@
|
|||||||
|
:root {
|
||||||
|
--bg-primary: #0f172a;
|
||||||
|
--bg-secondary: #1e293b;
|
||||||
|
--bg-card: #1e293b;
|
||||||
|
--text-primary: #f8fafc;
|
||||||
|
--text-secondary: #94a3b8;
|
||||||
|
--text-muted: #64748b;
|
||||||
|
--accent: #6d28d9;
|
||||||
|
--accent-light: #a78bfa;
|
||||||
|
--accent-dark: #4c1d95;
|
||||||
|
--border: #334155;
|
||||||
|
--radius: 12px;
|
||||||
|
--radius-sm: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
|
||||||
|
background: var(--bg-primary);
|
||||||
|
color: var(--text-primary);
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
background: rgba(15, 23, 42, 0.9);
|
||||||
|
backdrop-filter: blur(12px);
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-container {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 16px 24px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links a:not(.btn) {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
transition: color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links a:not(.btn):hover {
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
transition: all 0.2s;
|
||||||
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background: linear-gradient(135deg, var(--accent), var(--accent-dark));
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary:hover {
|
||||||
|
background: linear-gradient(135deg, var(--accent-light), var(--accent));
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary {
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
color: var(--text-primary);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary:hover {
|
||||||
|
border-color: var(--accent);
|
||||||
|
color: var(--accent-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-large {
|
||||||
|
padding: 14px 28px;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero {
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
padding: 120px 24px 80px;
|
||||||
|
background: radial-gradient(ellipse at top, rgba(109, 40, 217, 0.15) 0%, transparent 60%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-content {
|
||||||
|
max-width: 800px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero h1 {
|
||||||
|
font-size: clamp(2.5rem, 6vw, 4.5rem);
|
||||||
|
font-weight: 800;
|
||||||
|
line-height: 1.1;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gradient-text {
|
||||||
|
background: linear-gradient(135deg, var(--accent-light), #818cf8);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-clip: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-subtitle {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 0 auto 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
justify-content: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-meta {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
justify-content: center;
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.features {
|
||||||
|
padding: 100px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.features h2 {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 2.5rem;
|
||||||
|
margin-bottom: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
|
||||||
|
gap: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-card {
|
||||||
|
background: var(--bg-card);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: var(--radius);
|
||||||
|
padding: 32px;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-card:hover {
|
||||||
|
border-color: var(--accent);
|
||||||
|
transform: translateY(-4px);
|
||||||
|
box-shadow: 0 12px 40px rgba(109, 40, 217, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-icon {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-card h3 {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-card p {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.how {
|
||||||
|
padding: 100px 0;
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.how h2 {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 2.5rem;
|
||||||
|
margin-bottom: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.steps {
|
||||||
|
max-width: 700px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step {
|
||||||
|
display: flex;
|
||||||
|
gap: 24px;
|
||||||
|
margin-bottom: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-number {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
background: linear-gradient(135deg, var(--accent), var(--accent-dark));
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-content h3 {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-content p {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.try {
|
||||||
|
padding: 100px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.try-content {
|
||||||
|
text-align: center;
|
||||||
|
max-width: 700px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.try-content h2 {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.try-content > p {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.try-code {
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: var(--radius);
|
||||||
|
padding: 20px 24px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.try-code code {
|
||||||
|
font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: var(--accent-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.try-hint {
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
padding: 60px 0 40px;
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-links {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||||||
|
gap: 40px;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-col h4 {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
color: var(--text-muted);
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-col a {
|
||||||
|
display: block;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
padding: 6px 0;
|
||||||
|
transition: color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-col a:hover {
|
||||||
|
color: var(--accent-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-bottom {
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 40px;
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.nav-links a:not(.btn) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero h1 {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
138
www/docs/ai-providers.html
Normal file
138
www/docs/ai-providers.html
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>AI Providers - DearDiary</title>
|
||||||
|
<link rel="stylesheet" href="../css/styles.css">
|
||||||
|
<link rel="stylesheet" href="../css/docs.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav class="navbar">
|
||||||
|
<div class="nav-container">
|
||||||
|
<a href="../" class="logo">
|
||||||
|
<svg width="32" height="32" viewBox="0 0 100 100"><defs><linearGradient id="g" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" style="stop-color:#6d28d9"/><stop offset="100%" style="stop-color:#4c1d95"/></linearGradient></defs><rect width="100" height="100" rx="20" fill="url(#g)"/><path d="M25 25 L75 25 L75 80 L25 80 Z" fill="none" stroke="white" stroke-width="3"/></svg>
|
||||||
|
DearDiary
|
||||||
|
</a>
|
||||||
|
<div class="nav-links">
|
||||||
|
<a href="../">Home</a>
|
||||||
|
<a href="../docs/">Docs</a>
|
||||||
|
<a href="https://github.com/lotherk/deardiary" target="_blank">GitHub</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="docs-layout">
|
||||||
|
<aside class="docs-sidebar">
|
||||||
|
<div class="sidebar-section">
|
||||||
|
<h3>Getting Started</h3>
|
||||||
|
<a href="installation.html">Installation</a>
|
||||||
|
<a href="quick-start.html">Quick Start</a>
|
||||||
|
<a href="configuration.html">Configuration</a>
|
||||||
|
</div>
|
||||||
|
<div class="sidebar-section">
|
||||||
|
<h3>Features</h3>
|
||||||
|
<a href="events.html">Events</a>
|
||||||
|
<a href="diary-pages.html">Diary Pages</a>
|
||||||
|
<a href="ai-providers.html" class="active">AI Providers</a>
|
||||||
|
<a href="search.html">Search</a>
|
||||||
|
<a href="export-import.html">Export & Import</a>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<main class="docs-content">
|
||||||
|
<h1>AI Providers</h1>
|
||||||
|
|
||||||
|
<p>DearDiary supports multiple AI providers for diary generation. Choose the one that best fits your needs.</p>
|
||||||
|
|
||||||
|
<h2>Supported Providers</h2>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Provider</th>
|
||||||
|
<th>Default Model</th>
|
||||||
|
<th>Type</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>Groq</strong> (Recommended)</td>
|
||||||
|
<td>llama-3.3-70b-versatile</td>
|
||||||
|
<td>Cloud</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>OpenAI</td>
|
||||||
|
<td>gpt-4o</td>
|
||||||
|
<td>Cloud</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Anthropic</td>
|
||||||
|
<td>claude-3-5-sonnet-latest</td>
|
||||||
|
<td>Cloud</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Ollama</td>
|
||||||
|
<td>varies</td>
|
||||||
|
<td>Local</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>LM Studio</td>
|
||||||
|
<td>varies</td>
|
||||||
|
<td>Local</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h2>Groq (Recommended)</h2>
|
||||||
|
<p>Fast inference with a free tier available.</p>
|
||||||
|
<ol>
|
||||||
|
<li>Get an API key from <a href="https://console.groq.com" target="_blank">console.groq.com</a></li>
|
||||||
|
<li>Enter the API key in Settings</li>
|
||||||
|
<li>Select Groq as your provider</li>
|
||||||
|
<li>Test connection and save</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<h2>OpenAI</h2>
|
||||||
|
<ol>
|
||||||
|
<li>Get an API key from <a href="https://platform.openai.com" target="_blank">platform.openai.com</a></li>
|
||||||
|
<li>Optionally select a specific model:
|
||||||
|
<ul>
|
||||||
|
<li><code>gpt-4o</code> - Most capable</li>
|
||||||
|
<li><code>gpt-4o-mini</code> - Faster, cheaper</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<h2>Anthropic</h2>
|
||||||
|
<ol>
|
||||||
|
<li>Get an API key from <a href="https://console.anthropic.com" target="_blank">console.anthropic.com</a></li>
|
||||||
|
<li>Select Claude model:
|
||||||
|
<ul>
|
||||||
|
<li><code>claude-3-5-sonnet-latest</code> - Recommended</li>
|
||||||
|
<li><code>claude-3-opus-latest</code> - Most capable</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<h2>Local Models (Ollama)</h2>
|
||||||
|
<p>Run models locally on your machine for complete privacy.</p>
|
||||||
|
<ol>
|
||||||
|
<li>Install <a href="https://ollama.ai" target="_blank">Ollama</a></li>
|
||||||
|
<li>Pull a model: <code>ollama pull llama3.2</code></li>
|
||||||
|
<li>Set base URL: <code>http://localhost:11434/v1</code></li>
|
||||||
|
<li>Enter model name (e.g., <code>llama3.2</code>)</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<h2>Local Models (LM Studio)</h2>
|
||||||
|
<ol>
|
||||||
|
<li>Download <a href="https://lmstudio.ai" target="_blank">LM Studio</a></li>
|
||||||
|
<li>Download a model</li>
|
||||||
|
<li>Start local server (click "Start Server")</li>
|
||||||
|
<li>Set base URL: <code>http://localhost:1234/v1</code></li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<div class="next-steps">
|
||||||
|
<a href="diary-pages.html" class="btn">← Diary Pages</a>
|
||||||
|
<a href="events.html" class="btn">Events →</a>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
84
www/docs/index.html
Normal file
84
www/docs/index.html
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Documentation - DearDiary</title>
|
||||||
|
<link rel="stylesheet" href="../css/styles.css">
|
||||||
|
<link rel="stylesheet" href="../css/docs.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav class="navbar">
|
||||||
|
<div class="nav-container">
|
||||||
|
<a href="../" class="logo">
|
||||||
|
<svg width="32" height="32" viewBox="0 0 100 100"><defs><linearGradient id="g" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" style="stop-color:#6d28d9"/><stop offset="100%" style="stop-color:#4c1d95"/></linearGradient></defs><rect width="100" height="100" rx="20" fill="url(#g)"/><path d="M25 25 L75 25 L75 80 L25 80 Z" fill="none" stroke="white" stroke-width="3"/></svg>
|
||||||
|
DearDiary
|
||||||
|
</a>
|
||||||
|
<div class="nav-links">
|
||||||
|
<a href="../">Home</a>
|
||||||
|
<a href="../docs/" class="active">Docs</a>
|
||||||
|
<a href="https://github.com/lotherk/deardiary" target="_blank">GitHub</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="docs-layout">
|
||||||
|
<aside class="docs-sidebar">
|
||||||
|
<div class="sidebar-section">
|
||||||
|
<h3>Getting Started</h3>
|
||||||
|
<a href="installation.html">Installation</a>
|
||||||
|
<a href="quick-start.html">Quick Start</a>
|
||||||
|
<a href="configuration.html">Configuration</a>
|
||||||
|
</div>
|
||||||
|
<div class="sidebar-section">
|
||||||
|
<h3>Features</h3>
|
||||||
|
<a href="events.html">Events</a>
|
||||||
|
<a href="diary-pages.html">Diary Pages</a>
|
||||||
|
<a href="ai-providers.html">AI Providers</a>
|
||||||
|
<a href="search.html">Search</a>
|
||||||
|
<a href="export-import.html">Export & Import</a>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<main class="docs-content">
|
||||||
|
<h1>Documentation</h1>
|
||||||
|
|
||||||
|
<p>Welcome to the DearDiary documentation. Here you'll find everything you need to get started and make the most of your AI-powered journal.</p>
|
||||||
|
|
||||||
|
<h2>Quick Links</h2>
|
||||||
|
|
||||||
|
<div class="feature-grid" style="grid-template-columns: repeat(2, 1fr);">
|
||||||
|
<div class="feature-card">
|
||||||
|
<h3><a href="installation.html">Installation</a></h3>
|
||||||
|
<p>Get DearDiary up and running with Docker in minutes.</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature-card">
|
||||||
|
<h3><a href="quick-start.html">Quick Start</a></h3>
|
||||||
|
<p>Learn the basics and create your first diary entry.</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature-card">
|
||||||
|
<h3><a href="ai-providers.html">AI Providers</a></h3>
|
||||||
|
<p>Configure Groq, OpenAI, Anthropic, or local models.</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature-card">
|
||||||
|
<h3><a href="events.html">Events</a></h3>
|
||||||
|
<p>Learn about capturing and managing events.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Need Help?</h2>
|
||||||
|
|
||||||
|
<p>If you encounter issues:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Check the <a href="https://github.com/lotherk/deardiary/issues" target="_blank">GitHub Issues</a></li>
|
||||||
|
<li>Review the configuration settings</li>
|
||||||
|
<li>Ensure your AI provider API key is valid</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="next-steps">
|
||||||
|
<a href="installation.html" class="btn btn-primary">Get Started →</a>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
121
www/docs/installation.html
Normal file
121
www/docs/installation.html
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Installation - DearDiary</title>
|
||||||
|
<link rel="stylesheet" href="../css/styles.css">
|
||||||
|
<link rel="stylesheet" href="../css/docs.css">
|
||||||
|
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><defs><linearGradient id='g' x1='0%25' y1='0%25' x2='100%25' y2='100%25'><stop offset='0%25' style='stop-color:%236d28d9'/><stop offset='100%25' style='stop-color:%234c1d95'/></linearGradient></defs><rect width='100' height='100' rx='20' fill='url(%23g)'/><path d='M25 25 L75 25 L75 80 L25 80 Z' fill='none' stroke='white' stroke-width='3'/></svg>">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav class="navbar">
|
||||||
|
<div class="nav-container">
|
||||||
|
<a href="../" class="logo">
|
||||||
|
<svg width="32" height="32" viewBox="0 0 100 100"><defs><linearGradient id="g" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" style="stop-color:#6d28d9"/><stop offset="100%" style="stop-color:#4c1d95"/></linearGradient></defs><rect width="100" height="100" rx="20" fill="url(#g)"/><path d="M25 25 L75 25 L75 80 L25 80 Z" fill="none" stroke="white" stroke-width="3"/></svg>
|
||||||
|
DearDiary
|
||||||
|
</a>
|
||||||
|
<div class="nav-links">
|
||||||
|
<a href="../">Home</a>
|
||||||
|
<a href="../docs/">Docs</a>
|
||||||
|
<a href="https://github.com/lotherk/deardiary" target="_blank">GitHub</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="docs-layout">
|
||||||
|
<aside class="docs-sidebar">
|
||||||
|
<div class="sidebar-section">
|
||||||
|
<h3>Getting Started</h3>
|
||||||
|
<a href="installation.html" class="active">Installation</a>
|
||||||
|
<a href="quick-start.html">Quick Start</a>
|
||||||
|
<a href="configuration.html">Configuration</a>
|
||||||
|
</div>
|
||||||
|
<div class="sidebar-section">
|
||||||
|
<h3>Features</h3>
|
||||||
|
<a href="events.html">Events</a>
|
||||||
|
<a href="diary-pages.html">Diary Pages</a>
|
||||||
|
<a href="ai-providers.html">AI Providers</a>
|
||||||
|
<a href="search.html">Search</a>
|
||||||
|
<a href="export-import.html">Export & Import</a>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<main class="docs-content">
|
||||||
|
<h1>Installation</h1>
|
||||||
|
|
||||||
|
<h2>Prerequisites</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://docs.docker.com/get-docker/" target="_blank">Docker</a> and Docker Compose</li>
|
||||||
|
<li>Git</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Quick Install</h2>
|
||||||
|
|
||||||
|
<h3>1. Clone the repository</h3>
|
||||||
|
<pre><code>git clone https://github.com/lotherk/deardiary.git
|
||||||
|
cd deardiary</code></pre>
|
||||||
|
|
||||||
|
<h3>2. Copy the environment file</h3>
|
||||||
|
<pre><code>cp backend/.env.example backend/.env</code></pre>
|
||||||
|
|
||||||
|
<h3>3. Start with Docker</h3>
|
||||||
|
<pre><code>docker compose up -d</code></pre>
|
||||||
|
|
||||||
|
<h3>4. Access the app</h3>
|
||||||
|
<p>Open <code>http://localhost:5173</code> in your browser.</p>
|
||||||
|
|
||||||
|
<h2>Default Credentials</h2>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td><strong>Email</strong></td>
|
||||||
|
<td><code>admin@localhost</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>Password</strong></td>
|
||||||
|
<td><code>changeme123</code></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="tip">
|
||||||
|
<strong>Important:</strong> Change these credentials immediately after first login!
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Ports</h2>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Service</th>
|
||||||
|
<th>Port</th>
|
||||||
|
<th>Description</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Frontend</td>
|
||||||
|
<td>5173</td>
|
||||||
|
<td>Main application (nginx)</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>API</td>
|
||||||
|
<td>3000</td>
|
||||||
|
<td>Backend API (internal)</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Website</td>
|
||||||
|
<td>8080</td>
|
||||||
|
<td>This website (if enabled)</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h2>Data Storage</h2>
|
||||||
|
<p>All data is stored in Docker volumes:</p>
|
||||||
|
<ul>
|
||||||
|
<li><code>./data/db/</code> - SQLite database</li>
|
||||||
|
<li><code>./data/media/</code> - Uploaded photos and voice memos</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="next-steps">
|
||||||
|
<a href="quick-start.html" class="btn btn-primary">Next: Quick Start →</a>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
118
www/docs/quick-start.html
Normal file
118
www/docs/quick-start.html
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Quick Start - DearDiary</title>
|
||||||
|
<link rel="stylesheet" href="../css/styles.css">
|
||||||
|
<link rel="stylesheet" href="../css/docs.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav class="navbar">
|
||||||
|
<div class="nav-container">
|
||||||
|
<a href="../" class="logo">
|
||||||
|
<svg width="32" height="32" viewBox="0 0 100 100"><defs><linearGradient id="g" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" style="stop-color:#6d28d9"/><stop offset="100%" style="stop-color:#4c1d95"/></linearGradient></defs><rect width="100" height="100" rx="20" fill="url(#g)"/><path d="M25 25 L75 25 L75 80 L25 80 Z" fill="none" stroke="white" stroke-width="3"/></svg>
|
||||||
|
DearDiary
|
||||||
|
</a>
|
||||||
|
<div class="nav-links">
|
||||||
|
<a href="../">Home</a>
|
||||||
|
<a href="../docs/">Docs</a>
|
||||||
|
<a href="https://github.com/lotherk/deardiary" target="_blank">GitHub</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="docs-layout">
|
||||||
|
<aside class="docs-sidebar">
|
||||||
|
<div class="sidebar-section">
|
||||||
|
<h3>Getting Started</h3>
|
||||||
|
<a href="installation.html">Installation</a>
|
||||||
|
<a href="quick-start.html" class="active">Quick Start</a>
|
||||||
|
<a href="configuration.html">Configuration</a>
|
||||||
|
</div>
|
||||||
|
<div class="sidebar-section">
|
||||||
|
<h3>Features</h3>
|
||||||
|
<a href="events.html">Events</a>
|
||||||
|
<a href="diary-pages.html">Diary Pages</a>
|
||||||
|
<a href="ai-providers.html">AI Providers</a>
|
||||||
|
<a href="search.html">Search</a>
|
||||||
|
<a href="export-import.html">Export & Import</a>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<main class="docs-content">
|
||||||
|
<h1>Quick Start</h1>
|
||||||
|
|
||||||
|
<h2>First Steps</h2>
|
||||||
|
|
||||||
|
<h3>1. Configure AI Provider</h3>
|
||||||
|
<p>Before generating diaries, you need to set up an AI provider:</p>
|
||||||
|
<ol>
|
||||||
|
<li>Go to <strong>Settings</strong></li>
|
||||||
|
<li>Select your AI provider (Groq is recommended for free, fast inference)</li>
|
||||||
|
<li>Enter your API key</li>
|
||||||
|
<li>Click "Test Connection" to verify</li>
|
||||||
|
<li>Save settings</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<h3>2. Log Your First Event</h3>
|
||||||
|
<p>Navigate to <strong>Today</strong> and start logging events:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Type your event and press Enter</li>
|
||||||
|
<li>Use the type buttons to change event category</li>
|
||||||
|
<li>Events are timestamped automatically</li>
|
||||||
|
<li>Location is captured if you allow browser permission</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3>3. Generate Your Diary</h3>
|
||||||
|
<p>When you're ready to lock in your day:</p>
|
||||||
|
<ol>
|
||||||
|
<li>Click <strong>Generate Diary Page</strong></li>
|
||||||
|
<li>Wait for AI processing</li>
|
||||||
|
<li>Your diary page appears with a generated title</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<div class="tip">
|
||||||
|
Once generated, events become <strong>locked</strong> (immutable). To unlock, delete the diary page.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>4. Rewrite if Needed</h3>
|
||||||
|
<p>Click <strong>Rewrite</strong> to regenerate with additional instructions:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Add context like "Make it more detailed"</li>
|
||||||
|
<li>Focus on specific topics</li>
|
||||||
|
<li>Adjust the tone or style</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Keyboard Shortcuts</h2>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Shortcut</th>
|
||||||
|
<th>Action</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>Ctrl + J</code></td>
|
||||||
|
<td>Quick add event</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>Ctrl + K</code></td>
|
||||||
|
<td>Search</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h2>Tips</h2>
|
||||||
|
<ul>
|
||||||
|
<li>Log events throughout the day for richer diaries</li>
|
||||||
|
<li>Use the calendar view to browse past days</li>
|
||||||
|
<li>Export your data regularly for backup</li>
|
||||||
|
<li>Try different AI providers for varied writing styles</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="next-steps">
|
||||||
|
<a href="installation.html" class="btn">← Previous</a>
|
||||||
|
<a href="configuration.html" class="btn">Next: Configuration →</a>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
155
www/index.html
Normal file
155
www/index.html
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>DearDiary - AI-Powered Daily Journal</title>
|
||||||
|
<meta name="description" content="Self-hosted AI-powered daily journaling. Capture events throughout the day and let AI generate beautiful diary pages.">
|
||||||
|
<link rel="stylesheet" href="css/styles.css">
|
||||||
|
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><defs><linearGradient id='g' x1='0%25' y1='0%25' x2='100%25' y2='100%25'><stop offset='0%25' style='stop-color:%236d28d9'/><stop offset='100%25' style='stop-color:%234c1d95'/></linearGradient></defs><rect width='100' height='100' rx='20' fill='url(%23g)'/><path d='M25 25 L75 25 L75 80 L25 80 Z' fill='none' stroke='white' stroke-width='3'/><path d='M35 40 L65 40 M35 50 L65 50 M35 60 L55 60' stroke='white' stroke-width='2'/></svg>">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav class="navbar">
|
||||||
|
<div class="nav-container">
|
||||||
|
<a href="/" class="logo">
|
||||||
|
<svg width="32" height="32" viewBox="0 0 100 100"><defs><linearGradient id="g" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" style="stop-color:#6d28d9"/><stop offset="100%" style="stop-color:#4c1d95"/></linearGradient></defs><rect width="100" height="100" rx="20" fill="url(#g)"/><path d="M25 25 L75 25 L75 80 L25 80 Z" fill="none" stroke="white" stroke-width="3"/><path d="M35 40 L65 40 M35 50 L65 50 M35 60 L55 60" stroke="white" stroke-width="2"/></svg>
|
||||||
|
DearDiary
|
||||||
|
</a>
|
||||||
|
<div class="nav-links">
|
||||||
|
<a href="#features">Features</a>
|
||||||
|
<a href="docs/">Docs</a>
|
||||||
|
<a href="https://github.com/lotherk/deardiary" target="_blank">GitHub</a>
|
||||||
|
<a href="#try" class="btn btn-primary">Get Started</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<header class="hero">
|
||||||
|
<div class="hero-content">
|
||||||
|
<h1>Your AI-Powered<br><span class="gradient-text">Daily Journal</span></h1>
|
||||||
|
<p class="hero-subtitle">Capture events throughout the day and let AI transform them into beautiful, thoughtful diary pages. Self-hosted. Private. Yours.</p>
|
||||||
|
<div class="hero-actions">
|
||||||
|
<a href="#try" class="btn btn-primary btn-large">Start Free</a>
|
||||||
|
<a href="docs/" class="btn btn-secondary btn-large">Read Docs</a>
|
||||||
|
</div>
|
||||||
|
<div class="hero-meta">
|
||||||
|
<span>v0.1.0</span>
|
||||||
|
<span>•</span>
|
||||||
|
<span>Docker</span>
|
||||||
|
<span>•</span>
|
||||||
|
<span>MIT License</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<section id="features" class="features">
|
||||||
|
<div class="container">
|
||||||
|
<h2>Everything you need for journaling</h2>
|
||||||
|
<div class="feature-grid">
|
||||||
|
<div class="feature-card">
|
||||||
|
<div class="feature-icon">📝</div>
|
||||||
|
<h3>Quick Capture</h3>
|
||||||
|
<p>Log events instantly with Ctrl+J. Multiple types: text, photos, voice memos, health notes.</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature-card">
|
||||||
|
<div class="feature-icon">🤖</div>
|
||||||
|
<h3>AI Generation</h3>
|
||||||
|
<p>Let AI craft thoughtful diary pages from your events. Works with Groq, OpenAI, Anthropic, and local models.</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature-card">
|
||||||
|
<div class="feature-icon">📍</div>
|
||||||
|
<h3>Auto Geolocation</h3>
|
||||||
|
<p>Events are automatically tagged with your location. Remember where life happened.</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature-card">
|
||||||
|
<div class="feature-icon">🔒</div>
|
||||||
|
<h3>Immutable Memories</h3>
|
||||||
|
<p>Once a diary is generated, events lock. Your past stays authentic, untouched by today's edits.</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature-card">
|
||||||
|
<div class="feature-icon">🔍</div>
|
||||||
|
<h3>Full-Text Search</h3>
|
||||||
|
<p>Find any event or diary entry instantly across all your data.</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature-card">
|
||||||
|
<div class="feature-icon">📤</div>
|
||||||
|
<h3>Export & Import</h3>
|
||||||
|
<p>Your data, your control. Export everything as JSON. Migrate anytime.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="how" class="how">
|
||||||
|
<div class="container">
|
||||||
|
<h2>How it works</h2>
|
||||||
|
<div class="steps">
|
||||||
|
<div class="step">
|
||||||
|
<div class="step-number">1</div>
|
||||||
|
<div class="step-content">
|
||||||
|
<h3>Capture Throughout the Day</h3>
|
||||||
|
<p>Log events as they happen. Type, snap a photo, record a voice note. Add health data. Each entry is timestamped and geolocated.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="step">
|
||||||
|
<div class="step-number">2</div>
|
||||||
|
<div class="step-content">
|
||||||
|
<h3>Generate Your Diary</h3>
|
||||||
|
<p>When you're ready, click Generate. AI reads all your events and writes a thoughtful, narrative diary page just for you.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="step">
|
||||||
|
<div class="step-number">3</div>
|
||||||
|
<div class="step-content">
|
||||||
|
<h3>Rewrite if Needed</h3>
|
||||||
|
<p>Not happy with the result? Add instructions and regenerate. Focus on what matters to you.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="try" class="try">
|
||||||
|
<div class="container">
|
||||||
|
<div class="try-content">
|
||||||
|
<h2>Ready to start journaling?</h2>
|
||||||
|
<p>Self-host in minutes with Docker. Your data stays on your server.</p>
|
||||||
|
<div class="try-code">
|
||||||
|
<code>git clone https://github.com/lotherk/deardiary.git && cd deardiary && docker compose up -d</code>
|
||||||
|
</div>
|
||||||
|
<p class="try-hint">Default login: admin@localhost / changeme123</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="container">
|
||||||
|
<div class="footer-links">
|
||||||
|
<div class="footer-col">
|
||||||
|
<h4>Product</h4>
|
||||||
|
<a href="#features">Features</a>
|
||||||
|
<a href="docs/">Documentation</a>
|
||||||
|
<a href="#how">How it Works</a>
|
||||||
|
</div>
|
||||||
|
<div class="footer-col">
|
||||||
|
<h4>Resources</h4>
|
||||||
|
<a href="docs/getting-started/installation.html">Installation</a>
|
||||||
|
<a href="docs/getting-started/quick-start.html">Quick Start</a>
|
||||||
|
<a href="docs/features/ai-providers.html">AI Providers</a>
|
||||||
|
</div>
|
||||||
|
<div class="footer-col">
|
||||||
|
<h4>Project</h4>
|
||||||
|
<a href="https://github.com/lotherk/deardiary" target="_blank">GitHub</a>
|
||||||
|
<a href="https://github.com/lotherk/deardiary/issues" target="_blank">Issues</a>
|
||||||
|
<a href="https://github.com/lotherk/deardiary/releases" target="_blank">Releases</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer-bottom">
|
||||||
|
<p>MIT License • Copyright 2026 Konrad Lother</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script src="js/main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
21
www/js/main.js
Normal file
21
www/js/main.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const navbar = document.querySelector('.navbar');
|
||||||
|
|
||||||
|
window.addEventListener('scroll', () => {
|
||||||
|
if (window.scrollY > 50) {
|
||||||
|
navbar.style.background = 'rgba(15, 23, 42, 0.98)';
|
||||||
|
} else {
|
||||||
|
navbar.style.background = 'rgba(15, 23, 42, 0.9)';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
||||||
|
anchor.addEventListener('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
const target = document.querySelector(this.getAttribute('href'));
|
||||||
|
if (target) {
|
||||||
|
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user