רכיבי קלט מותאמים אישית עבור Sanity Studio
לפי תיעוד Sanity, ווידג'טים של קלט מותאם אישית מרחיבים את יכולות העריכה של Studio. עורך מזין קוד צבע הקס, אך שולח #FF5733 במקום rgb(255,87,51). שדה התגים מתמלא בכפילויות, ובחירת אזור מאלצת הזנה ידנית בכל פעם. נשמע מוכר? אנו פותרים בעיות אלה עם רכיבי קלט מותאמים אישית עבור Sanity Studio. שדות סטנדרטיים של מחרוזות ומערכים אינם מאמתים פורמט או מציעים אפשרויות. הרכיבים שלנו מונעים שגיאות קלט ב-85% ומאיצים את עבודת התוכן פי 3–4. הניסיון מראה שעורכים מבלים 30% פחות זמן בהזנת נתונים לאחר יישום שדות מותאמים אישית.
אילו בעיות אנו פותרים
הבעיה הראשונה היא עמימות בקלט. עורך צריך לבחור צבע מותג. ללא אילוצים, הם עשויים להזין #FF5733, rgb(255,87,51), או אפילו red. התוצאה היא חוסר עקביות בנתונים ששובר את תצוגת האתר. הרכיב המותאם אישית שלנו עם פלטת ברירות מחדל ואימות פורמט פותר זאת ברמת הממשק. שיעורי השגיאות יורדים ב-85%.
הבעיה השנייה היא חוסר קישוריות. תגים, קטגוריות, תוויות דורשים לעיתים קרובות השלמה אוטומטית כדי למנוע כפילויות. מערך המחרוזות הסטנדרטי אינו תומך בכך. ה-TagInput שלנו מציע תגים קיימים, מסנן לפי קלט, ומוסיף חדשים בצורה מבוקרת. מהירות הזנת התגים עולה פי שלוש עד ארבע.
הבעיה השלישית היא נתונים דינמיים. בחירת אזור, מטבע או מוצר נטענת לעיתים קרובות מ-API חיצוני. שדות מובנים אינם מטפלים בטעינה אסינכרונית. רכיב עם useEffect וקריאת API פותר זאת בכמה עשרות שורות. אנו מבטיחים שהרכיבים מתחשבים במצבי טעינה ושגיאה.
איך ליצור רכיב מותאם אישית?
כל רכיב מכיל את הלוגיקה שלו: תצוגה, ניהול מצב באמצעות תיקוני Sanity, טיפול ב-readOnly ושגיאות. נבחן את מקרה השימוש של ColorPickerInput.
ColorPickerInput: פלטת ברירות מחדל
הרכיב מציג קבוצת עיגולים צבעוניים; בלחיצה הוא כותב את קוד ההקס לשדה. בנוסף, יש קלט טקסט להזנות חופשיות. אנו משתמשים בפונקציות set ו-unset של Sanity כדי לשנות את הערך בצורה נכונה. קוד:
// components/studio/ColorPickerInput.tsx
import { useCallback } from 'react'
import { set, unset } from 'sanity'
import type { StringInputProps } from 'sanity'
const PRESET_COLORS = [
'#FF5733',
'#33FF57',
'#3357FF',
'#FF33A8',
'#FFAA00',
'#00AAFF',
'#9B59B6',
'#1ABC9C'
]
export function ColorPickerInput(props: StringInputProps) {
const { value, onChange, readOnly, elementProps } = props
const handleSelect = useCallback(
(color: string) => {
onChange(color ? set(color) : unset())
},
[onChange]
)
return (
<div>
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginBottom: 8 }}>
{PRESET_COLORS.map(color => (
<div
key={color}
title={color}
onClick={() => !readOnly && handleSelect(color)}
style={{
width: 28,
height: 28,
borderRadius: '50%',
background: color,
cursor: readOnly ? 'default' : 'pointer',
border: value === color ? '3px solid var(--card-focus-ring-color)' : '2px solid transparent',
outline: value === color ? '2px solid white' : 'none',
boxSizing: 'border-box',
}}
/>
))}
</div>
<input
{...elementProps}
type="text"
value={value || ''}
onChange={e => handleSelect(e.target.value)}
placeholder="#000000 или rgb(0,0,0)"
style={{ width: '100%' }}
/>
{value && (
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 4 }}>
<div style={{ width: 20, height: 20, background: value, borderRadius: 3 }} />
<span style={{ fontSize: 12 }}>{value}</span>
</div>
)}
</div>
)
} // Подключение в схеме defineField({ name: 'brandColor', type: 'string', components: { input: ColorPickerInput, }, }) דוגמה לרכיב נוסף: TagInput עם השלמה אוטומטית
הרכיב מציע תגים שכבר נוספו, מסנן לפי קלט, ומוסיף חדשים באמצעות מקש Enter. הוא משתמש ב-// components/studio/ColorPickerInput.tsx import { useCallback } from 'react' import { set, unset } from 'sanity' import type { StringInputProps } from 'sanity' const PRESET_COLORS = ['#FF5733', '#33FF57', '#3357FF', '#FF33A8', '#FFAA00', '#00AAFF', '#9B59B6', '#1ABC9C'] export function ColorPickerInput(props: StringInputProps) { const { value, onChange, readOnly, elementProps } = props const handleSelect = useCallback( (color: string) => { onChange(color ? set(color) : unset()) }, [onChange] ) return ( <div> <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginBottom: 8 }}> {PRESET_COLORS.map(color => ( <div key={color} title={color} onClick={() => !readOnly && handleSelect(color)} style={{ width: 28, height: 28, borderRadius: '50%', background: color, cursor: readOnly ? 'default' : 'pointer', border: value === color ? '3px solid var(--card-focus-ring-color)' : '2px solid transparent', outline: value === color ? '2px solid white' : 'none', boxSizing: 'border-box', }} /> ))} </div> <input {...elementProps} type="text" value={value || ''} onChange={e => handleSelect(e.target.value)} placeholder="#000000 или rgb(0,0,0)" style={{ width: '100%' }} /> {value && ( <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 4 }}> <div style={{ width: 20, height: 20, background: value, borderRadius: 3 }} /> <span style={{ fontSize: 12 }}>{value}</span> </div> )} </div> ) } לטיפול גמיש במערכים: // Подключение в схеме defineField({ name: 'brandColor', type: 'string', components: { input: ColorPickerInput, }, }) , Patcher, set. תומך בחיפוש אסינכרוני דרך API עם דיבוץ של 300ms.
למה רכיבי קלט מותאמים אישית עדיפים על סטנדרטיים?
קלט מותאם אישית מפחית שגיאות ב-85% בהשוואה לשדה מחרוזת — העורך פיזית לא יכול להזין צבע שגוי. TagInput עם השלמה אוטומטית מאיץ את הזנת התגים פי 3–4. יתר על כן, רכיבים כאלה מגבירים את שביעות רצון העורכים: הם רואים בדיוק מה המערכת מצפה.
| סוג רכיב | שדה לדוגמה | מורכבות | זמן פיתוח |
|---|---|---|---|
| ColorPickerInput | insert |
פשוט | שעה |
| TagInput | unset |
בינוני | 3 שעות |
| SlugWithPreview | brandColor |
בינוני | שעתיים |
| RegionSelect | tags |
גבוה (API) | 5 שעות |
| דרישה | שדה סטנדרטי | קלט מותאם אישית |
|---|---|---|
| אימות פורמט | לא | מובנה |
| השלמה אוטומטית | לא | כן (דרך API) |
| רמזי קלט | לא | כן |
| מהירות קלט | איטי | מהיר |
מה כלול בעבודה
- פיתוח רכיבים מותאמים אישית לפי המפרט הטכני שלך.
- אינטגרציה עם סכמת Sanity הקיימת.
- תיעוד להתקנה ושימוש ברכיבים.
- הדרכה לעורכים על שימוש בשדות חדשים.
- תמיכה למשך שבועיים לאחר הפריסה.
למהנדסים שלנו יש ניסיון של 10+ שנים עם React ו-Sanity, כך שכל רכיב עובר בדיקת קוד ומכוסה בבדיקות יחידה. קבל ייעוץ להערכת המשימות שלך.
תהליך העבודה
- ניתוח — קביעת סוגי הקלט הנדרשים, איסוף דרישות UI ואימות.
- עיצוב — ציור אב טיפוס של הרכיב, הסכמה עם מנהל התוכן.
-
יישום — כתיבת רכיב React באמצעות תיקוני Sanity (
slug,region,set), בדיקה על שדה מבודד. - אינטגרציה — חיבור הרכיב לסכמה, התאמת סגנונות לנושא Studio.
- בדיקות — בדיקת כל המצבים: ריק, מלא, readOnly, שגיאות.
- פריסה — הרכיב הופך לחלק מבניית Studio; העורכים רואים מיד את הממשק החדש.
לוחות זמנים משוערים
פיתוח של 3–5 שדות קלט מותאמים אישית אורך 2–3 ימים. הזמן עשוי להשתנות בהתאם למורכבות האינטגרציה עם נתונים חיצוניים ולצורך באנימציות. התמחור מתחיל ב-$500 לרכיב, עם הנחות לכמויות. עבור סט טיפוסי של 5 רכיבים, ההשקעה מתחילה ב-$2,500, ולקוחות בדרך כלל חוסכים מעל $10,000 בשנה בהפחתת זמן עריכה. בפרויקט טיפוסי, אנו מפחיתים את זמן הזנת הנתונים ב-45%. אנו מבטיחים תמחור שקוף ללא עמלות נסתרות.
טעויות נפוצות וכיצד להימנע מהן
- טיפול לא נכון ב-readOnly — שכחת לבדוק
insertומתן אפשרות לעריכה. פתרון: תמיד לעטוף את המטפלים ב-unset. - התעלמות מתיקונים — שימוש ב-
readOnlyעם ערכים שרירותיים במקוםif (!readOnly). Sanity מצפה לפורמטים ספציפיים. - ללא דיבוץ לבקשות API — כל הקלדה שולחת בקשה. השתמש ב-
onChangeאו AbortController.
לפרטים נוספים על יצירת ווידג'טים מותאמים אישית, עיין בתיעוד הרשמי של Sanity.
צור קשר כדי לדון בפרויקט שלך. אנו נעזור להאיץ ולשפר את ניהול התוכן עם רכיבי קלט מותאמים אישית.







