hazo_notes 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +661 -0
- package/SETUP_CHECKLIST.md +453 -0
- package/dist/api/create_files_handler.d.ts +42 -0
- package/dist/api/create_files_handler.d.ts.map +1 -0
- package/dist/api/create_files_handler.js +213 -0
- package/dist/api/create_files_handler.js.map +1 -0
- package/dist/api/create_notes_handler.d.ts +50 -0
- package/dist/api/create_notes_handler.d.ts.map +1 -0
- package/dist/api/create_notes_handler.js +242 -0
- package/dist/api/create_notes_handler.js.map +1 -0
- package/dist/api/index.d.ts +9 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +8 -0
- package/dist/api/index.js.map +1 -0
- package/dist/components/hazo_notes_entry.d.ts +6 -0
- package/dist/components/hazo_notes_entry.d.ts.map +1 -0
- package/dist/components/hazo_notes_entry.js +69 -0
- package/dist/components/hazo_notes_entry.js.map +1 -0
- package/dist/components/hazo_notes_file_preview.d.ts +16 -0
- package/dist/components/hazo_notes_file_preview.d.ts.map +1 -0
- package/dist/components/hazo_notes_file_preview.js +77 -0
- package/dist/components/hazo_notes_file_preview.js.map +1 -0
- package/dist/components/hazo_notes_icon.d.ts +6 -0
- package/dist/components/hazo_notes_icon.d.ts.map +1 -0
- package/dist/components/hazo_notes_icon.js +208 -0
- package/dist/components/hazo_notes_icon.js.map +1 -0
- package/dist/components/hazo_notes_panel.d.ts +6 -0
- package/dist/components/hazo_notes_panel.d.ts.map +1 -0
- package/dist/components/hazo_notes_panel.js +197 -0
- package/dist/components/hazo_notes_panel.js.map +1 -0
- package/dist/components/index.d.ts +8 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +8 -0
- package/dist/components/index.js.map +1 -0
- package/dist/hooks/index.d.ts +8 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +6 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/use_notes.d.ts +46 -0
- package/dist/hooks/use_notes.d.ts.map +1 -0
- package/dist/hooks/use_notes.js +146 -0
- package/dist/hooks/use_notes.js.map +1 -0
- package/dist/hooks/use_notes_file_upload.d.ts +52 -0
- package/dist/hooks/use_notes_file_upload.d.ts.map +1 -0
- package/dist/hooks/use_notes_file_upload.js +125 -0
- package/dist/hooks/use_notes_file_upload.js.map +1 -0
- package/dist/index.client.d.ts +16 -0
- package/dist/index.client.d.ts.map +1 -0
- package/dist/index.client.js +18 -0
- package/dist/index.client.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/config.d.ts +31 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +123 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/index.d.ts +6 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +6 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/logger/context.d.ts +49 -0
- package/dist/logger/context.d.ts.map +1 -0
- package/dist/logger/context.js +45 -0
- package/dist/logger/context.js.map +1 -0
- package/dist/logger/index.d.ts +9 -0
- package/dist/logger/index.d.ts.map +1 -0
- package/dist/logger/index.js +7 -0
- package/dist/logger/index.js.map +1 -0
- package/dist/logger/server.d.ts +27 -0
- package/dist/logger/server.d.ts.map +1 -0
- package/dist/logger/server.js +36 -0
- package/dist/logger/server.js.map +1 -0
- package/dist/logger/types.d.ts +20 -0
- package/dist/logger/types.d.ts.map +1 -0
- package/dist/logger/types.js +15 -0
- package/dist/logger/types.js.map +1 -0
- package/dist/types/index.d.ts +267 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/cn.d.ts +16 -0
- package/dist/utils/cn.d.ts.map +1 -0
- package/dist/utils/cn.js +19 -0
- package/dist/utils/cn.js.map +1 -0
- package/dist/utils/file_utils.d.ts +51 -0
- package/dist/utils/file_utils.d.ts.map +1 -0
- package/dist/utils/file_utils.js +128 -0
- package/dist/utils/file_utils.js.map +1 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +6 -0
- package/dist/utils/index.js.map +1 -0
- package/migrations/001_create_hazo_notes_table.sql +77 -0
- package/package.json +119 -0
- package/templates/config/hazo_notes_config.ini +43 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File utility functions for hazo_notes
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Generate a sequential file number (e.g., "0001", "0002")
|
|
6
|
+
*/
|
|
7
|
+
export function generate_file_no(existing_files) {
|
|
8
|
+
const max_no = existing_files.reduce((max, file) => {
|
|
9
|
+
const num = parseInt(file.file_no, 10);
|
|
10
|
+
return isNaN(num) ? max : Math.max(max, num);
|
|
11
|
+
}, 0);
|
|
12
|
+
return String(max_no + 1).padStart(4, '0');
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Convert File object to base64 string
|
|
16
|
+
*/
|
|
17
|
+
export async function file_to_base64(file) {
|
|
18
|
+
return new Promise((resolve, reject) => {
|
|
19
|
+
const reader = new FileReader();
|
|
20
|
+
reader.onload = () => {
|
|
21
|
+
const result = reader.result;
|
|
22
|
+
// Remove data URL prefix (e.g., "data:image/png;base64,")
|
|
23
|
+
const base64 = result.split(',')[1] || result;
|
|
24
|
+
resolve(base64);
|
|
25
|
+
};
|
|
26
|
+
reader.onerror = () => reject(new Error('Failed to read file'));
|
|
27
|
+
reader.readAsDataURL(file);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Get MIME type from filename extension
|
|
32
|
+
*/
|
|
33
|
+
export function get_mime_type(filename) {
|
|
34
|
+
const ext = filename.split('.').pop()?.toLowerCase() || '';
|
|
35
|
+
const mime_types = {
|
|
36
|
+
// Images
|
|
37
|
+
png: 'image/png',
|
|
38
|
+
jpg: 'image/jpeg',
|
|
39
|
+
jpeg: 'image/jpeg',
|
|
40
|
+
gif: 'image/gif',
|
|
41
|
+
webp: 'image/webp',
|
|
42
|
+
svg: 'image/svg+xml',
|
|
43
|
+
// Documents
|
|
44
|
+
pdf: 'application/pdf',
|
|
45
|
+
doc: 'application/msword',
|
|
46
|
+
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
47
|
+
xls: 'application/vnd.ms-excel',
|
|
48
|
+
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
49
|
+
txt: 'text/plain',
|
|
50
|
+
csv: 'text/csv',
|
|
51
|
+
// Archives
|
|
52
|
+
zip: 'application/zip',
|
|
53
|
+
rar: 'application/vnd.rar',
|
|
54
|
+
};
|
|
55
|
+
return mime_types[ext] || 'application/octet-stream';
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Check if file type is allowed
|
|
59
|
+
*/
|
|
60
|
+
export function is_allowed_file_type(filename, allowed_types) {
|
|
61
|
+
const ext = filename.split('.').pop()?.toLowerCase() || '';
|
|
62
|
+
return allowed_types.map(t => t.toLowerCase()).includes(ext);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Check if file is an image (can be embedded)
|
|
66
|
+
*/
|
|
67
|
+
export function is_image_file(filename) {
|
|
68
|
+
const ext = filename.split('.').pop()?.toLowerCase() || '';
|
|
69
|
+
return ['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg'].includes(ext);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Format file size for display
|
|
73
|
+
*/
|
|
74
|
+
export function format_file_size(bytes) {
|
|
75
|
+
if (bytes === 0)
|
|
76
|
+
return '0 B';
|
|
77
|
+
const k = 1024;
|
|
78
|
+
const sizes = ['B', 'KB', 'MB', 'GB'];
|
|
79
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
80
|
+
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Parse note text and extract file references
|
|
84
|
+
* Returns array of { type: 'embed' | 'attach', file_no: string }
|
|
85
|
+
*/
|
|
86
|
+
export function parse_file_references(note_text) {
|
|
87
|
+
const references = [];
|
|
88
|
+
// Match <<embed:0001>> pattern
|
|
89
|
+
const embed_regex = /<<embed:(\d+)>>/g;
|
|
90
|
+
let match;
|
|
91
|
+
while ((match = embed_regex.exec(note_text)) !== null) {
|
|
92
|
+
references.push({ type: 'embed', file_no: match[1] });
|
|
93
|
+
}
|
|
94
|
+
// Match <<attach:0001>> pattern
|
|
95
|
+
const attach_regex = /<<attach:(\d+)>>/g;
|
|
96
|
+
while ((match = attach_regex.exec(note_text)) !== null) {
|
|
97
|
+
references.push({ type: 'attachment', file_no: match[1] });
|
|
98
|
+
}
|
|
99
|
+
return references;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Create file reference syntax for inserting into note text
|
|
103
|
+
*/
|
|
104
|
+
export function create_file_reference(file_no, embed_type) {
|
|
105
|
+
return embed_type === 'embed' ? `<<embed:${file_no}>>` : `<<attach:${file_no}>>`;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Validate file before upload
|
|
109
|
+
*/
|
|
110
|
+
export function validate_file(file, options) {
|
|
111
|
+
// Check file size
|
|
112
|
+
const max_bytes = options.max_size_mb * 1024 * 1024;
|
|
113
|
+
if (file.size > max_bytes) {
|
|
114
|
+
return {
|
|
115
|
+
valid: false,
|
|
116
|
+
error: `File size (${format_file_size(file.size)}) exceeds maximum allowed (${options.max_size_mb} MB)`,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
// Check file type
|
|
120
|
+
if (!is_allowed_file_type(file.name, options.allowed_types)) {
|
|
121
|
+
return {
|
|
122
|
+
valid: false,
|
|
123
|
+
error: `File type not allowed. Allowed types: ${options.allowed_types.join(', ')}`,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
return { valid: true };
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=file_utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file_utils.js","sourceRoot":"","sources":["../../src/utils/file_utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for hazo_notes
|
|
3
|
+
*/
|
|
4
|
+
export { cn } from './cn.js';
|
|
5
|
+
export { generate_file_no, file_to_base64, get_mime_type, is_allowed_file_type, is_image_file, format_file_size, parse_file_references, create_file_reference, validate_file, } from './file_utils.js';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAC7B,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,oBAAoB,EACpB,aAAa,EACb,gBAAgB,EAChB,qBAAqB,EACrB,qBAAqB,EACrB,aAAa,GACd,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for hazo_notes
|
|
3
|
+
*/
|
|
4
|
+
export { cn } from './cn.js';
|
|
5
|
+
export { generate_file_no, file_to_base64, get_mime_type, is_allowed_file_type, is_image_file, format_file_size, parse_file_references, create_file_reference, validate_file, } from './file_utils.js';
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAC7B,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,oBAAoB,EACpB,aAAa,EACb,gBAAgB,EAChB,qBAAqB,EACrB,qBAAqB,EACrB,aAAa,GACd,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
-- Migration: Create hazo_notes table
|
|
2
|
+
-- Version: 001
|
|
3
|
+
-- Description: Initial table creation for notes system with JSONB storage
|
|
4
|
+
-- Compatible with: PostgreSQL 13+, SQLite 3.38+ (with JSON1 extension)
|
|
5
|
+
|
|
6
|
+
-- ============================================================================
|
|
7
|
+
-- PostgreSQL Version
|
|
8
|
+
-- ============================================================================
|
|
9
|
+
|
|
10
|
+
-- Create the hazo_notes table
|
|
11
|
+
CREATE TABLE IF NOT EXISTS hazo_notes (
|
|
12
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
13
|
+
ref_id UUID NOT NULL,
|
|
14
|
+
note JSONB NOT NULL DEFAULT '[]'::jsonb,
|
|
15
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
16
|
+
changed_at TIMESTAMPTZ,
|
|
17
|
+
note_count INTEGER NOT NULL DEFAULT 0
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
-- Create index on ref_id for efficient lookups
|
|
21
|
+
CREATE INDEX IF NOT EXISTS idx_hazo_notes_ref_id ON hazo_notes(ref_id);
|
|
22
|
+
|
|
23
|
+
-- Add comments for documentation
|
|
24
|
+
COMMENT ON TABLE hazo_notes IS 'Stores notes linked to any entity via ref_id. Notes are stored as JSONB array with user attribution and optional file attachments.';
|
|
25
|
+
COMMENT ON COLUMN hazo_notes.id IS 'Primary key UUID';
|
|
26
|
+
COMMENT ON COLUMN hazo_notes.ref_id IS 'UUID reference to the parent entity (e.g., form field, document, task)';
|
|
27
|
+
COMMENT ON COLUMN hazo_notes.note IS 'JSONB array of note entries: [{userid, created_at, note_text, note_files}]';
|
|
28
|
+
COMMENT ON COLUMN hazo_notes.created_at IS 'Timestamp when the notes row was first created';
|
|
29
|
+
COMMENT ON COLUMN hazo_notes.changed_at IS 'Timestamp of the last modification to the notes';
|
|
30
|
+
COMMENT ON COLUMN hazo_notes.note_count IS 'Denormalized count of notes for quick access without parsing JSONB';
|
|
31
|
+
|
|
32
|
+
-- ============================================================================
|
|
33
|
+
-- SQLite Version (for test-app)
|
|
34
|
+
-- Run this in SQLite instead of the PostgreSQL version above
|
|
35
|
+
-- ============================================================================
|
|
36
|
+
|
|
37
|
+
/*
|
|
38
|
+
-- SQLite version (uncomment to use):
|
|
39
|
+
|
|
40
|
+
CREATE TABLE IF NOT EXISTS hazo_notes (
|
|
41
|
+
id TEXT PRIMARY KEY,
|
|
42
|
+
ref_id TEXT NOT NULL,
|
|
43
|
+
note TEXT NOT NULL DEFAULT '[]',
|
|
44
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
45
|
+
changed_at TEXT,
|
|
46
|
+
note_count INTEGER NOT NULL DEFAULT 0
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
CREATE INDEX IF NOT EXISTS idx_hazo_notes_ref_id ON hazo_notes(ref_id);
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
-- ============================================================================
|
|
53
|
+
-- Note Entry JSONB Schema Reference
|
|
54
|
+
-- ============================================================================
|
|
55
|
+
/*
|
|
56
|
+
Each element in the `note` JSONB array follows this structure:
|
|
57
|
+
|
|
58
|
+
{
|
|
59
|
+
"userid": "550e8400-e29b-41d4-a716-446655440000",
|
|
60
|
+
"created_at": "2026-01-07T12:30:00.000Z",
|
|
61
|
+
"note_text": "This is the note content. See attachment: <<attach:0001>>",
|
|
62
|
+
"note_files": [
|
|
63
|
+
{
|
|
64
|
+
"file_no": "0001",
|
|
65
|
+
"embed_type": "attachment",
|
|
66
|
+
"filename": "document.pdf",
|
|
67
|
+
"filedata": "base64_encoded_content_or_file_path",
|
|
68
|
+
"mime_type": "application/pdf",
|
|
69
|
+
"file_size": 12345
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
File references in note_text:
|
|
75
|
+
- <<embed:0001>> - Renders file inline (images displayed directly)
|
|
76
|
+
- <<attach:0001>> - Renders as downloadable link
|
|
77
|
+
*/
|
package/package.json
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "hazo_notes",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Database-backed notes system with file attachment support for the hazo ecosystem",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.client.js",
|
|
7
|
+
"module": "./dist/index.client.js",
|
|
8
|
+
"types": "./dist/index.client.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/index.client.js",
|
|
12
|
+
"types": "./dist/index.client.d.ts"
|
|
13
|
+
},
|
|
14
|
+
"./api": {
|
|
15
|
+
"import": "./dist/api/index.js",
|
|
16
|
+
"types": "./dist/api/index.d.ts"
|
|
17
|
+
},
|
|
18
|
+
"./hooks": {
|
|
19
|
+
"import": "./dist/hooks/index.js",
|
|
20
|
+
"types": "./dist/hooks/index.d.ts"
|
|
21
|
+
},
|
|
22
|
+
"./components": {
|
|
23
|
+
"import": "./dist/components/index.js",
|
|
24
|
+
"types": "./dist/components/index.d.ts"
|
|
25
|
+
},
|
|
26
|
+
"./lib": {
|
|
27
|
+
"import": "./dist/lib/index.js",
|
|
28
|
+
"types": "./dist/lib/index.d.ts"
|
|
29
|
+
},
|
|
30
|
+
"./types": {
|
|
31
|
+
"import": "./dist/types/index.js",
|
|
32
|
+
"types": "./dist/types/index.d.ts"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist",
|
|
37
|
+
"templates",
|
|
38
|
+
"migrations",
|
|
39
|
+
"README.md",
|
|
40
|
+
"SETUP_CHECKLIST.md"
|
|
41
|
+
],
|
|
42
|
+
"workspaces": [
|
|
43
|
+
"test-app"
|
|
44
|
+
],
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "tsc -p tsconfig.build.json",
|
|
47
|
+
"dev:package": "tsc -p tsconfig.build.json --watch",
|
|
48
|
+
"dev:test-app": "npm run build && cd test-app && npm run dev",
|
|
49
|
+
"build:test-app": "npm run build && cd test-app && npm run build",
|
|
50
|
+
"clean": "rm -rf dist",
|
|
51
|
+
"prebuild": "npm run clean",
|
|
52
|
+
"prepublishOnly": "npm run build",
|
|
53
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
54
|
+
},
|
|
55
|
+
"repository": {
|
|
56
|
+
"type": "git",
|
|
57
|
+
"url": "git+https://github.com/pub12/hazo_notes.git"
|
|
58
|
+
},
|
|
59
|
+
"keywords": [
|
|
60
|
+
"notes",
|
|
61
|
+
"hazo",
|
|
62
|
+
"react",
|
|
63
|
+
"typescript",
|
|
64
|
+
"nextjs",
|
|
65
|
+
"file-attachments"
|
|
66
|
+
],
|
|
67
|
+
"author": "Pubs Abayasiri",
|
|
68
|
+
"license": "MIT",
|
|
69
|
+
"bugs": {
|
|
70
|
+
"url": "https://github.com/pub12/hazo_notes/issues"
|
|
71
|
+
},
|
|
72
|
+
"homepage": "https://github.com/pub12/hazo_notes#readme",
|
|
73
|
+
"dependencies": {
|
|
74
|
+
"clsx": "^2.1.1",
|
|
75
|
+
"hazo_config": "^1.0.0",
|
|
76
|
+
"server-only": "^0.0.1",
|
|
77
|
+
"tailwind-merge": "^2.5.4"
|
|
78
|
+
},
|
|
79
|
+
"devDependencies": {
|
|
80
|
+
"@types/node": "^20.10.0",
|
|
81
|
+
"@types/react": "^18.2.0",
|
|
82
|
+
"@types/react-dom": "^18.2.0",
|
|
83
|
+
"hazo_logs": "^1.0.0",
|
|
84
|
+
"next": "^14.2.33",
|
|
85
|
+
"typescript": "^5.3.0"
|
|
86
|
+
},
|
|
87
|
+
"peerDependencies": {
|
|
88
|
+
"@radix-ui/react-dialog": "^1.0.0",
|
|
89
|
+
"@radix-ui/react-popover": "^1.0.0",
|
|
90
|
+
"hazo_auth": "^5.0.0",
|
|
91
|
+
"hazo_connect": "^2.3.1",
|
|
92
|
+
"hazo_logs": "^1.0.0",
|
|
93
|
+
"next": ">=14.0.0",
|
|
94
|
+
"react": "^18.0.0",
|
|
95
|
+
"react-dom": "^18.0.0",
|
|
96
|
+
"react-icons": "^5.0.0",
|
|
97
|
+
"tailwindcss": ">=3.0.0"
|
|
98
|
+
},
|
|
99
|
+
"peerDependenciesMeta": {
|
|
100
|
+
"hazo_auth": {
|
|
101
|
+
"optional": true
|
|
102
|
+
},
|
|
103
|
+
"hazo_connect": {
|
|
104
|
+
"optional": true
|
|
105
|
+
},
|
|
106
|
+
"hazo_logs": {
|
|
107
|
+
"optional": true
|
|
108
|
+
},
|
|
109
|
+
"@radix-ui/react-popover": {
|
|
110
|
+
"optional": true
|
|
111
|
+
},
|
|
112
|
+
"@radix-ui/react-dialog": {
|
|
113
|
+
"optional": true
|
|
114
|
+
},
|
|
115
|
+
"react-icons": {
|
|
116
|
+
"optional": true
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# hazo_notes Configuration Template
|
|
2
|
+
# Copy this file to your application's config/ directory
|
|
3
|
+
# Path: config/hazo_notes_config.ini
|
|
4
|
+
|
|
5
|
+
[ui]
|
|
6
|
+
# Background color for notes panel (Tailwind CSS class)
|
|
7
|
+
# Examples: bg-yellow-100, bg-blue-50, bg-gray-100
|
|
8
|
+
background_color = bg-yellow-100
|
|
9
|
+
|
|
10
|
+
# Panel presentation style
|
|
11
|
+
# Options: popover | slide_panel
|
|
12
|
+
panel_style = popover
|
|
13
|
+
|
|
14
|
+
# Save behavior
|
|
15
|
+
# Options:
|
|
16
|
+
# explicit - User clicks Save/Cancel buttons
|
|
17
|
+
# auto - Note saved automatically when panel closes or on blur
|
|
18
|
+
save_mode = explicit
|
|
19
|
+
|
|
20
|
+
[storage]
|
|
21
|
+
# File storage mode
|
|
22
|
+
# Options:
|
|
23
|
+
# jsonb - Store files as Base64 in database (simpler, good for small files)
|
|
24
|
+
# filesystem - Store files on server filesystem (better for large files)
|
|
25
|
+
file_storage_mode = jsonb
|
|
26
|
+
|
|
27
|
+
# Path for filesystem storage (only used when file_storage_mode = filesystem)
|
|
28
|
+
# Must be an absolute path or relative to your application root
|
|
29
|
+
file_storage_path = /uploads/notes
|
|
30
|
+
|
|
31
|
+
[files]
|
|
32
|
+
# Maximum file size in MB
|
|
33
|
+
max_file_size_mb = 10
|
|
34
|
+
|
|
35
|
+
# Allowed file types (comma-separated extensions, no dots)
|
|
36
|
+
allowed_file_types = pdf,png,jpg,jpeg,gif,doc,docx
|
|
37
|
+
|
|
38
|
+
# Maximum files per single note entry
|
|
39
|
+
max_files_per_note = 5
|
|
40
|
+
|
|
41
|
+
[logging]
|
|
42
|
+
# Log file path (relative to application root)
|
|
43
|
+
logfile = logs/hazo_notes.log
|