mirror of
https://github.com/ichaly/cohere.git
synced 2026-07-22 07:47:20 +00:00
Refine device and connection settings UI
This commit is contained in:
parent
0440e48a2a
commit
4408b1f981
3 changed files with 107 additions and 60 deletions
53
src/main.ts
53
src/main.ts
|
|
@ -1,4 +1,4 @@
|
|||
import { App, Notice, Plugin, PluginSettingTab, requestUrl, TFile, TFolder } from "obsidian";
|
||||
import { App, Notice, Platform, Plugin, PluginSettingTab, requestUrl, TFile, TFolder } from "obsidian";
|
||||
import { createApp, reactive, type App as VueApp } from "vue";
|
||||
import { createRandomId, createVaultId, normalizeKey } from "./core/ids";
|
||||
import SettingsApp from "./settings/SettingsApp.vue";
|
||||
|
|
@ -6,6 +6,8 @@ import "./styles.scss";
|
|||
import { syncOnce, type LocalSyncState, type VaultIO } from "./sync/engine";
|
||||
import { S3ObjectStore } from "./store/s3";
|
||||
|
||||
declare const require: ((id: string) => unknown) | undefined;
|
||||
|
||||
interface ObsyncSettings {
|
||||
endpoint: string;
|
||||
bucket: string;
|
||||
|
|
@ -160,14 +162,14 @@ export default class ObsyncPlugin extends Plugin {
|
|||
this.settings.vaultKey = normalizeKey(this.app.vault.getName());
|
||||
}
|
||||
|
||||
if (!this.settings.deviceName) {
|
||||
this.settings.deviceName = "This device";
|
||||
}
|
||||
|
||||
if (!this.settings.deviceId) {
|
||||
this.settings.deviceId = createRandomId("dev");
|
||||
}
|
||||
|
||||
if (!this.settings.deviceName || this.settings.deviceName === "This device") {
|
||||
this.settings.deviceName = getCurrentDeviceName(this.settings.deviceId);
|
||||
}
|
||||
|
||||
if (!this.settings.syncState) {
|
||||
this.settings.syncState = { files: {} };
|
||||
}
|
||||
|
|
@ -215,6 +217,38 @@ export default class ObsyncPlugin extends Plugin {
|
|||
}
|
||||
}
|
||||
|
||||
function getCurrentDeviceName(deviceId: string): string {
|
||||
try {
|
||||
if (typeof require !== "function") {
|
||||
return getPlatformDeviceName(deviceId);
|
||||
}
|
||||
|
||||
const os = require("node:os") as { hostname?: () => string };
|
||||
return os.hostname?.().trim() || getPlatformDeviceName(deviceId);
|
||||
} catch {
|
||||
return getPlatformDeviceName(deviceId);
|
||||
}
|
||||
}
|
||||
|
||||
function getPlatformDeviceName(deviceId: string): string {
|
||||
const suffix = getDeviceNameSuffix(deviceId);
|
||||
|
||||
if (Platform.isIosApp) {
|
||||
return `${Platform.isTablet ? "iPad" : "iPhone"} ${suffix}`;
|
||||
}
|
||||
|
||||
if (Platform.isAndroidApp) {
|
||||
return `${Platform.isTablet ? "Android Tablet" : "Android Phone"} ${suffix}`;
|
||||
}
|
||||
|
||||
return `Desktop ${suffix}`;
|
||||
}
|
||||
|
||||
function getDeviceNameSuffix(deviceId: string): string {
|
||||
const compactId = deviceId.replace(/^dev_/, "");
|
||||
return compactId.slice(-4) || "0000";
|
||||
}
|
||||
|
||||
function parseConnectionConfig(configText: string): ConnectionConfig {
|
||||
let parsed: unknown;
|
||||
|
||||
|
|
@ -374,16 +408,17 @@ class ObsyncSettingTab extends PluginSettingTab {
|
|||
await this.plugin.updateSettings(update);
|
||||
Object.assign(connectionConfig, this.plugin.getConnectionConfig());
|
||||
},
|
||||
onCopyVaultId: async () => {
|
||||
await navigator.clipboard.writeText(this.plugin.settings.vaultId);
|
||||
new Notice("Vault ID 已复制。");
|
||||
onCopyDeviceId: async () => {
|
||||
await navigator.clipboard.writeText(this.plugin.settings.deviceId);
|
||||
new Notice("设备 ID 已复制。");
|
||||
},
|
||||
onCopyConnectionConfig: async () => {
|
||||
await navigator.clipboard.writeText(JSON.stringify(this.plugin.getConnectionConfig(), null, 2));
|
||||
new Notice("连接配置已复制。");
|
||||
},
|
||||
onImportConnectionConfig: async (configText: string) => {
|
||||
onPasteConnectionConfig: async () => {
|
||||
try {
|
||||
const configText = await navigator.clipboard.readText();
|
||||
await this.plugin.importConnectionConfig(configText);
|
||||
Object.assign(settings, this.plugin.settings);
|
||||
Object.assign(connectionConfig, this.plugin.getConnectionConfig());
|
||||
|
|
|
|||
|
|
@ -25,14 +25,13 @@ const props = defineProps<{
|
|||
|
||||
const emit = defineEmits<{
|
||||
update: [update: Partial<ObsyncSettings>];
|
||||
copyVaultId: [];
|
||||
copyDeviceId: [];
|
||||
copyConnectionConfig: [];
|
||||
importConnectionConfig: [configText: string];
|
||||
pasteConnectionConfig: [];
|
||||
}>();
|
||||
|
||||
const showSecretAccessKey = ref(false);
|
||||
const secretAccessKeyButton = ref<HTMLButtonElement | null>(null);
|
||||
const importConfigText = ref("");
|
||||
|
||||
watchEffect(() => {
|
||||
const button = secretAccessKeyButton.value;
|
||||
|
|
@ -186,7 +185,6 @@ watchEffect(() => {
|
|||
</div>
|
||||
<div class="obsync-readonly">
|
||||
<code>{{ props.settings.vaultId }}</code>
|
||||
<button type="button" @click="emit('copyVaultId')">复制</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
|
@ -194,7 +192,12 @@ watchEffect(() => {
|
|||
<section class="obsync-card">
|
||||
<div class="obsync-row">
|
||||
<div class="obsync-row-copy">
|
||||
<h3>设备名称</h3>
|
||||
<div class="obsync-row-title">
|
||||
<h3>设备名称</h3>
|
||||
<button type="button" class="obsync-link-button" @click="emit('copyDeviceId')">
|
||||
复制设备 ID
|
||||
</button>
|
||||
</div>
|
||||
<p>用于冲突文件名和界面展示。</p>
|
||||
</div>
|
||||
<div class="obsync-control">
|
||||
|
|
@ -205,16 +208,6 @@ watchEffect(() => {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="obsync-row">
|
||||
<div class="obsync-row-copy">
|
||||
<h3>设备 ID</h3>
|
||||
<p>首次启用插件时随机生成。</p>
|
||||
</div>
|
||||
<div class="obsync-readonly">
|
||||
<code>{{ props.settings.deviceId }}</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="obsync-row">
|
||||
<div class="obsync-row-copy">
|
||||
<h3>自动同步</h3>
|
||||
|
|
@ -238,24 +231,17 @@ watchEffect(() => {
|
|||
<p>复制到另一台设备导入。这里不包含 Access Key 和 Secret。</p>
|
||||
</div>
|
||||
|
||||
<pre>{{ JSON.stringify(props.connectionConfig, null, 2) }}</pre>
|
||||
<pre class="obsync-config-display">{{ JSON.stringify(props.connectionConfig, null, 2) }}</pre>
|
||||
|
||||
<button type="button" class="obsync-primary" @click="emit('copyConnectionConfig')">
|
||||
复制连接配置
|
||||
</button>
|
||||
<div class="obsync-action-row">
|
||||
<button type="button" class="obsync-primary" @click="emit('copyConnectionConfig')">
|
||||
复制连接配置
|
||||
</button>
|
||||
|
||||
<textarea
|
||||
v-model="importConfigText"
|
||||
placeholder="粘贴另一台设备复制的连接配置 JSON"
|
||||
></textarea>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="obsync-secondary"
|
||||
@click="emit('importConnectionConfig', importConfigText)"
|
||||
>
|
||||
导入连接配置
|
||||
</button>
|
||||
<button type="button" class="obsync-secondary" @click="emit('pasteConnectionConfig')">
|
||||
粘贴并导入
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
|
|
|||
|
|
@ -44,12 +44,20 @@
|
|||
}
|
||||
|
||||
.obsync-row {
|
||||
@apply flex items-center justify-between gap-5 px-5 py-4;
|
||||
border-bottom: 1px solid var(--background-modifier-border);
|
||||
@apply relative flex items-center justify-between gap-5 px-5 py-4;
|
||||
}
|
||||
|
||||
.obsync-row:last-child {
|
||||
@apply border-b-0;
|
||||
.obsync-row::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset-inline: 1.25rem;
|
||||
bottom: 0;
|
||||
height: 1px;
|
||||
background: var(--background-modifier-border);
|
||||
}
|
||||
|
||||
.obsync-row:last-child::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.obsync-row-copy {
|
||||
|
|
@ -73,6 +81,23 @@
|
|||
}
|
||||
}
|
||||
|
||||
.obsync-row-title {
|
||||
@apply flex items-center justify-between gap-3;
|
||||
}
|
||||
|
||||
.obsync-link-button {
|
||||
@apply shrink-0 cursor-pointer rounded px-2 py-1 text-xs font-semibold leading-4 transition;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.obsync-link-button:hover {
|
||||
background: var(--background-modifier-hover);
|
||||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
.obsync-control {
|
||||
@apply w-60 shrink-0;
|
||||
}
|
||||
|
|
@ -157,7 +182,6 @@
|
|||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
.obsync-readonly button,
|
||||
.obsync-primary {
|
||||
@apply shrink-0 cursor-pointer rounded-md border-0 px-3 py-2 text-sm font-semibold leading-5 transition;
|
||||
background: var(--interactive-accent);
|
||||
|
|
@ -171,13 +195,11 @@
|
|||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
.obsync-readonly button:hover,
|
||||
.obsync-primary:hover,
|
||||
.obsync-secondary:hover {
|
||||
@apply opacity-90;
|
||||
}
|
||||
|
||||
.obsync-readonly button:active,
|
||||
.obsync-primary:active,
|
||||
.obsync-secondary:active {
|
||||
@apply translate-y-px;
|
||||
|
|
@ -218,28 +240,25 @@
|
|||
@apply mb-3;
|
||||
}
|
||||
|
||||
.obsync-row-block pre {
|
||||
@apply mb-3 max-h-60 overflow-auto rounded-md p-3 text-xs leading-5;
|
||||
.obsync-config-display {
|
||||
@apply min-h-48 rounded-md p-3 font-mono text-xs leading-5;
|
||||
background: var(--background-primary);
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
color: var(--text-normal);
|
||||
overflow-wrap: anywhere;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.obsync-row-block textarea {
|
||||
@apply mt-3 h-28 w-full resize-y rounded-md p-3 text-xs leading-5 outline-none transition;
|
||||
background: var(--background-primary);
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
color: var(--text-normal);
|
||||
.obsync-action-row {
|
||||
@apply mt-3 flex gap-2;
|
||||
}
|
||||
|
||||
.obsync-row-block textarea:focus {
|
||||
border-color: var(--interactive-accent);
|
||||
box-shadow: 0 0 0 2px var(--background-modifier-border-focus);
|
||||
.obsync-action-row button {
|
||||
@apply flex-1;
|
||||
}
|
||||
|
||||
.obsync-row-block textarea::placeholder {
|
||||
color: var(--text-faint);
|
||||
.obsync-action-row .obsync-secondary {
|
||||
@apply mt-0;
|
||||
}
|
||||
|
||||
@container (max-width: 640px) {
|
||||
|
|
@ -255,10 +274,18 @@
|
|||
@apply block px-4 py-4;
|
||||
}
|
||||
|
||||
.obsync-row::after {
|
||||
inset-inline: 1rem;
|
||||
}
|
||||
|
||||
.obsync-row-copy {
|
||||
@apply mb-2;
|
||||
}
|
||||
|
||||
.obsync-row-title {
|
||||
@apply items-start;
|
||||
}
|
||||
|
||||
.obsync-control,
|
||||
.obsync-control-wide,
|
||||
.obsync-readonly {
|
||||
|
|
@ -273,7 +300,6 @@
|
|||
@apply text-left;
|
||||
}
|
||||
|
||||
.obsync-readonly button,
|
||||
.obsync-primary,
|
||||
.obsync-secondary {
|
||||
@apply w-full;
|
||||
|
|
|
|||
Loading…
Reference in a new issue