Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion chrome-extension/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "openlingo-extension",
"version": "0.4.0",
"version": "0.4.1",
"description": "OpenLingo — core extension (manifest, background SW)",
"type": "module",
"private": true,
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "openlingo",
"version": "0.4.0",
"version": "0.4.1",
"description": "OpenLingo — open-source bilingual page translator (DeepL)",
"license": "MIT",
"private": true,
Expand Down
2 changes: 1 addition & 1 deletion packages/translation/lib/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export const PROVIDER_PRESETS: ProviderPreset[] = [
{
id: 'openai-compatible',
name: 'Custom',
tier: 'OpenAI-compatible',
tier: 'OpenAI API',
endpoint: 'custom endpoint',
credentialFields: ['baseUrl', 'model', 'apiKey', 'systemPrompt'],
},
Expand Down
37 changes: 32 additions & 5 deletions pages/popup/src/Popup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { getProviderPreset, PROVIDER_PRESETS } from '@extension/translation';
import { ErrorDisplay, LoadingSpinner } from '@extension/ui';
import { useEffect, useRef, useState } from 'react';
import type { AsrPrepareResponse, AsrSessionState, AsrStartResponse, YouTubeAsrContext } from '@extension/shared';
import type { ProviderId } from '@extension/translation';
import type { ProviderId, ProviderPreset } from '@extension/translation';
import type { CSSProperties } from 'react';

type PageStatus = 'idle' | 'translating' | 'translated' | 'unknown';
Expand Down Expand Up @@ -451,7 +451,15 @@ const LanguageMenu = ({ active, onPick }: { active: string; onPick: (code: strin
</div>
);

const ProviderMenu = ({ active, onPick }: { active: ProviderId; onPick: (id: ProviderId) => void }) => (
const ProviderMenu = ({
presets,
active,
onPick,
}: {
presets: ProviderPreset[];
active: ProviderId;
onPick: (id: ProviderId) => void;
}) => (
<div
style={{
position: 'absolute',
Expand All @@ -476,7 +484,7 @@ const ProviderMenu = ({ active, onPick }: { active: ProviderId; onPick: (id: Pro
}}>
Provider
</div>
{PROVIDER_PRESETS.map(p => {
{presets.map(p => {
const isActive = p.id === active;
return (
<button
Expand Down Expand Up @@ -925,6 +933,22 @@ const Popup = () => {
: pageStatus === 'translated'
? 'translated'
: 'idle';
// Only offer providers that are ready to use (key configured, or keyless
// like Google); keep the active one visible so the selection is never hidden.
const menuPresets = PROVIDER_PRESETS.filter(
p => p.id === providerId || getProviderStatus(p.id, credsMap?.[p.id] ?? {}).isReady,
);
// The popup window sizes itself to the document and the root clips overflow,
// so absolutely-positioned menus get cut off. Reserve height while one is
// open; Chrome resizes the popup and shrinks it back on close.
const rootMinHeight =
openMenu === 'provider'
? menuPresets.length * 33 + 130
: openMenu === 'lang'
? activeTabId && youtubeContext
? 540
: 420
: undefined;
const providerSummary = !status.isReady
? `${preset.name} · no key`
: providerId === 'openai-compatible' ||
Expand All @@ -941,6 +965,9 @@ const Popup = () => {
ref={rootRef}
style={{
width: 360,
minHeight: rootMinHeight,
display: 'flex',
flexDirection: 'column',
position: 'relative',
background: BG,
overflow: 'hidden',
Expand Down Expand Up @@ -970,7 +997,7 @@ const Popup = () => {
</button>
</div>

<div style={{ padding: '4px 16px 14px' }}>
<div style={{ padding: '4px 16px 14px', flex: '1 0 auto' }}>
{activeTabId && youtubeContext && (
<div
style={{
Expand Down Expand Up @@ -1086,7 +1113,7 @@ const Popup = () => {
</span>
</button>

{openMenu === 'provider' && <ProviderMenu active={providerId} onPick={onPickProvider} />}
{openMenu === 'provider' && <ProviderMenu presets={menuPresets} active={providerId} onPick={onPickProvider} />}
</div>
</div>
);
Expand Down
Loading