Skip to content

Commit

Permalink
feat(options, config): add external links configuration and integrate…
Browse files Browse the repository at this point in the history
… into Options component

- Introduced a new TOML configuration file for external links used in the Askman Chrome extension, enhancing maintainability and organization of links.
- Updated the Options component to load and display external links dynamically, including documentation, issues, and social media links.
- Replaced hardcoded links with dynamic references to the new configuration, improving flexibility and reducing code duplication.
  • Loading branch information
crazygo committed Jan 19, 2025
1 parent 6819f2c commit 76168c5
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 5 deletions.
13 changes: 13 additions & 0 deletions src/assets/conf/external-links.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# External Links Configuration
# This file contains all external links used in the Askman Chrome extension

[docs]
# Documentation links
home = "https://docs.qq.com/aio/DWUxocmZJV05GQXF5?p=PaTh0e2q3XbD8s7W4xJGnb#wXyP39ceAltKZiZ02AZpR0"
issues = "https://github.com/askman-dev/askman-chrome-extension/issues"
discussions = "https://github.com/askman-dev/askman-chrome-extension/discussions"

[social]
# Social media links
wechat_id = "nob301"
wechat_qr = "https://github.com/askman-dev/askman-chrome-extension/raw/refs/heads/main/src/assets/img/askman-group.png"
24 changes: 19 additions & 5 deletions src/pages/options/Options.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useState, useEffect } from 'react';
import ConfigManager from '@src/components/config/ConfigManager';
import {
USER_TOOLS_KEY,
Expand All @@ -7,13 +7,21 @@ import {
USER_PREFERENCES_KEY,
} from '@src/utils/StorageManager';
import { getVersion } from '@src/utils/version';
import ExternalLinksManager, { ExternalLinks } from '@src/utils/ExternalLinksManager';

const Options: React.FC = () => {
const [activeTab, setActiveTab] = useState('Models');
const [showWechatImage, setShowWechatImage] = useState(false);
const [imageLoaded, setImageLoaded] = useState(false);
const [links, setLinks] = useState<ExternalLinks | null>(null);
const version = getVersion();

useEffect(() => {
ExternalLinksManager.loadLinks()
.then(setLinks)
.catch(error => console.error('Failed to load external links:', error));
}, []);

const tabs = ['Models', 'System Prompt', 'Prompts', 'Preferences'];

const handleImageLoad = () => {
Expand Down Expand Up @@ -63,22 +71,21 @@ const Options: React.FC = () => {
Askman<span className="font-normal text-gray-500">(v{version})</span>
<div className="flex items-center">
<a
href="https://github.com/askman-dev/askman-chrome-extension/issues"
href={links?.docs.issues}
className="ml-2 bg-black font-normal text-white px-2 py-1 text-sm rounded"
target="_blank"
rel="noopener noreferrer">
Roadmap
</a>
<div className="relative ml-2 flex items-center">
<button
title="WeChat ID: nob301"
className="bg-green-500 text-white px-2 py-1 text-sm rounded hover:bg-green-600"
onMouseEnter={() => setShowWechatImage(true)}
onMouseLeave={() => {
setShowWechatImage(false);
setImageLoaded(false);
}}>
WeChat
WeChat: {links?.social.wechat_id}
</button>
{showWechatImage && (
<div className="absolute left-0 top-full mt-2 z-50 w-[150px] h-[150px] bg-white rounded shadow-lg p-4">
Expand All @@ -88,7 +95,7 @@ const Options: React.FC = () => {
</div>
)}
<img
src="https://github.com/askman-dev/askman-chrome-extension/raw/refs/heads/main/src/assets/img/askman-group.png"
src={links?.social.wechat_qr}
alt="WeChat QR Code"
className={`w-full h-full object-contain rounded transition-opacity duration-300 ${
imageLoaded ? 'opacity-100' : 'opacity-0'
Expand All @@ -97,6 +104,13 @@ const Options: React.FC = () => {
/>
</div>
)}
<a
href={links?.docs.home}
className="ml-2 bg-blue-500 text-white px-2 py-1 text-sm rounded hover:bg-blue-600"
target="_blank"
rel="noopener noreferrer">
Docs
</a>
</div>
</div>
</h1>
Expand Down
69 changes: 69 additions & 0 deletions src/utils/ExternalLinksManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import toml from '@iarna/toml';

export interface ExternalLinks {
docs: {
home: string;
issues: string;
discussions: string;
};
social: {
wechat_id: string;
wechat_qr: string;
};
}

class ExternalLinksManager {
private static instance: ExternalLinksManager;
private links: ExternalLinks | null = null;

private constructor() {}

static getInstance(): ExternalLinksManager {
if (!ExternalLinksManager.instance) {
ExternalLinksManager.instance = new ExternalLinksManager();
}
return ExternalLinksManager.instance;
}

private validateLinks(data: unknown): data is ExternalLinks {
if (typeof data !== 'object' || data === null) return false;

const links = data as Record<string, unknown>;

return (
'docs' in links &&
typeof links.docs === 'object' &&
links.docs !== null &&
'home' in links.docs &&
'issues' in links.docs &&
'discussions' in links.docs &&
'social' in links &&
typeof links.social === 'object' &&
links.social !== null &&
'wechat_id' in links.social &&
'wechat_qr' in links.social
);
}

async loadLinks(): Promise<ExternalLinks> {
if (this.links) return this.links;

try {
const response = await fetch('/assets/conf/external-links.toml');
const text = await response.text();
const parsed = toml.parse(text);

if (this.validateLinks(parsed)) {
this.links = parsed;
return this.links;
}

throw new Error('Invalid external links configuration format');
} catch (error) {
console.error('Failed to load external links:', error);
throw error;
}
}
}

export default ExternalLinksManager.getInstance();

0 comments on commit 76168c5

Please sign in to comment.