diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 96be4c1..9d201c4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -32,7 +32,7 @@ jobs: tag="${GITHUB_REF#refs/tags/}" files=() - for file in main.js manifest.json style.css; do + for file in main.js manifest.json styles.css; do if [ -f "$file" ]; then files+=("$file") else diff --git a/src/main.ts b/src/main.ts index 07233e9..b0539d5 100644 --- a/src/main.ts +++ b/src/main.ts @@ -104,7 +104,7 @@ export default class DiscourseSyncPlugin extends Plugin { return imageUrls; } - async postTopic(): Promise<{ message: string }> { + async postTopic(): Promise<{ message: string; error?: string }> { const url = `${this.settings.baseUrl}/posts.json`; const headers = { "Content-Type": "application/json", @@ -131,21 +131,51 @@ export default class DiscourseSyncPlugin extends Plugin { category: this.settings.category }); - const response = await requestUrl({ - url: url, - method: "POST", - contentType: "application/json", - body, - headers, - }); + try { + const response = await requestUrl({ + url: url, + method: "POST", + contentType: "application/json", + body, + headers, + throw: false // 设置为 false 以获取错误响应 + }); - if (response.status !== 200) { - if (response.status == 422) { - new NotifyUser(this.app, `There's an error with this post, could be a duplicate or the title is too short: ${response.status}`).open(); + if (response.status === 200) { + return { message: "Success" }; + } else { + // 尝试从响应中获取错误信息 + try { + const errorResponse = response.json; + // Discourse 通常会在 errors 数组中返回错误信息 + if (errorResponse.errors && errorResponse.errors.length > 0) { + return { + message: "Error", + error: errorResponse.errors.join('\n') + }; + } + // 有些错误可能在 error 字段中 + if (errorResponse.error) { + return { + message: "Error", + error: errorResponse.error + }; + } + } catch (parseError) { + // 如果无法解析错误响应 + return { + message: "Error", + error: `发布失败 (${response.status})` + }; + } } - return { message: "Error publishing to Discourse" }; + } catch (error) { + return { + message: "Error", + error: `发布失败: ${error.message || '未知错误'}` + }; } - return { message: "Success" }; + return { message: "Error", error: "发布失败,请重试" }; } private async fetchCategories() { @@ -258,20 +288,21 @@ export class SelectCategoryModal extends Modal { constructor(app: App, plugin: DiscourseSyncPlugin, categories: {id: number; name: string }[]) { super(app); this.plugin = plugin; - this.categories = categories + this.categories = categories; } onOpen() { + // 添加模态框基础样式 + this.modalEl.addClass('mod-discourse-sync'); const { contentEl } = this; + contentEl.empty(); contentEl.addClass('discourse-sync-modal'); contentEl.createEl("h1", { text: '选择发布分类' }); // 创建选择器容器 const selectContainer = contentEl.createEl('div', { cls: 'select-container' }); - const selectLabel = selectContainer.createEl('label', { text: '分类' }); - selectLabel.style.display = 'block'; - selectLabel.style.marginBottom = '8px'; + selectContainer.createEl('label', { text: '分类' }); const selectEl = selectContainer.createEl('select'); @@ -297,22 +328,70 @@ export class SelectCategoryModal extends Modal { submitButton.disabled = true; submitButton.textContent = '发布中...'; - const reply = await this.plugin.postTopic(); - - // 显示提示信息 - noticeContainer.empty(); - noticeContainer.createEl('div', { - cls: `notice ${reply.message === 'Success' ? 'success' : 'error'}`, - text: reply.message === 'Success' ? '发布成功!' : '发布失败,请重试。' - }); - - if (reply.message === 'Success') { - // 成功后延迟关闭 - setTimeout(() => { - this.close(); - }, 1500); - } else { - // 失败时重置按钮状态 + try { + const reply = await this.plugin.postTopic(); + + // 显示提示信息 + noticeContainer.empty(); + if (reply.message === 'Success') { + noticeContainer.createEl('div', { + cls: 'notice success', + text: '✓ 发布成功!' + }); + // 成功后延迟关闭 + setTimeout(() => { + this.close(); + }, 1500); + } else { + const errorContainer = noticeContainer.createEl('div', { cls: 'notice error' }); + errorContainer.createEl('div', { + cls: 'error-title', + text: '发布失败' + }); + + // 显示 Discourse 返回的具体错误信息 + errorContainer.createEl('div', { + cls: 'error-message', + text: reply.error || '发布失败,请重试' + }); + + // 添加重试按钮 + const retryButton = errorContainer.createEl('button', { + cls: 'retry-button', + text: '重试' + }); + retryButton.onclick = () => { + noticeContainer.empty(); + submitButton.disabled = false; + submitButton.textContent = '发布'; + }; + } + } catch (error) { + noticeContainer.empty(); + const errorContainer = noticeContainer.createEl('div', { cls: 'notice error' }); + errorContainer.createEl('div', { + cls: 'error-title', + text: '发布出错' + }); + errorContainer.createEl('div', { + cls: 'error-message', + text: error.message || '未知错误' + }); + + // 添加重试按钮 + const retryButton = errorContainer.createEl('button', { + cls: 'retry-button', + text: '重试' + }); + retryButton.onclick = () => { + noticeContainer.empty(); + submitButton.disabled = false; + submitButton.textContent = '发布'; + }; + } + + // 如果发生错误,重置按钮状态 + if (submitButton.disabled) { submitButton.disabled = false; submitButton.textContent = '发布'; } diff --git a/style.css b/style.css deleted file mode 100644 index bfcd499..0000000 --- a/style.css +++ /dev/null @@ -1,64 +0,0 @@ -/* - -This CSS file will be included with your plugin, and -available in the app when your plugin is enabled. - -If your plugin does not need CSS, delete this file. - -*/ - -.discourse-sync-modal { - padding: 20px; -} - -.discourse-sync-modal h1 { - margin-bottom: 20px; - color: var(--text-normal); -} - -.discourse-sync-modal .select-container { - margin-bottom: 24px; -} - -.discourse-sync-modal select { - width: 100%; - padding: 8px 12px; - height: 42px; - line-height: 1.5; - border: 1px solid var(--background-modifier-border); - border-radius: 4px; - background-color: var(--background-primary); - color: var(--text-normal); -} - -.discourse-sync-modal .submit-button { - width: 100%; - padding: 10px; - background-color: var(--interactive-accent); - color: var(--text-on-accent); - border: none; - border-radius: 4px; - cursor: pointer; - font-weight: 500; -} - -.discourse-sync-modal .submit-button:hover { - background-color: var(--interactive-accent-hover); -} - -.discourse-sync-modal .notice { - margin-top: 16px; - padding: 10px; - border-radius: 4px; - text-align: center; -} - -.discourse-sync-modal .notice.success { - background-color: var(--background-modifier-success); - color: var(--text-success); -} - -.discourse-sync-modal .notice.error { - background-color: var(--background-modifier-error); - color: var(--text-error); -} diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..b245c70 --- /dev/null +++ b/styles.css @@ -0,0 +1,143 @@ +/* + +This CSS file will be included with your plugin, and +available in the app when your plugin is enabled. + +If your plugin does not need CSS, delete this file. + +*/ + +/* 基础模态框样式覆盖 */ +.modal.mod-discourse-sync { + max-width: 500px; + max-height: 80vh; + background-color: var(--background-primary); + border-radius: 8px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); +} + +/* 内容区域样式 */ +.discourse-sync-modal { + padding: 24px; + width: 100%; +} + +.discourse-sync-modal h1 { + margin: 0 0 24px 0; + font-size: 1.5em; + font-weight: 600; + color: var(--text-normal); +} + +.discourse-sync-modal .select-container { + margin-bottom: 24px; +} + +.discourse-sync-modal .select-container label { + display: block; + margin-bottom: 8px; + font-weight: 500; + color: var(--text-normal); +} + +.discourse-sync-modal select { + width: 100%; + padding: 8px 12px; + height: 42px; + line-height: 1.5; + border: 2px solid var(--background-modifier-border); + border-radius: 4px; + background-color: var(--background-primary); + color: var(--text-normal); + font-size: 14px; +} + +.discourse-sync-modal select:focus { + border-color: var(--interactive-accent); + outline: none; +} + +.discourse-sync-modal .submit-button { + width: 100%; + padding: 10px 16px; + background-color: var(--interactive-accent); + color: var(--text-on-accent); + border: none; + border-radius: 4px; + cursor: pointer; + font-weight: 500; + font-size: 14px; + transition: background-color 0.2s ease; +} + +.discourse-sync-modal .submit-button:hover { + background-color: var(--interactive-accent-hover); +} + +.discourse-sync-modal .submit-button:disabled { + opacity: 0.7; + cursor: not-allowed; +} + +/* 提示信息样式 */ +.discourse-sync-modal .notice { + margin-top: 16px; + padding: 16px; + border-radius: 8px; + text-align: left; + font-size: 14px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +} + +.discourse-sync-modal .notice.success { + background-color: var(--background-modifier-success-hover); + color: var(--text-success); + text-align: center; + font-weight: 500; +} + +.discourse-sync-modal .notice.error { + background: rgb(255, 235, 235); + border: 1px solid rgba(255, 82, 82, 0.2); + color: rgb(255, 82, 82); +} + +.discourse-sync-modal .error-title { + font-size: 15px; + font-weight: 600; + margin-bottom: 8px; + color: rgb(255, 82, 82); + display: flex; + align-items: center; + gap: 6px; +} + +.discourse-sync-modal .error-title::before { + content: "⚠️"; + font-size: 16px; +} + +.discourse-sync-modal .error-message { + color: rgb(255, 82, 82); + opacity: 0.8; + font-size: 13px; + line-height: 1.5; +} + +.discourse-sync-modal .retry-button { + margin-top: 12px; + padding: 6px 16px; + background-color: transparent; + color: rgb(255, 82, 82); + border: 1px solid rgb(255, 82, 82); + border-radius: 4px; + cursor: pointer; + font-size: 13px; + font-weight: 500; + transition: all 0.2s ease; +} + +.discourse-sync-modal .retry-button:hover { + background-color: rgb(255, 82, 82); + color: white; +}