Skip to content
Closed
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
10 changes: 5 additions & 5 deletions frontend/src/components/Explainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ArrowRight, BotIcon, LockIcon, MinusIcon, ServerIcon, SmartphoneIcon }
import { useEffect, useState } from "react";
import { Loader2, CheckCircle, XCircle } from "lucide-react";
import { useOpenSecret } from "@opensecret/react";
import { openExternalLink } from "@/utils/externalLinks";

function ArrowAndLock() {
return (
Expand Down Expand Up @@ -90,14 +91,13 @@ export function InfoContent() {
</div>
<div className="w-full pt-4 flex gap-4 items-center justify-between">
<VerificationStatus />
<a
href="https://blog.trymaple.ai"
<button
onClick={() => openExternalLink("https://blog.trymaple.ai")}
role="link"
className="text-center hover:underline font-medium text-sm"
target="_blank"
rel="noopener noreferrer"
>
Learn more
</a>
</button>
</div>
</>
);
Expand Down
31 changes: 15 additions & 16 deletions frontend/src/components/SimplifiedFooter.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { openExternalLink } from "@/utils/externalLinks";

export function SimplifiedFooter() {
return (
<div className="w-full border-t border-[hsl(var(--marketing-card-border))] py-6 mt-auto">
<div className="max-w-[45rem] mx-auto px-4 text-center">
<p className="text-[hsl(var(--marketing-text-muted))]/70 text-sm">
© {new Date().getFullYear()} Maple AI. All rights reserved. Powered by{" "}
<a
href="https://opensecret.cloud"
target="_blank"
rel="noopener noreferrer"
className="text-[hsl(var(--purple))] hover:text-[hsl(var(--purple))]/80 dark:text-[hsl(var(--blue))] dark:hover:text-[hsl(var(--blue))]/80 transition-colors"
<button
onClick={() => openExternalLink("https://opensecret.cloud")}
role="link"
className="text-[hsl(var(--purple))] hover:text-[hsl(var(--purple))]/80 dark:text-[hsl(var(--blue))] dark:hover:text-[hsl(var(--blue))]/80 transition-colors underline"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: add role='link' to button for better accessibility since this behaves like a link

>
OpenSecret
</a>
</button>
</p>
<div className="flex justify-center gap-6 mt-2">
<a
Expand All @@ -20,22 +21,20 @@ export function SimplifiedFooter() {
>
Downloads
</a>
<a
href="https://opensecret.cloud/terms"
target="_blank"
rel="noopener noreferrer"
<button
onClick={() => openExternalLink("https://opensecret.cloud/terms")}
role="link"
className="text-[hsl(var(--marketing-text-muted))] hover:text-foreground text-sm transition-colors"
>
Terms of Service
</a>
<a
href="https://opensecret.cloud/privacy"
target="_blank"
rel="noopener noreferrer"
</button>
<button
onClick={() => openExternalLink("https://opensecret.cloud/privacy")}
role="link"
className="text-[hsl(var(--marketing-text-muted))] hover:text-foreground text-sm transition-colors"
>
Privacy Policy
</a>
</button>
</div>
</div>
</div>
Expand Down
37 changes: 37 additions & 0 deletions frontend/src/utils/externalLinks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* Opens an external URL using the Tauri opener plugin when running on iOS in a Tauri environment,
* with fallback to window.open for web environments and other platforms.
*
* @param url - The external URL to open
*/
export const openExternalLink = async (url: string): Promise<void> => {
try {
// Check if we're in a Tauri environment first
const { isTauri } = await import("@tauri-apps/api/core");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: dynamically importing isTauri could be moved outside function to avoid performance overhead on every link click

const tauriEnv = await isTauri();

if (tauriEnv) {
// Check if we're on iOS
const { type } = await import("@tauri-apps/plugin-os");
const platform = await type();

if (platform === "ios") {
// Use Tauri opener plugin for iOS
const { invoke } = await import("@tauri-apps/api/core");
await invoke("plugin:opener|open_url", { url });
return;
}
}

// Fallback for non-iOS or non-Tauri environments
window.open(url, "_blank", "noopener,noreferrer");
} catch (error) {
// Final fallback if everything fails
console.warn("Failed to open URL with Tauri opener, falling back to window.open:", error);
try {
window.open(url, "_blank", "noopener,noreferrer");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: second window.open call unnecessarily repeats code from line 27 - consider extracting to shared function

} catch (windowError) {
console.error("Failed to open URL with window.open:", windowError);
}
}
};
Loading