2. Inline varkən fullscreen nə üçün lazımdır?
Öncəki dərsdə inline barədə artıq razılaşmışdıq: əgər tapşırıq qısadır və 5–7 obyektə və ya bir ekrana sığırsa, inline‑kart ideal seçimdir. Bir neçə hədiyyə siyahısı, bir neçə filtr, bir-iki düymə — bunların hamısı mesaj axınında əla yaşayır.
Amma elə an gəlir ki, “daha bir kart” artıq kömək etmir:
- çox parametr toplamaq lazımdır (alqı-satqı profili, çatdırılma məhdudiyyətləri, ödəniş üsulları);
- bir neçə addımdan ibarət vizard lazımdır;
- böyük cədvəllər, qrafiklər, xəritələr, uzun təsvirlər var.
Burada inline sıxılır: en çatın sütunu ilə, hündürlük də eləcə məhduddur, naviqasiya yoxdur və çatda skroll birdir. Məhz bu ssenarilər üçün Apps SDK-da fullscreen rejimi var — “immersive” interfeys, burada vidjetiniz ekranın böyük hissəsini tutur və mürəkkəb layout göstərə bilir.
Bugünkü ikinci qəhrəman — PiP, çatı üstündə yaşayan kiçik üzən pəncərədir. Onun tipik rolları: fon tapşırığının statusu, mini‑pleyer, taymer, irəliləyiş göstəricisi. Uzunmüddətli bir şey “fon”da gedəndə və istifadəçi GPT ilə söhbəti davam etdirmək istəyəndə PiP ideal seçimdir.
Yadda saxlayın: həm fullscreen, həm də PiP — inline üçün üst qatdır, əvəzləyici deyil. Başlanğıc inline-dır; inline dar gələndə fullscreen-ə keçir, hər şey işə salındıqdan və sadəcə statusu “göz önündə” saxlamaq lazım olanda isə PiP-ə gedirik.
3. Texniki fundament: displayMode və rejimlərin dəyişdirilməsi
Apps SDK baxımından vidjetinizin cari görünüş vəziyyəti — displayMode-dur. Bu dərsin yazıldığı anda üç əsas rejim var: "inline", "fullscreen" və "pip" (picture-in-picture).
Host (ChatGPT) cari rejimi vidjetinizə window.openai-dəki qlobal məlumatlar və SDK-dakı xüsusi hook-lar vasitəsilə bildirir. Tipik React şablonunda buna bənzər bir şey olur:
// Apps SDK şablonundan qısa ad
const mode = useDisplayMode(); // 'inline' | 'fullscreen' | 'pip'
if (mode === "fullscreen") {
// vizardı render edirik
} else {
// kompakt inline UI render edirik
}
SDK həmçinin window.openai.requestDisplayMode({ mode }) metodunu və/və ya useRequestDisplayMode hook-unu verir ki, hostdan rejimi dəyişməyi xahiş edəsiniz. Bu metod faktiki qoyulan rejimlə promise qaytarır, çünki platforma sorğunuzu rədd edə və ya korrektə edə bilər (məsələn, mobil cihazda PiP demək olar ki, həmişə fullscreen-ə çevrilir).
Rejimlərin həyat dövrünü sxematik belə təsvir etmək olar:
stateDiagram-v2
[*] --> Inline
Inline --> Fullscreen: requestDisplayMode('fullscreen')
Fullscreen --> Inline: requestDisplayMode('inline') / Geri düyməsi
Fullscreen --> PiP: requestDisplayMode('pip')
PiP --> Fullscreen: Genişləndir
PiP --> Inline: tapşırığın tamamlanması
Reallıqda adlar və rejimlərin dəqiq dəsti SDK versiyalarına görə dəyişə bilər, ona görə production-da həmişə dokumentasiyanı yoxlayın, “dərsdə necə idi”yə arxayın olmayın.
4. İlk keçid: “Tam ekrana aç” düyməsi hazırlayırıq
Kiçikdən başlayaq: əvvəlki modullardakı tədris App-ımız GiftGenius adlı mövcud inline‑vidjetimizi götürək — hazırda 3–5 hədiyyə kartı göstərir — və fullscreen-ə keçid üçün “Ətraflı seçimi aç” düyməsi əlavə edək.
Tutaq ki, şablonda iki hook var:
import { useDisplayMode, useRequestDisplayMode } from "@/sdk/display";
export const GiftGeniusWidget: React.FC = () => {
const mode = useDisplayMode();
const requestDisplayMode = useRequestDisplayMode();
if (mode === "fullscreen") {
return <GiftFullscreenWizard />;
}
return (
<InlineGiftPreview
onExpand={async () => {
await requestDisplayMode({ mode: "fullscreen" });
}}
/>
);
};
Burada InlineGiftPreview — mövcud inline‑UI-mızdır, GiftFullscreenWizard isə indi layihələndirəcəyimiz yeni vizard komponentidir. onExpand handler-ində sadəcə requestDisplayMode çağırmırıq, həm də promise-i gözləyirik — beləliklə rədd cavabına reaksiya verə bilərik (məsələn, hansısa səbəbdən fullscreen əlçatan deyilsə mesaj göstərmək).
InlineGiftPreview özü olduqca sadədir:
type InlineGiftPreviewProps = {
onExpand: () => void;
};
const InlineGiftPreview: React.FC<InlineGiftPreviewProps> = ({ onExpand }) => {
return (
<div>
<h3>Hədiyyə seçimi</h3>
{/* ...hədiyyə kartları... */}
<button onClick={onExpand}>Ətraflı seçimi aç</button>
<\/div>
);
};
Hələlik bu, “modal aç” davranışına bənzəyir, amma fərq ondadır ki, bunu sizin React yox, ChatGPT host‑tətbiqi idarə edir və o, başlıq, sistem “Geri” düyməsi və s. göstərə bilər.
5. GiftGenius üçün fullscreen‑vizardı layihələndiririk
İndi hədiyyə seçimi üçün fullscreen‑vizard layihələndirək. UX baxımından prosesi bir neçə məntiqi addıma bölmək məntiqlidir. Məsələn:
- Hədiyyə kimin üçündür və hansı münasibətlədir.
- Büdcə və hədiyyə tipi (fiziki, təəssürat, rəqəmsal).
- Yoxlama və seçimin təsdiqi.
Kodda bunu addımlara görə sadə bir vəziyyət maşını ilə əks etdirmək olar:
type WizardStep = "recipient" | "preferences" | "review";
type WizardState = {
step: WizardStep;
recipient?: { ageRange: string; relation: string };
preferences?: { budget: number; categories: string[] };
};
Bu vəziyyəti React daxilində saxlayan və uyğun ekranı render edən GiftFullscreenWizard komponentini yaradaq.
const GiftFullscreenWizard: React.FC = () => {
const [state, setState] = useState<WizardState>({ step: "recipient" });
const goNext = (partial: Partial<WizardState>) => {
setState((prev) => ({ ...prev, ...partial }));
};
if (state.step === "recipient") {
return <RecipientStep state={state} onNext={goNext} />;
}
if (state.step === "preferences") {
return <PreferencesStep state={state} onNext={goNext} />;
}
return <ReviewStep state={state} />;
};
Hər addım forması olan kiçik bir komponentdir. Məsələn, birinci addım:
type StepProps = {
state: WizardState;
onNext: (partial: Partial<WizardState>) => void;
};
const RecipientStep: React.FC<StepProps> = ({ state, onNext }) => {
const [relation, setRelation] = useState(state.recipient?.relation ?? "");
const [ageRange, setAgeRange] = useState(state.recipient?.ageRange ?? "");
return (
<div>
<h2>Kimin üçün hədiyyə seçirik?</h2>
<input
placeholder="Bu sizin üçün kimdir?"
value={relation}
onChange={(e) => setRelation(e.target.value)}
/>
<input
placeholder="Yaş (məsələn, 25–34)"
value={ageRange}
onChange={(e) => setAgeRange(e.target.value)}
/>
<button
onClick={() =>
onNext({
recipient: { relation, ageRange },
step: "preferences",
})
}
>
İrəli
</button>
</div>
);
};
İkinci addımda büdcə və kateqoriyaları toplayırıq, üçüncüdə isə artıq bu parametrlərə görə hədiyyə seçməyi bacaran callTool / MCP alətini çağırır və nəticələri göstəririk.
Vacibdir ki, fullscreen ekranda bizdə yer var:
- proqres bar və ya stepper üçün;
- daha geniş sahələr və ipucları üçün;
- xəta vəziyyətləri üçün (“nəsə səhv getdi, bir daha cəhd edin”).
UX qaydalarından tövsiyə: hər bir addım mümkün qədər sadə qalmalıdır, sahələrlə yükləməyin; bir böyük “monstr” forma əvəzinə 3–4 aydın addım daha yaxşıdır.
6. Fullscreen‑vizardın UX-i: irəliləyiş, xətalar, geri dönüş
Formanı tam ekranda göstərmək işin yarısıdır. İstifadəçi üçün vacibdir:
- hansı addımda olduğunu anlamaq;
- geri qayıtmaq imkanı;
- uzun əməliyyatlar zamanı nə baş verdiyini görmək.
Ən sadə stepper-i yalnız vizual şəkildə etmək olar:
const Stepper: React.FC<{ step: WizardStep }> = ({ step }) => {
const index = step === "recipient" ? 1 : step === "preferences" ? 2 : 3;
return <p>Addım {index} / 3</p>;
};
Və sadəcə hər ekrana Stepper-i daxil edin. Daha irəli səviyyədə üfüqi “pilləkan” çəkə bilərsiniz, amma kurs çərçivəsində detala girməyəcəyik.
Vacib məqam — xətaların işlənməsi. Tutaq ki, son addımda search_gifts alətini çağırırıq:
const ReviewStep: React.FC<StepProps> = ({ state }) => {
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const handleConfirm = async () => {
setLoading(true);
setError(null);
try {
await callTool("search_gifts", {
recipient: state.recipient,
preferences: state.preferences,
});
// Nəticələr sonra çatda / vidjetdə görünəcək
} catch (e) {
setError("Hədiyyələri seçmək alınmadı, yenidən cəhd edin.");
} finally {
setLoading(false);
}
};
return (
<div>
{/* parametrlərin xülasəsini göstərin */}
{error && <p style={{ color: "red" }}>{error}</p>}
<button disabled={loading} onClick={handleConfirm}>
{loading ? "Seçirik…" : "Təsdiqlə və seç"}
</button>
</div>
);
};
Giriş imkanı baxımından diqqət edin ki:
- fullscreen-də “İrəli”, “Geri” və “Ləğv et” kimi böyük düymələr kliklənməsi asan olsun;
- mətnin kontrastı adekvat olsun;
- Tab ilə bütün interaktiv elementləri ardıcıl keçmək mümkün olsun.
İmkan varsa, qeyri-standart kontrollerlərə (məsələn, kateqoriya seçicilərinə) aria-label əlavə etmək faydalıdır. Kurs WCAG imtahanına çevrilmir, amma a11y-yə əsas diqqət sonradan Store review-dan rahat keçməyə kömək edəcək.
Nəticədə fullscreen‑vizard çoxaddımlı mürəkkəb ssenariləri həll edir: formalar, proqres və xətalar üçün yer verir. Amma tətbiq həyatı bununla bitmir — bir çox tapşırıqlar “fon”da davam edir. Bunun üçün ikinci rejim — PiP var, indi onun haqqında danışaq.
7. ChatGPT-də PiP nədir və niyə “nazlı”dır
Mürəkkəb ssenarilər üçün fullscreen-dən necə istifadə etməyi anladıq. İndi isə əks halı nəzərdən keçirək — hər şey vacib artıq işə salınıb və yalnız irəliləyişi “nəzarətdə saxlamaq” lazımdır. Burada işə PiP daxil olur.
Veb dünyasında “picture-in-picture” adətən kontent üzərində küncdə asılan video ilə assosiasiya olunur. ChatGPT-də PiP — kiçik üzən vidjet pəncərəsidir; çat skrollu zamanı görünür qalır və status, irəliləyiş və ya kompakt UI göstərə bilər.
Dokumentasiya və early‑adopter təcrübəsindən bilməli olduğunuz bir neçə xüsusiyyət:
- PiP-də yer çox azdır. Bu, formalar və mürəkkəb layout-lar üçün məkan deyil; iki-üç əsas metrik və bir-iki düymə üçün uyğundur.
- Desktopda PiP yuxarıya “yapışır” və istənilən skrollda görünən qalır; mobil cihazlarda isə çox zaman avtomatik fullscreen-ə çevrilir.
- requestDisplayMode sorğusu mode "pip" ilə həqiqi PiP-ə zəmanət vermir. Platforma başqa rejim qaytara bilər (məsələn, fullscreen) və ya köhnə SDK versiyalarında qəribə davrana bilər; buna görə promise nəticəsini həmişə yoxlayın və fallback saxlayın.
Buradan sadə UX nəticəsi çıxır: PiP-də yalnız ən vacib olan göstərilməlidir. Taymer, çatdırılma indikatoru, tapşırıq statusu, “Genişləndir” düyməsi. 12 checkbox, 10 sütunlu cədvəl və “mənə bir də kofe hazırlayın” — yox.
8. GiftGenius + PiP: uzun axtarış və fon proqresi
GiftGenius-a qayıdaq. Ssenari təsəvvür edin: istifadəçi fullscreen‑vizarddan keçdi, “Təsdiqlə”yə basdı və indi backend xeyli ağır seçimi işə salır — ola bilsin, MCP serveri ilə bir neçə xarici API çağırırsınız, qiymətləri yenidən hesablayırsınız, bir yığın filtr tətbiq edirsiniz. Bu, məsələn, 10–20 saniyə çəkə bilər.
UX baxımından istifadəçini 20 saniyə fullscreen-də spinner ilə tutmaq istəmirsiniz. Daha yaxşısı:
- Seçimi işə salın.
- Interfeysi PiP-ə yığın və proqresi göstərin.
- İstifadəçiyə çatı davam etdirmək imkanı verin (məsələn, dəqiqləşdirici suallar vermək).
- Bitdikdən sonra — nəticəni inline qaytarın və ya hədiyyələrlə yeni fullscreen açın.
Belə davranışı idarə edəcək sadə hook yazaq:
const useLongGiftJob = () => {
const [status, setStatus] = useState<"idle" | "running" | "done">("idle");
const requestDisplayMode = useRequestDisplayMode();
const startJob = async (payload: any) => {
setStatus("running");
const resultMode = await requestDisplayMode({ mode: "pip" });
console.log("Faktiki rejim:", resultMode.mode);
await callTool("run_gift_job", payload);
setStatus("done");
await requestDisplayMode({ mode: "inline" });
};
return { status, startJob };
};
İndi ReviewStep-də birbaşa callTool yerinə bu hook-dan istifadə edirik:
const ReviewStep: React.FC<StepProps> = ({ state }) => {
const { status, startJob } = useLongGiftJob();
return (
<div>
{/* ...xülasə... */}
<button
disabled={status === "running"}
onClick={() => startJob(state)}
>
{status === "running" ? "Hədiyyələri seçirik…" : "Seçimi başlayın"}
</button>
</div>
);
};
Fon tapşırığının statusu həm fullscreen‑vizard, həm də PiP pəncərəsi üçün əlçatan olsun deyə, real kodda useLongGiftJob-u kontekstə çıxarmaq və onu useLongGiftJobContext ilə oxumaq məntiqlidir. Kontekstin detallarını (Provider, createContext) buraxırıq: vacib olan odur ki, job‑state bir yerdə yaşayır və fərqli UI qatları ona sadəcə abunə olur.
Və PiP nümayişi üçün ayrıca komponent:
const GiftPipView: React.FC<{ status: string }> = ({ status }) => {
return (
<div>
<p>GiftGenius işləyir…</p>
<p>Status: {status === "running" ? "prosesdə" : "hazır"}</p>
<button
onClick={() => window.openai.requestDisplayMode({ mode: "fullscreen" })}
>
Genişləndir
</button>
</div>
);
};
Ümumi vidjetdə render-i PiP-i də nəzərə alacaq şəkildə dəyişirik:
const GiftGeniusWidget: React.FC = () => {
const mode = useDisplayMode();
const { status } = useLongGiftJobContext(); // yuxarıda müzakirə etdiyimiz kimi kontekst vasitəsilə
if (mode === "pip") {
return <GiftPipView status={status} />;
}
if (mode === "fullscreen") {
return <GiftFullscreenWizard />;
}
return <InlineGiftPreview onExpand={/* əvvəlki kimi */} />;
};
Belə ssenari səs rejimləri ilə (onlar barədə voice dərsində danışacağıq) əla uyğunlaşır: səs ilə seçimi başlayırsınız, PiP proqresi göstərir, çat aşağıda qalır və öz həyatı ilə davam edir.
9. Video + çat: fullscreen və PiP media pleyerə çevriləndə
Tarixən PiP ən çox kontent üzərində küncdə görünən video ilə assosiasiya olunur. Buna görə “video + chat” ssenarisini ayrıca nəzərdən keçirmək məntiqlidir. Burada da sehr yoxdur: çox vaxt sadəcə videonu fullscreen və ya PiP pəncərəsində göstərirsiniz. OpenAI dokumentasiyası fullscreen və PiP istifadəsinə tipik misal kimi media ssenarilərini birbaşa göstərir.
Bu, GiftGenius üçün nə ifadə edə bilər? Məsələn:
- hədiyyənin promo-rolikini göstərmək;
- “hədiyyəni necə gözəl qablaşdırmaq olar” mövzusunda qısa dərslik;
- bir neçə məhsulun video icmalı.
Fullscreen-də tam <video>-nu təsvir və tövsiyələrlə birlikdə render edə bilərsiniz; PiP-də isə yalnız pleyeri və bəlkə kiçik bir başlıq saxlayın.
Ən sadə obyekti‑komponent:
const GiftVideoPlayer: React.FC<{ src: string; title: string }> = ({
src,
title,
}) => (
<div>
<h3>{title}</h3>
<video
src={src}
controls
style={{ width: "100%", borderRadius: 8 }}
/>
</div>
);
Fullscreen‑vizardda istifadəçiyə “Bu hədiyyənin video icmalına bax” təklifini verib sonra onu PiP-ə yığa bilərik:
const WatchVideoStep: React.FC = () => {
const requestDisplayMode = useRequestDisplayMode();
return (
<div>
<GiftVideoPlayer src="/videos/gift-wrap.mp4" title="Hədiyyəni necə qablaşdırmaq olar" />
<button
onClick={() => requestDisplayMode({ mode: "pip" })}
>
Videonu küncdə saxla və çata qayıt
</button>
</div>
);
};
Media ssenariləri üçün bir neçə praktik məsləhət:
- səsi açıq autoplay etməyin — bu, universal UX anti‑pattern-dir;
- subtitrlərə və klaviatura ilə pauza qoyma imkanına (boşluq, ox düymələri) fikir verin;
- PiP pəncərəsində bütün müşayiətedici mətni göstərməyə çalışmayın, yalnız videonun özünü saxlayın.
10. Vəziyyət, vidjetin yenidən yaradılması və mobil xüsusiyyətlər
Adətən bu mərhələdə verilən ən xoşagəlməz sual: “Inline-dan fullscreen-ə və geri keçsəm, React state saxlanılacaqmı?”
Qısa cavab: buna güvənməyin.
Texniki olaraq davranış SDK versiyasından və host implementasiyasından asılıdır: bəzən rejimlər arası keçid iframe-i yenidən yaratmadan baş verir, bəzən isə vidjet unmount olunur və yenidən mount edilir. Dokumentasiyada xüsusi vurğulanır ki, rejim dəyişəndə kontekstin saxlanılması konkret SDK implementasiyasından və versiyasından asılıdır və developer üçün zəmanət deyil.
Praktik yanaşma:
- Bütün kritik vəziyyəti (vizard addımı, daxil edilən məlumatlar, fon tapşırığının identifikatoru) ya:
- backend-də saxlayın (MCP serveriniz və sessiya tokenləri vasitəsilə),
- ya da ChatGPT kontekstində (məsələn, “workflow-un cari vəziyyətini” qaytaran alətlər vasitəsilə),
- ya da təhlükəsiz əsas varsa URL parametrlərində/local storage-da.
- React state-i UI keş/qatı kimi istifadə edin, amma rejim dəyişəndə sıfırlana biləcəyinə hazır olun — onda onu daha etibarlı mənbədən bərpa edirsiniz.
İkinci incəlik nəticə ilə bağlıdır: requestDisplayMode. Qeyd olunduğu kimi, mode "pip" sorğusu xüsusilə mobil cihazlarda tez-tez "fullscreen" kimi qayıda bilər — yəni həqiqi PiP dəstəklənmir və ya avtomatik tam ekrana açılır.
Tipik şablon:
const requestDisplayMode = useRequestDisplayMode();
const openPipSafe = async () => {
const result = await requestDisplayMode({ mode: "pip" });
if (result.mode !== "pip") {
// Fallback: məsələn, mesaj göstərmək və ya UI-ni fullscreen-ə uyğunlaşdırmaq
console.log("PiP əlçatandır deyil, bu rejimdə işləyirik:", result.mode);
}
};
Beləliklə, kiçik pəncərə gözləyib PiP-ə xas düymələrlə tam ekran UI almayacaqsınız. Belə halda interfeys qəribə görünəcək.
Nəhayət, maxHeight və daxili skrollu unutmayın: hətta fullscreen-də host konteynerin hündürlüyünü məhdudlaşdıra bilər və sizin vəzifəniz — üçqat skroll çubuğu yaranmasın deyə skrollu düzgün təşkil etməkdir.
11. Fullscreen və PiP ilə işləyərkən tipik səhvlər
Səhv №1: Fullscreen defolt rejim kimi.
Bəzi developer-lər “fullscreen” sözünü görən kimi App-ını çat daxilində ayrıca bir SPA-ya çevirməyə çalışırlar. Nəticədə hədiyyələrdən söz düşən kimi — istifadəçi dərhal tam ekran vizarda düşür, halbuki sadəcə bir neçə ideya istəyirdi. OpenAI qaydaları israrla inline-dan başlamağı və yalnız obyektiv zərurət olduqda fullscreen-ə genişlənməyi tövsiyə edir.
Səhv №2: PiP-i kiçik fullscreen kimi görmək.
PiP-in sahəsi çox məhduddur, amma bəzən ora hər şeyi yığmağa çalışırlar: tablar, formalar, filtrlər. İstifadəçi mikroskopik və istifadəolunmaz bir interfeys alır. Düzgün yanaşma — PiP-də yalnız status və bir-iki əsas düymə göstərməkdir (məsələn, “Genişləndir” və “Ləğv et”).
Səhv №3: Rejimlər arasında izahsız keçidlər.
Vidjet istifadəçinin açıq klikindən və ya GPT-dən gələn mətn olmadan qəfil fullscreen-ə açılarsa, bu çaşdırır. Eyni şey PiP-ə auto-minimallaşdırma və ya inline-a qayıtma üçün də doğrudur. Hər keçidi model mesajında qısa izahla müşayiət edin: fullscreen-dən əvvəl “İndi ətraflı vizardı açacağam”, PiP-dən əvvəl “Hesablama gedərkən seçimi kiçik pəncərəyə yığıram”.
Səhv №4: Mobil və platforma fərqlərini görməməzlikdən gəlmək.
Developer yalnız desktopda test edir, burada PiP gözlənildiyi kimi davranır, sonra mobil cihazda hər şey fullscreen-ə çevrilir, layout “dağılır”, düymələr safe‑area xaricində qalır. Dokumentasiya açıq şəkildə xəbərdar edir ki, mobil cihazlarda PiP fullscreen kimi həyata keçirilə bilər və davranış SDK versiyaları arasında dəyişə bilər; buna görə hədəf cihazlarda test və requestDisplayMode ilə diqqətli işləmək mütləqdir.
Səhv №5: Rejim dəyişəndə vəziyyətin qorunmasına tam inam.
Hər hansı server/perzistent dəstək olmadan yalnız React state-ə güvənmək gülməli situasiyalara gətirir: istifadəçi vizardın iki addımını keçdi, “PiP-ə yığ” düyməsini basdı və qayıdanda birinci addımda boş sahələrlə qaldı. Daha yaxşısı, rejim dəyişəndə komponentinizin unmount oluna biləcəyini qəbul edib, state‑menecmenti bu riskə uyğun layihələndirməkdir.
Səhv №6: Fullscreen‑vizardın giriş imkanını (a11y) unutmaq.
Böyük ekranda gözəl forma zəif görənlər və ya yalnız klaviatura istifadə edənlər üçün həmişə rahat olmur. Çox xırda mətn, aşağı kontrast, oxunmaz “İrəli” və “Geri” düymələri — yalnız pis UX deyil, həm də Store review-da problemlərin tipik səbəbləridir. Heç olmasa əsas şeyləri yoxlamağa dəyər: mətn kontrastı, şrift ölçüsü, Tab naviqasiyasının işləməsi və düymələr üçün anlaşılan mətn etiketləri.
GO TO FULL VERSION