mirror of
https://github.com/FranP-code/ChatGPT.git
synced 2025-10-13 00:13:25 +00:00
chore: export
This commit is contained in:
@@ -68,8 +68,7 @@ pub fn init() -> Menu {
|
|||||||
titlebar
|
titlebar
|
||||||
};
|
};
|
||||||
|
|
||||||
let system_tray =
|
let system_tray = CustomMenuItem::new("system_tray".to_string(), "System Tray");
|
||||||
CustomMenuItem::new("system_tray".to_string(), "System Tray");
|
|
||||||
let system_tray_menu = if chat_conf.tray {
|
let system_tray_menu = if chat_conf.tray {
|
||||||
system_tray.selected()
|
system_tray.selected()
|
||||||
} else {
|
} else {
|
||||||
@@ -291,11 +290,7 @@ pub fn menu_handler(event: WindowMenuEvent<tauri::Wry>) {
|
|||||||
}
|
}
|
||||||
"system_tray" => {
|
"system_tray" => {
|
||||||
let chat_conf = conf::ChatConfJson::get_chat_conf();
|
let chat_conf = conf::ChatConfJson::get_chat_conf();
|
||||||
ChatConfJson::amend(
|
ChatConfJson::amend(&serde_json::json!({ "tray": !chat_conf.tray }), None).unwrap();
|
||||||
&serde_json::json!({ "tray": !chat_conf.tray }),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
tauri::api::process::restart(&app.env());
|
tauri::api::process::restart(&app.env());
|
||||||
}
|
}
|
||||||
"theme_light" | "theme_dark" | "theme_system" => {
|
"theme_light" | "theme_dark" | "theme_system" => {
|
||||||
|
|||||||
@@ -66,6 +66,8 @@ pub fn init(app: &mut App) -> std::result::Result<(), Box<dyn std::error::Error>
|
|||||||
.initialization_script(include_str!("../vendors/floating-ui-dom.js"))
|
.initialization_script(include_str!("../vendors/floating-ui-dom.js"))
|
||||||
.initialization_script(include_str!("../vendors/html2canvas.js"))
|
.initialization_script(include_str!("../vendors/html2canvas.js"))
|
||||||
.initialization_script(include_str!("../vendors/jspdf.js"))
|
.initialization_script(include_str!("../vendors/jspdf.js"))
|
||||||
|
.initialization_script(include_str!("../vendors/turndown.js"))
|
||||||
|
.initialization_script(include_str!("../vendors/turndown-plugin-gfm.js"))
|
||||||
.initialization_script(include_str!("../scripts/core.js"))
|
.initialization_script(include_str!("../scripts/core.js"))
|
||||||
.initialization_script(include_str!("../scripts/popup.core.js"))
|
.initialization_script(include_str!("../scripts/popup.core.js"))
|
||||||
.initialization_script(include_str!("../scripts/export.js"))
|
.initialization_script(include_str!("../scripts/export.js"))
|
||||||
@@ -89,6 +91,8 @@ pub fn init(app: &mut App) -> std::result::Result<(), Box<dyn std::error::Error>
|
|||||||
.initialization_script(include_str!("../vendors/floating-ui-dom.js"))
|
.initialization_script(include_str!("../vendors/floating-ui-dom.js"))
|
||||||
.initialization_script(include_str!("../vendors/html2canvas.js"))
|
.initialization_script(include_str!("../vendors/html2canvas.js"))
|
||||||
.initialization_script(include_str!("../vendors/jspdf.js"))
|
.initialization_script(include_str!("../vendors/jspdf.js"))
|
||||||
|
.initialization_script(include_str!("../vendors/turndown.js"))
|
||||||
|
.initialization_script(include_str!("../vendors/turndown-plugin-gfm.js"))
|
||||||
.initialization_script(include_str!("../scripts/core.js"))
|
.initialization_script(include_str!("../scripts/core.js"))
|
||||||
.initialization_script(include_str!("../scripts/popup.core.js"))
|
.initialization_script(include_str!("../scripts/popup.core.js"))
|
||||||
.initialization_script(include_str!("../scripts/export.js"))
|
.initialization_script(include_str!("../scripts/export.js"))
|
||||||
|
|||||||
@@ -30,7 +30,9 @@ async fn main() {
|
|||||||
trace: Color::Cyan,
|
trace: Color::Cyan,
|
||||||
};
|
};
|
||||||
|
|
||||||
tauri::Builder::default()
|
let chat_conf = ChatConfJson::get_chat_conf();
|
||||||
|
|
||||||
|
let mut builder = tauri::Builder::default()
|
||||||
// https://github.com/tauri-apps/tauri/pull/2736
|
// https://github.com/tauri-apps/tauri/pull/2736
|
||||||
.plugin(
|
.plugin(
|
||||||
LoggerBuilder::new()
|
LoggerBuilder::new()
|
||||||
@@ -73,8 +75,13 @@ async fn main() {
|
|||||||
fs_extra::metadata,
|
fs_extra::metadata,
|
||||||
])
|
])
|
||||||
.setup(setup::init)
|
.setup(setup::init)
|
||||||
.menu(menu::init())
|
.menu(menu::init());
|
||||||
.system_tray(menu::tray_menu())
|
|
||||||
|
if chat_conf.tray {
|
||||||
|
builder = builder.system_tray(menu::tray_menu());
|
||||||
|
}
|
||||||
|
|
||||||
|
builder
|
||||||
.on_menu_event(menu::menu_handler)
|
.on_menu_event(menu::menu_handler)
|
||||||
.on_system_tray_event(menu::tray_handler)
|
.on_system_tray_event(menu::tray_handler)
|
||||||
.on_window_event(|event| {
|
.on_window_event(|event| {
|
||||||
|
|||||||
6
src-tauri/src/scripts/cmd.js
vendored
6
src-tauri/src/scripts/cmd.js
vendored
@@ -71,9 +71,9 @@ $(function() {
|
|||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
}
|
}
|
||||||
.chatappico.pdf {
|
.chatappico.pdf, .chatappico.md {
|
||||||
width: 24px;
|
width: 22px;
|
||||||
height: 24px;
|
height: 22px;
|
||||||
}
|
}
|
||||||
@media screen and (max-width: 767px) {
|
@media screen and (max-width: 767px) {
|
||||||
#download-png-button, #download-pdf-button, #download-html-button {
|
#download-png-button, #download-pdf-button, #download-html-button {
|
||||||
|
|||||||
39
src-tauri/src/scripts/export.js
vendored
39
src-tauri/src/scripts/export.js
vendored
@@ -117,6 +117,18 @@ function addActionsButtons(actionsArea, TryAgainButton) {
|
|||||||
// sendRequest();
|
// sendRequest();
|
||||||
// };
|
// };
|
||||||
// actionsArea.appendChild(exportHtml);
|
// actionsArea.appendChild(exportHtml);
|
||||||
|
const exportMd = TryAgainButton.cloneNode(true);
|
||||||
|
exportMd.id = "download-markdown-button";
|
||||||
|
downloadButton.setAttribute("share-ext", "true");
|
||||||
|
// exportHtml.innerText = "Share Link";
|
||||||
|
exportMd.title = "Download Markdown";
|
||||||
|
exportMd.innerHTML = setIcon('md');
|
||||||
|
exportMd.onclick = () => {
|
||||||
|
const md = ExportMD.turndown(document.querySelector("main div>div>div").innerHTML);
|
||||||
|
console.log('«128» /src/scripts/export.js ~> ', md);
|
||||||
|
|
||||||
|
};
|
||||||
|
actionsArea.appendChild(exportMd);
|
||||||
}
|
}
|
||||||
|
|
||||||
function downloadThread({ as = Format.PNG } = {}) {
|
function downloadThread({ as = Format.PNG } = {}) {
|
||||||
@@ -273,6 +285,31 @@ function setIcon(type) {
|
|||||||
return {
|
return {
|
||||||
// link: `<svg class="chatappico" viewBox="0 0 1024 1024"><path d="M1007.382 379.672L655.374 75.702C624.562 49.092 576 70.694 576 112.03v160.106C254.742 275.814 0 340.2 0 644.652c0 122.882 79.162 244.618 166.666 308.264 27.306 19.862 66.222-5.066 56.154-37.262C132.132 625.628 265.834 548.632 576 544.17V720c0 41.4 48.6 62.906 79.374 36.328l352.008-304c22.142-19.124 22.172-53.506 0-72.656z" p-id="8506" fill="currentColor"></path></svg>`,
|
// link: `<svg class="chatappico" viewBox="0 0 1024 1024"><path d="M1007.382 379.672L655.374 75.702C624.562 49.092 576 70.694 576 112.03v160.106C254.742 275.814 0 340.2 0 644.652c0 122.882 79.162 244.618 166.666 308.264 27.306 19.862 66.222-5.066 56.154-37.262C132.132 625.628 265.834 548.632 576 544.17V720c0 41.4 48.6 62.906 79.374 36.328l352.008-304c22.142-19.124 22.172-53.506 0-72.656z" p-id="8506" fill="currentColor"></path></svg>`,
|
||||||
png: `<svg class="chatappico" viewBox="0 0 1070 1024"><path d="M981.783273 0H85.224727C38.353455 0 0 35.374545 0 83.083636v844.893091c0 47.616 38.353455 86.574545 85.178182 86.574546h903.633454c46.917818 0 81.733818-38.958545 81.733819-86.574546V83.083636C1070.592 35.374545 1028.701091 0 981.783273 0zM335.825455 135.912727c74.193455 0 134.330182 60.974545 134.330181 136.285091 0 75.170909-60.136727 136.192-134.330181 136.192-74.286545 0-134.516364-61.021091-134.516364-136.192 0-75.264 60.229818-136.285091 134.516364-136.285091z m-161.512728 745.937455a41.890909 41.890909 0 0 1-27.648-10.379637 43.752727 43.752727 0 0 1-4.654545-61.067636l198.097454-255.162182a42.123636 42.123636 0 0 1 57.716364-6.702545l116.549818 128.139636 286.906182-352.814545c14.615273-18.711273 90.251636-106.775273 135.866182-6.935273 0.093091-0.093091 0.093091 112.965818 0.232727 247.761455 0.093091 140.8 0.093091 317.067636 0.093091 317.067636-1.024-0.093091-762.740364 0.093091-763.112727 0.093091z" fill="currentColor"></path></svg>`,
|
png: `<svg class="chatappico" viewBox="0 0 1070 1024"><path d="M981.783273 0H85.224727C38.353455 0 0 35.374545 0 83.083636v844.893091c0 47.616 38.353455 86.574545 85.178182 86.574546h903.633454c46.917818 0 81.733818-38.958545 81.733819-86.574546V83.083636C1070.592 35.374545 1028.701091 0 981.783273 0zM335.825455 135.912727c74.193455 0 134.330182 60.974545 134.330181 136.285091 0 75.170909-60.136727 136.192-134.330181 136.192-74.286545 0-134.516364-61.021091-134.516364-136.192 0-75.264 60.229818-136.285091 134.516364-136.285091z m-161.512728 745.937455a41.890909 41.890909 0 0 1-27.648-10.379637 43.752727 43.752727 0 0 1-4.654545-61.067636l198.097454-255.162182a42.123636 42.123636 0 0 1 57.716364-6.702545l116.549818 128.139636 286.906182-352.814545c14.615273-18.711273 90.251636-106.775273 135.866182-6.935273 0.093091-0.093091 0.093091 112.965818 0.232727 247.761455 0.093091 140.8 0.093091 317.067636 0.093091 317.067636-1.024-0.093091-762.740364 0.093091-763.112727 0.093091z" fill="currentColor"></path></svg>`,
|
||||||
pdf: `<svg class="chatappico pdf" viewBox="0 0 1024 1024"><path d="M821.457602 118.382249H205.725895c-48.378584 0-87.959995 39.583368-87.959996 87.963909v615.731707c0 48.378584 39.581411 87.959995 87.959996 87.959996h615.733664c48.380541 0 87.961952-39.581411 87.961952-87.959996V206.346158c-0.001957-48.378584-39.583368-87.963909-87.963909-87.963909zM493.962468 457.544987c-10.112054 32.545237-21.72487 82.872662-38.806571 124.248336-8.806957 22.378397-8.380404 18.480717-15.001764 32.609808l5.71738-1.851007c58.760658-16.443827 99.901532-20.519564 138.162194-27.561607-7.67796-6.06371-14.350194-10.751884-19.631237-15.586807-26.287817-29.101504-35.464584-34.570387-70.440002-111.862636v0.003913z m288.36767 186.413594c-7.476424 8.356924-20.670227 13.191847-40.019704 13.191847-33.427694 0-63.808858-9.229597-107.79277-31.660824-75.648648 8.356924-156.097 17.214754-201.399704 31.729308-2.199293 0.876587-4.832967 1.759043-7.916674 3.077836-54.536215 93.237125-95.031389 132.767663-130.621199 131.19646-11.286054-0.49895-27.694661-7.044-32.973748-10.11988l-6.52157-6.196764-2.29517-4.353583c-3.07588-7.91863-3.954423-15.395054-2.197337-23.751977 4.838837-23.309771 29.907651-60.251638 82.686779-93.237126 8.356924-6.159587 27.430511-15.897917 45.020944-24.25484 13.311204-21.177004 19.45905-34.744531 36.341171-72.259702 19.102937-45.324228 36.505531-99.492589 47.500041-138.191543v-0.44025c-16.267727-53.219378-25.945401-89.310095-9.67376-147.80856 3.958337-16.71189 18.46702-33.864031 34.748444-33.864031h10.552304c10.115967 0 19.791684 3.520043 26.829814 10.552304 29.029107 29.031064 15.39114 103.824649 0.8805 162.323113-0.8805 2.63563-1.322707 4.832967-1.761 6.153717 17.59239 49.697378 45.400538 98.774492 73.108895 121.647926 11.436717 8.791304 22.638634 18.899444 36.71098 26.814161 19.791684-2.20125 37.517128-4.11487 55.547812-4.11487 54.540128 0 87.525615 9.67963 100.279169 30.351814 4.400543 7.034217 6.595923 15.389184 5.281043 24.1844-0.44025 10.996467-4.39663 21.112434-12.31526 29.031064z m-27.796407-36.748157c-4.394673-4.398587-17.024957-16.936907-78.601259-16.936907-3.073923 0-10.622744-0.784623-14.57521 3.612007 32.104987 14.072347 62.830525 24.757704 83.058545 24.757703 3.083707 0 5.72325-0.442207 8.356923-0.876586h1.759044c2.20125-0.8805 3.520043-1.324663 3.960293-5.71738-0.87463-1.324663-1.757087-3.083707-3.958336-4.838837z m-387.124553 63.041845c-9.237424 5.27713-16.71189 10.112054-21.112433 13.634053-31.226444 28.586901-51.018128 57.616008-53.217422 74.331812 19.789727-6.59788 45.737084-35.626987 74.329855-87.961952v-0.003913z m125.574957-297.822284l2.197336-1.761c3.079793-14.072347 5.232127-29.189554 7.87167-38.869184l1.318794-7.036174c4.39663-25.070771 2.71781-39.720334-4.76057-50.272637l-6.59788-2.20125a57.381208 57.381208 0 0 0-3.079794 5.27713c-7.474467 18.47289-7.063567 55.283661 3.0524 94.865072l-0.001956-0.001957z" fill="currentColor"></path></svg>`
|
pdf: `<svg class="chatappico pdf" viewBox="0 0 1024 1024"><path d="M821.457602 118.382249H205.725895c-48.378584 0-87.959995 39.583368-87.959996 87.963909v615.731707c0 48.378584 39.581411 87.959995 87.959996 87.959996h615.733664c48.380541 0 87.961952-39.581411 87.961952-87.959996V206.346158c-0.001957-48.378584-39.583368-87.963909-87.963909-87.963909zM493.962468 457.544987c-10.112054 32.545237-21.72487 82.872662-38.806571 124.248336-8.806957 22.378397-8.380404 18.480717-15.001764 32.609808l5.71738-1.851007c58.760658-16.443827 99.901532-20.519564 138.162194-27.561607-7.67796-6.06371-14.350194-10.751884-19.631237-15.586807-26.287817-29.101504-35.464584-34.570387-70.440002-111.862636v0.003913z m288.36767 186.413594c-7.476424 8.356924-20.670227 13.191847-40.019704 13.191847-33.427694 0-63.808858-9.229597-107.79277-31.660824-75.648648 8.356924-156.097 17.214754-201.399704 31.729308-2.199293 0.876587-4.832967 1.759043-7.916674 3.077836-54.536215 93.237125-95.031389 132.767663-130.621199 131.19646-11.286054-0.49895-27.694661-7.044-32.973748-10.11988l-6.52157-6.196764-2.29517-4.353583c-3.07588-7.91863-3.954423-15.395054-2.197337-23.751977 4.838837-23.309771 29.907651-60.251638 82.686779-93.237126 8.356924-6.159587 27.430511-15.897917 45.020944-24.25484 13.311204-21.177004 19.45905-34.744531 36.341171-72.259702 19.102937-45.324228 36.505531-99.492589 47.500041-138.191543v-0.44025c-16.267727-53.219378-25.945401-89.310095-9.67376-147.80856 3.958337-16.71189 18.46702-33.864031 34.748444-33.864031h10.552304c10.115967 0 19.791684 3.520043 26.829814 10.552304 29.029107 29.031064 15.39114 103.824649 0.8805 162.323113-0.8805 2.63563-1.322707 4.832967-1.761 6.153717 17.59239 49.697378 45.400538 98.774492 73.108895 121.647926 11.436717 8.791304 22.638634 18.899444 36.71098 26.814161 19.791684-2.20125 37.517128-4.11487 55.547812-4.11487 54.540128 0 87.525615 9.67963 100.279169 30.351814 4.400543 7.034217 6.595923 15.389184 5.281043 24.1844-0.44025 10.996467-4.39663 21.112434-12.31526 29.031064z m-27.796407-36.748157c-4.394673-4.398587-17.024957-16.936907-78.601259-16.936907-3.073923 0-10.622744-0.784623-14.57521 3.612007 32.104987 14.072347 62.830525 24.757704 83.058545 24.757703 3.083707 0 5.72325-0.442207 8.356923-0.876586h1.759044c2.20125-0.8805 3.520043-1.324663 3.960293-5.71738-0.87463-1.324663-1.757087-3.083707-3.958336-4.838837z m-387.124553 63.041845c-9.237424 5.27713-16.71189 10.112054-21.112433 13.634053-31.226444 28.586901-51.018128 57.616008-53.217422 74.331812 19.789727-6.59788 45.737084-35.626987 74.329855-87.961952v-0.003913z m125.574957-297.822284l2.197336-1.761c3.079793-14.072347 5.232127-29.189554 7.87167-38.869184l1.318794-7.036174c4.39663-25.070771 2.71781-39.720334-4.76057-50.272637l-6.59788-2.20125a57.381208 57.381208 0 0 0-3.079794 5.27713c-7.474467 18.47289-7.063567 55.283661 3.0524 94.865072l-0.001956-0.001957z" fill="currentColor"></path></svg>`,
|
||||||
|
md: `<svg class="chatappico md" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1380" width="200" height="200"><path d="M128 128h768a42.666667 42.666667 0 0 1 42.666667 42.666667v682.666666a42.666667 42.666667 0 0 1-42.666667 42.666667H128a42.666667 42.666667 0 0 1-42.666667-42.666667V170.666667a42.666667 42.666667 0 0 1 42.666667-42.666667z m170.666667 533.333333v-170.666666l85.333333 85.333333 85.333333-85.333333v170.666666h85.333334v-298.666666h-85.333334l-85.333333 85.333333-85.333333-85.333333H213.333333v298.666666h85.333334z m469.333333-128v-170.666666h-85.333333v170.666666h-85.333334l128 128 128-128h-85.333333z" p-id="1381" fill="currentColor"></path></svg>`
|
||||||
}[type];
|
}[type];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function downloadMD() {
|
||||||
|
console.log("markdown");
|
||||||
|
const chatThread = document.querySelector('main div>div>div');
|
||||||
|
const chatBlocks = $(chatThread, '>div');
|
||||||
|
|
||||||
|
console.log('«296» /src/scripts/export.js ~> ', chatThread, chatThread.innerHTML);
|
||||||
|
|
||||||
|
|
||||||
|
const content = new TurndownService()
|
||||||
|
.use(turndownPluginGfm.gfm)
|
||||||
|
.addRule({
|
||||||
|
filter: function (node, options) {
|
||||||
|
return node.nodeName === 'code' && node.classList.includes('hljs')
|
||||||
|
},
|
||||||
|
replacement: function (content) {
|
||||||
|
return '```\n' + content + '\n```'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.turndown(chatThread.innerHTML);
|
||||||
|
|
||||||
|
console.log('«8» /src/scripts/markdown.export.js ~> ', content);
|
||||||
|
}
|
||||||
43
src-tauri/src/scripts/markdown.export.js
vendored
43
src-tauri/src/scripts/markdown.export.js
vendored
@@ -1,9 +1,36 @@
|
|||||||
// *** Core Script - Markdown ***
|
var ExportMD = (function () {
|
||||||
|
if (!TurndownService || !turndownPluginGfm) return;
|
||||||
|
const hljsREG = /^.*(hljs).*(language-[a-z0-9]+).*$/i;
|
||||||
|
const gfm = turndownPluginGfm.gfm
|
||||||
|
const turndownService = new TurndownService()
|
||||||
|
.use(gfm)
|
||||||
|
.addRule('code', {
|
||||||
|
filter: (node) => {
|
||||||
|
if (node.nodeName === 'CODE' && hljsREG.test(node.classList.value)) {
|
||||||
|
return 'code';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
replacement: (content, node) => {
|
||||||
|
const classStr = node.getAttribute('class');
|
||||||
|
if (hljsREG.test(classStr)) {
|
||||||
|
const lang = classStr.match(/.*language-(\w+)/)[1];
|
||||||
|
if (lang) {
|
||||||
|
return `\`\`\`${lang}\n${content}\n\`\`\``;
|
||||||
|
}
|
||||||
|
return `\`\`\`\n${content}\n\`\`\``;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.addRule('ignore', {
|
||||||
|
filter: ['button', 'img'],
|
||||||
|
replacement: () => '',
|
||||||
|
})
|
||||||
|
.addRule('table', {
|
||||||
|
filter: 'table',
|
||||||
|
replacement: function(content, node) {
|
||||||
|
return `\`\`\`${content}\n\`\`\``;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
(function () {
|
return turndownService;
|
||||||
console.log("markdown");
|
}({}));
|
||||||
const chatThread = $('main .items-center');
|
|
||||||
const chatBlocks = $(chatThread, '>div');
|
|
||||||
|
|
||||||
console.log('«8» /src/scripts/markdown.export.js ~> ', chatBlocks);
|
|
||||||
})(window);
|
|
||||||
|
|||||||
164
src-tauri/src/vendors/turndown-plugin-gfm.js
vendored
Normal file
164
src-tauri/src/vendors/turndown-plugin-gfm.js
vendored
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
var turndownPluginGfm = (function (exports) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var highlightRegExp = /highlight-(?:text|source)-([a-z0-9]+)/;
|
||||||
|
|
||||||
|
function highlightedCodeBlock (turndownService) {
|
||||||
|
turndownService.addRule('highlightedCodeBlock', {
|
||||||
|
filter: function (node) {
|
||||||
|
var firstChild = node.firstChild;
|
||||||
|
return (
|
||||||
|
node.nodeName === 'DIV' &&
|
||||||
|
highlightRegExp.test(node.className) &&
|
||||||
|
firstChild &&
|
||||||
|
firstChild.nodeName === 'PRE'
|
||||||
|
)
|
||||||
|
},
|
||||||
|
replacement: function (content, node, options) {
|
||||||
|
var className = node.className || '';
|
||||||
|
var language = (className.match(highlightRegExp) || [null, ''])[1];
|
||||||
|
|
||||||
|
return (
|
||||||
|
'\n\n' + options.fence + language + '\n' +
|
||||||
|
node.firstChild.textContent +
|
||||||
|
'\n' + options.fence + '\n\n'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function strikethrough (turndownService) {
|
||||||
|
turndownService.addRule('strikethrough', {
|
||||||
|
filter: ['del', 's', 'strike'],
|
||||||
|
replacement: function (content) {
|
||||||
|
return '~' + content + '~'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var indexOf = Array.prototype.indexOf;
|
||||||
|
var every = Array.prototype.every;
|
||||||
|
var rules = {};
|
||||||
|
|
||||||
|
rules.tableCell = {
|
||||||
|
filter: ['th', 'td'],
|
||||||
|
replacement: function (content, node) {
|
||||||
|
return cell(content, node)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
rules.tableRow = {
|
||||||
|
filter: 'tr',
|
||||||
|
replacement: function (content, node) {
|
||||||
|
var borderCells = '';
|
||||||
|
var alignMap = { left: ':--', right: '--:', center: ':-:' };
|
||||||
|
|
||||||
|
if (isHeadingRow(node)) {
|
||||||
|
for (var i = 0; i < node.childNodes.length; i++) {
|
||||||
|
var border = '---';
|
||||||
|
var align = (
|
||||||
|
node.childNodes[i].getAttribute('align') || ''
|
||||||
|
).toLowerCase();
|
||||||
|
|
||||||
|
if (align) border = alignMap[align] || border;
|
||||||
|
|
||||||
|
borderCells += cell(border, node.childNodes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '\n' + content + (borderCells ? '\n' + borderCells : '')
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
rules.table = {
|
||||||
|
// Only convert tables with a heading row.
|
||||||
|
// Tables with no heading row are kept using `keep` (see below).
|
||||||
|
filter: function (node) {
|
||||||
|
return node.nodeName === 'TABLE' && isHeadingRow(node.rows[0])
|
||||||
|
},
|
||||||
|
|
||||||
|
replacement: function (content) {
|
||||||
|
// Ensure there are no blank lines
|
||||||
|
content = content.replace('\n\n', '\n');
|
||||||
|
return '\n\n' + content + '\n\n'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
rules.tableSection = {
|
||||||
|
filter: ['thead', 'tbody', 'tfoot'],
|
||||||
|
replacement: function (content) {
|
||||||
|
return content
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// A tr is a heading row if:
|
||||||
|
// - the parent is a THEAD
|
||||||
|
// - or if its the first child of the TABLE or the first TBODY (possibly
|
||||||
|
// following a blank THEAD)
|
||||||
|
// - and every cell is a TH
|
||||||
|
function isHeadingRow (tr) {
|
||||||
|
var parentNode = tr.parentNode;
|
||||||
|
return (
|
||||||
|
parentNode.nodeName === 'THEAD' ||
|
||||||
|
(
|
||||||
|
parentNode.firstChild === tr &&
|
||||||
|
(parentNode.nodeName === 'TABLE' || isFirstTbody(parentNode)) &&
|
||||||
|
every.call(tr.childNodes, function (n) { return n.nodeName === 'TH' })
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function isFirstTbody (element) {
|
||||||
|
var previousSibling = element.previousSibling;
|
||||||
|
return (
|
||||||
|
element.nodeName === 'TBODY' && (
|
||||||
|
!previousSibling ||
|
||||||
|
(
|
||||||
|
previousSibling.nodeName === 'THEAD' &&
|
||||||
|
/^\s*$/i.test(previousSibling.textContent)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function cell (content, node) {
|
||||||
|
var index = indexOf.call(node.parentNode.childNodes, node);
|
||||||
|
var prefix = ' ';
|
||||||
|
if (index === 0) prefix = '| ';
|
||||||
|
return prefix + content + ' |'
|
||||||
|
}
|
||||||
|
|
||||||
|
function tables (turndownService) {
|
||||||
|
turndownService.keep(function (node) {
|
||||||
|
return node.nodeName === 'TABLE' && !isHeadingRow(node.rows[0])
|
||||||
|
});
|
||||||
|
for (var key in rules) turndownService.addRule(key, rules[key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function taskListItems (turndownService) {
|
||||||
|
turndownService.addRule('taskListItems', {
|
||||||
|
filter: function (node) {
|
||||||
|
return node.type === 'checkbox' && node.parentNode.nodeName === 'LI'
|
||||||
|
},
|
||||||
|
replacement: function (content, node) {
|
||||||
|
return (node.checked ? '[x]' : '[ ]') + ' '
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function gfm (turndownService) {
|
||||||
|
turndownService.use([
|
||||||
|
highlightedCodeBlock,
|
||||||
|
strikethrough,
|
||||||
|
tables,
|
||||||
|
taskListItems
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.gfm = gfm;
|
||||||
|
exports.highlightedCodeBlock = highlightedCodeBlock;
|
||||||
|
exports.strikethrough = strikethrough;
|
||||||
|
exports.tables = tables;
|
||||||
|
exports.taskListItems = taskListItems;
|
||||||
|
|
||||||
|
return exports;
|
||||||
|
}({}));
|
||||||
99
src/layout/index.tsx
vendored
99
src/layout/index.tsx
vendored
@@ -1,5 +1,5 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import {Layout, Menu, Tooltip, ConfigProvider, theme, Tag } from 'antd';
|
import { Layout, Menu, Tooltip, ConfigProvider, theme, Tag } from 'antd';
|
||||||
import { SyncOutlined } from '@ant-design/icons';
|
import { SyncOutlined } from '@ant-design/icons';
|
||||||
import { useNavigate, useLocation } from 'react-router-dom';
|
import { useNavigate, useLocation } from 'react-router-dom';
|
||||||
import { getName, getVersion } from '@tauri-apps/api/app';
|
import { getName, getVersion } from '@tauri-apps/api/app';
|
||||||
@@ -29,58 +29,61 @@ export default function ChatLayout() {
|
|||||||
await invoke('run_check_update', { silent: false, hasMsg: true });
|
await invoke('run_check_update', { silent: false, hasMsg: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
const isDark = appInfo.appTheme === "dark";
|
||||||
<ConfigProvider theme={{algorithm: appInfo.appTheme === "dark" ? theme.darkAlgorithm : theme.defaultAlgorithm}}>
|
|
||||||
<Layout style={{ minHeight: '100vh' }} hasSider>
|
|
||||||
<Sider
|
|
||||||
theme={appInfo.appTheme === "dark" ? "dark" : "light"}
|
|
||||||
collapsible
|
|
||||||
collapsed={collapsed}
|
|
||||||
onCollapse={(value) => setCollapsed(value)}
|
|
||||||
style={{
|
|
||||||
overflow: 'auto',
|
|
||||||
height: '100vh',
|
|
||||||
position: 'fixed',
|
|
||||||
left: 0,
|
|
||||||
top: 0,
|
|
||||||
bottom: 0,
|
|
||||||
zIndex: 999,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="chat-logo"><img src="/logo.png" /></div>
|
|
||||||
<div className="chat-info">
|
|
||||||
<Tag>{appInfo.appName}</Tag>
|
|
||||||
<Tag>
|
|
||||||
<span style={{ marginRight: 5 }}>{appInfo.appVersion}</span>
|
|
||||||
<Tooltip title="click to check update">
|
|
||||||
<a onClick={checkAppUpdate}><SyncOutlined /></a>
|
|
||||||
</Tooltip>
|
|
||||||
</Tag>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Menu
|
return (
|
||||||
defaultSelectedKeys={[location.pathname]}
|
<ConfigProvider theme={{ algorithm: isDark ? theme.darkAlgorithm : theme.defaultAlgorithm }}>
|
||||||
mode="inline"
|
<Layout style={{ minHeight: '100vh' }} hasSider>
|
||||||
theme={ appInfo.appTheme === "dark" ? "dark" : "light" }
|
<Sider
|
||||||
inlineIndent={12}
|
theme={isDark ? "dark" : "light"}
|
||||||
items={menuItems}
|
collapsible
|
||||||
defaultOpenKeys={['/model']}
|
collapsed={collapsed}
|
||||||
onClick={(i) => go(i.key)}
|
onCollapse={(value) => setCollapsed(value)}
|
||||||
/>
|
|
||||||
</Sider>
|
|
||||||
<Layout className="chat-layout" style={{ marginLeft: collapsed ? 80 : 200, transition: 'margin-left 300ms ease-out' }}>
|
|
||||||
<Content
|
|
||||||
className="chat-container"
|
|
||||||
style={{
|
style={{
|
||||||
overflow: 'inherit'
|
overflow: 'auto',
|
||||||
|
height: '100vh',
|
||||||
|
position: 'fixed',
|
||||||
|
left: 0,
|
||||||
|
top: 0,
|
||||||
|
bottom: 0,
|
||||||
|
zIndex: 999,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Routes />
|
<div className="chat-logo"><img src="/logo.png" /></div>
|
||||||
</Content>
|
<div className="chat-info">
|
||||||
<Footer style={{ textAlign: 'center' }}>
|
<Tag>{appInfo.appName}</Tag>
|
||||||
<a href="https://github.com/lencx/chatgpt" target="_blank">ChatGPT Desktop Application</a> ©2022 Created by lencx</Footer>
|
<Tag>
|
||||||
|
<span style={{ marginRight: 5 }}>{appInfo.appVersion}</span>
|
||||||
|
<Tooltip title="click to check update">
|
||||||
|
<a onClick={checkAppUpdate}><SyncOutlined /></a>
|
||||||
|
</Tooltip>
|
||||||
|
</Tag>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Menu
|
||||||
|
defaultSelectedKeys={[location.pathname]}
|
||||||
|
mode="inline"
|
||||||
|
theme={ appInfo.appTheme === "dark" ? "dark" : "light" }
|
||||||
|
inlineIndent={12}
|
||||||
|
items={menuItems}
|
||||||
|
defaultOpenKeys={['/model']}
|
||||||
|
onClick={(i) => go(i.key)}
|
||||||
|
/>
|
||||||
|
</Sider>
|
||||||
|
<Layout className="chat-layout" style={{ marginLeft: collapsed ? 80 : 200, transition: 'margin-left 300ms ease-out' }}>
|
||||||
|
<Content
|
||||||
|
className="chat-container"
|
||||||
|
style={{
|
||||||
|
overflow: 'inherit'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Routes />
|
||||||
|
</Content>
|
||||||
|
<Footer style={{ textAlign: 'center' }}>
|
||||||
|
<a href="https://github.com/lencx/chatgpt" target="_blank">ChatGPT Desktop Application</a> ©2022 Created by lencx
|
||||||
|
</Footer>
|
||||||
|
</Layout>
|
||||||
</Layout>
|
</Layout>
|
||||||
</Layout>
|
|
||||||
</ConfigProvider>
|
</ConfigProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
1
src/main.scss
vendored
1
src/main.scss
vendored
@@ -51,6 +51,7 @@ html, body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chat-file-path,
|
||||||
.chat-sync-path {
|
.chat-sync-path {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
|||||||
13
src/routes.tsx
vendored
13
src/routes.tsx
vendored
@@ -5,6 +5,7 @@ import {
|
|||||||
SyncOutlined,
|
SyncOutlined,
|
||||||
FileSyncOutlined,
|
FileSyncOutlined,
|
||||||
UserOutlined,
|
UserOutlined,
|
||||||
|
DownloadOutlined,
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import type { MenuProps } from 'antd';
|
import type { MenuProps } from 'antd';
|
||||||
|
|
||||||
@@ -13,6 +14,7 @@ import UserCustom from '@/view/model/UserCustom';
|
|||||||
import SyncPrompts from '@/view/model/SyncPrompts';
|
import SyncPrompts from '@/view/model/SyncPrompts';
|
||||||
import SyncCustom from '@/view/model/SyncCustom';
|
import SyncCustom from '@/view/model/SyncCustom';
|
||||||
import SyncRecord from '@/view/model/SyncRecord';
|
import SyncRecord from '@/view/model/SyncRecord';
|
||||||
|
import Download from '@/view/download';
|
||||||
|
|
||||||
export type ChatRouteMetaObject = {
|
export type ChatRouteMetaObject = {
|
||||||
label: string;
|
label: string;
|
||||||
@@ -36,6 +38,14 @@ export const routes: Array<ChatRouteObject> = [
|
|||||||
icon: <DesktopOutlined />,
|
icon: <DesktopOutlined />,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'download',
|
||||||
|
element: <Download />,
|
||||||
|
meta: {
|
||||||
|
label: 'Download',
|
||||||
|
icon: <DownloadOutlined />,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/model',
|
path: '/model',
|
||||||
meta: {
|
meta: {
|
||||||
@@ -51,6 +61,7 @@ export const routes: Array<ChatRouteObject> = [
|
|||||||
icon: <UserOutlined />,
|
icon: <UserOutlined />,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// --- Sync
|
||||||
{
|
{
|
||||||
path: 'sync-prompts',
|
path: 'sync-prompts',
|
||||||
element: <SyncPrompts />,
|
element: <SyncPrompts />,
|
||||||
@@ -72,7 +83,7 @@ export const routes: Array<ChatRouteObject> = [
|
|||||||
element: <SyncRecord />,
|
element: <SyncRecord />,
|
||||||
hideMenu: true,
|
hideMenu: true,
|
||||||
},
|
},
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
38
src/view/download/config.tsx
vendored
Normal file
38
src/view/download/config.tsx
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { Switch, Tag, Tooltip, Space, Popconfirm } from 'antd';
|
||||||
|
|
||||||
|
export const syncColumns = () => [
|
||||||
|
{
|
||||||
|
title: 'Name',
|
||||||
|
dataIndex: 'name',
|
||||||
|
fixed: 'left',
|
||||||
|
// width: 120,
|
||||||
|
key: 'name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Type',
|
||||||
|
dataIndex: 'type',
|
||||||
|
key: 'type',
|
||||||
|
render: () => {
|
||||||
|
return <Tag>{}</Tag>;
|
||||||
|
}
|
||||||
|
// width: 200,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Action',
|
||||||
|
render: (_: any, row: any, actions: any) => {
|
||||||
|
return (
|
||||||
|
<Space>
|
||||||
|
<a>View</a>
|
||||||
|
<Popconfirm
|
||||||
|
title="Are you sure to delete this file?"
|
||||||
|
onConfirm={() => actions.setRecord(row, 'delete')}
|
||||||
|
okText="Yes"
|
||||||
|
cancelText="No"
|
||||||
|
>
|
||||||
|
<a>Delete</a>
|
||||||
|
</Popconfirm>
|
||||||
|
</Space>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
12
src/view/download/index.scss
vendored
Normal file
12
src/view/download/index.scss
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
.chat-table-tip, .chat-table-btns {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-table-btns {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
|
||||||
|
.num {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
38
src/view/download/index.tsx
vendored
Normal file
38
src/view/download/index.tsx
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
import { Table } from 'antd';
|
||||||
|
import { path, shell } from '@tauri-apps/api';
|
||||||
|
|
||||||
|
import useInit from '@/hooks/useInit';
|
||||||
|
import useColumns from '@/hooks/useColumns';
|
||||||
|
import useTable, { TABLE_PAGINATION } from '@/hooks/useTable';
|
||||||
|
import { chatRoot } from '@/utils';
|
||||||
|
import { syncColumns } from './config';
|
||||||
|
import './index.scss';
|
||||||
|
|
||||||
|
export default function SyncPrompts() {
|
||||||
|
const { rowSelection, selectedRowIDs } = useTable();
|
||||||
|
const [downloadPath, setDownloadPath] = useState('');
|
||||||
|
const { columns, ...opInfo } = useColumns(syncColumns());
|
||||||
|
|
||||||
|
useInit(async () => {
|
||||||
|
setDownloadPath(await path.join(await chatRoot(), 'download'));
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="chat-table-tip">
|
||||||
|
<div className="chat-file-path">
|
||||||
|
<div>PATH: <a onClick={() => shell.open(downloadPath)} title={downloadPath}>{downloadPath}</a></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Table
|
||||||
|
rowKey="name"
|
||||||
|
columns={columns}
|
||||||
|
scroll={{ x: 'auto' }}
|
||||||
|
dataSource={[]}
|
||||||
|
rowSelection={rowSelection}
|
||||||
|
pagination={TABLE_PAGINATION}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user