2026-09-25 20:50:00 +08:00
<!DOCTYPE html>
< html lang = "en" >
< head >
< meta charset = "utf-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1" >
2026-10-26 00:50:43 +08:00
< title > ReplyPier UI options gallery</ title >
2026-09-25 20:50:00 +08:00
< style >
* { box-sizing : border-box ; }
body { font-family : system-ui ; margin : 0 ; padding : 32 px ; background : #f7f7f5 ; color : #1c1c1e ; }
h1 { margin : 0 0 4 px ; }
. hint { color : #666 ; margin-bottom : 20 px ; }
. grid { display : grid ; grid-template-columns : repeat ( auto - fill , minmax ( 280 px , 1 fr )); gap : 14 px ; }
a . card { display : block ; background : #fff ; border : 1 px solid #e2e2df ; border-radius : 12 px ; padding : 16 px ; text-decoration : none ; color : inherit ; }
a . card : hover { border-color : #f34611 ; }
. card h3 { margin : 0 0 6 px ; font-size : 15 px ; }
. card p { margin : 0 ; font-size : 13 px ; color : #666 ; line-height : 1.5 ; }
code { background : #eee ; padding : 1 px 5 px ; border-radius : 4 px ; font-size : 12 px ; }
. settings { background : #fff ; border : 1 px solid #e2e2df ; border-radius : 12 px ; padding : 16 px ; margin-bottom : 24 px ; display : flex ; gap : 12 px ; flex-wrap : wrap ; align-items : end ; }
. settings label { display : flex ; flex-direction : column ; gap : 4 px ; font-size : 12 px ; color : #666 ; }
. settings input , . settings select { padding : 6 px 10 px ; border : 1 px solid #ccc ; border-radius : 8 px ; font-size : 13 px ; min-width : 230 px ; }
. settings button { padding : 8 px 16 px ; border : none ; border-radius : 8 px ; background : #f34611 ; color : #fff ; cursor : pointer ; }
</ style >
</ head >
< body >
2026-10-26 00:50:43 +08:00
< h1 > ReplyPier UI options gallery</ h1 >
2026-09-25 20:50:00 +08:00
< p class = "hint" >
One card per placement/behaviour. < strong > Stub</ strong > mode fakes the widget (no backend
needed — good for checking the loader UI alone). < strong > Real</ strong > mode loads your
actual widget: fill in the widget ID and API URL below.
< br >
The loader is loaded from the < strong > frontend</ strong > (< code > npm run dev</ code > in
< code > frontend/</ code > ), the same origin the dashboard's embed snippet points at — the
backend does not serve it, and no copy is kept in this folder. The loader is a build
artifact: after changing its source run
< code > cd frontend && npm run build:webclient:prod</ code > .
</ p >
< div class = "settings" >
< label > Mode
< select id = "mode" >
< option value = "stub" > Stub (no backend)</ option >
< option value = "real" > Real backend</ option >
</ select >
</ label >
< label > Loader URL (served by the frontend)
2026-10-26 00:50:43 +08:00
< input id = "loaderUrl" placeholder = "http://localhost:5173/webclient/replypier.min.js" >
2026-09-25 20:50:00 +08:00
</ label >
< label > Widget ID (real mode)
< input id = "widgetId" placeholder = "widget uuid" >
</ label >
< label > API base URL (real mode)
< input id = "baseUrl" placeholder = "http://localhost:8000/api/v1" >
</ label >
< button onclick = "saveSettings()" > Save</ button >
</ div >
< div class = "grid" >
< a class = "card" data-config = "" >
< h3 > 1. Default (zero config)</ h3 >
< p > Legacy behaviour — floating bubble, bottom right. The regression baseline.</ p >
</ a >
< a class = "card" data-config = '{"position":{"side":"left"}}' >
< h3 > 2. Floating, left side</ h3 >
< p > Bubble and window hugging the bottom-left corner.</ p >
</ a >
< a class = "card" data-config = '{"width":520,"height":700}' >
< h3 > 3. Floating, custom size</ h3 >
< p > 520 × 700 window instead of the 400 × 560 default.</ p >
</ a >
< a class = "card" data-config = '{"position":{"bottom":90,"offset":24}}' >
< h3 > 4. Custom offsets</ h3 >
< p > Launcher lifted 90px — e.g. to clear a fixed bottom nav bar.</ p >
</ a >
< a class = "card" data-config = '{"displayMode":"sidebar-right","sidebarWidth":460}' >
< h3 > 5. Sidebar drawer, right</ h3 >
< p > Full-height panel sliding in from the right edge, 460px wide.</ p >
</ a >
< a class = "card" data-config = '{"displayMode":"sidebar-left"}' >
< h3 > 6. Sidebar drawer, left</ h3 >
< p > Full-height panel from the left edge, default width.</ p >
</ a >
< a class = "card" data-config = '{"displayMode":"search-bar","searchBar":{"placeholder":"Ask our AI anything...","width":380}}' >
< h3 > 7. Search bar trigger</ h3 >
< p > The launcher becomes a search-style bar (desktop; bubble on mobile).</ p >
</ a >
< a class = "card" data-config = '{"launcher":false,"trigger":"#my-trigger"}' >
< h3 > 8. Hidden launcher + own button</ h3 >
2026-10-26 00:50:43 +08:00
< p > No built-in launcher. Open via the page’ s buttons, the < code > trigger</ code > selector, < code > data-replypier-open</ code > , or the JS API.</ p >
2026-09-25 20:50:00 +08:00
</ a >
< a class = "card" data-config = '{"zIndex":50}' >
< h3 > 9. Custom z-index</ h3 >
< p > Widget at z-index 50 — the page’ s fixed overlay (z-index 100) must cover it.</ p >
</ a >
< a class = "card" data-dashboard = '{"mode":"sidebar-right","sidebar_width":420,"offset_bottom":30,"offset_side":30}' >
< h3 > 10. Dashboard defaults (stub only)</ h3 >
< p > No page config; the fake widget delivers < code > widget_display</ code > as saved in the dashboard’ s Widget placement section.</ p >
</ a >
< a class = "card" data-config = '{"width":520}' data-dashboard = '{"mode":"floating","width":320,"height":800,"side":"left"}' >
< h3 > 11. Page config beats dashboard (stub only)</ h3 >
< p > Dashboard says 320-wide, left; the page sets width 520. Expect 520 wide, left side, 800 tall.</ p >
</ a >
< a class = "card" data-config = '{"displayMode":"search-bar"}' data-style = "ASK_ANYTHING" >
< h3 > 12. Ask AI palette (⌘K)</ h3 >
< p > Ask Anything/Aurora open as a centered command palette over a dimmed page. Try ⌘K, Esc, and clicking the backdrop. Use Real mode to see the redesigned interior.</ p >
</ a >
< a class = "card" data-config = '{"displayMode":"sidebar-left"}' data-style = "ASK_ANYTHING" >
< h3 > 13. Drawer + Ask Anything (stub only)</ h3 >
< p > Ask Anything/Aurora draw no in-panel chevron, so the launcher must stay reachable beside the drawer. Every other style hides it while open.</ p >
</ a >
< a class = "card" data-config = '{"displayMode":"sidebar-right"}' >
< h3 > 14. Mobile check</ h3 >
< p > Open any card with device emulation / a narrow window: fullscreen chat must win in every mode.</ p >
</ a >
</ div >
< script >
2026-10-26 00:50:43 +08:00
const S_KEY = 'rp-test-settings'
2026-09-25 20:50:00 +08:00
const saved = JSON . parse ( localStorage . getItem ( S_KEY ) || '{}' )
document . getElementById ( 'mode' ). value = saved . mode || 'stub'
2026-10-26 00:50:43 +08:00
// The frontend serves the loader (the backend does not). '/replypier.min.js' is a
2026-09-25 20:50:00 +08:00
// stale saved value from an earlier version of this page — ignore it.
2026-10-26 00:50:43 +08:00
const savedLoader = saved . loaderUrl === '/replypier.min.js' ? '' : saved . loaderUrl
2026-09-25 20:50:00 +08:00
document . getElementById ( 'loaderUrl' ). value = savedLoader
2026-10-26 00:50:43 +08:00
|| ` ${ location . protocol } //localhost:5173/webclient/replypier.min.js`
2026-09-25 20:50:00 +08:00
document . getElementById ( 'widgetId' ). value = saved . widgetId || ''
document . getElementById ( 'baseUrl' ). value = saved . baseUrl || 'http://localhost:8000/api/v1'
function saveSettings () {
localStorage . setItem ( S_KEY , JSON . stringify ({
mode : document . getElementById ( 'mode' ). value ,
loaderUrl : document . getElementById ( 'loaderUrl' ). value . trim (),
widgetId : document . getElementById ( 'widgetId' ). value . trim (),
baseUrl : document . getElementById ( 'baseUrl' ). value . trim (),
}))
alert ( 'Saved' )
}
document . querySelectorAll ( 'a.card' ). forEach ( card => {
const q = new URLSearchParams ()
if ( card . dataset . config ) q . set ( 'config' , card . dataset . config )
if ( card . dataset . dashboard ) q . set ( 'dashboard' , card . dataset . dashboard )
if ( card . dataset . style ) q . set ( 'style' , card . dataset . style )
q . set ( 'title' , card . querySelector ( 'h3' ). textContent )
card . href = 'ui-test.html?' + q . toString ()
})
</ script >
</ body >
</ html >