Signed-off-by: DanRoscigno <dan@roscigno.com>
This commit is contained in:
DanRoscigno 2025-09-22 12:26:03 -04:00
parent 737dc0ed19
commit 7532b4b2ff
No known key found for this signature in database
GPG Key ID: 173762EABBD1ACE4
3 changed files with 139 additions and 0 deletions

View File

@ -0,0 +1,66 @@
import React, { useState, useEffect } from "react";
import { HelpCircle } from "lucide-react"; // icon library
export default function ModalWidgetPersistent({ url, buttonLabel = "Open Widget" }) {
const [open, setOpen] = useState(false);
const [expanded, setExpanded] = useState(false); // user-controlled expansion
// Close modal on Escape key
useEffect(() => {
if (!open) return;
const handleKeyDown = (e) => {
if (e.key === "Escape") {
setOpen(false);
}
};
window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown);
}, [open]);
return (
<>
{/* Floating Button: Icon + optional label */}
<div className="fixed bottom-4 right-4 z-50 flex items-center space-x-2">
{expanded && (
<button
className="modal-launch-btn"
onClick={() => setOpen(true)}
>
{buttonLabel}
</button>
)}
<button
className="help-icon-btn"
onClick={() => setExpanded(!expanded)}
aria-label="Toggle Help Button"
>
<HelpCircle size={24} />
</button>
</div>
{/* Full-Screen Modal */}
<div
className={`fixed inset-0 z-50 modal-overlay flex flex-col transition-opacity duration-300 ${
open ? "opacity-100 visible" : "opacity-0 invisible"
}`}
>
{/* Close Button */}
<div className="absolute top-4 right-4 z-60">
<button
className="modal-close-btn"
onClick={() => setOpen(false)}
>
Close
</button>
</div>
{/* Persistent iframe */}
<iframe
src={url}
title="Modal Widget"
className="flex-1 w-full h-full border-0"
/>
</div>
</>
);
}

View File

@ -85,6 +85,61 @@ a {
var(--ifm-transition-timing-default);
}
/* Modal overlay */
.modal-overlay {
background: rgba(0, 0, 0, 0.8);
}
/* Launch button (text) */
.modal-launch-btn {
background-color: var(--ifm-color-primary);
color: white;
border: none;
padding: 0.6rem 1rem;
border-radius: 0.5rem;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);
cursor: pointer;
transition: background-color 0.2s ease;
}
.modal-launch-btn:hover {
background-color: var(--ifm-color-primary-dark);
}
/* Close button inside modal */
.modal-close-btn {
background-color: #e53e3e;
color: white;
padding: 0.3rem 0.8rem;
border-radius: 0.4rem;
border: none;
cursor: pointer;
}
.modal-close-btn:hover {
background-color: #c53030;
}
/* Small floating icon button */
.help-icon-btn {
background-color: var(--ifm-color-primary);
color: white;
border: none;
border-radius: 50%;
width: 44px;
height: 44px;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);
cursor: pointer;
transition: background-color 0.2s ease;
}
.help-icon-btn:hover {
background-color: var(--ifm-color-primary-dark);
}
/* When we generate PDF files:
- avoid breaks in the middle of:
@ -108,3 +163,4 @@ a {
display: none;
}
}

View File

@ -0,0 +1,17 @@
import React from "react";
import ModalWidgetPersistent from "@site/src/components/ModalWidgetPersistent";
export default function Root({ children }) {
return (
<>
{children}
{/* Floating widget trigger in bottom-right, always visible */}
<div className="fixed bottom-4 right-4 z-50">
<ModalWidgetPersistent
url="https://example.com/app"
buttonLabel="Help"
/>
</div>
</>
);
}