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
|
||||
|
||||
COPY --from=builder /app/docs/dist /usr/share/nginx/html
|
||||
COPY docs/nginx.conf /etc/nginx/http.d/default.conf
|
||||
COPY www/ /usr/share/nginx/html/
|
||||
|
||||
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.
|
||||
|
||||
[](https://github.com/lotherk/deardiary)
|
||||
[](https://lotherk.github.io/deardiary)
|
||||
|
||||
## Features
|
||||
|
||||
@@ -33,21 +32,19 @@ cd deardiary
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Access the app at `http://localhost:8080`
|
||||
Access the app at `http://localhost:5173`
|
||||
|
||||
Default credentials: `admin@localhost` / `changeme123`
|
||||
|
||||
## 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:
|
||||
- [Installation](https://lotherk.github.io/deardiary/getting-started/installation/)
|
||||
- [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/)
|
||||
- [API Reference](https://lotherk.github.io/deardiary/api/authentication/)
|
||||
- [Deployment](https://lotherk.github.io/deardiary/deployment/docker/)
|
||||
```bash
|
||||
docker compose up -d docs
|
||||
```
|
||||
|
||||
Access at `http://localhost:4000`
|
||||
|
||||
## Configuration
|
||||
|
||||
@@ -81,14 +78,6 @@ npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Build Docs Locally
|
||||
|
||||
```bash
|
||||
cd docs
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Docker Build
|
||||
|
||||
```bash
|
||||
@@ -106,7 +95,9 @@ docker compose build && docker compose up -d
|
||||
│ ├── pages/ # Page components
|
||||
│ ├── components/
|
||||
│ └── lib/ # API client, geolocation
|
||||
├── docs/ # Starlight documentation site
|
||||
├── www/ # Product website with docs
|
||||
├── Dockerfile # App container
|
||||
├── Dockerfile.docs # Website container
|
||||
└── 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