fix keyboard ui
This commit is contained in:
1 parent
83f4d7c728
commit
a26ae28189
5 files changed
+54
-8
No files matched your search
@@ -1,2 +1,2 @@
|
||||
/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
|
||||
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-leading:initial;--tw-font-weight:initial;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-tracking:initial;--tw-border-style:solid;--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-content:""}}}@layer theme{:root,:host{--font-sans:Vazirmatn,ui-sans-serif,system-ui;--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-50:oklch(97.1% .013 17.38);--color-red-200:oklch(88.5% .062 18.334);--color-red-500:oklch(63.7% .237 25.331);--color-red-700:oklch(50.5% .213 27.518);--color-amber-50:oklch(98.7% .022 95.277);--color-amber-400:oklch(82.8% .189 84.429);--color-amber-500:oklch(76.9% .188 70.08);--color-amber-800:oklch(47.3% .137 46.201);--color-emerald-50:oklch(97.9% .021 166.113);--color-emerald-200:oklch(90.5% .093 164.15);--color-emerald-800:oklch(43.2% .095 166.913);--color-slate-100:oklch(96.8% .007 247.896);--color-slate-400:oklch(70.4% .04 256.788);--color-white:#fff;--spacing:.25rem;--container-sm:24rem;--container-md:28rem;--container-lg:32rem;--container-xl:36rem;--container-2xl:42rem;--container-5xl:64rem;--container-6xl:72rem;--container-7xl:80rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--text-5xl:3rem;--text-5xl--line-height:1;--font-weight-normal:400;--font-weight-medium:500;--font-weight-bold:700;--font-weight-extrabold:800;--font-weight-black:900;--tracking-tight:-.025em;--tracking-wide:.025em;--tracking-wider:.05em;--tracking-widest:.1em;--leading-tight:1.25;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--animate-ping:ping 1s cubic-bezier(0, 0, .2, 1) infinite;--blur-sm:8px;--blur-xl:24px;--blur-2xl:40px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-ink:#08376b;--color-ink-soft:#0b4c8c;--color-cream:#eee;--color-soft:#eaeaea;--color-paper:#fff;--color-sea:#0693e3;--color-sea-dark:#1977ce;--color-blue:#1977ce;--color-mint:#e5f4ff;--color-coral:#fa9f00;--color-sun:#ffc451;--shadow-panel:0 18px 55px -35px #08376b59}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-Line truncated
|
||||
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-leading:initial;--tw-font-weight:initial;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-tracking:initial;--tw-border-style:solid;--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-content:""}}}@layer theme{:root,:host{--font-sans:Vazirmatn,ui-sans-serif,system-ui;--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-50:oklch(97.1% .013 17.38);--color-red-200:oklch(88.5% .062 18.334);--color-red-500:oklch(63.7% .237 25.331);--color-red-700:oklch(50.5% .213 27.518);--color-amber-50:oklch(98.7% .022 95.277);--color-amber-400:oklch(82.8% .189 84.429);--color-amber-500:oklch(76.9% .188 70.08);--color-amber-800:oklch(47.3% .137 46.201);--color-emerald-50:oklch(97.9% .021 166.113);--color-emerald-200:oklch(90.5% .093 164.15);--color-emerald-800:oklch(43.2% .095 166.913);--color-slate-100:oklch(96.8% .007 247.896);--color-slate-400:oklch(70.4% .04 256.788);--color-white:#fff;--spacing:.25rem;--container-sm:24rem;--container-md:28rem;--container-lg:32rem;--container-xl:36rem;--container-2xl:42rem;--container-5xl:64rem;--container-6xl:72rem;--container-7xl:80rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--text-5xl:3rem;--text-5xl--line-height:1;--font-weight-normal:400;--font-weight-medium:500;--font-weight-bold:700;--font-weight-extrabold:800;--font-weight-black:900;--tracking-tight:-.025em;--tracking-wide:.025em;--tracking-wider:.05em;--tracking-widest:.1em;--leading-tight:1.25;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--animate-ping:ping 1s cubic-bezier(0, 0, .2, 1) infinite;--blur-sm:8px;--blur-xl:24px;--blur-2xl:40px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-ink:#08376b;--color-ink-soft:#0b4c8c;--color-cream:#eee;--color-soft:#eaeaea;--color-paper:#fff;--color-sea:#0693e3;--color-sea-dark:#1977ce;--color-blue:#1977ce;--color-mint:#e5f4ff;--color-coral:#fa9f00;--color-sun:#ffc451;--shadow-panel:0 18px 55px -35px #08376b59}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-Line truncated
|
||||
@@ -28,20 +28,40 @@ document.querySelectorAll('[data-conversation-workspace]').forEach(workspace=>{
|
||||
const layoutObserver='ResizeObserver' in window?new ResizeObserver(()=>{if(followLatest)requestAnimationFrame(()=>scrollLatest(false))}):null;
|
||||
layoutObserver?.observe(scroller);
|
||||
if(composer)layoutObserver?.observe(composer);
|
||||
window.addEventListener('appviewportchange',()=>{if(followLatest)requestAnimationFrame(()=>scrollLatest(false))});
|
||||
let stableViewportHeight=Math.max(window.visualViewport?.height||window.innerHeight,window.innerHeight);
|
||||
let inputVisibilityFrame=0;
|
||||
const ensureInputVisible=()=>{
|
||||
inputVisibilityFrame=0;
|
||||
if(!composer||!input||document.activeElement!==input||composer.classList.contains('is-collapsed'))return;
|
||||
const composerBox=composer.getBoundingClientRect(),inputBox=input.getBoundingClientRect(),padding=10;
|
||||
if(inputBox.top<composerBox.top+padding)composer.scrollTop+=inputBox.top-composerBox.top-padding;
|
||||
else if(inputBox.bottom>composerBox.bottom-padding)composer.scrollTop+=inputBox.bottom-composerBox.bottom+padding;
|
||||
};
|
||||
const scheduleInputVisibility=()=>{if(!inputVisibilityFrame)inputVisibilityFrame=requestAnimationFrame(()=>requestAnimationFrame(ensureInputVisible))};
|
||||
const updateKeyboardState=height=>{
|
||||
const inputFocused=document.activeElement===input;
|
||||
if(!inputFocused)stableViewportHeight=Math.max(stableViewportHeight,height);
|
||||
const keyboardOpen=inputFocused&&stableViewportHeight-height>120;
|
||||
composer?.classList.toggle('is-keyboard-active',keyboardOpen);
|
||||
composer?.setAttribute('data-keyboard-open',String(keyboardOpen));
|
||||
if(keyboardOpen)scheduleInputVisibility();
|
||||
};
|
||||
window.addEventListener('appviewportchange',event=>{if(followLatest)requestAnimationFrame(()=>scrollLatest(false));updateKeyboardState(event.detail?.height||window.visualViewport?.height||window.innerHeight)});
|
||||
input?.addEventListener('focus',()=>{updateKeyboardState(window.visualViewport?.height||window.innerHeight);scheduleInputVisibility()});
|
||||
input?.addEventListener('blur',()=>setTimeout(()=>updateKeyboardState(window.visualViewport?.height||window.innerHeight),0));
|
||||
|
||||
const groupDates=()=>{scroller.querySelectorAll('.date-divider').forEach(item=>item.remove());let previousDate='';scroller.querySelectorAll('[data-message]').forEach(message=>{if(message.dataset.date!==previousDate){const divider=document.createElement('div');divider.className='date-divider';divider.innerHTML=`<span>${message.dataset.dayLabel}</span>`;message.before(divider);previousDate=message.dataset.date}})};
|
||||
groupDates();
|
||||
document.body.addEventListener('htmx:beforeSwap',event=>{if(event.detail.target?.matches('[data-load-older]')){scroller.dataset.previousHeight=scroller.scrollHeight}});
|
||||
document.body.addEventListener('htmx:afterSwap',event=>{if(event.detail.target?.matches('[data-load-older]')){const previous=Number(scroller.dataset.previousHeight||0);groupDates();scroller.scrollTop+=scroller.scrollHeight-previous}});
|
||||
|
||||
const resize=()=>{if(!input)return;input.style.height='auto';input.style.height=`${Math.min(Math.max(input.scrollHeight,112),240)}px`};
|
||||
const resize=()=>{if(!input)return;input.style.height='auto';input.style.height=`${Math.min(Math.max(input.scrollHeight,112),240)}px`;scheduleInputVisibility()};
|
||||
const draftKey=()=>`${baseKey}-${mode}`;
|
||||
const status=workspace.querySelector('[data-draft-status]');
|
||||
const replyResult=workspace.dataset.replyResult||new URLSearchParams(location.search).get('reply_result')||'';
|
||||
const submissionSucceeded=replyResult==='reply'||replyResult==='note';
|
||||
if(submissionSucceeded){sessionStorage.removeItem(`${baseKey}-reply`);sessionStorage.removeItem(`${baseKey}-note`)}
|
||||
const setComposerOpen=(open,focus=true)=>{const keepLatestVisible=followLatest||atBottom();composer?.classList.toggle('is-collapsed',!open);composerToggle?.setAttribute('aria-expanded',String(open));[0,80,240].forEach(delay=>setTimeout(()=>{if(keepLatestVisible)scrollLatest(false)},delay));if(open&&focus)setTimeout(()=>input?.focus({preventScroll:true}),80)};
|
||||
const setComposerOpen=(open,focus=true)=>{const keepLatestVisible=followLatest||atBottom();composer?.classList.toggle('is-collapsed',!open);composerToggle?.setAttribute('aria-expanded',String(open));[0,80,240].forEach(delay=>setTimeout(()=>{if(keepLatestVisible)scrollLatest(false)},delay));if(open&&focus)setTimeout(()=>{input?.focus({preventScroll:true});scheduleInputVisibility()},80)};
|
||||
const saveDraft=()=>{if(!input)return;sessionStorage.setItem(draftKey(),input.value);if(status){status.textContent=input.value?'پیشنویس ذخیره شد':'';clearTimeout(saveDraft.timer);saveDraft.timer=setTimeout(()=>status.textContent='',1800)}};
|
||||
const loadDraft=()=>{if(!input)return;input.value=sessionStorage.getItem(draftKey())||'';resize();input.dispatchEvent(new Event('input',{bubbles:true}))};
|
||||
if(input){input.setAttribute('rows','5');input.setAttribute('placeholder','شرح کامل پاسخ، اطلاعات تکمیلی و نتیجه مورد انتظار خود را بنویسید…');input.addEventListener('input',()=>{resize();saveDraft()});loadDraft()}
|
||||
@@ -122,7 +142,7 @@ document.querySelectorAll('[data-conversation-workspace]').forEach(workspace=>{
|
||||
// cancel a recursively scheduled timeout. pollRunning prevents overlap and
|
||||
// nextPollAt preserves the normal interval and network-error backoff.
|
||||
const pollHeartbeat=setInterval(startPolling,1000);
|
||||
window.addEventListener('beforeunload',()=>{clearInterval(pollHeartbeat);stopPolling();layoutObserver?.disconnect()},{once:true});
|
||||
window.addEventListener('beforeunload',()=>{clearInterval(pollHeartbeat);stopPolling();layoutObserver?.disconnect();if(inputVisibilityFrame)cancelAnimationFrame(inputVisibilityFrame)},{once:true});
|
||||
startPolling();
|
||||
|
||||
const resetMessageMenu=menu=>{if(!menu)return;const editor=menu.querySelector('[data-message-editor]');const choices=menu.querySelector('[data-message-menu-choices]');const input=menu.querySelector('[data-message-edit-input]');if(editor)editor.hidden=true;if(choices)choices.hidden=false;if(input){input.value=input.dataset.originalValue||'';input.dispatchEvent(new Event('input',{bubbles:true}))}};
|
||||
|
||||
@@ -33,6 +33,7 @@ body:has(.ticket-workspace){overflow:hidden;overscroll-behavior:none}.customer-m
|
||||
.sms-delivery-heading{display:flex;align-items:center;justify-content:space-between;gap:.75rem}.sms-delivery-heading h3,.sms-delivery-heading small{display:block}.sms-delivery-heading small{margin-top:.2rem;color:rgba(8,55,107,.48);font-size:.6rem}.sms-delivery-heading>span{display:grid;width:1.75rem;height:1.75rem;flex:none;place-items:center;border-radius:999px;background:var(--color-mint);color:var(--color-sea);font-weight:900}.sms-delivery-list{display:grid;gap:.45rem;margin-top:.75rem}.sms-delivery-item{border:1px solid rgba(8,55,107,.09);border-radius:.75rem;background:var(--color-paper);overflow:hidden}.sms-delivery-item>summary{display:grid;grid-template-columns:minmax(0,1fr) auto 1.6rem;align-items:center;gap:.45rem;min-height:2.8rem;padding:.5rem .6rem;cursor:pointer;list-style:none}.sms-delivery-item>summary::-webkit-details-marker{display:none}.sms-delivery-event{min-width:0;overflow:hidden;color:rgba(8,55,107,.68);font-size:.65rem;font-weight:700;text-overflow:ellipsis;white-space:nowrap}.sms-delivery-item>summary b{font-size:.64rem;color:var(--color-ink)}.sms-delivery-info{display:grid;width:1.55rem;height:1.55rem;place-items:center;border:1px solid rgba(6,147,227,.25);border-radius:999px;background:#eef8ff;color:var(--color-sea);font-size:.68rem;font-weight:900}.sms-delivery-item[open] .sms-delivery-info{background:var(--color-sea);color:#fff}.sms-delivery-timeline{display:grid;gap:.7rem;margin:0;padding:.7rem .75rem .75rem;list-style:none;border-top:1px solid rgba(8,55,107,.07);background:var(--color-cream)}.sms-delivery-timeline li{display:grid;grid-template-columns:.65rem minmax(0,1fr);gap:.55rem;align-items:start;color:rgba(8,55,107,.48)}.sms-delivery-timeline li>span{width:.55rem;height:.55rem;margin-top:.28rem;border:2px solid #aab9c6;border-radius:999px;background:#fff}.sms-delivery-timeline li.is-complete>span{border-color:var(--color-sea);background:var(--color-sea)}.sms-delivery-timeline b,.sms-delivery-timeline time,.sms-delivery-timeline small{display:block}.sms-delivery-timeline b{font-size:.62rem}.sms-delivery-timeline time,.sms-delivery-timeline small{margin-top:.12rem;font-size:.58rem;color:rgba(8,55,107,.58)}.sms-delivery-timeline li.is-complete b{color:var(--color-ink)}.sms-delivery-description,.sms-delivery-error,.sms-delivery-tracking{display:block;margin:0;padding:.55rem .75rem;border-top:1px solid rgba(8,55,107,.07);font-size:.58rem;line-height:1.75}.sms-delivery-description{color:#526b85}.sms-delivery-error{color:#8e2d2d;background:#fff2f2}.sms-delivery-tracking{overflow-wrap:anywhere;color:#647b91;text-align:left}
|
||||
@media(max-width:1023px){body:has(.ticket-workspace) .mobile-dock,body:has(.ticket-workspace) .staff-mobile-dock{display:none}.staff-conversation-grid,.customer-grid{grid-template-columns:minmax(0,1fr)}.workspace-side{position:fixed;top:calc(var(--visual-viewport-offset-top,0px) + 4.25rem);right:0;bottom:0;z-index:60;width:min(88vw,22rem);transform:translateX(105%);overflow-y:auto;overscroll-behavior:contain;border-left:1px solid rgba(8,55,107,.1);box-shadow:-20px 0 60px -35px rgba(8,55,107,.7);transition:transform .25s ease}.workspace-side.panel-open{transform:translateX(0)}.panel-close{@apply mb-3 grid size-10 place-items-center rounded-xl bg-ink text-white}.message-bubble{max-width:86%}}
|
||||
@media(max-width:1023px){.ticket-workspace .composer{min-width:0;max-height:min(45svh,max(7rem,calc(var(--visual-viewport-height,100svh) - 18rem)),28rem);overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch}}
|
||||
@media(max-width:1023px){.customer-workspace .composer.is-keyboard-active{max-height:min(75svh,calc(var(--visual-viewport-height,100svh) - 9rem),32rem)}.staff-ticket-workspace .composer.is-keyboard-active{max-height:min(75svh,calc(var(--visual-viewport-height,100svh) - 11rem),32rem)}.ticket-workspace .composer.is-keyboard-active textarea{min-height:5rem;max-height:min(30svh,8rem)!important}}
|
||||
@media(max-width:639px){.site-header{display:none}.customer-main:has(.ticket-workspace){padding:0}.ticket-workspace{height:min(100svh,var(--visual-viewport-height,100svh))}.staff-ticket-workspace{height:min(calc(100svh - 4.5rem),calc(var(--visual-viewport-height,100svh) - 4.5rem))}.ticket-workspace-head{@apply min-h-16}.workspace-grid{height:auto}.ticket-title h1{@apply max-w-[48vw] text-sm}.ticket-head-actions .badge{@apply max-w-24 truncate}.conversation-toolbar{@apply min-h-10}.ticket-workspace .conversation{@apply px-2.5 py-3}.message-avatar{@apply size-7 rounded-lg}.message-bubble{max-width:88%;padding:.6rem .7rem}.message.note .message-bubble{width:96%}.ticket-workspace .composer{@apply px-2.5 pt-2}.composer-context small{max-width:70vw}.composer-hint{display:none}.send-button{@apply px-3}.new-message-jump{bottom:8.5rem}.ticket-head-actions form{display:none}.workspace-side{top:var(--visual-viewport-offset-top,0px)}}
|
||||
@media(prefers-reduced-motion:reduce){.ticket-workspace .conversation{scroll-behavior:auto}.workspace-side{transition:none}}
|
||||
.load-older{@apply mx-auto my-3 flex min-h-9 rounded-full border border-ink/10 bg-paper px-4 py-2 text-[10px] font-bold text-sea shadow-sm hover:bg-mint}.load-older.htmx-request{@apply pointer-events-none opacity-60}
|
||||
|
||||
@@ -36,6 +36,23 @@ def assert_workspace_fits_visual_viewport(page):
|
||||
assert metrics["pageWidth"] <= metrics["viewportWidth"] + 1
|
||||
|
||||
|
||||
def assert_reply_input_is_visible(page):
|
||||
metrics = page.evaluate(
|
||||
"""() => {
|
||||
const input = document.querySelector('form[data-ticket-composer] textarea');
|
||||
const composer = document.querySelector('[data-composer-shell]');
|
||||
const inputBox = input.getBoundingClientRect();
|
||||
const composerBox = composer.getBoundingClientRect();
|
||||
const viewportTop = window.visualViewport?.offsetTop || 0;
|
||||
const viewportBottom = viewportTop + (window.visualViewport?.height || window.innerHeight);
|
||||
const visibleTop = Math.max(inputBox.top, composerBox.top, viewportTop);
|
||||
const visibleBottom = Math.min(inputBox.bottom, composerBox.bottom, viewportBottom);
|
||||
return {visibleHeight: Math.max(0, visibleBottom - visibleTop), inputHeight: inputBox.height};
|
||||
}"""
|
||||
)
|
||||
assert metrics["visibleHeight"] >= min(64, metrics["inputHeight"] * 0.6)
|
||||
|
||||
|
||||
def test_magic_link_mobile_viewport_keeps_composer_messages_and_credit_visible(live_server, browser_page):
|
||||
branding = SiteBranding.load()
|
||||
branding.developer_credit_text = "امضای مقدس توسعهدهنده E2E"
|
||||
@@ -61,16 +78,19 @@ def test_magic_link_mobile_viewport_keeps_composer_messages_and_credit_visible(l
|
||||
conversation.expect_latest_message_above_composer()
|
||||
|
||||
conversation.open_composer()
|
||||
page.set_viewport_size({"width": 390, "height": 620})
|
||||
page.set_viewport_size({"width": 390, "height": 430})
|
||||
expect(page.locator('form[data-ticket-composer] textarea')).to_be_focused()
|
||||
expect(page.locator("[data-composer-shell]")).to_have_attribute("data-keyboard-open", "true")
|
||||
page.locator('form[data-ticket-composer] textarea').fill("متن پاسخ باید هنگام تایپ دیده شود")
|
||||
assert_reply_input_is_visible(page)
|
||||
expect(credit).to_be_visible()
|
||||
assert_workspace_fits_visual_viewport(page)
|
||||
conversation.expect_latest_message_above_composer()
|
||||
|
||||
page.locator("[data-composer-close]").click()
|
||||
expect(page.locator("[data-composer-shell].is-collapsed")).to_be_visible()
|
||||
expect(credit).to_be_visible()
|
||||
assert_workspace_fits_visual_viewport(page)
|
||||
conversation.expect_latest_message_above_composer()
|
||||
|
||||
|
||||
def test_staff_ticket_mobile_viewport_survives_open_close_and_rotation(live_server, browser_page):
|
||||
@@ -95,9 +115,12 @@ def test_staff_ticket_mobile_viewport_survives_open_close_and_rotation(live_serv
|
||||
conversation.open_composer()
|
||||
page.set_viewport_size({"width": 844, "height": 390})
|
||||
assert_workspace_fits_visual_viewport(page)
|
||||
conversation.expect_latest_message_above_composer()
|
||||
expect(page.locator("[data-composer-shell]")).to_have_attribute("data-keyboard-open", "true")
|
||||
page.locator('form[data-ticket-composer] textarea').fill("پاسخ کارشناس هنگام باز بودن کیبورد")
|
||||
assert_reply_input_is_visible(page)
|
||||
expect(page.locator("[data-composer-close]")).to_be_visible()
|
||||
|
||||
page.locator("[data-composer-close]").click()
|
||||
expect(page.locator("[data-composer-shell].is-collapsed")).to_be_visible()
|
||||
assert_workspace_fits_visual_viewport(page)
|
||||
conversation.expect_latest_message_above_composer()
|
||||
@@ -461,6 +461,8 @@ def test_ticket_workspace_uses_mobile_viewport_and_keyboard_safe_layout_contract
|
||||
assert feature in ui_script
|
||||
assert "layoutObserver?.observe(composer)" in conversation_script
|
||||
assert "focus({preventScroll:true})" in conversation_script
|
||||
for feature in ("is-keyboard-active","ensureInputVisible","stableViewportHeight-height>120","data-keyboard-open"):
|
||||
assert feature in conversation_script or feature in source_css
|
||||
assert '<footer class="ticket-detail-credit">{{ developer_credit }}</footer>' in magic_template
|
||||
|
||||
def test_frontend_runtime_libraries_are_local_and_versioned():
|
||||
|
||||
Reference in new issue
Block a user