303 |
├── .eslintrc.cjs
├── .github
└── FUNDING.yml
├── .gitignore
├── .vscode
└── extensions.json
├── LICENSE
├── README.md
├── _locales
├── en
│ └── messages.json
└── zh_CN
│ └── messages.json
├── manifest.json
├── package.json
├── postcss.config.js
├── public
├── icons
│ ├── nut-mark-128x128.png
│ ├── nut-mark-16x16.png
│ ├── nut-mark-32x32.png
│ ├── nut-mark-48x48.png
│ ├── nut-unmark-128x128.png
│ ├── nut-unmark-16x16.png
│ ├── nut-unmark-32x32.png
│ └── nut-unmark-48x48.png
├── install-in-chrome.png
├── install-in-chrome.svg
├── install-in-edge.png
├── install-in-edge.svg
├── install-in-github.png
├── install-in-github.svg
├── nut-mark-cover.png
├── nut-mark.svg
├── nut-unmark.svg
└── screenshot.png
├── src
├── assets
│ ├── icons
│ │ ├── nut-mark-128x128.png
│ │ ├── nut-mark-16x16.png
│ │ ├── nut-mark-32x32.png
│ │ ├── nut-mark-48x48.png
│ │ ├── nut-unmark-128x128.png
│ │ ├── nut-unmark-16x16.png
│ │ ├── nut-unmark-32x32.png
│ │ └── nut-unmark-48x48.png
│ ├── introduction
│ │ ├── pin-extension-cn.gif
│ │ ├── pin-extension.gif
│ │ ├── screenshot-cn.png
│ │ └── screenshot.png
│ ├── nut-mark.svg
│ └── nut-unmark.svg
├── background
│ └── main.js
├── composables
│ ├── changeActionIcon.js
│ ├── checkBookmarkState.js
│ ├── getFaviconURL.js
│ ├── getTabInfo.js
│ ├── getTranslation.js
│ └── getTreeId.js
├── popup
│ ├── App.vue
│ ├── components
│ │ ├── BookmarkFolderSession.vue
│ │ ├── BookmarkUrlSession.vue
│ │ ├── FolderGrid.vue
│ │ ├── FolderGridItem.vue
│ │ └── SearchFolder.vue
│ ├── index.html
│ └── main.js
└── style.css
├── tailwind.config.js
└── vite.config.js
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | WebExtensions: true,
4 | browser: true,
5 | es2021: true,
6 | node: true,
7 | },
8 | extends: [
9 | 'plugin:vue/vue3-recommended',
10 | 'airbnb-base',
11 | ],
12 | overrides: [
13 | ],
14 | parserOptions: {
15 | ecmaVersion: 'latest',
16 | sourceType: 'module',
17 | },
18 | plugins: [
19 | 'vue',
20 | ],
21 | rules: {
22 | },
23 | };
24 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | ko_fi: benbinbin
2 | custom: https://afdian.com/a/benbinbin
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
26 | yarn.lock
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"]
3 | }
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Benbinbin
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # Nut Mark
4 | Nut Mark is a browser extension to help you collect bookmarks more easily.
5 |
6 | [](https://microsoftedge.microsoft.com/addons/detail/ajoonjmbgcebacpkibmillgghjnoinbh)
7 | [](https://github.com/Benbinbin/NutMark/releases)
8 |
9 | :bulb: check out the [Introduction Page](https://nutmark.benbinbin.com/) for more information.
10 |
11 | :clapper: check out the [Youtube Playlist](https://www.youtube.com/playlist?list=PLqLRbo_6ezAH4dX-RJxExHDVa956wKvTT) to see the DEMO.
12 |
13 | ## Why call "Nut Mark"
14 | I like to collect and organize bookmarks like a squirrel hoards nuts, so I build this browser extension and call it "Nut Mark".
15 |
16 | ## Feature
17 |
18 | Nut Mark focus on collecting bookmarks with the following features to make the process more smoothly and easily
19 |
20 | :sparkles: Clean "dirty" URL with one click
21 |
22 | :sparkles: Navigate freely through the directory tree
23 |
24 | :sparkles: Quick search to find the directory to hold the bookmark
25 |
26 | ## Screenshot
27 |
28 | 
29 |
30 | ## License
31 | [MIT](https://github.com/Benbinbin/NutMark/blob/main/LICENSE)
32 |
33 | ## Feedback
34 | If you have any problem or suggestion about this project, feel free to open an [issue](https://github.com/Benbinbin/NutMark/issues/new) in Github or contact with me by email [benthomsonbin@gmail.com](benthomsonbin@gmail.com)
--------------------------------------------------------------------------------
/_locales/en/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "extension_description": {
3 | "message": "Nut Mark make bookmarking a breeze"
4 | },
5 | "popup_header_show_similar_bookmarks_btn_title": {
6 | "message": "click the button to show the similar bookmarks list"
7 | },
8 | "popup_header_bookmark_state_saved": {
9 | "message": "Saved"
10 | },
11 | "popup_header_bookmark_state_unsaved": {
12 | "message": "Unsaved"
13 | },
14 | "popup_header_delete_bookmarks_btn_content": {
15 | "message": "Delete"
16 | },
17 | "popup_header_delete_bookmarks_btn_title": {
18 | "message": "click the button to delete bookmark"
19 | },
20 | "popup_header_update_bookmarks_btn_content": {
21 | "message": "Update"
22 | },
23 | "popup_header_update_bookmarks_btn_content_hover": {
24 | "message": "Save"
25 | },
26 | "popup_header_update_bookmarks_btn_title": {
27 | "message": "click the button to update bookmark"
28 | },
29 | "popup_header_create_bookmarks_btn_content": {
30 | "message": "Save"
31 | },
32 | "popup_header_create_bookmarks_btn_title": {
33 | "message": "click the button to create a bookmark"
34 | },
35 | "popup_header_info_btn_title": {
36 | "message": "click the button to learn more about Nut Mark"
37 | },
38 | "popup_main_bookmark_title_section_name": {
39 | "message": "Name"
40 | },
41 | "popup_main_bookmark_title_section_set_tab_name_btn_title": {
42 | "message": "click the button to set the tab name as bookmark name"
43 | },
44 | "popup_main_bookmark_title_section_reset_btn_title": {
45 | "message": "click the button to reset bookmark name"
46 | },
47 | "popup_main_bookmark_title_section_textarea_placeholder": {
48 | "message": "Please enter a name for the bookmark"
49 | },
50 | "popup_modal_delete_bookmark_prompt_title": {
51 | "message": "Delete the Bookmark"
52 | },
53 | "popup_modal_delete_bookmark_prompt_confirm_btn_title": {
54 | "message": "click the button to confirm"
55 | },
56 | "popup_modal_delete_bookmark_prompt_confirm_btn_content": {
57 | "message": "Confirm"
58 | },
59 | "popup_modal_delete_bookmark_prompt_cancel_btn_title": {
60 | "message": "click the button to cancel"
61 | },
62 | "popup_modal_delete_bookmark_prompt_cancel_btn_content": {
63 | "message": "Cancel"
64 | },
65 | "popup_modal_similar_bookmarks_list_title": {
66 | "message": "Similar Bookmarks"
67 | },
68 | "popup_modal_similar_bookmarks_list_btn_title": {
69 | "message": "click the button to edit the bookmark information"
70 | },
71 | "popup_main_bookmark_url_section_name": {
72 | "message": "URL"
73 | },
74 | "popup_main_bookmark_url_section_format_warning": {
75 | "message": "Please Enter a Link in the Correct Format"
76 | },
77 | "popup_main_bookmark_url_section_edit_bookmark_with_duplicated_url_btn_title": {
78 | "message": "click the button to edit the saved bookmark with the same url"
79 | },
80 | "popup_main_bookmark_url_section_edit_bookmark_with_duplicated_url_btn_content": {
81 | "message": "A Saved bookmark with the same URL"
82 | },
83 | "popup_main_bookmark_url_section_one_click_mode_btn_title": {
84 | "message": "click the button to enable the one click mode to edit URL"
85 | },
86 | "popup_main_bookmark_url_section_reset_url_btn_title": {
87 | "message": "click the button to reset the URL"
88 | },
89 | "popup_main_bookmark_url_section_textarea_placeholder": {
90 | "message": "Please Enter the Link of the Bookmark"
91 | },
92 | "popup_main_bookmark_url_section_show_url_hostname_btn_title": {
93 | "message": "hover the button to highlight the hostname of the URL"
94 | },
95 | "popup_main_bookmark_url_section_delete_url_path_btn_title": {
96 | "message": "click the button to delete the part of the URL from path to the end"
97 | },
98 | "popup_main_bookmark_url_section_delete_url_search_btn_title": {
99 | "message": "click the button to delete the part of the URL from search to the end"
100 | },
101 | "popup_main_bookmark_url_section_delete_url_hash_btn_title": {
102 | "message": "click the button to delete the part of the URL hash"
103 | },
104 | "popup_main_bookmark_folder_section_name": {
105 | "message": "Folder"
106 | },
107 | "popup_main_bookmark_folder_section_set_node_tree_id_btn_old_title": {
108 | "message": "click the button to show where the folder is located"
109 | },
110 | "popup_main_bookmark_folder_section_set_node_tree_id_btn_prompt_content": {
111 | "message": "please select the folder 👇"
112 | },
113 | "popup_main_bookmark_folder_section_set_node_tree_id_btn_new_title": {
114 | "message": "click the button to show where the new folder is located"
115 | },
116 | "popup_main_bookmark_folder_section_toggle_search_folder_btn_title": {
117 | "message": "click the button to toggle showing or hiding the search folder panel"
118 | },
119 | "popup_main_bookmark_folder_section_reset_folder_btn_title": {
120 | "message": "click the button to reset the folder of bookmark"
121 | },
122 | "popup_main_bookmark_folder_section_toggle_bookmark_btn_title": {
123 | "message": "show bookmark or just show folder"
124 | },
125 | "popup_main_bookmark_folder_section_folder_path_nav_btn_title": {
126 | "message": "click the button to show where the folder is located"
127 | },
128 | "popup_main_bookmark_folder_section_folder_path_nav_root_btn_content": {
129 | "message": "Root Folder"
130 | },
131 | "popup_main_bookmark_folder_section_add_new_folder_btn_title": {
132 | "message": "click the button to add new folder"
133 | },
134 | "popup_main_bookmark_folder_section_new_folder_name_input_placeholder": {
135 | "message": "Please Enter a Directory Name"
136 | },
137 | "popup_main_bookmark_folder_section_confirm_new_folder_name_btn_title": {
138 | "message": "click the button to confirm the new folder name"
139 | },
140 | "popup_main_bookmark_folder_section_edit_new_folder_name_btn_title": {
141 | "message": "click the button to edit the new folder name"
142 | },
143 | "popup_main_bookmark_folder_section_open_folder_btn_title": {
144 | "message": "click the button to open the folder in place"
145 | },
146 | "popup_main_bookmark_folder_section_expand_folder_btn_title": {
147 | "message": "click the button to expand the folder"
148 | },
149 | "popup_main_bookmark_folder_section_close_folder_btn_title": {
150 | "message": "click the button to close the folder"
151 | },
152 | "popup_main_bookmark_folder_section_select_folder_btn_title": {
153 | "message": "click to select this folder"
154 | },
155 | "popup_main_bookmark_folder_section_folder_nav_btn_title": {
156 | "message": "click to show this folder"
157 | },
158 | "popup_main_bookmark_folder_section_folder_nav_left_scroll_btn_title": {
159 | "message": "click the button to scroll to the left"
160 | },
161 | "popup_main_bookmark_folder_section_folder_nav_right_scroll_btn_title": {
162 | "message": "click the button to scroll to the right"
163 | },
164 | "popup_main_bookmark_folder_section_search_folder_include_bookmark_btn_title": {
165 | "message": "click the button to toggle search entry include bookmarks or note"
166 | },
167 | "popup_main_bookmark_folder_section_search_folder_input_placeholder": {
168 | "message": "Please Enter Content to Search"
169 | },
170 | "popup_main_bookmark_folder_section_search_folder_focus_to_input_box_btn_title": {
171 | "message": "click to focus the input box"
172 | },
173 | "popup_main_bookmark_folder_section_search_folder_state_waiting": {
174 | "message": "Type to Search"
175 | },
176 | "popup_main_bookmark_folder_section_search_folder_state_search": {
177 | "message": "Searching"
178 | },
179 | "popup_main_bookmark_folder_section_search_folder_state_solved": {
180 | "message": "Oops! Empty Entry"
181 | },
182 | "bookmark_folder_default_name": {
183 | "message": "Unnamed Folder"
184 | },
185 | "bookmark_default_name": {
186 | "message": "Unnamed Bookmark"
187 | },
188 | "bookmark_favicon_img_alt": {
189 | "message": "bookmark icon"
190 | },
191 | "bookmark_new_folder_default_title": {
192 | "message": "New folder"
193 | }
194 | }
--------------------------------------------------------------------------------
/_locales/zh_CN/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "extension_description": {
3 | "message": "Nut Mark 让收藏书签变得更轻松"
4 | },
5 | "popup_header_show_similar_bookmarks_btn_title": {
6 | "message": "点击按钮显示相似书签列表"
7 | },
8 | "popup_header_bookmark_state_saved": {
9 | "message": "已保存"
10 | },
11 | "popup_header_bookmark_state_unsaved": {
12 | "message": "未保存"
13 | },
14 | "popup_header_delete_bookmarks_btn_content": {
15 | "message": "删除"
16 | },
17 | "popup_header_delete_bookmarks_btn_title": {
18 | "message": "点击按钮删除书签"
19 | },
20 | "popup_header_update_bookmarks_btn_content": {
21 | "message": "更新"
22 | },
23 | "popup_header_update_bookmarks_btn_content_hover": {
24 | "message": "保存"
25 | },
26 | "popup_header_update_bookmarks_btn_title": {
27 | "message": "点击按钮更新书签"
28 | },
29 | "popup_header_create_bookmarks_btn_content": {
30 | "message": "保存"
31 | },
32 | "popup_header_create_bookmarks_btn_title": {
33 | "message": "点击按钮创建书签"
34 | },
35 | "popup_header_info_btn_title": {
36 | "message": "点击按钮以了解更多 Nut Mark"
37 | },
38 | "popup_main_bookmark_title_section_name": {
39 | "message": "名称"
40 | },
41 | "popup_main_bookmark_title_section_set_tab_name_btn_title": {
42 | "message": "点击按钮将选项卡名称设置为书签名称"
43 | },
44 | "popup_main_bookmark_title_section_reset_btn_title": {
45 | "message": "点击按钮重置书签名称"
46 | },
47 | "popup_main_bookmark_title_section_textarea_placeholder": {
48 | "message": "请输入书签名称"
49 | },
50 | "popup_modal_delete_bookmark_prompt_title": {
51 | "message": "删除书签"
52 | },
53 | "popup_modal_delete_bookmark_prompt_confirm_btn_title": {
54 | "message": "点击按钮确认"
55 | },
56 | "popup_modal_delete_bookmark_prompt_confirm_btn_content": {
57 | "message": "确认"
58 | },
59 | "popup_modal_delete_bookmark_prompt_cancel_btn_title": {
60 | "message": "点击按钮取消"
61 | },
62 | "popup_modal_delete_bookmark_prompt_cancel_btn_content": {
63 | "message": "取消"
64 | },
65 | "popup_modal_similar_bookmarks_list_title": {
66 | "message": "相似书签"
67 | },
68 | "popup_modal_similar_bookmarks_list_btn_title": {
69 | "message": "点击按钮编辑书签信息"
70 | },
71 | "popup_main_bookmark_url_section_name": {
72 | "message": "网址"
73 | },
74 | "popup_main_bookmark_url_section_format_warning": {
75 | "message": "请输入正确格式的链接"
76 | },
77 | "popup_main_bookmark_url_section_edit_bookmark_with_duplicated_url_btn_title": {
78 | "message": "点击按钮编辑已保存的相同网址的书签"
79 | },
80 | "popup_main_bookmark_url_section_edit_bookmark_with_duplicated_url_btn_content": {
81 | "message": "已保存相同网址的书签"
82 | },
83 | "popup_main_bookmark_url_section_one_click_mode_btn_title": {
84 | "message": "点击按钮启用一键编辑网址模式"
85 | },
86 | "popup_main_bookmark_url_section_reset_url_btn_title": {
87 | "message": "点击按钮重置网址"
88 | },
89 | "popup_main_bookmark_url_section_textarea_placeholder": {
90 | "message": "请输入书签的链接"
91 | },
92 | "popup_main_bookmark_url_section_show_url_hostname_btn_title": {
93 | "message": "悬停在按钮上以突出显示链接的主机名"
94 | },
95 | "popup_main_bookmark_url_section_delete_url_path_btn_title": {
96 | "message": "点击按钮删除链接路径到结尾的部分"
97 | },
98 | "popup_main_bookmark_url_section_delete_url_search_btn_title": {
99 | "message": "点击按钮删除链接搜索到结尾的部分"
100 | },
101 | "popup_main_bookmark_url_section_delete_url_hash_btn_title": {
102 | "message": "点击按钮删除链接哈希部分"
103 | },
104 | "popup_main_bookmark_folder_section_name": {
105 | "message": "文件夹"
106 | },
107 | "popup_main_bookmark_folder_section_set_node_tree_id_btn_old_title": {
108 | "message": "点击按钮显示文件夹所在位置"
109 | },
110 | "popup_main_bookmark_folder_section_set_node_tree_id_btn_prompt_content": {
111 | "message": "请选择文件夹 👇"
112 | },
113 | "popup_main_bookmark_folder_section_set_node_tree_id_btn_new_title": {
114 | "message": "点击按钮显示新文件夹所在位置"
115 | },
116 | "popup_main_bookmark_folder_section_toggle_search_folder_btn_title": {
117 | "message": "点击按钮切换显示或隐藏搜索文件夹面板"
118 | },
119 | "popup_main_bookmark_folder_section_reset_folder_btn_title": {
120 | "message": "点击按钮重置书签的文件夹"
121 | },
122 | "popup_main_bookmark_folder_section_toggle_bookmark_btn_title": {
123 | "message": "显示书签或只显示文件夹"
124 | },
125 | "popup_main_bookmark_folder_section_folder_path_nav_btn_title": {
126 | "message": "点击按钮显示文件夹所在位置"
127 | },
128 | "popup_main_bookmark_folder_section_folder_path_nav_root_btn_content": {
129 | "message": "根目录"
130 | },
131 | "popup_main_bookmark_folder_section_add_new_folder_btn_title": {
132 | "message": "点击按钮添加新的文件夹"
133 | },
134 | "popup_main_bookmark_folder_section_new_folder_name_input_placeholder": {
135 | "message": "请输入目录名称"
136 | },
137 | "popup_main_bookmark_folder_section_confirm_new_folder_name_btn_title": {
138 | "message": "点击按钮确认新文件夹名称"
139 | },
140 | "popup_main_bookmark_folder_section_edit_new_folder_name_btn_title": {
141 | "message": "点击按钮编辑新文件夹名称"
142 | },
143 | "popup_main_bookmark_folder_section_open_folder_btn_title": {
144 | "message": "点击按钮在原地打开文件夹"
145 | },
146 | "popup_main_bookmark_folder_section_expand_folder_btn_title": {
147 | "message": "点击按钮展开文件夹"
148 | },
149 | "popup_main_bookmark_folder_section_close_folder_btn_title": {
150 | "message": "点击按钮关闭文件夹"
151 | },
152 | "popup_main_bookmark_folder_section_select_folder_btn_title": {
153 | "message": "点击选择此文件夹"
154 | },
155 | "popup_main_bookmark_folder_section_folder_nav_btn_title": {
156 | "message": "单击以显示此文件夹"
157 | },
158 | "popup_main_bookmark_folder_section_folder_nav_left_scroll_btn_title": {
159 | "message": "点击按钮向左滚动"
160 | },
161 | "popup_main_bookmark_folder_section_folder_nav_right_scroll_btn_title": {
162 | "message": "点击按钮向右滚动"
163 | },
164 | "popup_main_bookmark_folder_section_search_folder_include_bookmark_btn_title": {
165 | "message": "点击按钮切换搜索条目包括书签或注释"
166 | },
167 | "popup_main_bookmark_folder_section_search_folder_input_placeholder": {
168 | "message": "请输入要搜索的内容"
169 | },
170 | "popup_main_bookmark_folder_section_search_folder_focus_to_input_box_btn_title": {
171 | "message": "单击聚焦输入框"
172 | },
173 | "popup_main_bookmark_folder_section_search_folder_state_waiting": {
174 | "message": "输入搜索"
175 | },
176 | "popup_main_bookmark_folder_section_search_folder_state_search": {
177 | "message": "搜索中"
178 | },
179 | "popup_main_bookmark_folder_section_search_folder_state_solved": {
180 | "message": "抱歉!未搜索到条目"
181 | },
182 | "bookmark_folder_default_name": {
183 | "message": "未命名文件夹"
184 | },
185 | "bookmark_default_name": {
186 | "message": "未命名书签"
187 | },
188 | "bookmark_favicon_img_alt": {
189 | "message": "书签图标"
190 | },
191 | "bookmark_new_folder_default_title": {
192 | "message": "新建文件夹"
193 | }
194 | }
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "manifest_version": 3,
3 | "name": "Nut Mark",
4 | "version": "1.1.0",
5 | "description": "__MSG_extension_description__",
6 | "permissions": [
7 | "bookmarks",
8 | "tabs",
9 | "favicon",
10 | "storage"
11 | ],
12 | "default_locale": "en",
13 | "background": {
14 | "service_worker": "src/background/main.js",
15 | "type": "module"
16 | },
17 | "action": {
18 | "default_title": "Nut Mark",
19 | "default_popup": "src/popup/index.html",
20 | "default_icon": {
21 | "16": "src/assets/icons/nut-unmark-16x16.png",
22 | "32": "src/assets/icons/nut-unmark-32x32.png",
23 | "48": "src/assets/icons/nut-unmark-48x48.png",
24 | "128": "src/assets/icons/nut-unmark-128x128.png"
25 | }
26 | },
27 | "icons": {
28 | "16": "src/assets/icons/nut-mark-16x16.png",
29 | "32": "src/assets/icons/nut-mark-32x32.png",
30 | "48": "src/assets/icons/nut-mark-48x48.png",
31 | "128": "src/assets/icons/nut-mark-128x128.png"
32 | }
33 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nut-mark",
3 | "private": true,
4 | "version": "1.1.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "dependencies": {
12 | "vue": "^3.2.47"
13 | },
14 | "devDependencies": {
15 | "@crxjs/vite-plugin": "^2.0.0-beta.16",
16 | "@iconify/vue": "^4.1.1",
17 | "@vitejs/plugin-vue": "^4.2.1",
18 | "autoprefixer": "^10.4.14",
19 | "eslint": "^7.32.0 || ^8.2.0",
20 | "eslint-config-airbnb-base": "^15.0.0",
21 | "eslint-plugin-import": "^2.25.2",
22 | "eslint-plugin-vue": "^9.10.0",
23 | "postcss": "^8.4.22",
24 | "sass": "^1.62.0",
25 | "tailwindcss": "^3.3.1",
26 | "vite": "^4.3.3"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/public/icons/nut-mark-128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Benbinbin/NutMark/7f8a9cf2e88b5520b59b25340eb7fe50e2751643/public/icons/nut-mark-128x128.png
--------------------------------------------------------------------------------
/public/icons/nut-mark-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Benbinbin/NutMark/7f8a9cf2e88b5520b59b25340eb7fe50e2751643/public/icons/nut-mark-16x16.png
--------------------------------------------------------------------------------
/public/icons/nut-mark-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Benbinbin/NutMark/7f8a9cf2e88b5520b59b25340eb7fe50e2751643/public/icons/nut-mark-32x32.png
--------------------------------------------------------------------------------
/public/icons/nut-mark-48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Benbinbin/NutMark/7f8a9cf2e88b5520b59b25340eb7fe50e2751643/public/icons/nut-mark-48x48.png
--------------------------------------------------------------------------------
/public/icons/nut-unmark-128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Benbinbin/NutMark/7f8a9cf2e88b5520b59b25340eb7fe50e2751643/public/icons/nut-unmark-128x128.png
--------------------------------------------------------------------------------
/public/icons/nut-unmark-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Benbinbin/NutMark/7f8a9cf2e88b5520b59b25340eb7fe50e2751643/public/icons/nut-unmark-16x16.png
--------------------------------------------------------------------------------
/public/icons/nut-unmark-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Benbinbin/NutMark/7f8a9cf2e88b5520b59b25340eb7fe50e2751643/public/icons/nut-unmark-32x32.png
--------------------------------------------------------------------------------
/public/icons/nut-unmark-48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Benbinbin/NutMark/7f8a9cf2e88b5520b59b25340eb7fe50e2751643/public/icons/nut-unmark-48x48.png
--------------------------------------------------------------------------------
/public/install-in-chrome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Benbinbin/NutMark/7f8a9cf2e88b5520b59b25340eb7fe50e2751643/public/install-in-chrome.png
--------------------------------------------------------------------------------
/public/install-in-chrome.svg:
--------------------------------------------------------------------------------
1 |
24 |
--------------------------------------------------------------------------------
/public/install-in-edge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Benbinbin/NutMark/7f8a9cf2e88b5520b59b25340eb7fe50e2751643/public/install-in-edge.png
--------------------------------------------------------------------------------
/public/install-in-edge.svg:
--------------------------------------------------------------------------------
1 |
49 |
--------------------------------------------------------------------------------
/public/install-in-github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Benbinbin/NutMark/7f8a9cf2e88b5520b59b25340eb7fe50e2751643/public/install-in-github.png
--------------------------------------------------------------------------------
/public/install-in-github.svg:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/public/nut-mark-cover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Benbinbin/NutMark/7f8a9cf2e88b5520b59b25340eb7fe50e2751643/public/nut-mark-cover.png
--------------------------------------------------------------------------------
/public/nut-mark.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/public/nut-unmark.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/public/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Benbinbin/NutMark/7f8a9cf2e88b5520b59b25340eb7fe50e2751643/public/screenshot.png
--------------------------------------------------------------------------------
/src/assets/icons/nut-mark-128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Benbinbin/NutMark/7f8a9cf2e88b5520b59b25340eb7fe50e2751643/src/assets/icons/nut-mark-128x128.png
--------------------------------------------------------------------------------
/src/assets/icons/nut-mark-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Benbinbin/NutMark/7f8a9cf2e88b5520b59b25340eb7fe50e2751643/src/assets/icons/nut-mark-16x16.png
--------------------------------------------------------------------------------
/src/assets/icons/nut-mark-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Benbinbin/NutMark/7f8a9cf2e88b5520b59b25340eb7fe50e2751643/src/assets/icons/nut-mark-32x32.png
--------------------------------------------------------------------------------
/src/assets/icons/nut-mark-48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Benbinbin/NutMark/7f8a9cf2e88b5520b59b25340eb7fe50e2751643/src/assets/icons/nut-mark-48x48.png
--------------------------------------------------------------------------------
/src/assets/icons/nut-unmark-128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Benbinbin/NutMark/7f8a9cf2e88b5520b59b25340eb7fe50e2751643/src/assets/icons/nut-unmark-128x128.png
--------------------------------------------------------------------------------
/src/assets/icons/nut-unmark-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Benbinbin/NutMark/7f8a9cf2e88b5520b59b25340eb7fe50e2751643/src/assets/icons/nut-unmark-16x16.png
--------------------------------------------------------------------------------
/src/assets/icons/nut-unmark-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Benbinbin/NutMark/7f8a9cf2e88b5520b59b25340eb7fe50e2751643/src/assets/icons/nut-unmark-32x32.png
--------------------------------------------------------------------------------
/src/assets/icons/nut-unmark-48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Benbinbin/NutMark/7f8a9cf2e88b5520b59b25340eb7fe50e2751643/src/assets/icons/nut-unmark-48x48.png
--------------------------------------------------------------------------------
/src/assets/introduction/pin-extension-cn.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Benbinbin/NutMark/7f8a9cf2e88b5520b59b25340eb7fe50e2751643/src/assets/introduction/pin-extension-cn.gif
--------------------------------------------------------------------------------
/src/assets/introduction/pin-extension.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Benbinbin/NutMark/7f8a9cf2e88b5520b59b25340eb7fe50e2751643/src/assets/introduction/pin-extension.gif
--------------------------------------------------------------------------------
/src/assets/introduction/screenshot-cn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Benbinbin/NutMark/7f8a9cf2e88b5520b59b25340eb7fe50e2751643/src/assets/introduction/screenshot-cn.png
--------------------------------------------------------------------------------
/src/assets/introduction/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Benbinbin/NutMark/7f8a9cf2e88b5520b59b25340eb7fe50e2751643/src/assets/introduction/screenshot.png
--------------------------------------------------------------------------------
/src/assets/nut-mark.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/src/assets/nut-unmark.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/src/background/main.js:
--------------------------------------------------------------------------------
1 | import { useCheckBookmarkState } from '@/composables/checkBookmarkState'
2 | import { useChangeActionIcon } from '@/composables/changeActionIcon'
3 |
4 |
5 | /**
6 | * show page after install extension
7 | */
8 | // open the introduction page when the extension is installed
9 | chrome.runtime.onInstalled.addListener(({reason}) => {
10 | if (reason === 'install') {
11 | chrome.tabs.create({
12 | url: 'https://nutmark.benbinbin.com'
13 | })
14 | }
15 | });
16 |
17 | /**
18 | * change action icon
19 | */
20 | const checkActiveWindowTabState = async () => {
21 | // get the active tab of current focus window
22 | const [tab] = await chrome.tabs.query({
23 | active: true,
24 | currentWindow: true,
25 | });
26 |
27 | if (!tab) return;
28 |
29 | const url = tab.url || tab.pendingUrl;
30 |
31 | let bookmarkState = false;
32 | if (url) {
33 | const result = await useCheckBookmarkState(url);
34 | if(result) bookmarkState = true
35 | }
36 |
37 | // change action icon
38 | await useChangeActionIcon(bookmarkState);
39 | }
40 |
41 | // watching the active tab change
42 | chrome.tabs.onActivated.addListener(async (activeInfo) => {
43 | await checkActiveWindowTabState();
44 | });
45 |
46 | // watching the window focus change
47 | chrome.windows.onFocusChanged.addListener(async (windowId) => {
48 | await checkActiveWindowTabState();
49 | });
50 |
51 | // watching tab (url) update
52 | chrome.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => {
53 | if (!changeInfo.url) return;
54 |
55 | await checkActiveWindowTabState();
56 | });
57 |
58 | // watching bookmark create
59 | chrome.bookmarks.onCreated.addListener(async (id, bookmarkNode) => {
60 | await checkActiveWindowTabState();
61 | });
62 |
63 | // watching bookmark delete
64 | chrome.bookmarks.onRemoved.addListener(async (id, bookmarkNode) => {
65 | await checkActiveWindowTabState();
66 | });
67 |
--------------------------------------------------------------------------------
/src/composables/changeActionIcon.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * change action icon
4 | */
5 | export async function useChangeActionIcon(state = false) {
6 | let iconsPath = {
7 | "16": "src/assets/icons/nut-unmark-16x16.png",
8 | "32": "src/assets/icons/nut-unmark-32x32.png",
9 | "48": "src/assets/icons/nut-unmark-48x48.png",
10 | "128": "src/assets/icons/nut-unmark-128x128.png"
11 | }
12 |
13 | if (state) {
14 | iconsPath = {
15 | "16": "src/assets/icons/nut-mark-16x16.png",
16 | "32": "src/assets/icons/nut-mark-32x32.png",
17 | "48": "src/assets/icons/nut-mark-48x48.png",
18 | "128": "src/assets/icons/nut-mark-128x128.png"
19 | }
20 | }
21 |
22 | await chrome.action.setIcon({
23 | path: iconsPath
24 | });
25 | };
--------------------------------------------------------------------------------
/src/composables/checkBookmarkState.js:
--------------------------------------------------------------------------------
1 | export async function useCheckBookmarkState(url) {
2 | const nodes = await chrome.bookmarks.search({
3 | url,
4 | });
5 | if (nodes.length === 0) {
6 | return false;
7 | }
8 | const bookmark = nodes[0];
9 | return bookmark;
10 | };
--------------------------------------------------------------------------------
/src/composables/getFaviconURL.js:
--------------------------------------------------------------------------------
1 | // refer to https://developer.chrome.com/docs/extensions/mv3/favicon/
2 | export function useGetFaviconURL(link) {
3 | const url = new URL(chrome.runtime.getURL('/_favicon/'));
4 | url.searchParams.set("pageUrl", link);
5 | url.searchParams.set("size", "32");
6 | return url.toString();
7 | }
8 |
--------------------------------------------------------------------------------
/src/composables/getTabInfo.js:
--------------------------------------------------------------------------------
1 | export async function useGetTabInfo() {
2 | // get current tab
3 | const [tab] = await chrome.tabs.query({
4 | active: true,
5 | currentWindow: true,
6 | });
7 |
8 | return {
9 | tabTitle: tab.title,
10 | tabUrl: tab.url || tab.pendingUrl
11 | }
12 | }
--------------------------------------------------------------------------------
/src/composables/getTranslation.js:
--------------------------------------------------------------------------------
1 | /**
2 | * i18n
3 | */
4 | export function useGetTranslation(title) {
5 | return chrome.i18n.getMessage(title)
6 | }
--------------------------------------------------------------------------------
/src/composables/getTreeId.js:
--------------------------------------------------------------------------------
1 | /**
2 | * get the folder id for the node tree based on a given folder id
3 | */
4 | export async function useGetTreeId(folderId) {
5 | const resultForFolderNode = await chrome.bookmarks.get(folderId);
6 | const folderNode = resultForFolderNode[0];
7 |
8 | let targetId;
9 | if (folderNode.parentId) {
10 | // if the folder node has parent folder
11 | targetId = folderNode.parentId;
12 | } else {
13 | // if the folder node doesn't have parent folder
14 | // (when the folder is the root folder)
15 | // then set the node tree id as this folder
16 | targetId = folderNode.id;
17 | }
18 | return targetId;
19 | }
--------------------------------------------------------------------------------
/src/popup/App.vue:
--------------------------------------------------------------------------------
1 |
253 |
254 |
255 |
303 |
119 |
175 | {{ useGetTranslation('popup_modal_delete_bookmark_prompt_title') }}
340 | {{ useGetTranslation('popup_modal_similar_bookmarks_list_title') }}
354 |
356 |
370 |
246 |
247 |
248 | {{ `${urlObj.protocol}//` }}
249 | {{ `${urlObj.username}:${urlObj.password}@` }}
250 | {{ urlObj.hostname }}
251 | {{ `:${urlObj.port}` }}
252 |
253 |
254 |
255 | {{ urlObj.pathname }}
256 |
257 |
258 | {{ urlObj.search }}
259 |
260 |
261 | {{ `${urlObj.hash}` }}
262 |
263 |
120 |
319 |
157 |
187 |