/
index.tsx
121 lines (109 loc) · 3.61 KB
/
index.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import { Form, ActionPanel, Action, showToast, Clipboard, getPreferenceValues, closeMainWindow, popToRoot } from "@raycast/api";
import { useEffect, useState, useRef } from "react";
import axios from "axios"
import { load } from "cheerio";
import fs from "node:fs"
import path from "node:path"
type Values = {
url: string;
title: string;
description: string;
tags: string[];
customTags?: string
date: string;
};
export default function Command() {
const [url, setUrl] = useState("");
const [title, setTitle] = useState("");
const [isLoading, setIsLoading] = useState(true);
const [customTags, setCustomTags] = useState(""); // State for custom tags input
const descriptionRef = useRef(null); // Ref for the description field
const fetchTitle = async (url: string) => {
try {
const { data } = await axios.get(url);
const $ = load(data);
const title = $('head title').text();
setTitle(title);
} catch (error) {
showToast({ title: "Error", message: "Could not fetch the website title" });
}
};
// Effect to autofill the URL from the clipboard
useEffect(() => {
Clipboard.readText().then((clipboardText) => {
if (clipboardText && clipboardText.startsWith("http")) {
setUrl(clipboardText);
fetchTitle(clipboardText);
}
setIsLoading(false);
});
}, []);
useEffect(() => {
if (url) {
fetchTitle(url);
}
}, [url]);
useEffect(() => {
if (!isLoading && descriptionRef.current) {
(descriptionRef.current as HTMLInputElement).focus();
}
}, [isLoading]);
function handleSubmit(values: Values) {
if (!values.url) {
return
}
try {
let tagsArray
if (values.customTags) {
tagsArray = values.customTags.split(/,|\s+/).filter(tag => tag.trim() !== "")
delete values.customTags;
}
saveDataToFile({ ...values, tags: tagsArray || [], date: new Date().toISOString() });
popToRoot()
closeMainWindow({ clearRootSearch: true });
} catch (error) {
console.log(error)
showToast({ title: 'Error', message: 'Something went wrong' });
}
}
function saveDataToFile(data: Values) {
const preferences = getPreferenceValues();
const saveDirectory = preferences.saveDirectory || process.env.HOME; // Fallback to home directory
const filePath = path.join(saveDirectory, 'raycast-bookmarks.json'); // Save file in home directory
fs.readFile(filePath, (err, fileData) => {
let bookmarks = [];
if (!err) {
bookmarks = JSON.parse(fileData.toString());
}
bookmarks.push(data);
fs.writeFile(filePath, JSON.stringify(bookmarks, null, 2), (writeErr) => {
if (writeErr) {
showToast({ title: 'Error', message: 'Failed to save data' });
}
});
});
}
return (
<Form
isLoading={isLoading}
actions={
<ActionPanel>
<Action.SubmitForm onSubmit={handleSubmit} />
</ActionPanel>
}
initialFocus="description"
>
<Form.Description text="Bookmark Gatherer" />
<Form.TextField id="url" title="URL" placeholder="URL" value={url} onChange={setUrl} />
<Form.TextField id="title" title="Title" placeholder="Title" value={title} onChange={setTitle} />
<Form.TextArea id="description" title="Description" placeholder="What did you find compelling or intriguing about this?" ref={descriptionRef} />
<Form.TextField
id="customTags"
title="Custom Tags"
placeholder="Enter custom tags separated by comma or space"
value={customTags}
onChange={setCustomTags}
/>
</Form>
);
}