Compare commits
10 Commits
7342c18c00
...
83cba54bf5
Author | SHA1 | Date |
---|---|---|
root | 83cba54bf5 | |
Dallas Hoffman | 45f446e2f3 | |
Dallas Hoffman | c09373d552 | |
Dallas Hoffman | 20e8488e3c | |
Dallas Hoffman | b9b1e55736 | |
Dallas Hoffman | 4ca3900a3d | |
Dallas Hoffman | a37dc39503 | |
Dallas Hoffman | ea3b5facb1 | |
Dallas Hoffman | 00991e66bd | |
Dallas Hoffman | 73551c5596 |
|
@ -11,5 +11,11 @@
|
||||||
"svelte.plugin.svelte.compilerWarnings": {
|
"svelte.plugin.svelte.compilerWarnings": {
|
||||||
"a11y-no-noninteractive-element-interactions": "ignore",
|
"a11y-no-noninteractive-element-interactions": "ignore",
|
||||||
"a11y-click-events-have-key-events": "ignore"
|
"a11y-click-events-have-key-events": "ignore"
|
||||||
|
},
|
||||||
|
"[typescript]": {
|
||||||
|
"editor.defaultFormatter": "vscode.typescript-language-features"
|
||||||
|
},
|
||||||
|
"[json]": {
|
||||||
|
"editor.defaultFormatter": "vscode.json-language-features"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,3 +8,10 @@ A simple notes app built with [SvelteKit](https://kit.svelte.dev/), [Kysely](htt
|
||||||
- Local-first; all data is stored on-device
|
- Local-first; all data is stored on-device
|
||||||
|
|
||||||
Hosted at https://notes.dallashoffman.com/
|
Hosted at https://notes.dallashoffman.com/
|
||||||
|
|
||||||
|
|
||||||
|
# ollama
|
||||||
|
|
||||||
|
```
|
||||||
|
OLLAMA_HOST=0.0.0.0:11434 ollama serve
|
||||||
|
```
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
33
package.json
33
package.json
|
@ -18,23 +18,28 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@bytemd/plugin-gfm": "^1.21.0",
|
"@bytemd/plugin-gfm": "^1.21.0",
|
||||||
"bytemd": "1.21.0",
|
"bytemd": "1.21.0",
|
||||||
"kysely": "^0.26.3",
|
"kysely": "^0.27.3",
|
||||||
"sqlocal": "^0.6.2"
|
"sqlocal": "^0.11.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@picocss/pico": "^1.5.10",
|
"@picocss/pico": "^1.5.10",
|
||||||
"@sveltejs/adapter-static": "^2.0.3",
|
"@sveltejs/adapter-static": "^3.0.6",
|
||||||
"@sveltejs/kit": "^1.20.4",
|
"@vite-pwa/assets-generator": "^0.2.4",
|
||||||
"@vite-pwa/assets-generator": "^0.0.10",
|
"@vite-pwa/sveltekit": "^0.4.0",
|
||||||
"@vite-pwa/sveltekit": "^0.2.7",
|
|
||||||
"patch-package": "^8.0.0",
|
"patch-package": "^8.0.0",
|
||||||
"prettier": "^2.8.0",
|
"prettier": "^3.3.2",
|
||||||
"prettier-plugin-svelte": "^2.10.1",
|
"prettier-plugin-svelte": "^3.2.6",
|
||||||
"sass": "^1.66.1",
|
"sass": "^1.69.5",
|
||||||
"svelte": "^4.0.5",
|
"@sveltejs/adapter-node": "^5.2.2",
|
||||||
"svelte-check": "^3.4.3",
|
"@sveltejs/kit": "^2.5.25",
|
||||||
"tslib": "^2.4.1",
|
"@sveltejs/vite-plugin-svelte": "^4.0.0",
|
||||||
"typescript": "^5.2.2",
|
"svelte": "^5.0.0",
|
||||||
"vite": "^4.4.9"
|
"svelte-check": "^3.6.8",
|
||||||
|
"tslib": "^2.6.2",
|
||||||
|
"typescript": "^5.4.3",
|
||||||
|
"vite": "^5.0.3",
|
||||||
|
"fast-glob": "^3.3.2",
|
||||||
|
"openai": "^4.74.0",
|
||||||
|
"ollama": "^0.5.10"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,3 +1,15 @@
|
||||||
|
diff --git a/node_modules/bytemd/package.json b/node_modules/bytemd/package.json
|
||||||
|
index 9103d88..e59f261 100644
|
||||||
|
--- a/node_modules/bytemd/package.json
|
||||||
|
+++ b/node_modules/bytemd/package.json
|
||||||
|
@@ -16,6 +16,7 @@
|
||||||
|
"author": "Rongjian Zhang",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
+ "svelte": "./svelte/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"import": "./dist/index.mjs",
|
||||||
|
"require": "./dist/index.js"
|
||||||
diff --git a/node_modules/bytemd/svelte/editor.svelte b/node_modules/bytemd/svelte/editor.svelte
|
diff --git a/node_modules/bytemd/svelte/editor.svelte b/node_modules/bytemd/svelte/editor.svelte
|
||||||
index 652a063..9ab0895 100644
|
index 652a063..9ab0895 100644
|
||||||
--- a/node_modules/bytemd/svelte/editor.svelte
|
--- a/node_modules/bytemd/svelte/editor.svelte
|
||||||
|
|
|
@ -3,11 +3,11 @@
|
||||||
import ThemeToggle from '$lib/components/theme-toggle.svelte';
|
import ThemeToggle from '$lib/components/theme-toggle.svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<header class="app-header">
|
<!-- <header class="app-header">
|
||||||
<ThemeToggle />
|
<ThemeToggle />
|
||||||
<h1 class="app-header__title">Notes</h1>
|
<h1 class="app-header__title">Notes</h1>
|
||||||
<SettingsButton />
|
<SettingsButton />
|
||||||
</header>
|
</header> -->
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.app-header {
|
.app-header {
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
button {
|
button {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 2rem;
|
bottom: 1rem;
|
||||||
right: 1rem;
|
right: 1rem;
|
||||||
width: 4rem;
|
width: 4rem;
|
||||||
height: 4rem;
|
height: 4rem;
|
||||||
|
|
|
@ -34,8 +34,12 @@
|
||||||
<article class="note-card" style:--note-color={NoteColor[note.color][$themeUpperCase]}>
|
<article class="note-card" style:--note-color={NoteColor[note.color][$themeUpperCase]}>
|
||||||
<header class="note-card__header" hidden={$editing}>
|
<header class="note-card__header" hidden={$editing}>
|
||||||
<div class="note-card__header-buttons">
|
<div class="note-card__header-buttons">
|
||||||
|
{#if !$editing}
|
||||||
|
<NoteEditButton on:click={noteEditorStore.startEditing} />
|
||||||
|
{/if}
|
||||||
<NoteDeleteButton {note} {noteEditorStore} />
|
<NoteDeleteButton {note} {noteEditorStore} />
|
||||||
<div class="note-card__spacer" />
|
<div class="note-card__spacer" />
|
||||||
|
<NoteTimestamp {note} />
|
||||||
<NoteColorPicker {note} {noteEditorStore} />
|
<NoteColorPicker {note} {noteEditorStore} />
|
||||||
<NoteTagButton on:click={focusTags} />
|
<NoteTagButton on:click={focusTags} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -51,16 +55,13 @@
|
||||||
>
|
>
|
||||||
<NoteContent {note} {noteEditorStore} />
|
<NoteContent {note} {noteEditorStore} />
|
||||||
</div>
|
</div>
|
||||||
<footer class="note-card__footer">
|
{#if $editing}
|
||||||
{#if !$editing}
|
<footer class="note-card__footer">
|
||||||
<NoteEditButton on:click={noteEditorStore.startEditing} />
|
|
||||||
{:else}
|
|
||||||
<NoteSaveButton on:click={noteEditorStore.save} />
|
<NoteSaveButton on:click={noteEditorStore.save} />
|
||||||
<NoteDiscardButton on:click={noteEditorStore.discard} />
|
<NoteDiscardButton on:click={noteEditorStore.discard} />
|
||||||
{/if}
|
<div class="note-card__spacer" />
|
||||||
<div class="note-card__spacer" />
|
</footer>
|
||||||
<NoteTimestamp {note} />
|
{/if}
|
||||||
</footer>
|
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
@ -75,6 +76,7 @@
|
||||||
background-color: var(--note-color);
|
background-color: var(--note-color);
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
box-shadow: var(--card-shadow);
|
box-shadow: var(--card-shadow);
|
||||||
|
scrollbar-color: hsl(0 0% 0% / 0.2) hsl(0 0% 0% / 0.2);
|
||||||
|
|
||||||
&__header,
|
&__header,
|
||||||
&__footer {
|
&__footer {
|
||||||
|
|
|
@ -5,5 +5,4 @@
|
||||||
|
|
||||||
<Button icon plain on:click>
|
<Button icon plain on:click>
|
||||||
<FaPenToSquare />
|
<FaPenToSquare />
|
||||||
Edit
|
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
@ -6,18 +6,20 @@
|
||||||
import { get, type Unsubscriber } from 'svelte/store';
|
import { get, type Unsubscriber } from 'svelte/store';
|
||||||
|
|
||||||
let noteListElement: HTMLUListElement;
|
let noteListElement: HTMLUListElement;
|
||||||
const noteHeight = 385;
|
const noteHeight = 400;
|
||||||
const noteGap = 16;
|
const noteGap = 16;
|
||||||
const paddingRows = 2;
|
const paddingRows = 2;
|
||||||
let scrollHeight = 0;
|
let scrollHeight = 0;
|
||||||
let scrollOffset = 0;
|
let scrollOffset = 0;
|
||||||
let flipDuration = 0;
|
|
||||||
|
|
||||||
let notesOffset = 0;
|
let notesOffset = 0;
|
||||||
let notesLimit = 100;
|
let notesLimit = 100;
|
||||||
let prevNotesCount = 0;
|
let prevNotesCount = 0;
|
||||||
let prevRowHeight = 0;
|
let prevRowHeight = 0;
|
||||||
|
|
||||||
|
let flipDuration = 0;
|
||||||
|
let flipTimeout: ReturnType<typeof setTimeout> | undefined;
|
||||||
|
|
||||||
const { noteScale } = settings;
|
const { noteScale } = settings;
|
||||||
let scaleUnsubscribe: Unsubscriber;
|
let scaleUnsubscribe: Unsubscriber;
|
||||||
let countUnsubscribe: Unsubscriber;
|
let countUnsubscribe: Unsubscriber;
|
||||||
|
@ -41,7 +43,8 @@
|
||||||
|
|
||||||
if (notesCount !== prevNotesCount) {
|
if (notesCount !== prevNotesCount) {
|
||||||
flipDuration = 300;
|
flipDuration = 300;
|
||||||
setTimeout(() => {
|
clearTimeout(flipTimeout);
|
||||||
|
flipTimeout = setTimeout(() => {
|
||||||
flipDuration = 0;
|
flipDuration = 0;
|
||||||
}, 300);
|
}, 300);
|
||||||
}
|
}
|
||||||
|
@ -102,8 +105,8 @@
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.note-list {
|
.note-list {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(0, calc(var(--note-height, 385px) * 0.92)));
|
grid-template-columns: repeat(auto-fill, minmax(0, var(--note-height)));
|
||||||
grid-auto-rows: var(--note-height, 385px);
|
grid-auto-rows: var(--note-height);
|
||||||
gap: var(--note-gap, 1rem);
|
gap: var(--note-gap, 1rem);
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
height: var(--scroll-height, auto);
|
height: var(--scroll-height, auto);
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import FaPlus from '$icon/fa-potato.svelte';
|
||||||
|
import { notes } from '$lib/stores';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
aria-label="Search note"
|
||||||
|
data-tooltip="Search note"
|
||||||
|
data-placement="left"
|
||||||
|
on:click={() => notes.search()}
|
||||||
|
>
|
||||||
|
<FaPlus />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
button {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 1rem;
|
||||||
|
right: 6rem;
|
||||||
|
width: 4rem;
|
||||||
|
height: 4rem;
|
||||||
|
margin: 0;
|
||||||
|
border-radius: 50%;
|
||||||
|
box-shadow: var(--card-shadow);
|
||||||
|
|
||||||
|
& > :global(svg) {
|
||||||
|
width: 2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -4,7 +4,8 @@
|
||||||
import { settings } from '$lib/stores';
|
import { settings } from '$lib/stores';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Button
|
<button
|
||||||
|
type="button"
|
||||||
plain
|
plain
|
||||||
icon
|
icon
|
||||||
size="lg"
|
size="lg"
|
||||||
|
@ -13,4 +14,21 @@
|
||||||
on:click={() => settings.open.set(true)}
|
on:click={() => settings.open.set(true)}
|
||||||
>
|
>
|
||||||
<FaGear />
|
<FaGear />
|
||||||
</Button>
|
</button>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
button {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 6rem;
|
||||||
|
right: 1rem;
|
||||||
|
width: 4rem;
|
||||||
|
height: 4rem;
|
||||||
|
margin: 0;
|
||||||
|
border-radius: 50%;
|
||||||
|
box-shadow: var(--card-shadow);
|
||||||
|
|
||||||
|
& > :global(svg) {
|
||||||
|
width: 2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -12,7 +12,7 @@ export class NoteEditorStore {
|
||||||
readonly draftContent = readonly(this._draftContent);
|
readonly draftContent = readonly(this._draftContent);
|
||||||
readonly expanded = readonly(this._expanded);
|
readonly expanded = readonly(this._expanded);
|
||||||
|
|
||||||
constructor(private noteId: Note['id'], private notes: NotesStore) {}
|
constructor(private noteId: Note['id'], private notes: NotesStore) { }
|
||||||
|
|
||||||
startEditing = () => {
|
startEditing = () => {
|
||||||
const note = this.notes.get(this.noteId);
|
const note = this.notes.get(this.noteId);
|
||||||
|
|
|
@ -4,6 +4,8 @@ import type { Insertable, Selectable, Updateable } from 'kysely';
|
||||||
import { writable, type Readable, get, readonly } from 'svelte/store';
|
import { writable, type Readable, get, readonly } from 'svelte/store';
|
||||||
import type { TagsStore } from './tags';
|
import type { TagsStore } from './tags';
|
||||||
import { settings } from '.';
|
import { settings } from '.';
|
||||||
|
import OpenAI from 'openai';
|
||||||
|
import { Ollama } from 'ollama'
|
||||||
|
|
||||||
export type Note = Selectable<Schema['note']>;
|
export type Note = Selectable<Schema['note']>;
|
||||||
export type NewNote = Insertable<Schema['note']>;
|
export type NewNote = Insertable<Schema['note']>;
|
||||||
|
@ -35,13 +37,13 @@ export class NotesStore implements Readable<Note[]> {
|
||||||
selectedTags.length === 0
|
selectedTags.length === 0
|
||||||
? db.selectFrom('note').selectAll().orderBy('createdAt desc')
|
? db.selectFrom('note').selectAll().orderBy('createdAt desc')
|
||||||
: db
|
: db
|
||||||
.selectFrom('noteTag')
|
.selectFrom('noteTag')
|
||||||
.innerJoin('note', 'note.id', 'noteTag.noteId')
|
.innerJoin('note', 'note.id', 'noteTag.noteId')
|
||||||
.selectAll('note')
|
.selectAll('note')
|
||||||
.where('tagId', 'in', selectedTags)
|
.where('tagId', 'in', selectedTags)
|
||||||
.groupBy('noteId')
|
.groupBy('noteId')
|
||||||
.having(({ fn }) => fn.count('noteId'), '=', selectedTags.length)
|
.having(({ fn }) => fn.count('noteId'), '=', selectedTags.length)
|
||||||
.orderBy('createdAt desc');
|
.orderBy('createdAt desc');
|
||||||
|
|
||||||
const notesData = await query.offset(this.offset).limit(this.limit).execute();
|
const notesData = await query.offset(this.offset).limit(this.limit).execute();
|
||||||
const { notesCount } = await db
|
const { notesCount } = await db
|
||||||
|
@ -66,6 +68,20 @@ export class NotesStore implements Readable<Note[]> {
|
||||||
return notes.find((note) => note.id === noteId);
|
return notes.find((note) => note.id === noteId);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
search = async () => {
|
||||||
|
|
||||||
|
const ol = new Ollama({ host: 'http://deve.work:11434' })
|
||||||
|
const response = await ol.chat({
|
||||||
|
model: 'qwen2.5-coder:14b',
|
||||||
|
messages: [{ role: 'user', content: 'python编写1+1=?' }],
|
||||||
|
})
|
||||||
|
alert(response.message.content)
|
||||||
|
|
||||||
|
// const all = await db.selectFrom('note').selectAll().execute();
|
||||||
|
// alert(all[0].content);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
add = async (newNote?: NewNote, scrollToTop?: boolean) => {
|
add = async (newNote?: NewNote, scrollToTop?: boolean) => {
|
||||||
if (!newNote) {
|
if (!newNote) {
|
||||||
newNote = {
|
newNote = {
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
import '$styles/index.scss';
|
import '$styles/index.scss';
|
||||||
export const ssr = false;
|
export const ssr = false;
|
||||||
|
export const prerender = true;
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
import AppHeader from '$lib/components/app-header.svelte';
|
import AppHeader from '$lib/components/app-header.svelte';
|
||||||
import AppUpdatePrompt from '$lib/components/app-update-prompt.svelte';
|
import AppUpdatePrompt from '$lib/components/app-update-prompt.svelte';
|
||||||
import FilterTags from '$lib/components/filter-tags.svelte';
|
import FilterTags from '$lib/components/filter-tags.svelte';
|
||||||
|
import NoteSearchButton from '$lib/components/notes/note-search-button.svelte';
|
||||||
|
import SettingsButton from '$lib/components/settings/settings-button.svelte';
|
||||||
import NoteAddButton from '$lib/components/notes/note-add-button.svelte';
|
import NoteAddButton from '$lib/components/notes/note-add-button.svelte';
|
||||||
import NoteListPlaceholder from '$lib/components/notes/note-list-placeholder.svelte';
|
import NoteListPlaceholder from '$lib/components/notes/note-list-placeholder.svelte';
|
||||||
import NoteList from '$lib/components/notes/note-list.svelte';
|
import NoteList from '$lib/components/notes/note-list.svelte';
|
||||||
|
@ -23,6 +25,8 @@
|
||||||
{:else if $notesCount === 0}
|
{:else if $notesCount === 0}
|
||||||
<NoteListPlaceholder />
|
<NoteListPlaceholder />
|
||||||
{/if}
|
{/if}
|
||||||
|
<SettingsButton />
|
||||||
|
<NoteSearchButton />
|
||||||
<NoteAddButton />
|
<NoteAddButton />
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
|
|
|
@ -68,6 +68,10 @@
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:where(dl, ol, ul) {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
.task-list-item {
|
.task-list-item {
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ html {
|
||||||
background-size: min(20vw, 150px);
|
background-size: min(20vw, 150px);
|
||||||
background-position: center center;
|
background-position: center center;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
|
scrollbar-color: var(--range-thumb-color) var(--range-border-color);
|
||||||
|
|
||||||
&[data-theme] {
|
&[data-theme] {
|
||||||
background-image: none;
|
background-image: none;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import adapter from '@sveltejs/adapter-static';
|
import adapter from '@sveltejs/adapter-static';
|
||||||
import { vitePreprocess } from '@sveltejs/kit/vite';
|
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
||||||
|
|
||||||
/** @type {import('@sveltejs/kit').Config} */
|
/** @type {import('@sveltejs/kit').Config} */
|
||||||
const config = {
|
const config = {
|
||||||
|
|
Loading…
Reference in New Issue