दस्तावेज़
डिज़ाइन गाइड
Native Shell से बने ऐप के लिए कंपोनेंट चुनने या लेआउट कोड लिखने से पहले इस गाइड का उपयोग करें। इसमें वह प्रोडक्ट-विवेक दर्ज है जो GPUI Kit ने डेस्कटॉप पर वर्षों के काम में जमा किया और जिसे NSH में आगे बढ़ाया गया है: इंटरफ़ेस नेटिव, संयमित, सटीक और बिना अंदाज़े के समझ में आने वाला लगना चाहिए।
यह एक मानक (normative) गाइड है। अनिवार्य किसी शुद्धता या इकोसिस्टम की बाध्यता को दर्शाता है, चाहिए वह डिफ़ॉल्ट है जिसे बदलने के लिए ठोस कारण चाहिए, और वैकल्पिक एक ऐच्छिक तकनीक है। अलग-अलग props और मेथड के लिए Elements और API पृष्ठ ही प्रामाणिक स्रोत बने रहते हैं।
ये नियम nsh/base (Rust में nsh_base), थीम और उसके टोकन, तथा हर प्लेटफ़ॉर्म के उपयोगकर्ताओं को पहले से परिचित इंटरैक्शन के व्यवहार पर आधारित हैं। NSH हर प्लेटफ़ॉर्म की अपनी UI से रेंडर करता है और रूप-रंग ऐप पर छोड़ देता है: nsh/base के कंपोनेंट व्यवहार, स्टेट, फ़ोकस और एक्सेसिबिलिटी देते हैं, जबकि हर रंग, आकार, रेडियस और स्पेसिंग ऐप के अपने कंपोनेंट से आती है, इसलिए ये नियम ऐप के डिज़ाइन सिस्टम का मार्गदर्शन करते हैं। shadcn/ui उपयोगी तरीके देता है (ओपन कोड, कंपोज़िशन और भरोसेमंद डिफ़ॉल्ट), लेकिन यह तय नहीं करता कि NSH ऐप कैसा दिखे। जब प्रभावों में टकराव हो, तो प्लेटफ़ॉर्म के व्यवहार और उस इंटरैक्शन को सुरक्षित रखें जिसे लोग पहले से समझते हैं।
#डिज़ाइन सिद्धांत
ऐसे इंटरफ़ेस बनाएँ जो नेटिव, शांत और सटीक लगें। अनुभव को कंटेंट, पदानुक्रम और इंटरैक्शन उठाने दें; सजावट उनका सहयोग करे, उनसे प्रतिस्पर्धा नहीं।
- व्यक्तित्व से पहले स्पष्टता। ब्रांड की अभिव्यक्ति जोड़ने से पहले मुख्य कार्य और अगली कार्रवाई स्पष्ट करें।
- आविष्कार से पहले कंपोज़िशन। स्थापित कंपोनेंट से शुरू करें और उन्हें प्रोडक्ट-विशिष्ट वर्कफ़्लो में जोड़ें। नया प्राइमिटिव तभी बनाएँ जब उसका व्यवहार वास्तव में नया हो।
- मानों से पहले टोकन। रंग, रेडियस, टाइपोग्राफ़ी और स्पेसिंग एक सिस्टम बनाएँ। ऐसे अलग-थलग लिटरल से बचें जो थीम के अनुसार नहीं बदल सकते। देखें Styling, Tailwind और थीम।
- वेब की परिपाटी से पहले प्लेटफ़ॉर्म। जहाँ कार्य को लाभ हो, वहाँ डेस्कटॉप पर कीबोर्ड एक्सेस, विंडो क्रोम, मेन्यू, सघन डेटा व्यू, आकार बदलने योग्य क्षेत्र और स्थायी नेविगेशन को बनाए रखें, और फ़ोन व टैबलेट पर सिस्टम के हेडर, बैक जेस्चर, अलर्ट और टच टारगेट को।
- स्टेट दिखनी चाहिए। Hover, pressed, फ़ोकस, चयन, disabled, लोडिंग, वैलिडेशन और विनाशकारी स्टेट को अलग और एकसमान ट्रीटमेंट चाहिए।
- ज्यामिति समाहित होने को समझाती है। रेडियस, इनसेट और सीमाएँ एक सुसंगत पदानुक्रम बताएँ, भले ही सतहें एक-दूसरे पर चढ़ी हों।
- फ़ीडबैक वास्तविकता को दर्शाए। लोडिंग, टूलटिप और मोशन किसी वास्तविक स्टेट या बदलाव को स्पष्ट करें, तुरंत होने वाली कार्रवाई में औपचारिकता न जोड़ें।
#Shadcn से सीख
Shadcn का सबसे उपयोगी योगदान कोई खास बॉर्डर रंग नहीं है। वह सिस्टम बनाने का एक तरीका है:
- इंटरफ़ेस की ऊपरी परत के मालिक बनें, बंद एब्स्ट्रैक्शन से जूझने के बजाय;
- छोटे, अनुमानित हिस्सों को जोड़कर प्रोडक्ट-विशिष्ट कंपोनेंट बनाएँ;
- ऐसे डिफ़ॉल्ट दें जो पहले से एक दृश्य भाषा बनाते हों;
- कोड और कंपोज़िशन को लोगों और AI दोनों के लिए पठनीय रखें;
- व्यवहार वाले प्राइमिटिव को स्टाइल वाली परत से अलग रखें।
NSH इन विचारों को nsh के प्राइमिटिव, nsh/base के बिना-स्टाइल वाले बेस कंपोनेंट और स्टाइल वाली परत के विभाजन से लागू करता है, और स्टाइल वाली परत ऐप की होती है (तीन परतें)। ऐप अपने कंपोनेंट nsh/base पर बनाते हैं, TSX में या ऐप के Rust क्रेट में; दोबारा उपयोग होने वाला व्यवहार nsh/base में रहे, और दृश्य नीति उसके ऊपर रहे।
इन वेब मान्यताओं की आँख मूँदकर नकल न करें:
| वेब की आदत | NSH डिफ़ॉल्ट |
|---|---|
| हर बटन पर पॉइंटिंग-हैंड कर्सर | डिफ़ॉल्ट कर्सर; लिंक के लिए पॉइंटिंग हैंड (cursor-pointer) |
| मुख्य ढाँचे के रूप में पेज नेविगेशन | डेस्कटॉप पर स्थायी विंडो, पेन, साइडबार, टैब और मेन्यू; फ़ोन पर सिस्टम के बैक के साथ NavStack |
| फ़ॉलबैक के रूप में ब्राउज़र फ़ोकस और स्क्रॉलिंग | स्पष्ट फ़ोकस स्वामित्व और क्षेत्र-स्वामित्व वाली स्क्रॉलिंग (Scroll, List) |
| मोबाइल-फ़र्स्ट सिंगल कॉलम | फ़ोन पर एक कॉलम, डेस्कटॉप पर निर्धारित न्यूनतम विंडो आकार वाला आकार बदलने योग्य शेल |
| Hover पर दिखने वाली ज़रूरी कार्रवाइयाँ | ऐसी कार्रवाइयाँ जो कीबोर्ड, टच और पॉइंटर से पहुँच में हों और hover पर निर्भर न हों |
| सिर्फ़ hover पर दिखने वाले आइकन बटनों की पंक्ति | एक दृश्यमान प्राथमिक कार्रवाई, और द्वितीयक कमांड के लिए Menu या ContextMenu |
| ऐप कमांड के लिए लिंक-स्टाइल टेक्स्ट | ऐप की default, outline या ghost स्टाइल में Button; लिंक स्टाइलिंग केवल URL, वेब संसाधनों या ईमेल पतों के लिए |
| हर जगह बड़ी टच सघनता | टच स्क्रीन पर टच-आकार के टारगेट; पॉइंटर के साथ मध्यम सघनता, और कॉम्पैक्ट केवल वहाँ जहाँ सूचना-कार्य को लाभ हो |
| हर प्लेटफ़ॉर्म पर बनाया हुआ हेडर और अलर्ट कार्ड | iOS और Android पर सिस्टम का हेडर और AlertDialog; डेस्कटॉप और वेब पर पेज का header स्लॉट |
| वंशजों पर CSS ओवरराइड | ऐप के कंपोनेंट, उनके पार्ट और थीम के टोकन |
#कार्य से शुरू करें
स्क्रीन बनाने से पहले लिख लें:
- उपयोगकर्ता का मुख्य कार्य;
- जिस ऑब्जेक्ट को देखा या बदला जा रहा है;
- वे कार्रवाइयाँ जो तुरंत उपलब्ध रहनी चाहिए;
- निर्णय लेने के लिए आवश्यक जानकारी;
- खाली, लोडिंग, त्रुटि, ऑफ़लाइन, केवल-पढ़ने योग्य और अनुमति-अस्वीकृत स्टेट;
- वर्कफ़्लो में कीबोर्ड, टच और स्क्रीन-रीडर का रास्ता;
- ऐप कहाँ दिखाया जाता है: अकेले, या किसी होस्ट ऐप के अंदर।
स्क्रीन को इन्हीं उत्तरों के इर्द-गिर्द व्यवस्थित करें। डैशबोर्ड ग्रिड या कंपोनेंट कैटलॉग से शुरुआत न करें। अच्छा इंटरफ़ेस उपयोगकर्ता का मानसिक मॉडल सामने रखता है: दस्तावेज़, खाते, प्रोजेक्ट, संदेश, सेटिंग या कोई और स्थिर ऑब्जेक्ट, न कि आंतरिक सर्विस आर्किटेक्चर।
कंट्रोल बाँटने से पहले मुख्य कार्य डिज़ाइन करें। उसका दृश्य भार, स्थान और सूचना की गहराई प्रोडक्ट में उसके महत्व के अनुरूप हो। जब गौण कंटेंट पेज घेर रहा हो, तब मुख्य परिणाम को छोटी गिनती, कोने के आइकन या कमज़ोर फ़ुटर कार्रवाई तक सीमित नहीं करना चाहिए। जब परिणाम-समूह ही प्रोडक्ट का मुख्य मूल्य हो, तो ऐसा सारांश क्षेत्र या कार्ड सोचें जो गिनती, प्रतिनिधि परिणाम, सार्थक स्टेट और स्पष्ट अगली कार्रवाई दिखाए।
प्रस्तावित हर कार्रवाई के लिए उसका दृश्यमान ऑब्जेक्ट, मौजूदा स्टेट, दायरा और परिणाम बताएँ। यदि इंटरफ़ेस ये बातें दिखाता या स्पष्ट रूप से इंगित नहीं करता, तो कार्रवाई समय से पहले है। किसी क्षमता को केवल इसलिए सामने न रखें कि बैकएंड में वह है; पहले डिज़ाइन करें कि ऑब्जेक्ट उपयोगकर्ता के मानसिक मॉडल में कैसे प्रवेश करता है।
#दृश्य भाषा
#पदानुक्रम
कुछ स्पष्ट स्तरों को प्राथमिकता दें:
- विंडो या पेज शीर्षक मौजूदा ऑब्जेक्ट या वर्कस्पेस की पहचान कराता है;
- सेक्शन शीर्षक सार्थक क्षेत्रों को अलग करता है (
role="header", ताकि स्क्रीन रीडर उनके बीच कूद सकें); - बॉडी टेक्स्ट काम का कंटेंट रखता है;
- म्यूट टेक्स्ट द्वितीयक मेटाडेटा और सहायता देता है;
- लेबल कंट्रोल और मानों की पहचान कराते हैं।
रंग या कंटेनर जोड़ने से पहले आकार, वज़न, स्पेसिंग और विभाजकों का उपयोग करें। कार्ड के अंदर कार्ड रखने से बचें: अधिकांश क्षेत्रों को केवल एक बैकग्राउंड, एक हेयरलाइन सीमा और सोची-समझी स्पेसिंग चाहिए।
पदानुक्रम का मूल्यांकन पूरी फ़ीचर पर करें, कंपोनेंट-दर-कंपोनेंट नहीं। समीक्षा के दौरान एक्सेंट रंग और सजावट छिपा दें: मुख्य कार्य, मौजूदा चयन, परिणाम सारांश और अगली कार्रवाई तब भी संरचना से स्पष्ट होनी चाहिए। जिस स्क्रीन के कंट्रोल अलग-अलग ठीक लगते हों, वह भी विफल हो सकती है यदि वे एक पठन-क्रम और एक निर्णय-पथ नहीं बनाते।
ज़ोर को सीमित बजट मानें। एक स्थानीय सतह को एक स्पष्ट केंद्र-बिंदु चाहिए, प्रतिस्पर्धी हाइलाइट का जमावड़ा नहीं। यदि सब कुछ रंगीन, बैज वाला, बोल्ड, बॉक्स में बंद या अलर्ट में बदला हुआ है, तो कुछ भी महत्वपूर्ण नहीं दिखता। प्राथमिकता पहले संरचना और निकटता से तय करें; गहरा रंग और अधिक कंपोनेंट केवल वहीं खर्च करें जहाँ कोई भेद इस बात को बदलता है कि उपयोगकर्ता क्या नोटिस करता या करता है।
#रंग और थीम
रंग थीम से पढ़ें (Rust में theme(), TSX में टोकन क्लास) और उन्हें सिमेंटिक भूमिका के अनुसार उपयोग करें:
- मुख्य सतह और टेक्स्ट के लिए
backgroundऔरforeground; - अपनी नामित सतहों के लिए
card,popover,sidebarऔर उनके फ़ोरग्राउंड टोकन; - सहायक जानकारी के लिए
mutedऔरmuted-foreground; - मुख्य कार्रवाई या चयन के ज़ोर के लिए
primary, और शांत ज़ोर तथा hover या फ़ोकस वाली पंक्तियों के लिएsecondaryऔरaccent; destructiveकेवल विनाशकारी कार्रवाइयों और त्रुटियों के लिए, और ऐप द्वारा अपनी थीम में जोड़े गए स्टेटस रंग (success,warning) केवल अपने अर्थों के लिए;- डेटा सीरीज़ के लिए
chart-1सेchart-5तक; - संरचना और इंटरैक्शन के लिए
border,inputऔरring।
use nsh_base::theme;
view()
.rounded(move || theme().radius)
.border_1()
.border_color(move || theme().border)
.bg(move || theme().background)
.p_4()
.gap_1()
.child(text("Balance").text_color(move || theme().foreground))
.child(text("Updated just now").text_sm().text_color(move || theme().muted_foreground))<View class="gap-1 rounded-(--radius) border border-border bg-background p-4">
<Text class="text-foreground">Balance</Text>
<Text class="text-sm text-muted-foreground">Updated just now</Text>
</View>सिमेंटिक स्टेटस रंग को सजावट के रूप में उपयोग न करें। अर्थ को केवल रंग से एन्कोड न करें। हर कस्टम सतह को लाइट और डार्क थीम में और कस्टम थीम मानों के साथ जाँचें, जिनमें आपको एम्बेड करने वाले होस्ट ऐप की थीम भी शामिल है; यह कभी न मानें कि फ़ोरग्राउंड काला है या बैकग्राउंड सफ़ेद।
बैज का उपयोग छोटी स्टेट, गिनती या वर्गीकरण के लिए करें जिसे तेज़ स्कैन से लाभ हो, हर लेबल, मेटाडेटा मान, फ़िल्टर या सेक्शन शीर्षक के लिए नहीं। अधिकांश बैज न्यूट्रल रखें; सिमेंटिक रंग उन स्टेट के लिए सुरक्षित रखें जो वास्तव में सफलता, चेतावनी, विनाश या सूचना का अर्थ रखती हों। बहुरंगी बैजों की पंक्ति आमतौर पर पदानुक्रम या समूहीकरण के छूटे हुए निर्णय का संकेत होती है।
ऐप UI में रॉ hex, rgb()/rgba() या hsl() रंग, या bg-zinc-100 जैसी पैलेट क्लास नहीं होनी चाहिए। रंग थीम से सिमेंटिक भूमिका के अनुसार हल करें। यदि आवश्यक भूमिका मौजूद नहीं है, तो उसे ऐप की थीम फ़ाइल में परिभाषित करें (Theme tokens: इसके light और dark में "up": "#16a34a" से TSX में text-up, bg-up/30, token("up") और Rust में theme().color("up") बनते हैं), बजाय इसके कि कॉल साइट पर पैलेट मान डालें। रॉ रंग केवल थीम परिभाषाओं के अंदर या ऑडिट किए गए डेटा/रास्टर कंटेंट में होने चाहिए जिनका रंग ही डेटा है।
#रेडियस, स्पेसिंग और सघनता
टाइप और कंट्रोल आकारों की तरह रेडियस का भी सीमित पैमाना रखें। हर एलिमेंट के लिए नया रेडियस गढ़ने के बजाय थीम के radius (कंट्रोल और सतहों दोनों के लिए, rounded-(--radius)), ऐप द्वारा थीम में जोड़े गए रेडियस, और Tailwind के rounded-sm … rounded-2xl में से उनके बीच के मान चुनें। बड़े कंटेनर अपने भीतर के कंट्रोल से अधिक मुलायम स्तर ले सकते हैं; कॉम्पैक्ट कंट्रोल और ओवरले कसे हुए स्तर लें। सामान्य आयत के लिए रेडियस उसकी छोटी भुजा के आधे से स्पष्ट रूप से कम रहना चाहिए। rounded-full (.rounded_full()) केवल जान-बूझकर बनाए गए वृत्तों और पिल के लिए उपयोग करें; टूलटिप गलती से कैप्सूल नहीं बनना चाहिए।
नेस्टेड सतहें संकेंद्री आकृतियों जैसी दिखनी चाहिए। निकटतम उपयुक्त रेडियस चुनने के लिए inner radius ≈ max(0, outer radius − gap) का उपयोग करें; मोड़ के दौरान दिखने वाली पट्टी एकसमान रहे। यदि कोई दोहराई जाने वाली कंपोज़िशन बीच का मान माँगती है, तो थीम में नामित टोकन जोड़ें ("radius-inset": "0.375rem", rounded-(--radius-inset))। सेगमेंटेड कंट्रोल एक ही सिल्हूट है: उसके सिरों के सेगमेंट कंटेनर के भीतरी कोनों का अनुसरण करते हैं, बीच के सेगमेंट चौकोर रहते हैं, और हर सीमा पर एकसमान मोटाई का एक ही विभाजक होता है।
रेडियस पूरी दृश्यमान सतह पर लागू होना चाहिए, केवल उसके बॉर्डर पर नहीं। खुले कोने अपने पीछे की सतह के लिए पारदर्शी रहें; चाइल्ड बैकग्राउंड, चयन फ़िल और स्क्रॉल होता कंटेंट भी सीमा का अनुसरण करें। भीतरी सतहों को उनका अपना रेडियस दें, या कंटेनर को overflow-hidden (.overflow_hidden()) से क्लिप करें, फिर दोनों थीम में विपरीत बैकग्राउंड पर कंपोज़िशन की जाँच करें। क्लिप चुनते समय बाहरी फ़ोकस रिंग सुरक्षित रखें।
संक्षिप्त स्पेसिंग पैमाना उपयोग करें और उसे दोहराएँ। संबंधित लेबल/कंट्रोल जोड़े अलग समूहों से अधिक पास हों; अलग समूह अलग सेक्शनों से अधिक पास हों। एक-बार की ऊँचाइयों के बजाय ऐप के कंपोनेंट के आकारों (small, डिफ़ॉल्ट medium, large) को प्राथमिकता दें। कॉम्पैक्ट वेरिएंट टूलबार और डेटा-सघन स्क्रीन के लिए उपयोग करें, अस्पष्ट लेआउट को कम जगह में ठूँसने के लिए नहीं।
साझा सिमेंटिक पैमाना जान-बूझकर छोटा रखा गया है: स्पेसिंग लगभग 2, 4, 8, 12, 16, 24 और 32 पॉइंट के क्रम में बढ़ती है, जबकि टाइपोग्राफ़ी 12, 14, 16, 18 और 20 पॉइंट के आसपास रहती है। इन्हें संबंध मानें, इस बात की अनुमति नहीं कि इनके वर्तमान मान फ़ीचर कोड में बिखेर दिए जाएँ। Tailwind का स्पेसिंग पैमाना इन्हें देता है: एक स्टेप 4 पॉइंट है (p-4 यानी 16pt), क्लास और टाइप्ड Rust मेथड दोनों में; nsh.json के "tailwind" में "spacing" क्लास का स्टेप बदलता है, जबकि टाइप्ड मेथड Tailwind का डिफ़ॉल्ट पैमाना रखते हैं। जिस ऐप को अलग पैमाना चाहिए, वह उसका स्वामी अपने कंपोनेंट या थीम टोकन (p-(--gap-card)) में बने और उसे एकरूपता से उपयोग करे।
#स्पेसिंग का व्याकरण
स्पेसिंग संबंध को व्यक्त करती है। सिमेंटिक स्केल से गैप चुनने के लिए यह पूछें कि दोनों चीज़ें एक-दूसरे के लिए क्या अर्थ रखती हैं:
| संबंध | सामान्य क्लास | वर्तमान स्केल | उदाहरण |
|---|---|---|---|
| ऑप्टिकल करेक्शन | gap-0.5 | 2 pt | आइकन बेसलाइन, कॉम्पैक्ट सेपरेटर |
| एक कंट्रोल के हिस्से | gap-1 | 4 pt | मेनू आइकन/लेबल, शीर्षक/विवरण |
| निकट से संबंधित कंट्रोल | gap-2 | 8 pt | बटन आइकन/लेबल, डायलॉग एक्शन |
| एक कंटेंट समूह | gap-3 | 12 pt | नोटिफिकेशन कॉलम, कॉम्पैक्ट फ़ॉर्म पंक्तियाँ |
| एक सेक्शन में अलग-अलग समूह | gap-4 | 16 pt | पैनल पैडिंग, फ़ॉर्म समूह |
| अलग-अलग सेक्शन | gap-6 | 24 pt | पेज या इंस्पेक्टर के प्रमुख ब्लॉक |
| प्रमुख क्षेत्र की सीमा | gap-8 | 32 pt | एम्प्टी-स्टेट की खुली जगह, पेज बैंड |
ये मान डिफ़ॉल्ट स्केल का वर्णन करते हैं, दोहराने के लिए शाब्दिक मान नहीं हैं। स्पेसिंग क्लासेस और टाइप्ड मेथड (gap-2,
.gap_2(), p-4, .p_4()) या थीम के टोकन का उपयोग करें। उत्पाद का अपना स्केल क्रम और संबंधों को बनाए रखे, और उसे हर कॉल साइट पर लिखने के बजाय एप्लिकेशन के अपने कंपोनेंट्स के माध्यम से पास किया जाए।
क्षैतिज और ऊर्ध्वाधर स्पेस तय करते समय इन नियमों का उपयोग करें:
- पहले अंदर, फिर बाहर। कंपोनेंट की पैडिंग उसी कंपोनेंट की होती है; कंपोनेंट्स के बीच का गैप उनके पैरेंट का होता है।
- ऊर्ध्वाधर लय समूहीकरण दिखाती है। शीर्षक और उसके विवरण के बीच का गैप, उस विवरण से अगले सेक्शन तक के गैप से छोटा होता है। समान गैप समान संबंध दर्शाते हैं।
- क्षैतिज स्पेस स्कैनिंग में सहायक होती है। दोहराई जाने वाली पंक्तियों में आइकन, लेबल, मान, बैज और ट्रेलिंग एक्शन स्थिर कॉलम में रहें।
- लीडिंग और ट्रेलिंग सिमेंटिक हैं। रीडिंग-ऑर्डर के किनारों के आधार पर सोचें और उन्हें start और end के रूप में लिखें (
ps-*,me-*,.ps_4()), ताकि लेआउट दाएँ-से-बाएँ में मिरर हो जाए। - पैडिंग को दोगुना न करें। पहले से पैडिंग वाले पैनल में रखा गया कार्ड अपने आप एक और पूरा पैनल इनसेट न जोड़े।
- ऑप्टिकल अलाइनमेंट का उपयोग कम करें। आइकन या ग्लिफ़ की ज्यामिति के लिए एक या दो पॉइंट का करेक्शन मान्य है, लेकिन दस्तावेज़ में लिखें कि वह स्केल से अलग क्यों है।
सामान्य कंपोज़िशन इन संबंधों को स्पष्ट करते हैं:
- बटन की सामग्री छोटे आकार में 4 pt और सामान्य आकार में 8 pt का उपयोग करती है;
- डायलॉग हेडर और फ़ुटर 8 pt का आंतरिक गैप रखते हैं;
- कॉम्पैक्ट लिस्ट और मेनू पंक्तियाँ 4 pt ऊर्ध्वाधर और 8–12 pt क्षैतिज पैडिंग रखती हैं;
- शीट हेडर में लगभग 16 pt लीडिंग और 12 pt ट्रेलिंग स्पेस होता है, जिससे क्लोज़ एफ़ोर्डेंस के लिए जगह बचती है, जबकि फ़ुटर 16 pt क्षैतिज और 12 pt ऊर्ध्वाधर स्पेस रखते हैं;
- नोटिफिकेशन 16 pt क्षैतिज पैडिंग और 12 pt कॉलम गैप का उपयोग करते हैं, क्योंकि आइकन, संदेश और एक्शन अलग-अलग समूह हैं।
इन्हें हर सतह के लिए कॉपी-पेस्ट रेसिपी न समझें। ये सिस्टम को उजागर करते हैं: कंट्रोल भीतर से अधिक कसे होते हैं, पंक्तियाँ स्कैनिंग के लिए अनुकूलित होती हैं, और कंटेनर अपनी सामग्री के बीच की तुलना में अपनी सीमा पर अधिक स्पेस खर्च करते हैं।
#अनुपात और लेयर पदानुक्रम
पहले कंटेंट की आवश्यकताओं से शुरू करें, फिर अनुपात तय करें। जब किसी पेन की भूमिका स्पष्ट रूप से अलग हो, तो मनमाने आधे-आधे विभाजन से बचें।
- नेविगेशन साइडबार इतना चौड़ा हो कि लेबल स्थिर रहें, लेकिन कार्य क्षेत्र के सामने स्पष्ट रूप से गौण दिखे। उसे केवल प्रतिशत देने के बजाय न्यूनतम, पसंदीदा और अधिकतम चौड़ाई दें (
min-w-*,w-*,max-w-*)। - मास्टर–डिटेल लेआउट में कलेक्शन को स्कैन करने योग्य रहने दें और अतिरिक्त स्पेस डिटेल पेन को दें। लगभग एक-तिहाई/दो-तिहाई का प्रारंभिक बिंदु अक्सर उपयोगी होता है, लेकिन कंटेंट की सीमाएँ ही निर्णायक हैं। फ़ोन पर ये दोनों
NavStackके दो पेज बन जाते हैं। - इंस्पेक्टर और सहायक शीट्स डिफ़ॉल्ट रूप से प्राथमिक ऑब्जेक्ट को नहीं ढकें। उनकी सामग्री बढ़ने पर वे आकार बदलने योग्य या बंद करने योग्य हों;
Sheetअपने बैकड्रॉप, Escape और बैक से बंद होता है। - डायलॉग की चौड़ाई निर्णय से तय होती है: छोटी पुष्टि के लिए
AlertDialog, मध्यम फ़ॉर्म, या जटिल कार्य के लिए समर्पित विंडो/पेज। केवल खाली जगह बनाने के लिए डायलॉग को बड़ा न करें। - सबसे मज़बूत एलिवेशन सबसे ऊपरी निर्णय लेयर के लिए सुरक्षित रखें। एक लेयर के भीतर पदानुक्रम दिखाने के लिए क्रमशः बड़े शैडो के बजाय बैकग्राउंड और हेयरलाइन का उपयोग करें।
हर प्रमुख क्षेत्र के लिए तीन आकार-सीमाएँ परिभाषित करें: वह न्यूनतम जिस पर उसका कार्य अब भी काम करे, एक आरामदायक डिफ़ॉल्ट, और वह अतिरिक्त स्पेस का उपयोग कैसे करता है। जब उपयोगकर्ता-नियंत्रित स्प्लिट वर्कफ़्लो की पसंद को दर्शाते हों, तो उन्हें सहेजें, और पुनर्स्थापित मानों को वर्तमान विंडो के अनुसार क्लैम्प करें।
#अलाइनमेंट के विवरण
अलाइनमेंट एक संरचनात्मक प्रणाली है, अंतिम पॉलिश का चरण नहीं। हर सतह के लिए अलाइनमेंट स्पाइन का एक छोटा सेट स्थापित करें: साझा लीडिंग और ट्रेलिंग किनारे, टेक्स्ट बेसलाइन, सेंटर लाइनें, और निश्चित कार्यात्मक लेन। एक ही स्तर के एलिमेंट ऊपर से नीचे या लीडिंग से ट्रेलिंग तक एक ही स्पाइन से जुड़े हों, भले ही वे अलग-अलग कंपोनेंट प्रकार के हों।
ऊर्ध्वाधर लाल रेखाएँ कंटेंट, स्टेटस, समय और ट्रेलिंग एक्शन के साझा किनारों या कंट्रोल सेंटर के पास होती हैं। क्षैतिज रेखाएँ टेक्स्ट बेसलाइन के नीचे होती हैं या बॉटम और वर्टिकल-सेंटर अलाइनमेंट दिखाने के लिए पंक्ति के केंद्र से गुज़रती हैं। कॉम्पैक्ट तुलना एक रेंडर किए गए पिक्सेल के ड्रिफ़्ट को अलग करके दिखाती है, जिसे उसके संरचनात्मक स्वामी पर ठीक किया जाना चाहिए।
- सहोदर क्षेत्रों को साझा कंटेंट इनसेट दें। एक ही स्तर का वर्णन करने वाले हेडिंग, टूलबार, लिस्ट पंक्ति, एम्प्टी स्टेट और फ़ुटर में से हर एक अपना थोड़ा अलग लीडिंग किनारा न बनाए।
- कॉलम ज्यामिति को पूरे क्षेत्र में दोहराएँ। हेडर, पंक्तियाँ, सारांश, लोडिंग स्टेट और इनलाइन एडिटर पहचान, मेटाडेटा, स्टेटस, संख्याओं और एक्शन के लिए वही लेन आरक्षित करें।
- पंक्तियों और सेक्शन में संबंधित कंट्रोल को अलाइन करें। फ़ॉर्म लेबल, फ़ील्ड, विवरण और वैलिडेशन संदेश पेज को ऊपर से नीचे स्कैन करने पर एक स्थिर ऊर्ध्वाधर ग्रिड दिखाएँ।
- क्षैतिज बैंड को सुसंगत रखें। टूलबार, हेडर, स्टेटस बार या पंक्ति साझा करने वाले आइटम अलग-अलग ट्यून किए गए ऑफ़सेट के बजाय एक ही बेसलाइन या सेंटर लाइन का उपयोग करें।
- इंडेंटेशन केवल वास्तविक पदानुक्रम, कंटेनमेंट या डिस्क्लोज़र के लिए लाएँ। सजावटी इंडेंटेशन सहोदरों को अधीनस्थ दिखाता है और सतह की रीडिंग लाइन तोड़ देता है।
- जब कोई नेस्टेड स्तर समाप्त हो, तो ठीक पैरेंट स्पाइन पर लौटें। संचित पैडिंग को नेस्टेड कंटेनरों में ड्रिफ़्ट न होने दें।
- वैकल्पिक कंटेंट के बावजूद स्पाइन को बनाए रखें। गायब आइकन, बैज, विवरण या ट्रेलिंग एक्शन शेष लेबल को न हिलाएँ; जब पंक्तियों की आपस में तुलना मायने रखती हो, तो जानबूझकर बनाए गए स्लॉट या लेन का उपयोग करें।
- प्रमुख क्षेत्रों को एक-दूसरे से तब अलाइन करें जब उनका पदानुक्रम मेल खाता हो। साइडबार हेडर, कंटेंट शीर्षक, स्प्लिट पेन, टूलबार और बॉटम बार का हर निर्देशांक साझा करना आवश्यक नहीं है, लेकिन समान स्तर की रेखाएँ दिखने में निरंतर होनी चाहिए।
हर किनारा अलाइन नहीं होना चाहिए। कोई चाइल्ड इंडेंट हो सकता है, कोई प्राथमिक मान अपने सहायक मेटाडेटा से आगे हो सकता है, और कोई विनाशकारी निर्णय अधिक अलगाव पा सकता है। ऐसे अपवाद पदानुक्रम या अर्थ को संप्रेषित करें; वे असमन्वित कंपोनेंट पैडिंग का परिणाम नहीं होने चाहिए। साझा स्पाइन से शुरू करें, फिर अपवाद को स्पष्ट बनाएँ।
सटीक अलाइनमेंट और दोहराए गए गैप को गुणवत्ता के अपरिवर्तनीय नियम मानें। जब दो किनारे या स्पेस बराबर होने चाहिए, तो एक रेंडर किए गए पिक्सेल का अंतर स्वीकार्य ऑप्टिकल सन्निकटन नहीं, बल्कि दोष है। प्रतिनिधि विंडो आकारों, टेक्स्ट आकारों और डिस्प्ले स्केल फ़ैक्टर पर मापन टूल से रिज़ॉल्व किए गए बाउंड्स का निरीक्षण करें। निर्देशांकों और दूरियों की तुलना करें; अलाइनमेंट को केवल सरसरी स्क्रीनशॉट देखकर स्वीकृत न करें।
रेंडर-पिक्सेल सहनशीलता एक सत्यापन नियम है, कोड को कच्चे पॉइंट ऑफ़सेट से पैच करने की अनुमति नहीं। समान संबंध एक ही स्पेसिंग क्लास या मेथड, टोकन, ग्रिड परिभाषा या साझा कंपोनेंट इनसेट से रिज़ॉल्व होने चाहिए। जब वे अलग हों, तो साझा स्वामी को ठीक करें। फ्रैक्शनल लेआउट और डिवाइस राउंडिंग (2× और 3× फ़ोन, फ्रैक्शनल डेस्कटॉप स्केल) का ध्यान रखें, ताकि इच्छित स्पाइन उसी भौतिक पिक्सेल पर आएँ और विशेष स्केल पर ड्रिफ़्ट न हों।
- जब मिश्रित आकार एक पंक्ति साझा करें, तो टेक्स्ट को बाउंडिंग-बॉक्स सेंटर के बजाय बेसलाइन से अलाइन करें।
- आइकनों को निश्चित स्लॉट में केंद्रित करें ताकि आइकनों की आंतरिक चौड़ाई अलग होने पर लेबल न हिलें।
- तुलनीय संख्याओं को end की ओर अलाइन करें और टैबुलर फ़िगर का उपयोग करें (
tabular-nums); गद्य और आइडेंटिफ़ायर को start की ओर अलाइन करें, जब तक कि लोकेल को अन्यथा आवश्यक न हो। - ट्रेलिंग पंक्ति एक्शन और डिस्क्लोज़र इंडिकेटर को निश्चित-चौड़ाई वाली लेन में रखें।
- फ़ॉर्म कंट्रोल को उनके इंटरैक्टिव फ़्रेम से अलाइन करें, उनके नीचे के सहायता टेक्स्ट से नहीं।
justify-between(.justify_between()) का उपयोग केवल तब करें जब दोनों पक्ष वास्तव में विपरीत किनारों के स्वामी हों; यह बीच की गायब संरचना को छिपाने के लिए नहीं होना चाहिए।- हेयरलाइन सीमा के स्वामी की होती है। दो आसन्न क्षेत्र दोनों एक ही सेपरेटर न खींचें।
- स्क्रॉलबार उस क्षेत्र का होता है जो स्क्रॉल करता है और उस पैनल, एडिटर या विंडो के ट्रेलिंग किनारे से सटा रहता है। कंटेंट पैडिंग टेक्स्ट और पंक्तियों को इनसेट कर सकती है; वह स्क्रॉलबार को सतह के बीच में नहीं खींचनी चाहिए। स्क्रॉल व्यू में नहीं, बल्कि स्क्रॉल व्यू के कंटेंट में पैडिंग दें।
#डेंसिटी टियर
Medium डिफ़ॉल्ट है। डेंसिटी पूरे स्थानीय संदर्भ के लिए बदलें, किसी एक अलग कंट्रोल के लिए नहीं:
- comfortable / large: ऑनबोर्डिंग, विरल फ़ॉर्म, प्रमुख निर्णय;
- standard / medium: अधिकांश एप्लिकेशन क्रोम और वर्कफ़्लो, और हर टच स्क्रीन;
- compact / small: डेस्कटॉप टूलबार, मेनू, टेबल और दोहराया जाने वाला पेशेवर डेटा;
- extra compact / xsmall: असाधारण उच्च-घनत्व वाली यूटिलिटीज़, पूरे एप्लिकेशन के लिए कभी स्वचालित विकल्प नहीं।
मनमाने आकार के बजाय सीमित स्केल का उपयोग करें। टच स्क्रीन पर हर दबाने योग्य लक्ष्य कम से कम 44 × 44 पॉइंट का हो (Touch targets)। पॉइंटर के साथ, बटन आमतौर पर लगभग 24, 28 और 32 pt फ़्रेम से गुज़रते हैं, इनपुट large आकार में लगभग 40 pt तक बढ़ते हैं, और टेबल पंक्तियाँ लगभग 28, 32 और 40 pt का उपयोग करती हैं। ऐप के कंपोनेंट्स को ऐसा साइज़ दें जो टाइपोग्राफ़ी, आइकन, पैडिंग और हिट टार्गेट को एक साथ बदले; केवल बाहरी बॉक्स बदलने वाली कस्टम ऊँचाई आमतौर पर अधूरी होती है।
#टेक्स्ट आकार, बेस फ़ॉन्ट और पॉइंट
एक अच्छी तरह डिज़ाइन किया गया स्केल टेक्स्ट बढ़ने पर भी पदानुक्रम बनाए रखता है। बड़ा टेक्स्ट तब सफल होता है जब शीर्षक और बॉडी, कंट्रोल और आइकन, भीतरी और बाहरी स्पेसिंग, प्राथमिक और द्वितीयक क्षेत्रों का संबंध हर आकार पर वैसा ही लगे, न कि केवल हर ऑब्जेक्ट बड़ा हो जाए।
NSH की लंबाइयाँ पॉइंट में होती हैं, और उपयोगकर्ता का टेक्स्ट आकार (iOS पर Dynamic Type, Android पर फ़ॉन्ट आकार, डेस्कटॉप की टेक्स्ट स्केलिंग, होस्ट ऐप की अपनी सेटिंग) टेक्स्ट को स्केल करता है: फ़ॉन्ट स्केलिंग की अनुमति देने वाला हर टेक्स्ट और इनपुट बढ़ता है, जबकि स्पेसिंग, रेडियाई, बॉर्डर और इमेज अपना आकार बनाए रखती हैं (Text size)। ऐप का बेस टेक्स्ट आकार (Tailwind का text-base, 16 पॉइंट) वह बॉडी आकार है जिसके आसपास टाइप स्केल के चरण बनते हैं।
अनुपातों में डिज़ाइन करें:
- टाइप स्टेप बेस बॉडी आकार के आसपास वही पदानुक्रम बनाए रखते हैं;
- स्पेसिंग स्टेप टाइप के आसपास वही समूहीकरण संबंध बनाए रखते हैं;
- कंट्रोल फ़्रेम और हिट टार्गेट अपने लेबल के साथ बढ़ते हैं: उन्हें निश्चित ऊँचाई के बजाय उनकी सामग्री और एक न्यूनतम (
min-h-11) से आकार दें; - पेन के न्यूनतम और आरामदायक चौड़ाई बड़े टेक्स्ट का ध्यान रखें;
- कॉर्नर रेडियाई और फ़ोकस ट्रीटमेंट कंट्रोल फ़्रेम के साथ ऑप्टिकली सुसंगत रहें।
क्योंकि टेक्स्ट अपने आप बढ़ता है, इसलिए उसके चारों ओर का निश्चित फ़्रेम टूट जाता है: निश्चित ऊँचाई वाले बटन में बड़ा लेबल, निश्चित पेन न्यूनतम में बड़ा दस्तावेज़, या निश्चित पंक्ति ऊँचाई में बड़ी पंक्तियाँ मूल लय को बिगाड़ देती हैं और सामग्री को क्लिप कर सकती हैं। जब टेक्स्ट बड़ा हो जाए, तो पंक्तियों को रैप होने दें या कॉलम में बदलने दें (fontScale(), font_scale()), और पहले से बड़े टेक्स्ट, जैसे 34pt के शीर्षक, के स्केल को सीमित करें (maxFontSizeMultiplier)।
नियम के रूप में, एप्लिकेशन लेआउट में शाब्दिक पॉइंट मान नहीं लिखे जाने चाहिए (p-[13px], px(13.0))। स्पेसिंग स्केल (p-2, gap-3, w-64, text-sm और उनकी टाइप्ड मेथड) या ऐप के कंपोनेंट साइज़ का उपयोग करें। शाब्दिक पॉइंट का उपयोग केवल तब करें जब मान किसी भौतिक या रास्टर सीमा को दर्शाता हो: हेयरलाइन, प्लेटफ़ॉर्म विंडो इनसेट, बिटमैप आयाम, न्यूनतम हिट-टेस्ट सहनशीलता, या ऐसी ज्यामिति जो किसी बाहरी सतह से मेल खानी चाहिए। ये ऑडिट किए गए, प्रलेखित अपवाद हैं। उत्पाद की स्पेसिंग, टाइपोग्राफ़ी, आइकन आकार और सामान्य कंट्रोल ज्यामिति स्केल पर ही रहती हैं।
केवल डिफ़ॉल्ट पर नहीं, बल्कि कई टेक्स्ट आकारों पर परीक्षण करें। पदानुक्रम, रैपिंग, ट्रंकेशन, न्यूनतम विंडो आकार, पेन रीसाइज़िंग, फ़ोकस-रिंग क्लीयरेंस, पॉपअप प्लेसमेंट और लिस्ट पंक्ति मापन की जाँच करें।
#सतहें और एलिवेशन
एलिवेशन का उपयोग स्टैकिंग समझाने के लिए करें, महत्व दिखाने के लिए नहीं। आधार सतह सपाट रहती है; विभाजक और पृष्ठभूमि का कंट्रास्ट उसके क्षेत्रों को परिभाषित करते हैं। Popover, मेन्यू, शीट, डायलॉग और नोटिफ़िकेशन क्रमशः अधिक गहरी छाया का उपयोग कर सकते हैं, क्योंकि वे अन्य सामग्री के ऊपर होते हैं। हर कार्ड पर छाया न लगाएँ।
एक ही प्रकार की सभी सतहों का ट्रीटमेंट एक जैसा होना चाहिए। Popup परिवारों को एक थीम वाली सतह दें (popover टोकन, बॉर्डर, radius और एक छाया), ताकि Popover, Menu, ContextMenu और Tooltip एक-दूसरे से अलग न होने लगें। जब कोई एप्लिकेशन कोई और एंकर्ड सतह बनाए, तो असंबंधित बॉर्डर और छाया के literal मानों से उसका अनुमान लगाने के बजाय इसी ट्रीटमेंट का पुन: उपयोग करें।
#टाइपोग्राफ़ी और आइकन
इंटरफ़ेस टेक्स्ट के लिए प्लेटफ़ॉर्म का UI फ़ॉन्ट और मोनोस्पेस केवल कोड, आइडेंटिफ़ायर, शॉर्टकट और संरेखित संख्यात्मक डेटा के लिए इस्तेमाल करें। बॉडी टेक्स्ट को पठनीय रखें और अत्यधिक अपरकेस या लेटर स्पेसिंग से बचें, विशेषकर CJK टेक्स्ट के लिए।
एक उत्पाद में एक ही आइकन परिवार का उपयोग करें। आइकन लेबल के पूरक होते हैं; वे अपरिचित क्रियाओं को अनुमान के भरोसे नहीं छोड़ने चाहिए। केवल-आइकन वाले बटनों को हमेशा एक एक्सेसिबल नाम चाहिए (accessibilityLabel)। उनकी दृश्य व्याख्या नीचे दी गई tooltip नीति का पालन करती है। किसी स्थिति को बताने के लिए भरे हुए या रंगीन आइकन का उपयोग करें, केवल टूलबार को आकर्षक बनाने के लिए नहीं।
#लेआउट पैटर्न
#एक स्थिर शेल चुनें
अधिकांश एप्लिकेशन को इनमें से किसी एक शेल का उपयोग करना चाहिए:
- single workspace: एक मुख्य व्यू के ऊपर हेडर या टूलबार;
- navigation stack: push और pop होने वाले पेज (
NavStack), फ़ोन पर सिस्टम के बैक जेस्चर के साथ; - sidebar workspace: बदलते डिटेल व्यू के बगल में स्थायी नेविगेशन;
- master–detail: आकार बदलने योग्य कलेक्शन और डिटेल पैन, फ़ोन पर दो पेज;
- document workspace: कई दीर्घकालिक ऑब्जेक्ट के लिए टैब;
- utility window: एक केंद्रित कार्य, छोटे और निश्चित एक्शन पथ के साथ।
सामग्री बदलने पर भी ग्लोबल नेविगेशन को स्थिर रखें। मुख्य कार्य क्षेत्र को flex-1 (.flex_1()) से बचा हुआ स्थान दें, और जहाँ ओवरफ़्लो करने वाले चाइल्ड को सिकुड़ना चाहिए वहाँ min-w-0 / min-h-0 का उपयोग करें। स्क्रोलिंग या वर्चुअलाइज़ेशन को नेस्टेड व्यू से दोबारा बनाने के बजाय Scroll और List का उपयोग उनके निर्धारित व्यवहार के लिए करें।
डेस्कटॉप पर, ऐप का अपना टाइटल बार (nsh/desktop) सबसे पहले विंडो क्रोम है। उसका ड्रैग क्षेत्र सुरक्षित रखें (.window_drag(true)) और सामान्य टाइटल क्लिक को कभी-कभार होने वाले संपादन कमांड से न जोड़ें। नाम बदलना किसी स्पष्ट ऑब्जेक्ट कमांड के पीछे होना चाहिए, और जहाँ उचित हो वहाँ कीबोर्ड पथ के साथ।
#रिस्पॉन्सिव विंडो
विंडो किसी भी आकार की हो सकती है: उसे उपयोगकर्ता, स्प्लिट व्यू या होस्ट ऐप तय करता है। तय करें कि विंडो के संकरी होने पर क्या होता है:
- मुख्य कार्य को सुरक्षित रखें;
- आकार बदलने योग्य क्षेत्रों को एक प्रलेखित न्यूनतम आकार तक पहुँचने दें;
- गौण लेबल या इंस्पेक्टर को संक्षिप्त करें;
- कम बार उपयोग होने वाली क्रियाओं को मेन्यू में ले जाएँ;
- केवल उसी क्षेत्र को स्क्रोल कराएँ जिसकी सामग्री वास्तव में ओवरफ़्लो करती है।
किसी क्रिया को छिपाते समय उस तक पहुँचने का दूसरा रास्ता अवश्य दें। जब केवल सूची या दस्तावेज़ की बॉडी को स्क्रोल होना चाहिए, तब पूरी विंडो को स्क्रोल कराने से बचें। ब्रेकपॉइंट (md:, lg:) और windowSize() (Rust में window()) उस सतह का अनुसरण करते हैं जिसमें NSH रेंडर करता है।
NSH के flex लेआउट में वही intrinsic-size दबाव होता है जो अन्य लेआउट सिस्टम में मिलता है: flex-1 चाइल्ड लंबी सामग्री के कारण फिर भी सिकुड़ने से इनकार कर सकता है। डिज़ाइन और इम्प्लीमेंटेशन को इस पर सहमत होना चाहिए कि कौन से पैन सिकुड़ सकते हैं, ट्रंकेट हो सकते हैं, रैप हो सकते हैं या स्क्रोल हो सकते हैं। क्लिप किया गया क्षेत्र बाहर की ओर फैले फ़ोकस रिंग को भी क्लिप कर देता है; ओवरफ़्लो को सरल बनाने के लिए कभी भी कीबोर्ड दृश्यता का त्याग न करें।
#फ़ॉर्म और सेटिंग
हर फ़ील्ड के लिए एक दिखाई देने वाला लेबल रखें और सहायता या वैलिडेशन संदेश को उसी फ़ील्ड के पास रखें जिसका वह वर्णन करता है। संबंधित फ़ील्ड को संरेखित करें, लेकिन लंबे लेबल को संकरे निश्चित कॉलम में न ठूँसें। उपयुक्त कंट्रोल चुनें: स्वतंत्र विकल्पों के लिए Checkbox, छोटे दृश्यमान समूह के लिए Radio का RadioGroup, लंबे समूह के लिए विकल्पों का Menu, और तुरंत प्रभावी होने वाली सेटिंग के लिए Switch। इनके हिस्से (स्विच का ट्रैक और थंब, चेकबॉक्स का इंडिकेटर) ऐप द्वारा स्टाइल किए जाते हैं, checked:, indeterminate: और disabled: क्लास के साथ जो कंट्रोल का अनुसरण करती हैं:
use nsh_base::{switch, theme};
fn setting_switch(label: &'static str, on: Signal<bool>) -> impl IntoElement {
switch()
.checked(on)
.on_change(move |next: &bool| on.set(*next))
.flex_row()
.items_center()
.gap_3()
.track_style(|s| {
s.w(px(44.0))
.p(px(2.0))
.rounded_full()
.bg(move || theme().muted)
.transition_colors()
.checked(|s| s.bg(move || theme().primary))
})
.thumb_style(|s| {
s.size(px(20.0))
.rounded_full()
.bg(move || theme().background)
.shadow_sm()
.transition_transform()
.checked(|s| s.translate_x(px(20.0)))
})
.child(text(label).text_color(move || theme().foreground))
}import { Text } from "nsh";
import { Switch } from "nsh/base";
function SettingSwitch(props: { label: string; on: boolean; onChange: (e: { checked: boolean }) => void }) {
return (
<Switch
checked={props.on}
onChange={props.onChange}
class="flex-row items-center gap-3"
trackClass="w-11 rounded-full bg-muted p-0.5 transition-colors checked:bg-primary"
thumbClass="size-5 rounded-full bg-background shadow-sm transition-transform checked:translate-x-5"
>
<Text class="text-foreground">{props.label}</Text>
</Switch>
);
}“सभी चुनें” चेकबॉक्स अपनी indeterminate स्थिति से आंशिक चयन दिखाता है:
use nsh_base::{checkbox, theme};
fn select_all(selected: Signal<usize>, total: usize) -> impl IntoElement {
checkbox()
.checked(move || selected.get() == total)
.indeterminate(move || selected.get() > 0 && selected.get() < total)
.on_change(move |all: &bool| selected.set(if *all { total } else { 0 }))
.flex_row()
.items_center()
.gap_2()
.indicator_style(|s| {
s.size(px(20.0))
.items_center()
.justify_center()
.rounded(move || theme().radius)
.border_2()
.border_color(move || theme().border)
.checked(|s| s.bg(move || theme().primary).border_color(move || theme().primary))
.indeterminate(|s| s.bg(move || theme().primary).border_color(move || theme().primary))
})
.indicator(text(move || mark(selected.get(), total)).text_color(move || theme().primary_foreground))
.child(text("Select all").text_color(move || theme().foreground))
}
fn mark(selected: usize, total: usize) -> &'static str {
if selected == total { "✓" } else if selected > 0 { "–" } else { "" }
}import { Text } from "nsh";
import { Checkbox } from "nsh/base";
function SelectAll(props: { selected: number; total: number; onChange: (e: { checked: boolean }) => void }) {
return (
<Checkbox
checked={props.selected === props.total}
indeterminate={props.selected > 0 && props.selected < props.total}
onChange={props.onChange}
class="flex-row items-center gap-2"
indicatorClass="size-5 items-center justify-center rounded-(--radius) border-2 border-border checked:border-primary checked:bg-primary indeterminate:border-primary indeterminate:bg-primary"
indicator={
<Text class="text-primary-foreground">
{props.selected === props.total ? "✓" : props.selected > 0 ? "–" : ""}
</Text>
}
>
<Text class="text-foreground">Select all</Text>
</Checkbox>
);
}ऑपरेशन चलने के दौरान सबमिशन को अक्षम करें, उपयोगकर्ता का इनपुट बनाए रखें और परिणाम क्रिया के पास दिखाएँ। इनपुट को सॉफ़्टवेयर कीबोर्ड के ऊपर रखें (env(keyboard-inset-height))। डायलॉग को छोटे, केंद्रित निर्णयों के लिए आरक्षित रखें; जिन वर्कफ़्लो में खोजबीन या कई फ़ील्ड की ज़रूरत हो उनके लिए पूरा पेज या शीट इस्तेमाल करें।
लोडिंग ट्रीटमेंट को वास्तविक प्रतीक्षा दर्शाना चाहिए। जिन सेटिंग पैनल की सामग्री पहले से उपलब्ध है, उनके बीच स्विच करना तुरंत होना चाहिए; स्केलेटन तभी उचित है जब सामग्री वास्तव में लोड हो रही हो और उसका आकार ज्ञात हो।
#कंपोनेंट और कंपोज़िशन
Shadcn के उस सिद्धांत का पालन करें कि कंपोनेंट एक बंद डिज़ाइन सिस्टम नहीं, बल्कि निर्माण सामग्री हैं। nsh/base व्यवहार प्रदान करता है; ऐप अपने कंपोनेंट में सुसंगत डिफ़ॉल्ट देता है और कंपोज़िशन तथा उत्पाद के अर्थ का स्वामी होता है।
- कंपोनेंट वेरिएंट का उपयोग अर्थ के अनुसार करें। Primary केवल किसी निर्णय क्षेत्र में स्पष्ट डिफ़ॉल्ट कमिट के लिए आरक्षित है, सामान्यतः वह क्रिया जो डेस्कटॉप पर Return से चलती है। अकेली, बार-बार होने वाली या वांछनीय क्रिया अपने आप primary नहीं हो जाती। प्रबंधन टूलबार में
Addकमांड सामान्यतः default बटन का उपयोग करता है; फ़ॉर्म का डिफ़ॉल्टCreateकमिट primary का उपयोग कर सकता है। विनाशकारी प्रतिबद्धता के लिए destructive और शांत टूलबार क्रियाओं के लिए ghost का उपयोग करें। - मनमाने डिसेंडेंट को स्टाइल करने के बजाय स्पष्ट पार्ट और स्लॉट को प्राथमिकता दें।
- दोहराए जाने वाले पैटर्न को पूरे उत्पाद में सुसंगत रखें। जब वह डोमेन की भाषा या नीति धारण करता हो, तो उसे एप्लिकेशन कंपोनेंट में लपेटें।
- मानक कंपोनेंट का उपयोग उसकी अर्थगत भूमिका के लिए करें।
Menu,ContextMenu,Popover,Sheet,DialogऔरAlertDialogआपस में बदले जा सकने वाले बॉक्स नहीं हैं; हर एक के चयन, फ़ोकस, कीबोर्ड, डिसमिसल और लेआउट के अनुबंध अलग हैं, और हर डिवाइस पर उसका अपना रूप होता है। - कंपोनेंट परिवार की ज्यामिति सुरक्षित रखें। मेन्यू की पंक्तियाँ ऊर्ध्वाधर और क्षैतिज पैडिंग, ऊँचाई, आइकन और चेकमार्क स्लॉट, विभाजक, रेडियस और स्टेट ट्रीटमेंट साझा करती हैं। किसी मेन्यू की नकल ऐसे कस्टम popup से न करें जिसकी स्पेसिंग सिस्टम का केवल अनुमान हो।
- केवल हर prop का नाम बदलने या उसकी सभी क्षमताओं को स्थिर करने के लिए कंपोनेंट को न लपेटें।
- उत्पाद की स्टाइलिंग के बिना पुन: उपयोग योग्य व्यवहार को
nsh/baseमें, या ऐप के उत्पादों द्वारा साझा किए जाने वाले क्रेट में ले जाएँ; थीम वाली, विचारशील प्रस्तुति को एप्लिकेशन के कंपोनेंट में रखें।
use nsh_base::{button, theme};
/// The footer of a form: a default Cancel and the primary commit.
fn form_actions(cancel: impl Fn() + 'static, create: impl Fn() + 'static) -> impl IntoElement {
view()
.flex_row()
.justify_end()
.gap_2()
.child(
button()
.on_press(cancel)
.rounded(move || theme().radius)
.border_1()
.border_color(move || theme().border)
.px_4()
.py_2()
.active(|s| s.bg(move || theme().muted))
.child(text("Cancel").text_color(move || theme().foreground)),
)
.child(
button()
.on_press(create)
.rounded(move || theme().radius)
.bg(move || theme().primary)
.px_4()
.py_2()
.active(|s| s.bg(move || theme().primary.opacity(0.9)))
.child(text("Create").text_color(move || theme().primary_foreground)),
)
}import { Text, View } from "nsh";
import { Button } from "nsh/base";
// The footer of a form: a default Cancel and the primary commit.
function FormActions(props: { onCancel: () => void; onCreate: () => void }) {
return (
<View class="flex-row justify-end gap-2">
<Button onPress={props.onCancel} class="rounded-(--radius) border border-border px-4 py-2 active:bg-muted">
<Text class="text-foreground">Cancel</Text>
</Button>
<Button onPress={props.onCreate} class="rounded-(--radius) bg-primary px-4 py-2 active:bg-primary/90">
<Text class="text-primary-foreground">Create</Text>
</Button>
</View>
);
}#इंटरैक्शन स्टेट
#क्लिक से पहले ही परिणाम समझ में आए
कंट्रोल को अपने परिणाम का पूर्वानुमान देना चाहिए। परिचित प्लेटफ़ॉर्म कंट्रोल और स्थान का उपयोग करें ताकि लोग इंटरफ़ेस सीखे बिना ही कार्य कर सकें। उसका लेबल क्रिया और ऑब्जेक्ट का नाम बताए, उसकी स्थिति उपलब्धता दिखाए, और उसकी फ़ीडबैक उसी परिणाम की पुष्टि करे।
यदि Button कोई कॉन्फ़िगरेशन फ़्लो खोलता है तो उसे Save लेबल न दें, और यदि वह केवल किसी आइटम को समूह से हटाता है तो Delete लेबल न दें। जब संदर्भ से स्पष्ट न हो, तो दायरे का नाम बताएँ। सक्रियण पर तुरंत प्रतिक्रिया दें, लंबे काम के दौरान दोहराए गए सबमिशन को रोकें और परिणाम उस ऑब्जेक्ट के पास दिखाएँ जो बदला है। सफलता संदेश तभी जोड़ें जब परिणाम स्वयं दिखाई न दे रहा हो।
हर इंटरैक्टिव कंट्रोल को इनके लिए डिज़ाइन किया जाना चाहिए:
| स्थिति | NSH | डिज़ाइन आवश्यकता |
|---|---|---|
| Rest | दृश्य शोर के बिना स्पष्ट एफ़ोर्डेंस | |
| Hover | hover: | सूक्ष्म पॉइंटर फ़ीडबैक, कभी भी एकमात्र संकेत नहीं |
| Pressed | active: | तत्काल प्रेस फ़ीडबैक, ऐप द्वारा स्टाइल किया हुआ |
| Open / pressed | popup का open | संलग्न popup खुला रहने तक स्थायी फ़ीडबैक |
| Focus visible | focus-visible: | उच्च-कंट्रास्ट कीबोर्ड फ़ोकस रिंग |
| Selected / checked | selected:, checked: | hover से अलग, स्थायी स्थिति |
| Disabled | disabled: | कम ज़ोर और भ्रामक hover/pressed प्रतिक्रिया का अभाव |
| Loading | संदर्भ सुरक्षित रखें, दोहराई गई क्रिया रोकें, लंबी प्रतीक्षा समझाएँ | |
| Error | बताएँ कि क्या हुआ और कैसे उबरें |
जिन कमांड को कीबोर्ड से काम करना चाहिए, उन्हें डेस्कटॉप और वेब पर keymap से बाइंड करें। परिचित प्लेटफ़ॉर्म शॉर्टकट का पालन करें ("mod+k" macOS पर Command और अन्य जगह Control है), शॉर्टकट को मेन्यू या tooltip में दिखाएँ, और ओवरले खोलने या बंद करने के बाद फ़ोकस को तर्कसंगत स्थान पर रखें।
चयन सूचना मॉडल का हिस्सा है, वैकल्पिक सजावट नहीं। टैब, सेगमेंटेड विकल्प, चुनने योग्य पंक्तियाँ, फ़िल्टर और नेविगेशन गंतव्यों को स्थायी चयनित स्थिति दिखानी चाहिए (selected, जिसे स्क्रीन रीडर घोषित करते हैं)। जिस बटन के पास मेन्यू है, वह popup बंद होने तक स्पष्ट रूप से दबा हुआ या खुला दिखना चाहिए; अकेला hover ट्रिगर और सतह के संबंध को नहीं समझा सकता।
use nsh_base::{tab, theme};
fn section_tab(label: &'static str, id: Section, current: Signal<Section>) -> impl IntoElement {
let selected = move || current.get() == id;
tab()
.selected(selected)
.on_press(move || current.set(id))
.rounded(move || theme().radius)
.px_3()
.py_2()
.selected_style(|s| s.bg(move || theme().muted))
.child(text(label).text_color(move || {
if selected() { theme().foreground } else { theme().muted_foreground }
}))
}import { Text } from "nsh";
import { Tab } from "nsh/base";
function SectionTab(props: { label: string; selected: boolean; onPress: () => void }) {
return (
<Tab
selected={props.selected}
onPress={props.onPress}
class="group rounded-(--radius) px-3 py-2 selected:bg-muted"
>
<Text class="text-muted-foreground group-selected:text-foreground">{props.label}</Text>
</Tab>
);
}सेगमेंटेड कंट्रोल में, चयनित फ़िल और अचयनित सतह को कंटेनर की सिल्हूट साझा करनी चाहिए। कोई भी किसी सिरे के कोने को चौकोर न करे और न किसी सीमा को अपने समकक्षों से भारी दिखाए।
चयनित नेविगेशन आइटम, सूची पंक्ति या टैब को आइटम की अपनी सतह से दिखाएँ: चयनित फ़िल, गहरा फ़ोरग्राउंड या भारी वज़न। चयन चिह्न के रूप में अग्रणी किनारे की पट्टी या एक-तरफ़ा बॉर्डर न जोड़ें। यह वेब टेम्पलेट की आदत है, नेटिव परंपरा नहीं; यह आइटम की गोल सिल्हूट को तोड़ती है और ऐसे कॉलम में दूसरा, प्रतिस्पर्धी किनारा जोड़ती है जो पहले से ही अपने टेक्स्ट पर संरेखित है।
विनाशकारी क्रियाओं के लिए, उलटने योग्य और अपरिवर्तनीय कार्य में अंतर करें। उलटने योग्य बदलावों के लिए undo या अस्थायी नोटिफ़िकेशन को प्राथमिकता दें। जब परिणाम गंभीर हो और उसे पूर्ववत न किया जा सके, तब AlertDialog का उपयोग करें; पुष्टि की कॉपी में विशिष्ट ऑब्जेक्ट और परिणाम का नाम लें।
#पॉइंटर परंपराएँ
बटन, चेकबॉक्स, मेन्यू आइटम, टैब और अन्य कंट्रोल के लिए डिफ़ॉल्ट कर्सर का उपयोग करें। लिंक और लिंक की तरह व्यवहार करने वाली सामग्री के लिए पॉइंटिंग हैंड (cursor-pointer) का उपयोग करें। टेक्स्ट, रीसाइज़, ग्रैब और निषिद्ध कर्सर का उपयोग केवल तब करें जब वे सक्रिय मैनिपुलेशन का वर्णन करें। कर्सर एफ़ोर्डेंस को सुदृढ़ करता है; वह कंट्रोल की दृश्य स्थिति या एक्सेसिबल रोल का स्थान नहीं लेता।
hover प्रभाव मामूली रखें, क्योंकि टच, कीबोर्ड और एक्सेसिबिलिटी इंटरैक्शन में hover नहीं होता। किसी विनाशकारी या आवश्यक क्रिया की एकमात्र प्रति hover पर प्रकट न करें। संदर्भ पंक्ति क्रियाएँ विश्राम अवस्था में शांत हो सकती हैं, यदि वही कमांड चयन, कीबोर्ड या कॉन्टेक्स्ट मेन्यू से उपलब्ध रहें।
#hover टूलबार के बजाय कमांड सतहों को प्राथमिकता दें
कमांड की आवृत्ति और दायरे के आधार पर चुनें कि क्रिया कहाँ रहे:
- मुख्य या बार-बार होने वाली क्रिया को लेबल वाले बटन या परिचित टूलबार कंट्रोल के रूप में दिखाई देता रखें;
- वर्तमान क्षेत्र की गौण क्रियाओं को दिखाई देने वाले
Menuट्रिगर के पीछे रखें; - पॉइंटर या उंगली के नीचे के ऑब्जेक्ट पर काम करने वाले कमांड को
ContextMenuमें रखें: डेस्कटॉप पर राइट क्लिक, टच स्क्रीन पर उंगली को दबाए रखना; - जब किसी महत्वपूर्ण कमांड का स्वाभाविक कीबोर्ड रूप हो, तो उसे कीबोर्ड शॉर्टकट (
keymap) से और एप्लिकेशन मेन्यू में (Menu.setApplicationMenu,nsh/desktopसे) उपलब्ध कराएँ; - hover पर प्रकट होने वाले आइकन का उपयोग केवल ऐसे कमांड के शॉर्टकट के रूप में करें जो कहीं और भी पहुँच में रहता है।
यह केवल दृश्य पसंद से अधिक है। nsh/base के मेन्यू पहले से ही ट्रिगर पर प्लेसमेंट, डेस्कटॉप पर कैस्केडिंग सबमेन्यू और फ़ोन पर सबमेन्यू वाली शीट, आइटम चुनने, बाहर प्रेस करने, Escape या बैक से डिसमिसल, और स्क्रीन रीडर के लिए menu और menu item रोल के स्वामी हैं। hover बटनों की कस्टम पट्टी को इन सभी व्यवहारों को दोबारा बनाना पड़ेगा, और वह टच, केवल-कीबोर्ड और कई सहायक तकनीक वर्कफ़्लो के लिए अदृश्य है।
use nsh_base::{menu, menu_item, menu_separator, theme};
use nsh_core::{color::black, element::StyleRefinement};
/// The app's popup surface, shared by its menus, popovers and tooltips.
fn popup(s: StyleRefinement) -> StyleRefinement {
s.min_w(px(192.0))
.p_1()
.rounded(move || theme().radius)
.border_1()
.border_color(move || theme().border)
.bg(move || theme().popover)
.shadow_lg()
}
fn item(label: &'static str, on_select: impl Fn() + 'static) -> impl IntoElement {
menu_item()
.on_select(on_select)
.px_3()
.py_2()
.rounded(move || theme().radius)
.hover(|s| s.bg(move || theme().muted))
.active(|s| s.bg(move || theme().muted))
.child(text(label).text_color(move || theme().foreground))
}
fn more_menu(rename: impl Fn() + 'static, duplicate: impl Fn() + 'static, delete: impl Fn() + 'static) -> impl IntoElement {
menu()
.offset(px(4.0))
.popup_style(popup)
.backdrop_style(|s| s.bg(black().opacity(0.5)))
.trigger(
view()
.label("More actions")
.size(px(44.0))
.items_center()
.justify_center()
.rounded_full()
.active(|s| s.bg(move || theme().muted))
.child(text("⋯").text_color(move || theme().foreground)),
)
.child(item("Rename…", rename))
.child(item("Duplicate", duplicate))
.child(menu_separator().h(px(1.0)).my_1().bg(move || theme().border))
.child(item("Delete…", delete))
}import { Text, View } from "nsh";
import { Menu, MenuItem, MenuSeparator } from "nsh/base";
/** The app's popup surface, shared by its menus, popovers and tooltips. */
export const popup = "min-w-48 rounded-(--radius) border border-border bg-popover p-1 shadow-lg";
const item = "rounded-(--radius) px-3 py-2 hover:bg-muted active:bg-muted";
function MoreMenu(props: { onRename: () => void; onDuplicate: () => void; onDelete: () => void }) {
return (
<Menu
offset={4}
popupClass={popup}
backdropClass="bg-black/50"
trigger={
<View accessibilityLabel="More actions" class="size-11 items-center justify-center rounded-full active:bg-muted">
<Text class="text-foreground">⋯</Text>
</View>
}
>
<MenuItem onSelect={props.onRename} class={item}><Text class="text-foreground">Rename…</Text></MenuItem>
<MenuItem onSelect={props.onDuplicate} class={item}><Text class="text-foreground">Duplicate</Text></MenuItem>
<MenuSeparator class="my-1 h-px bg-border" />
<MenuItem onSelect={props.onDelete} class={item}><Text class="text-foreground">Delete…</Text></MenuItem>
</Menu>
);
}जब उपयोगकर्ताओं को यह दृश्य संकेत चाहिए कि और कमांड मौजूद हैं, तब Menu चुनें, जैसे टूलबार ओवरफ़्लो, दस्तावेज़ क्रियाएँ या अकाउंट मेन्यू। चयन या ऑब्जेक्ट के दायरे वाले कमांड, जैसे rename, duplicate, reveal या remove, के लिए ContextMenu चुनें। कॉन्टेक्स्ट मेन्यू किसी आवश्यक कमांड को करने का एकमात्र तरीका नहीं होना चाहिए; उचित रूप से मेन्यू-बार, टूलबार, कीबोर्ड या डिटेल व्यू का पथ दें।
स्क्रीन को न्यूनतम दिखाने के लिए हर क्रिया को मेन्यू में न डालें। खोज और गति मायने रखती है: मुख्य क्रिया दिखाई देती रहे, ख़तरनाक आइटम स्पष्ट रूप से लेबल और अलग किए गए रहें, और मेन्यू आइटम जहाँ भी दिखे वहाँ उसकी क्रिया, आइकन, शॉर्टकट, सक्षम स्थिति और परिणाम समान हों।
#Button का मतलब है एप्लिकेशन की क्रिया; Link का मतलब है बाहरी संसाधन
जब activation से एप्लिकेशन की स्थिति बदलती हो, कोई निर्णय पक्का होता हो, कोई टूल खुलता हो, डेटा submit होता हो या कोई कमांड चलती हो, तब Button का उपयोग करें। उसका रूप स्थानीय पदानुक्रम के आधार पर चुनें:
- primary button: किसी निर्णय क्षेत्र में उस एकमात्र क्रिया के लिए जिस पर ज़ोर देना है;
- default button: सामान्य दिखने वाली क्रियाओं के लिए;
- outline button: जब किसी क्रिया को कम ज़ोर के साथ स्पष्ट सीमा चाहिए;
- ghost button: जाने-पहचाने, कम ज़ोर वाले toolbar और inline क्रियाओं के लिए;
- icon button: केवल सुपरिचित प्रतीक के लिए, accessible name के साथ, और अर्थ या दायरा अस्पष्ट हो तो tooltip के साथ।
Primary इसलिए न दें कि स्क्रीन पर वह बटन अकेली क्रिया है, वह ऊपर दाईं ओर रखा है, या टीम चाहती है कि उस पर अधिक क्लिक हों। Primary डिफ़ॉल्ट प्रतिबद्धता और कीबोर्ड व्यवहार को दर्शाता है। यदि activation केवल एक सामान्य कमांड है, जैसे आइटम जोड़ना, कोई टूल खोलना या व्यू रिफ़्रेश करना, तो उसके स्थानीय पदानुक्रम के अनुसार default, outline या ghost button का उपयोग करें।
रेखांकित link (role="link") का उपयोग केवल बाहरी संसाधन के लिए करें: URL, वेब पेज, ऑनलाइन दस्तावेज़ या ईमेल पता। यह pointing-hand कर्सर का उपयोग करता है, क्योंकि उसका अनुबंध वर्तमान एप्लिकेशन संदर्भ को छोड़कर उस संसाधन तक जाना है। किसी कार्यात्मक कमांड को शांत दिखाने के लिए link स्टाइल का उपयोग न करें। link जैसा दिखने वाला Delete, Save, Refresh, Add, Open-menu या एप्लिकेशन के भीतर navigation की क्रिया नियंत्रण की affordance छिपा देती है और गलत accessibility role प्रकट करती है।
“View” शब्द किसी एप्लिकेशन-आंतरिक गंतव्य को link नहीं बना देता। पूरी रिपोर्ट, विश्लेषण, विवरण पैनल या स्थानीय रिकॉर्ड फिर भी button, row, card, tab या disclosure नियंत्रण से ही खुलता है। जब आसपास का card पहले ही बता देता है कि क्या खुलेगा, तब Full analysis जैसे संक्षिप्त, संदर्भ-सजग लेबल का उपयोग करें; रेखांकन केवल उस संसाधन के लिए रखें जो वास्तव में ब्राउज़र या मेल क्लाइंट में खुलता है।
सभी आंतरिक navigation (sidebar की पंक्तियाँ, tabs, breadcrumbs, सूची आइटम, स्थानीय व्यू खोलना, या workspace बदलना) में navigation stack, Button या उसके अनुरूप component का उपयोग होना चाहिए। दृश्य ज़ोर button के variant या navigation component की selected स्थिति से चुना जाता है, कभी semantics को गलत बताकर नहीं।
#Feedback और overlays
निर्णय के लिए सबसे छोटी उपयुक्त सतह चुनें:
- tooltip: छोटी व्याख्या या shortcut (
Tooltip, या किसी भी element काtooltip); - popover: ऐसे संदर्भगत नियंत्रण जो कार्य में बाधा नहीं डालते (
Popover); - menu: क्रियाओं की संक्षिप्त सूची (
Menu); - notification: ऐसी asynchronous स्थिति जिसमें निर्णय की ज़रूरत नहीं;
- dialog: केंद्रित निर्णय या छोटा फ़ॉर्म (
Dialog); - alert dialog: किसी परिणामकारी क्रिया की स्पष्ट पुष्टि (
AlertDialog); - sheet: ऐसा अतिरिक्त कार्य जिसे अधिक स्थायी जगह से लाभ होता है (
Sheet)।
हर एक वही रूप लेता है जो उसके डिवाइस से अपेक्षित है, और सभी एक ही संरचना से बनते हैं जिसे ऐप स्टाइल करता है (popupClass, backdropClass):
| डेस्कटॉप | फ़ोन और टैबलेट | |
|---|---|---|
Tooltip | पॉइंटर के element पर कुछ देर ठहरने के बाद | केवल तब जब ऐप उसे खोले |
Popover | anchored; बाहर प्रेस करने पर वह बंद होता है और प्रेस आगे बढ़ जाता है | anchored; बाहर प्रेस करने पर वह केवल बंद होता है |
Menu | trigger पर एक popup, cascading submenus के साथ | नीचे एक sheet; submenu अपने आइटमों की जगह ले लेता है |
ContextMenu | secondary button, पॉइंटर की जगह पर | उंगली दबाए रखने पर sheet खुलती है |
Sheet | backdrop के ऊपर एक किनारे का पैनल | वही |
AlertDialog | प्लेटफ़ॉर्म की dialog शैली में एक alert | सिस्टम का alert या action sheet |
Tooltip अनुपस्थित अर्थ देता है; वह किसी स्पष्ट क्रिया को दोहराता नहीं। इसे अपरिचित प्रतीक, अस्पष्ट दायरे या किसी ऐसे उपयोगी shortcut के लिए रखें जो अन्यथा छिपा रहेगा। संदेश के footer में Copy और Download जैसी बार-बार आने वाली, पहचानी जाने वाली कमांडों को accessible name और कीबोर्ड पहुँच चाहिए, लेकिन उनके hover लेबल स्पष्टता बढ़ाने के बजाय व्यवधान बढ़ाते हैं। फ़ोन पर tooltip केवल तब दिखता है जब ऐप उसे खोले, इसलिए tooltip में वह जानकारी कभी नहीं होनी चाहिए जो touch उपयोगकर्ता को चाहिए।
Alert modal न खोले तब भी दृश्य पदानुक्रम में बाधा डालता है। इसे महत्वपूर्ण, असाधारण जानकारी के लिए उपयोग करें जिस पर वर्तमान कार्य में ध्यान देना ज़रूरी है; सामान्य विवरणों, सुझावों या खाली जगह के लिए सजाए हुए कंटेनर के रूप में नहीं। जब सामग्री पर तुरंत ध्यान देने या कार्रवाई करने की ज़रूरत न हो, तो inline सहायता, muted टेक्स्ट या सामान्य section को प्राथमिकता दें।
Overlays को एक के ऊपर एक रखने से बचें। Escape और Android का back button सबसे ऊपरी dismiss की जा सकने वाली परत को बंद करते हैं; ऐप की स्थिति onOpenChange से सिंक में रखें, और focus को trigger या अगले तार्किक लक्ष्य पर लौटाएँ।
Overlay की क्रिया उसी ऑब्जेक्ट या स्थिति से संबंधित होनी चाहिए जो overlay वास्तव में दिखाता है। उदाहरण के लिए, Clear history तभी दिखाएँ जब हाल के इतिहास का अलग section दिख रहा हो और उसमें प्रविष्टियाँ हों। खोज परिणाम, हाल के आइटम और पसंदीदा अलग-अलग संग्रह हैं; उन्हें एक अस्पष्ट सूची में मिलाने के बजाय लेबल देकर अलग करें। जो क्रिया लागू न हो उसे छिपाएँ, या उपयोगी कारण के साथ disabled करें; footer में अस्पष्ट trash icon न रखें।
Footer उन क्षमताओं का कचरादान नहीं है जिन्हें डिज़ाइन में जगह नहीं मिली। Footer में shortcuts, स्थिति, या पूरी सतह पर लागू होने वाली क्रियाएँ हो सकती हैं, लेकिन हर आइटम को इन प्रश्नों का उत्तर देना चाहिए: उसका ऑब्जेक्ट क्या है, वह अभी क्यों उपलब्ध है, वह किस दायरे को प्रभावित करता है, और activation के बाद कौन-सी दिखने वाली स्थिति बदलती है?
#Motion
Motion परिवर्तन को समझाता है; यह परिवेशी सजावट नहीं है। प्रकट होने, हटने, विस्तार और स्थानिक निरंतरता के लिए छोटे transitions का उपयोग करें। जब opacity या transform वही संबंध बता सकते हों, तब बड़े layout परिवर्तनों को animate करने से बचें। reduced-motion प्राथमिकताओं का सम्मान करें (motion-reduce:, reduceMotion()), स्थिति समझने के लिए कभी animation को आवश्यक न बनाएँ, और हर component में डिफ़ॉल्ट animation न जोड़ें।
view()
.on_press(open)
.transition_transform()
.duration(150.0)
.when(!reduce_motion(), |v| v.active(|s| s.scale(0.97)))<View onPress={open} class="transition-transform duration-150 active:scale-[0.97] motion-reduce:active:scale-100" />Motion की नीति एप्लिकेशन परत की ज़िम्मेदारी है। nsh/base transition के लिए आवश्यक lifecycle तंत्र या ज्यामिति का स्वामी है, लेकिन यह तय नहीं करता कि हर उत्पाद fade या slide करे। स्वतंत्र रूप से animate होने वाले मानों को स्थिर पहचान दें, और व्यवधान आने पर animation पुराने अंतिम बिंदु से दोबारा शुरू होने के बजाय वर्तमान में नमूने के रूप में लिए गए मान से सहजता से उलटे।
Motion इंटरैक्शन की निरंतरता का अनुसरण करता है। जब पॉइंटर या scroll स्थिति संबंधित लक्ष्यों के बीच घूम रही हो, तब preview सतह को स्थिर रखें और उसकी सामग्री या स्थिति को उसी जगह अपडेट करें। उसे इंटरैक्शन समाप्त होने के बाद ही हटाएँ; हर अपडेट पर बार-बार fade-out और दोबारा प्रवेश झिलमिलाहट जैसा लगता है।
#डेटा-प्रधान इंटरफ़ेस डिज़ाइन करना
Dense का मतलब भीड़भाड़ वाला नहीं है। tables, trees, लंबी सूचियों और editors में:
- headers और पंक्ति की प्राथमिक पहचान को दृश्य रूप से स्थिर रखें;
- तुलनीय मानों को संरेखित करें और जहाँ उचित हो वहाँ tabular numerals का उपयोग करें;
- focus, hover, सक्रिय पंक्ति और multi-selection में अंतर दिखाएँ;
- sorting और filtering को दृश्यमान और उलटने योग्य रखें;
- filtering और पुनर्क्रमण के दौरान selection को डोमेन पहचान के आधार पर सुरक्षित रखें;
- बड़े संग्रहों को virtualize करें (
List), कीबोर्ड semantics बदले बिना; - द्वितीयक columns और inspectors के लिए progressive disclosure का उपयोग करें;
- ऐसी उपयोगी खाली स्थिति दें जो अगली क्रिया समझाए।
सुसंगत फ़ील्ड्स में तुलना के लिए table चुनें, विषम आइटमों को स्कैन करने के लिए list चुनें, और वास्तविक पदानुक्रम के लिए tree चुनें। जटिल डेटा layout को दृश्य शैली के रूप में उपयोग न करें।
#इंटरफ़ेस की भाषा
शब्द इंटरफ़ेस की संरचना का हिस्सा हैं। किसी फ़ीचर की शब्दावली को एक तंत्र के रूप में लिखें, यानी गंतव्य, ऑब्जेक्ट, कमांड, स्थितियाँ और परिणाम, न कि implementation फ़ीचर्स के अलग-अलग अनुवादों के रूप में। जो सबसे छोटा शब्दांकन अपने वास्तविक संदर्भ में सटीक बना रहे, उसे प्राथमिकता दें।
#संदर्भ को संदर्भ ढोने दें
जो जानकारी आसपास की सतह पहले ही स्थापित कर देती है, उसे दोहराएँ नहीं। Sidebar का गंतव्य आमतौर पर स्वयं ऑब्जेक्ट या डोमेन होता है: Users का उपयोग करें, User Management का नहीं; Shortcuts का उपयोग करें, Shortcut Configuration Management का नहीं। जिस column की पंक्तियों में पहले से क्रियाएँ हों, वह सामान्य Operation शीर्षक छोड़ सकता है। Delete “Roadmap”? शीर्षक वाले dialog को ऐसे मुख्य टेक्स्ट की ज़रूरत नहीं जो वही प्रश्न फिर पूछे।
यह संदर्भ की मितव्ययिता है, केवल हटाने के लिए हटाना नहीं। टेक्स्ट तब जोड़ें जब वह निर्णय बदलता हो: प्रभावित दायरा बताए, अपरिवर्तनीय परिणाम बताए, कोई असामान्य पूर्वापेक्षा बताए, या पुनर्प्राप्ति का तरीका बताए। हर अतिरिक्त शब्द को ऐसे प्रश्न का उत्तर देना चाहिए जिसका उत्तर वर्तमान layout पहले से नहीं देता।
गंतव्यों और ऑब्जेक्ट्स के लिए संज्ञाओं (Users, Appearance, Orders), कमांड के लिए क्रियाओं (Save, Duplicate, Export), और स्थितियों के लिए विशेषणों या छोटे वाक्यांशों (Offline, Up to date, Pending review) का उपयोग करें। Management, Module, Page, Function, Operation और System जैसे आवरण शब्दों से बचें, जब तक कि वह शब्द किसी वास्तविक डोमेन अवधारणा को अलग न करता हो।
#हर भाषा को लिखें, उसके ढाँचे का अनुवाद न करें
साझा आशय, पदानुक्रम और शब्दावली से शुरुआत करें, फिर हर locale को स्वाभाविक इंटरफ़ेस भाषा के रूप में रचें। स्रोत भाषा का शब्द क्रम, शब्दों की संख्या, शिष्टाचार वाले भराव शब्द या व्याकरणिक श्रेणी बनाए न रखें। अंग्रेज़ी Users किसी ऐसी चीनी फ़ीचर अवधारणा को व्यक्त कर सकता है जो शाब्दिक रूप से “user management” में फैल जाती; निष्ठा का अर्थ उद्देश्य को सुरक्षित रखना है, टोकन को नहीं।
वे शब्द हटाएँ जो आसपास की सूचना संरचना पहले से देती है। Settings सतह के भीतर गंतव्य अक्सर केवल Account होता है, Account Settings नहीं, और कभी अस्वाभाविक एकवचन Account Setting नहीं। सही अंग्रेज़ी लेबल उसकी भूमिका और पड़ोसी लेबलों से चुना जाता है, अकेले स्रोत वाक्यांश से नहीं।
बार-बार आने वाले ऑब्जेक्ट्स, कमांड और स्थितियों के लिए एक छोटी उत्पाद शब्दावली बनाए रखें। toolbar, menu, context menu, dialog, shortcut खोज और दस्तावेज़ीकरण में वही शब्द उपयोग करें, जब तक संदर्भ वास्तव में उसका अर्थ न बदल दे। कॉपी की समीक्षा रेंडर की गई सतह में करें: पड़ोसी लेबल अक्सर ऐसी पुनरावृत्ति या असंगत दायरा उजागर करते हैं जो locale फ़ाइल में नहीं दिखता।
स्थानीयकृत तकनीकी लेखन में, जब अनुवाद कम सटीक हो तो स्थापित framework शब्द को बनाए रखें। API identifiers को उनके मूल रूप में रखें और code के रूप में फ़ॉर्मैट करें। केवल तकनीकी दिखने के लिए सामान्य विदेशी शब्द न रखें। जहाँ आवश्यक हो, रखे गए शब्द को पहली बार उपयोग पर समझाएँ, फिर इंटरफ़ेस, दस्तावेज़ीकरण और API उदाहरणों में उसी रूप का उपयोग करें।
दस्तावेज़ीकरण में, किसी नामित API, component, स्रोत फ़ाइल या गाइड के लिए link टेक्स्ट में सटीक अंग्रेज़ी नाम का उपयोग करें, स्थानीयकृत पृष्ठों में भी। उदाहरण के लिए, उनके नामों का अनुवाद करने या अनावश्यक NSH उपसर्ग जोड़ने के बजाय View, Button, Menu और Text लिखें। आसपास की व्याख्याएँ पृष्ठ की भाषा में रखें। केवल नामित लक्ष्य को link करें; “source” जैसे शब्द, जब वे बताते हैं कि उसका हवाला क्यों दिया गया है, link के बाहर रखें।
कई locales में साझा तकनीकी तुलना तालिका में, क्षमताओं के नाम, framework नाम, API नाम और मॉडल नाम को उनके स्थापित अंग्रेज़ी रूप में रखें। तालिका के आसपास की व्याख्या का अनुवाद करें, उसके तकनीकी लेबल का नहीं। जिन सामान्य इंटरफ़ेस शब्दों का स्थानीय नाम स्थापित है, उन्हें उस तुलना संदर्भ के बाहर स्थानीयकृत किया जा सकता है।
#बटन और पुष्टि संवाद
बटन के लेबल डिफ़ॉल्ट रूप से छोटे होते हैं, आमतौर पर एक या दो शब्द, और वे परिणाम बताते हैं, इशारे या कॉम्पोनेंट को नहीं।
Click to save, Perform move या Confirm deletion के बजाय Save, Move या Delete चुनें। जो क्रिया बिना कमिट किए बाहर निकलती है, उसके लिए हमेशा Cancel का ही उपयोग करें। OK को केवल विशुद्ध सूचनात्मक सामग्री को स्वीकार करने के लिए रखें।
छोटा होना एक डिफ़ॉल्ट है, अक्षर-सीमा नहीं। जब किसी जानबूझकर लंबे लेबल के शब्द कोई परिणाम स्पष्ट करते हैं या ऐसे विकल्पों में अंतर बताते हैं जिन्हें उपयोगकर्ता आपस में मिला सकते हैं, तब वह बेहतर होता है, जैसे Delete from this group बनाम Delete everywhere, or Restart without saving। लंबाई से निर्णय के लिए ज़रूरी जानकारी मिलनी चाहिए; वह संवाद के शीर्षक या मुख्य भाग को दोहराए नहीं।
जब संभव हो, पुष्टि लेबल के रूप में सबसे specific और संक्षिप्त परिणाम चुनें:
| संदर्भ | कमज़ोर | बेहतर |
|---|---|---|
| हटाने का संवाद | Yes, Sure, Confirm deletion | Delete |
| बिना सहेजे बदलाव | Confirm, Yes | Discard changes |
| केवल स्वीकृति | Confirm operation | OK या Done |
| जटिल सहमति, जिसके परिणाम के लिए कोई स्पष्ट क्रिया नहीं है | Yes | Confirm |
Confirm तब एक उपयोगी विकल्प है जब आसपास का संवाद किसी जटिल प्रतिबद्धता को पूरी तरह नाम दे देता है और कोई छोटी परिणाम-क्रिया सटीक नहीं बैठती। इसे किसी स्पष्ट कमांड की जगह नहीं लेनी चाहिए। Sure बोलचाल का प्रयोग है, कोई स्थिर अंग्रेज़ी कमांड नहीं, और मानक शब्दावली के लिए बहुत अस्पष्ट है।
पुष्टि संवाद को एक संक्षिप्त निर्णय बनाना चाहिए:
- शीर्षक: निर्णय या स्थिति, जैसे
Delete “Roadmap”?; - मुख्य भाग: केवल नया दायरा, परिणाम या पुनर्प्राप्ति की जानकारी;
- क्रियाएँ:
Cancelऔर परिणाम, जैसेDelete; - विनाशकारी स्टाइलिंग: विनाशकारी परिणाम पर लागू हो (
destructiveभूमिका वालीAlertDialogक्रिया), सटीक शब्दों की जगह लेने के लिए नहीं।
जब वास्तविक स्थिति को नाम दिया जा सकता हो, तब Notice, Warning, Error और Confirmation जैसे सामान्य शीर्षकों से बचें।
“Are you sure you want to…”, “Would you like to…”, “Please note that…” जैसे रस्मी वाक्यांशों से बचें, और “successfully” जैसे शब्दों से भी, जब संरचना या स्थिति पहले से वही बता रही हो। शिष्टता शांत और सम्मानपूर्ण लहजे से आनी चाहिए, बार-बार please से नहीं।
#कैपिटलाइज़ेशन, विराम चिह्न और प्रतीक
अंग्रेज़ी UI के लिए डिफ़ॉल्ट रूप से sentence case का उपयोग करें: Reset layout, न कि Reset Layout या RESET LAYOUT। विशेष नाम और स्थापित संक्षिप्त रूप जस के तस रखें। नेटिव मेनू कमांड के लिए title case जैसे प्लेटफ़ॉर्म नियम का पालन तभी करें जब प्लेटफ़ॉर्म इंटीग्रेशन को उससे लाभ हो, और उसे कॉम्पोनेंट वर्ग के भीतर एकरूपता से लागू करें।
ALL CAPS बहुत छोटे सेक्शन लेबल, eyebrow, स्थितियों, स्थापित संक्षिप्त रूपों और कोड जैसे आइडेंटिफ़ायर पर संयमित टाइपोग्राफ़िक ज़ोर दे सकता है। इसका सघन आकार और नपी-तुली ट्रैकिंग बोल्ड टाइप जैसा स्तर बना सकती है, लेकिन यह बटन, लंबे शीर्षकों, वाक्यों या सघन सूचियों में नहीं होना चाहिए। एक ही क्षेत्र में अपरकेस, गहरे रंग और बोल्ड वज़न को एक साथ न मिलाएँ, और हर स्ट्रिंग को अपने आप न बदलें: उत्पाद नाम, संक्षिप्त रूप और स्थानीयकृत सामग्री का इच्छित केसिंग बना रहना चाहिए।
लेबल, बटन, मेनू आइटम, टैब, शीर्षक, प्लेसहोल्डर और छोटी स्थितियों के अंत में पूर्ण विराम नहीं लगता। पूर्ण व्याख्यात्मक, चेतावनी और त्रुटि वाक्यों में लगता है। नियमित सफलता और विफलता संदेशों में विस्मयादिबोधक चिह्न से बचें। चीनी भाषा में वाक्यों में full-width विराम चिह्न का उपयोग करें और उसी अर्थ-नियम से छोटे कंट्रोल लेबल में अंतिम विराम चिह्न छोड़ दें।
तीन बिंदुओं के बजाय एकल ellipsis वर्ण (…) का उपयोग करें। इसे हर उस बटन या मेनू आइटम में जोड़ें जो संवाद, शीट या अलग विंडो खोलता है, और उस कमांड में भी जिसे पूरा होने से पहले और इनपुट या विकल्प चाहिए, जैसे Settings… या Export…। तुरंत चलने वाले कमांड में ellipsis नहीं लगता। जारी कार्य बताने के लिए सजावटी बिंदुओं के बजाय indeterminate progress indicator का उपयोग करें।
त्रुटियों को बताना चाहिए कि क्या हुआ और, उपयोगी होने पर, अगली पुनर्प्राप्ति क्रिया। सफलता फ़ीडबैक परिणामी स्थिति का नाम तभी ले जब वह स्थिति पहले से दिख न रही हो। तकनीकी कोड या लंबी क्षमायाचना के बजाय Couldn’t save. Check your connection and try again. को प्राथमिकता दें; जब दस्तावेज़ स्पष्ट रूप से सहेजा हुआ दिखने लगे, तब Saved successfully toast छोड़ दें।
#अंतर्राष्ट्रीयकरण और प्लेटफ़ॉर्म के अनुरूपता
एक्सेसिबिलिटी (A11y) नाम और लेबल अंग्रेज़ी में रह सकते हैं; इन स्ट्रिंग का स्थानीयकरण आवश्यक नहीं है। किसी आइटम पर कार्य करने वाले कंट्रोल को नाम देते समय उस आइटम का अपना लेबल बनाए रखें, भले ही वह स्थानीयकृत हो। यह अपवाद दिखाई देने वाली UI कॉपी पर लागू नहीं होता।
कॉपी को टेक्स्ट विस्तार, CJK टाइपोग्राफ़ी, दाएँ-से-बाएँ लिपियों और अलग-अलग शॉर्टकट संकेतन में टिके रहना चाहिए। किसी कंट्रोल का आकार एक अंग्रेज़ी लेबल के आधार पर तय न करें। टेक्स्ट को रास्टर एसेट से बाहर रखें, अनुवादित टुकड़ों को जोड़ने से बचें, और लेबल को तभी wrap या truncate होने दें जब उत्पाद ने पुनर्प्राप्ति का कोई रास्ता, जैसे tooltip, परिभाषित किया हो।
उन प्लेटफ़ॉर्म अंतरों का सम्मान करें जिनका अर्थ होता है: Command बनाम Control, नेटिव विंडो सजावट, सिस्टम अपीयरेंस, स्क्रॉलबार व्यवहार, मेनू, नोटिफ़िकेशन क्षमताएँ, और फ़ोन पर सिस्टम हेडर, बैक जेस्चर और अलर्ट। उत्पाद की सूचना संरचना को प्लेटफ़ॉर्म भर में स्थिर रखें, लेकिन ऊपरी पिक्सेल-समानता के लिए परिचित प्लेटफ़ॉर्म व्यवहार को न मिटाएँ।
NSH ऐप फ़ोन, टैबलेट, डेस्कटॉप और वेब पर चलते हैं, और अक्सर किसी होस्ट ऐप के भीतर भी। हर एक के लिए डिज़ाइन करें:
- सिस्टम UI प्लेटफ़ॉर्म का रूप बनाए रखता है। iOS और Android पर पेज का हेडर सिस्टम का होता है (
NavPageकाtitleऔर हेडर विकल्प); डेस्कटॉप और वेब पेज काheaderस्लॉट दिखाते हैं, जिसे ऐप खुद बनाता है। हर पेज में दोनों दें (Navigation)। पुष्टि के लिएAlertDialogका उपयोग करें; स्टेटस बार ऊपर के पेज या संवाद का अनुसरण करता है (statusBar)। - होस्ट की थीम। एम्बेड किए गए ऐप को उसके होस्ट की थीम दी जा सकती है; टोकन पढ़ने वाली क्लासें और Rust बाइंडिंग उसे स्वाभाविक रूप से अपनाती हैं (Theme tokens)।
- सेफ़ एरिया और कीबोर्ड। सामग्री को सेफ़ एरिया (
env(safe-area-inset-*),safeAreaInsets()) के भीतर और इनपुट को सॉफ़्टवेयर कीबोर्ड (env(keyboard-inset-height)) के ऊपर रखें (Device and environment)। - अपीयरेंस, टेक्स्ट आकार और गति। हर सतह लाइट और डार्क (
dark:,colorScheme()) में, उपयोगकर्ता के टेक्स्ट आकार पर, और कम गति (motion-reduce:,reduceMotion()) के साथ काम करे। - दाएँ से बाएँ। लेआउट की दिशा लोकेल का अनुसरण करती है, और
directionस्टाइल किसी व्यू और उसके सबट्री के लिए इसे सेट करती है; start और end प्रॉपर्टी मिरर होती हैं (Right to left)। - स्पर्श और पॉइंटर। स्पर्श लक्ष्य कम से कम 44 × 44 पॉइंट के हों; hover और tooltip केवल पॉइंटर के साथ मौजूद होते हैं।
use nsh_base::nav_page;
nav_page()
.title("Inbox")
.header(page_header("Inbox"))
.child(inbox())import { NavPage } from "nsh/base";
<NavPage title="Inbox" header={<PageHeader title="Inbox" />}>
<Inbox />
</NavPage>#AI द्वारा बनाए गए इंटरफ़ेस के लिए मार्गदर्शन
NSH इंटरफ़ेस बदलने वाले AI को पहले निकटतम फ़ीचर, ऐप के कॉम्पोनेंट और थीम टोकन, तथा कॉम्पोनेंट दस्तावेज़ और घोषणाओं (.nsh/types) का निरीक्षण करना चाहिए। कोड बनाने से पहले उसे मुख्य कार्य, स्टेट का स्वामी, कॉम्पोनेंट संरचना, और कीबोर्ड तथा स्पर्श के रास्ते बताने चाहिए। उसे React, React Native या Shadcn के उदाहरणों से कोई API अनुमानित नहीं करना चाहिए, और केवल इसलिए कोई NSH prop या मेथड नहीं गढ़नी चाहिए कि नाम सही लगता है; जो मौजूद नहीं है, उसे nsh check और बिल्ड की क्लास जाँच बताती हैं।
AI का आउटपुट तब तक अधूरा है जब तक कोई व्यक्ति यह न समझा सके कि पदानुक्रम, घनत्व, कॉम्पोनेंट का चुनाव और अपवाद रूप literal मान इस उत्पाद में क्यों उचित हैं। देखने में ठीक लगने वाला स्क्रीनशॉट प्रमाण नहीं है: कीबोर्ड और स्पर्श व्यवहार, फ़ोकस, गतिशील सामग्री, थीम, आकार बदलना, टेक्स्ट आकार और विफलता की स्थितियाँ भी डिज़ाइन का हिस्सा हैं।
#एक्सेसिबिलिटी चेकलिस्ट
किसी स्क्रीन को पूर्ण मानने से पहले सत्यापित करें कि:
- हर क्रिया कीबोर्ड, स्पर्श और स्क्रीन रीडर से पहुँचने और चलाने योग्य है;
- फ़ोकस क्रम दृश्य और कार्य के क्रम का अनुसरण करता है;
- फ़ोकस दिखाई देता रहता है और ओवरले के बाद पुनर्स्थापित होता है;
- कंट्रोल के एक्सेसिबल नाम हैं; केवल आइकन वाले कंट्रोल में, जब उनके अर्थ, दायरे या शॉर्टकट को स्पष्टीकरण चाहिए, tooltip का उपयोग हो;
- टेक्स्ट और अर्थपूर्ण सीमाओं में पर्याप्त कंट्रास्ट है;
- स्थिति केवल रंग से नहीं बताई जाती;
- disabled और read-only स्थितियाँ अलग पहचानी जा सकती हैं;
- लेबल, त्रुटियाँ और विवरण अपने कंट्रोल के पास रहते हैं;
- लंबे अनुवादों, दाएँ-से-बाएँ और बड़े टेक्स्ट के साथ सामग्री उपयोग योग्य रहती है;
- स्पर्श लक्ष्य कम से कम 44 × 44 पॉइंट के हैं, और सघन लेआउट में भी पॉइंटर लक्ष्य आराम से उपयोग योग्य आकार के हैं।
#डिज़ाइन समीक्षा चेकलिस्ट
समीक्षा कॉम्पोनेंट की गिनती नहीं करती; वह परखती है कि इंटरफ़ेस ने सही निर्णय लिए या नहीं। क्रम से पूछें:
- क्या कार्य स्पष्ट है? क्या नया उपयोगकर्ता बिना सीखे, अनुमान लगाए या प्रयोग किए उद्देश्य, मुख्य क्रिया और अगला कदम पहचान सकता है?
- क्या हर क्रिया अपना वादा निभाती है? क्या लेबल, कंट्रोल, स्थिति, दायरा, फ़ीडबैक और परिणाम एक ही सुसंगत नतीजे का वर्णन करते हैं?
- क्या पदानुक्रम निर्णायक और संयमित है? क्या मुख्य फ़ीचर को उतनी जगह मिलती है जितनी उसे चाहिए, जबकि गहरे रंग, बोल्ड टाइप, बैज, अलर्ट और प्राथमिक बटन दुर्लभ रहते हैं?
- क्या इंटरफ़ेस कम में बेहतर कर सकता है? क्या पूरे कार्य को कमज़ोर किए बिना किसी प्रवेश बिंदु, विकल्प या स्थिति को हटाया, मिलाया या टाला जा सकता है?
- क्या संरचना सटीक है? क्या समकक्ष तत्व एक ही अलाइनमेंट रेखा साझा करते हैं, बराबर अंतराल रेंडर किए गए पिक्सेल तक बराबर रहते हैं, और स्क्रॉलबार अपने वास्तविक स्क्रॉल क्षेत्र के किनारे पर हैं?
- क्या यह कॉम्पोनेंट सिस्टम का पालन करता है? क्या मानक कंट्रोल अपनी ज्यामिति, स्थितियाँ, कीबोर्ड व्यवहार और बंद होने का मॉडल बनाए रखते हैं, जबकि रूप थीम और स्केल टोकन से आता है?
- क्या यह हर स्थिति और बाधा में उपयोग योग्य रहता है? कीबोर्ड, स्पर्श और फ़ोकस व्यवहार, खाली/लोडिंग/विफलता/अनुमति की स्थितियाँ, लंबे अनुवाद, बड़ा टेक्स्ट, दाएँ-से-बाएँ, दोनों अपीयरेंस, न्यूनतम विंडो आकार और कम गति सत्यापित करें।
- क्या इसे वास्तविक प्लेटफ़ॉर्म पर परखा गया है? हर उस प्लेटफ़ॉर्म पर, जिस पर यह जारी होता है (
nsh run --target …,nsh test --target …), वास्तविक कॉम्पोनेंट, कॉपी और प्रतिनिधि सामग्री के साथ कार्य पूरा करें, केवल आदर्श स्क्रीनशॉट से नहीं।