כל טכנולוגיה מתקדמת מספיק לא ניתנת להבחנה מקסם. אלא אם אתם מבינים אותו. שמי תומס שטיינר, אני עובד בצוות Developer Relations ב-Google. במאמר הזה, שמתבסס על ההרצאה שלי ב-Google I/O, אבחן כמה ממשקי Fugu API חדשים ואסביר איך הם משפרים את תהליכי המשתמשים העיקריים ב-PWA של Excalidraw. כך תוכלו לקבל השראה מהרעיונות האלה וליישם אותם באפליקציות שלכם.
איך הגעתי ל-Excalidraw
אני רוצה להתחיל עם סיפור. ב-1 בינואר 2020, כריסטופר שדו, מהנדס תוכנה בפייסבוק, צייץ על אפליקציית ציור קטנה שהוא התחיל לעבוד עליה. בעזרת הכלי הזה, תוכלו לצייר תיבות וחצים שנראים כמו ציור מצויר או ציור ידני. ביום שלמחרת, תוכלו גם לשרטט אליפסות וטקסט, וגם לבחור אובייקטים ולהזיז אותם. ב-3 בינואר, האפליקציה קיבלה את השם Excalidraw, וכמו בכל פרויקט צדדי טוב, אחת הפעולות הראשונות של כריסטופר הייתה לקנות את שם הדומיין. בשלב הזה, אפשר להשתמש בצבעים ולייצא את הציור כולו כקובץ PNG.
ב-15 בינואר, כריסטופר פרסם פוסט בבלוג שמשך תשומת לב רבה בטוויטר, כולל תשומת הלב שלי. הפוסט התחיל עם כמה נתונים סטטיסטיים מרשימים:
- 12,000 משתמשים פעילים ייחודיים
- 1,500 כוכבים ב-GitHub
- 26 תורמי תוכן
לפרויקט שהתחיל לפני שבועיים בלבד, זה לא רע בכלל. אבל מה שבאמת משך את תשומת הלב שלי היה בהמשך הפוסט. כריסטופר כתב שהוא ניסה משהו חדש הפעם: הוא נתן לכל מי ששלח בקשת משיכה גישת קומיט ללא תנאים. באותו יום שבו קראתי את הפוסט בבלוג, כבר היה לי בקשת מיזוג שמוסיפה תמיכה ב-File System Access API ל-Excalidraw, וכך תיקנתי בקשת תכונה שמישהו הגיש.
בקשת המיזוג שלי אושרה יום לאחר מכן, ומאז יש לי גישה מלאה לביצוע קומיטים. ברור שלא עשיתי שימוש לרעה בסמכות שלי. וגם אף אחד מ-149 המשתתפים עד כה.
היום, Excalidraw היא אפליקציית אינטרנט מתקדמת (PWA) מלאה שאפשר להתקין, עם תמיכה במצב אופליין, מצב כהה מדהים, וכן, אפשרות לפתוח ולשמור קבצים בזכות File System Access API.
ליפיס מסביר למה הוא מקדיש כל כך הרבה זמן ל-Excalidraw
אז כאן מסתיים הסיפור שלי על איך הגעתי ל-Excalidraw, אבל לפני שאציג כמה מהתכונות המדהימות של Excalidraw, יש לי את הכבוד להציג את פנאיוטיס. פנאיוטיס ליפירידיס, שמוכר באינטרנט פשוט כ-lipis, הוא התורם הפורה ביותר ל-Excalidraw. שאלתי את ליפיס מה מניע אותו להקדיש כל כך הרבה זמן ל-Excalidraw:
כמו כולם, גם אני למדתי על הפרויקט הזה מהציוץ של כריסטופר. התרומה הראשונה שלי הייתה הוספה של ספריית Open Color, הצבעים שעדיין מהווים חלק מ-Excalidraw היום. כשהפרויקט גדל והיו לנו הרבה בקשות, התרומה הגדולה הבאה שלי הייתה בניית קצה עורפי לאחסון ציורים כדי שהמשתמשים יוכלו לשתף אותם. אבל מה שבאמת מניע אותי לתרום הוא שכל מי שניסה את Excalidraw מחפש תירוצים להשתמש בו שוב.
אני מסכים/ה לגמרי עם lipis. מי שניסה את Excalidraw מחפש תירוצים כדי להשתמש בו שוב.
Excalidraw בפעולה
עכשיו אני רוצה להראות לך איך אפשר להשתמש ב-Excalidraw בפועל. אני לא אמן גדול, אבל הלוגו של Google I/O פשוט מספיק, אז אנסה לצייר אותו. התיבה היא האות i, הקו יכול להיות הקו הנטוי, והאות o היא עיגול. אני לוחץ לחיצה ארוכה על Shift כדי לקבל עיגול מושלם. אני אזיז קצת את הקו הנטוי כדי שזה ייראה טוב יותר. עכשיו יש צבע לאותיות i ו-o. הצבע הכחול טוב. אולי סגנון מילוי אחר? האם כל הצורות מלאות או שיש בהן קווים מצטלבים? לא, ההצגה באמצעות קווים קצרים נראית מצוינת. הוא לא מושלם, אבל זה הרעיון של Excalidraw, אז אשמור אותו.
לוחצים על סמל השמירה ומזינים שם קובץ בתיבת הדו-שיח של שמירת הקובץ. ב-Chrome, דפדפן שתומך ב-File System Access API, הפעולה הזו היא לא הורדה, אלא שמירה אמיתית. אני יכול לבחור את המיקום והשם של הקובץ, ואם אני מבצע עריכות, אני יכול פשוט לשמור אותן באותו קובץ.
אני רוצה לשנות את הלוגו ולהפוך את האות i לאדומה. אם אלחץ עכשיו שוב על 'שמירה', השינוי שלי יישמר באותו קובץ כמו קודם. כדי להוכיח את זה, אנקה את אזור העריכה ואפתח מחדש את הקובץ. כמו שאפשר לראות, הלוגו האדום-כחול ששונה מופיע שוב.
עבודה עם קבצים
בדפדפנים שלא תומכים כרגע בממשק ה-API של File System Access, כל פעולת שמירה היא הורדה, ולכן כשאני מבצע שינויים, נוצרים כמה קבצים עם מספר עולה בשם הקובץ, שממלאים את תיקיית ההורדות שלי. אבל למרות החיסרון הזה, עדיין אפשר לשמור את הקובץ.
פתיחת קבצים
אז מה הסוד? איך אפשר לפתוח ולשמור קבצים בדפדפנים שונים שאולי תומכים ב-File System Access API ואולי לא? פתיחת קובץ ב-Excalidraw מתבצעת בפונקציה שנקראת
loadFromJSON)(
), שבתורה קוראת לפונקציה שנקראת fileOpen()
.
export const loadFromJSON = async (localAppState: AppState) => {
const blob = await fileOpen({
description: 'Excalidraw files',
extensions: ['.json', '.excalidraw', '.png', '.svg'],
mimeTypes: ['application/json', 'image/png', 'image/svg+xml'],
});
return loadFromBlob(blob, localAppState);
};
הפונקציה fileOpen()
מגיעה מספרייה קטנה שכתבתי בשם browser-fs-access, שבה אנחנו משתמשים ב-Excalidraw. הספרייה הזו מספקת גישה למערכת הקבצים דרך File System Access API עם חזרה לגרסה קודמת, כך שאפשר להשתמש בה בכל דפדפן.
קודם אראה לך את ההטמעה כשה-API נתמך. אחרי משא ומתן על סוגי ה-MIME וסיומות הקבצים המקובלים, החלק המרכזי הוא קריאה לפונקציה showOpenFilePicker()
של File System Access API. הפונקציה מחזירה מערך של קבצים או קובץ יחיד, בהתאם למספר הקבצים שנבחרו. כל מה שנותר לעשות הוא להוסיף את ה-file handle לאובייקט הקובץ, כדי שאפשר יהיה לאחזר אותו שוב.
export default async (options = {}) => {
const accept = {};
// Not shown: deal with extensions and MIME types.
const handleOrHandles = await window.showOpenFilePicker({
types: [
{
description: options.description || '',
accept: accept,
},
],
multiple: options.multiple || false,
});
const files = await Promise.all(handleOrHandles.map(getFileWithHandle));
if (options.multiple) return files;
return files[0];
const getFileWithHandle = async (handle) => {
const file = await handle.getFile();
file.handle = handle;
return file;
};
};
ההטמעה של חלופת ברירת המחדל מסתמכת על רכיב input
מסוג "file"
. אחרי המשא ומתן על סוגי ה-MIME והתוספים שצריך לאשר, השלב הבא הוא ללחוץ באופן אוטומטי על רכיב הקלט כדי להציג את תיבת הדו-שיח של פתיחת הקובץ. ההבטחה מתקבלת כשהמשתמש בוחר קובץ אחד או כמה קבצים.
export default async (options = {}) => {
return new Promise((resolve) => {
const input = document.createElement('input');
input.type = 'file';
const accept = [
...(options.mimeTypes ? options.mimeTypes : []),
options.extensions ? options.extensions : [],
].join();
input.multiple = options.multiple || false;
input.accept = accept || '*/*';
input.addEventListener('change', () => {
resolve(input.multiple ? Array.from(input.files) : input.files[0]);
});
input.click();
});
};
שמירת קבצים
עכשיו נסביר איך שומרים. ב-Excalidraw, השמירה מתבצעת בפונקציה שנקראת saveAsJSON()
. קודם הוא מבצע סריאליזציה של מערך הרכיבים של Excalidraw ל-JSON, ממיר את ה-JSON ל-blob ואז קורא לפונקציה בשם fileSave()
. הפונקציה הזו מסופקת גם על ידי הספרייה browser-fs-access.
export const saveAsJSON = async (
elements: readonly ExcalidrawElement[],
appState: AppState,
) => {
const serialized = serializeAsJSON(elements, appState);
const blob = new Blob([serialized], {
type: 'application/vnd.excalidraw+json',
});
const fileHandle = await fileSave(
blob,
{
fileName: appState.name,
description: 'Excalidraw file',
extensions: ['.excalidraw'],
},
appState.fileHandle,
);
return { fileHandle };
};
אני רוצה קודם לבדוק את ההטמעה בדפדפנים עם תמיכה ב-File System Access API. השתיים הראשונות נראות קצת מסובכות, אבל כל מה שהן עושות זה לנהל משא ומתן על סוגי MIME וסיומות קבצים. אם כבר שמרתי בעבר ויש לי כבר ידית קובץ, לא צריך להציג תיבת דו-שיח לשמירה. אבל אם זה השמירה הראשונה, מוצג דו-שיח של קובץ והאפליקציה מקבלת בחזרה את נקודת האחיזה של הקובץ לשימוש עתידי. הפעולה שנותרת היא כתיבה לקובץ, שמתבצעת באמצעות זרם שניתן לכתיבה.
export default async (blob, options = {}, handle = null) => {
options.fileName = options.fileName || 'Untitled';
const accept = {};
// Not shown: deal with extensions and MIME types.
handle =
handle ||
(await window.showSaveFilePicker({
suggestedName: options.fileName,
types: [
{
description: options.description || '',
accept: accept,
},
],
}));
const writable = await handle.createWritable();
await writable.write(blob);
await writable.close();
return handle;
};
התכונה 'שמירה בשם'
אם מחליטים להתעלם מטיפול בקובץ שכבר קיים, אפשר להטמיע תכונה של 'שמירה בשם' כדי ליצור קובץ חדש על סמך קובץ קיים. כדי להראות את זה, אפתח קובץ קיים, אבצע בו שינוי כלשהו ואז לא אדרוס את הקובץ הקיים, אלא אצור קובץ חדש באמצעות התכונה 'שמירה בשם'. הקובץ המקורי יישאר ללא שינוי.
ההטמעה בדפדפנים שלא תומכים ב-File System Access API היא קצרה, כי כל מה שהיא עושה זה ליצור אלמנט anchor עם מאפיין download
שהערך שלו הוא שם הקובץ הרצוי, וכתובת URL של blob כערך של המאפיין href
.
export default async (blob, options = {}) => {
const a = document.createElement('a');
a.download = options.fileName || 'Untitled';
a.href = URL.createObjectURL(blob);
a.addEventListener('click', () => {
setTimeout(() => URL.revokeObjectURL(a.href), 30 * 1000);
});
a.click();
};
לאחר מכן מתבצעת לחיצה על רכיב העוגן באופן פרוגרמטי. כדי למנוע דליפות זיכרון, צריך לבטל את כתובת ה-URL של ה-blob אחרי השימוש. מכיוון שמדובר רק בהורדה, אף פעם לא מוצג דו-שיח לשמירת קבצים, וכל הקבצים מגיעים לתיקייה Downloads
שמוגדרת כברירת מחדל.
גרירה ושחרור
אחת מהאינטגרציות האהובות עליי במערכת במחשב היא גרירה ושחרור. ב-Excalidraw, כשאני גורר קובץ .excalidraw
לאפליקציה, הוא נפתח מיד ואני יכול להתחיל לערוך אותו. בדפדפנים שתומכים ב-File System Access API, אני יכול אפילו לשמור את השינויים שלי באופן מיידי. אין צורך להשתמש בתיבת דו-שיח לשמירת קובץ כי הטיפול הנדרש בקובץ התקבל מפעולת הגרירה וההשלכה.
הסוד הוא לבצע קריאה ל-getAsFileSystemHandle()
בפריט data transfer כשיש תמיכה ב-File System Access API. אחר כך אני מעביר את הטיפול בקובץ הזה אל loadFromBlob()
, שאולי אתם זוכרים מהפסקה שלמעלה. אפשר לעשות כל כך הרבה דברים עם קבצים: לפתוח, לשמור, לשמור מחדש, לגרור, להפיל. הקולגה שלי, פיט, ואני תיעדנו את כל הטריקים האלה ועוד במאמר שלנו, כדי שתוכלו להשלים את הפערים אם כל זה היה מהיר מדי.
const file = event.dataTransfer?.files[0];
if (file?.type === 'application/json' || file?.name.endsWith('.excalidraw')) {
this.setState({ isLoading: true });
// Provided by browser-fs-access.
if (supported) {
try {
const item = event.dataTransfer.items[0];
file as any.handle = await item as any
.getAsFileSystemHandle();
} catch (error) {
console.warn(error.name, error.message);
}
}
loadFromBlob(file, this.state).then(({ elements, appState }) =>
// Load from blob
).catch((error) => {
this.setState({ isLoading: false, errorMessage: error.message });
});
}
שיתוף קבצים
שילוב מערכת נוסף שקיים כרגע ב-Android, ב-ChromeOS וב-Windows הוא באמצעות Web Share Target API. אני נמצא באפליקציית הקבצים בתיקייה Downloads
. אני רואה שני קבצים, אחד מהם עם השם הלא ברור untitled
וחותמת זמן. כדי לבדוק מה יש בו, אני לוחץ על סמל שלוש הנקודות, ואז על סמל השיתוף, ואחת מהאפשרויות שמופיעות היא Excalidraw. כשאני מקיש על הסמל, אני רואה שהקובץ מכיל שוב רק את הלוגו של I/O.
Lipis על גרסת Electron שהוצאה משימוש
אפשרות נוספת שלא הזכרתי עד עכשיו היא ללחוץ לחיצה כפולה על קבצים. בדרך כלל, כשלוחצים לחיצה כפולה על קובץ, האפליקציה שמשויכת לסוג ה-MIME של הקובץ נפתחת. לדוגמה, עבור .docx
זה יהיה Microsoft Word.
בעבר הייתה ל-Excalidraw גרסת Electron של האפליקציה שתמכה בשיוכים כאלה לסוגי קבצים, כך שכשלחצתם לחיצה כפולה על קובץ .excalidraw
, אפליקציית Excalidraw Electron נפתחה. ליפיס, שכבר פגשתם אותו, היה גם היוצר וגם מי שהוציא משימוש את Excalidraw Electron. שאלתי אותו למה הוא חושב שאפשר להוציא משימוש את גרסת Electron:
אנשים ביקשו אפליקציית Electron מההתחלה, בעיקר כי הם רצו לפתוח קבצים בלחיצה כפולה. התכוונו גם להוסיף את האפליקציה לחנויות אפליקציות. במקביל, מישהו הציע ליצור אפליקציית PWA במקום, אז פשוט עשינו את שתי האפשרויות. למזלנו, הכרנו את ממשקי ה-API של Project Fugu, כמו גישה למערכת הקבצים, גישה ללוח, טיפול בקבצים ועוד. בלחיצה אחת בלבד תוכלו להתקין את האפליקציה במחשב או בנייד, בלי המשקל הנוסף של Electron. היה קל להחליט להוציא משימוש את גרסת Electron, להתמקד רק באפליקציית האינטרנט ולהפוך אותה ל-PWA הכי טוב שאפשר. בנוסף, עכשיו אפשר לפרסם אפליקציות PWA בחנות Play וב-Microsoft Store. זה ענק!
אפשר לומר ש-Excalidraw for Electron לא הוצא משימוש כי Electron לא טובה, ממש לא, אלא כי האינטרנט הפך להיות טוב מספיק. אהבתי!
טיפול בקבצים
כשאני אומר שהאינטרנט נהיה מספיק טוב, זה בגלל תכונות כמו הטיפול הקרוב בקבצים.
זו התקנה רגילה של macOS Big Sur. עכשיו נבדוק מה קורה כשלוחצים לחיצה ימנית על קובץ Excalidraw. אני יכול לבחור לפתוח אותו באמצעות Excalidraw, אפליקציית ה-PWA שהתקנתי. כמובן שאפשר גם ללחוץ לחיצה כפולה, אבל זה פחות מרשים להדגמה בצילום מסך.
איך זה עובד? השלב הראשון הוא להגדיר למערכת ההפעלה את סוגי הקבצים שהאפליקציה יכולה לטפל בהם. אני עושה את זה בשדה חדש שנקרא file_handlers
במניפסט של אפליקציית האינטרנט. הערך שלו הוא מערך של אובייקטים עם פעולה ומאפיין accept
. הפעולה קובעת את נתיב כתובת ה-URL שמערכת ההפעלה מפעילה את האפליקציה בו, ואובייקט ה-accept הוא צמד מפתח/ערך של סוגי MIME ותוספי הקבצים המשויכים.
{
"name": "Excalidraw",
"description": "Excalidraw is a whiteboard tool...",
"start_url": "/",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff",
"file_handlers": [
{
"action": "/",
"accept": {
"application/vnd.excalidraw+json": [".excalidraw"]
}
}
]
}
השלב הבא הוא לטפל בקובץ כשהאפליקציה מופעלת. זה קורה בממשק launchQueue
שבו אני צריך להגדיר צרכן על ידי קריאה ל-setConsumer()
. הפרמטר של הפונקציה הזו הוא פונקציה אסינכרונית שמקבלת את launchParams
. לאובייקט launchParams
הזה יש שדה שנקרא files, שמקבל מערך של נקודות אחיזה לקבצים שאפשר לעבוד איתם. הקובץ הראשון חשוב לי, ומתוך ה-handle שלו אני מקבל blob שאני מעביר לחבר הוותיק שלנו loadFromBlob()
.
if ('launchQueue' in window && 'LaunchParams' in window) {
window as any.launchQueue
.setConsumer(async (launchParams: { files: any[] }) => {
if (!launchParams.files.length) return;
const fileHandle = launchParams.files[0];
const blob: Blob = await fileHandle.getFile();
blob.handle = fileHandle;
loadFromBlob(blob, this.state).then(({ elements, appState }) =>
// Initialize app state.
).catch((error) => {
this.setState({ isLoading: false, errorMessage: error.message });
});
});
}
אם ההסבר היה מהיר מדי, אפשר לקרוא מידע נוסף על File Handling API במאמר שלי. כדי להפעיל את הטיפול בקבצים, צריך להגדיר את הדגל של התכונות הניסיוניות של פלטפורמת האינטרנט. ההשקה מתוכננת ל-Chrome בהמשך השנה.
שילוב עם הלוח
תכונה מגניבה נוספת של Excalidraw היא השילוב עם הלוח. אני יכול להעתיק את הציור כולו או רק חלקים ממנו ללוח, אולי להוסיף סימן מים אם מתחשק לי, ואז להדביק אותו באפליקציה אחרת. אגב, זו גרסת אינטרנט של אפליקציית הצייר של Windows 95.
הדרך שבה זה עובד היא פשוטה באופן מפתיע. כל מה שאני צריך זה את אזור הציור כ-blob, שאותו אני כותב ללוח על ידי העברת מערך עם אלמנט אחד עם ClipboardItem
עם ה-blob לפונקציה navigator.clipboard.write()
. מידע נוסף על האפשרויות של Clipboard API זמין במאמר שלי ושל ג'ייסון.
export const copyCanvasToClipboardAsPng = async (canvas: HTMLCanvasElement) => {
const blob = await canvasToBlob(canvas);
await navigator.clipboard.write([
new window.ClipboardItem({
'image/png': blob,
}),
]);
};
export const canvasToBlob = async (canvas: HTMLCanvasElement): Promise<Blob> => {
return new Promise((resolve, reject) => {
try {
canvas.toBlob((blob) => {
if (!blob) {
return reject(new CanvasError(t('canvasError.canvasTooBig'), 'CANVAS_POSSIBLY_TOO_BIG'));
}
resolve(blob);
});
} catch (error) {
reject(error);
}
});
};
עבודה משותפת עם אחרים
שיתוף כתובת URL של סשן
ידעתם שב-Excalidraw יש גם מצב שיתוף פעולה? אנשים שונים יכולים לעבוד יחד על אותו מסמך. כדי להתחיל סבב חדש, אני לוחץ על לחצן הפעילות המשותפת בזמן אמת ואז מתחיל סבב. אני יכול לשתף בקלות את כתובת ה-URL של הסשן עם משתפי הפעולה שלי בזכות Web Share API שמשולב ב-Excalidraw.
שיתוף פעולה בזמן אמת
ביצעתי סימולציה של סשן שיתוף פעולה באופן מקומי על ידי עבודה על הלוגו של Google I/O ב-Pixelbook שלי, בטלפון Pixel 3a שלי וב-iPad Pro שלי. אפשר לראות שהשינויים שאני מבצע במכשיר אחד משתקפים בכל המכשירים האחרים.
אני אפילו יכול לראות את כל הסמנים זזים. הסמן ב-Pixelbook נע בצורה יציבה כי הוא נשלט על ידי משטח מגע, אבל הסמן בטלפון Pixel 3a והסמן בטאבלט iPad Pro קופצים כי אני שולט במכשירים האלה באמצעות הקשה עם האצבע.
איך רואים את הסטטוסים של שותפי העריכה
כדי לשפר את חוויית שיתוף הפעולה בזמן אמת, פועלת גם מערכת לזיהוי חוסר פעילות. הסמן של iPad Pro מציג נקודה ירוקה כשאני משתמש בו. הנקודה הופכת לשחורה כשאני עובר לכרטיסייה אחרת בדפדפן או לאפליקציה אחרת. וכשאני באפליקציית Excalidraw, אבל לא עושה כלום, הסמן מראה שאני לא פעיל, וזה מסומל על ידי שלושת האותיות zZZ.
קוראים אדוקים של הפרסומים שלנו עשויים לחשוב שזיהוי מצב לא פעיל מתבצע באמצעות Idle Detection API, הצעה בשלב מוקדם שעליה עבדנו במסגרת פרויקט Fugu. ספוילר: לא. הייתה לנו הטמעה שמבוססת על ה-API הזה ב-Excalidraw, אבל בסופו של דבר החלטנו ללכת על גישה מסורתית יותר שמבוססת על מדידת תנועת מצביע ועמוד גלוי.
שלחנו משוב על הסיבה לכך ש-Idle Detection API לא פתר את תרחיש השימוש שהיה לנו. כל ממשקי ה-API של Project Fugu מפותחים באופן פתוח, כך שכל אחד יכול להביע את דעתו ולהשמיע את קולו.
Lipis on what is holding back Excalidraw
אם כבר מדברים על זה, שאלתי את lipis עוד שאלה אחת לגבי מה שלדעתו חסר בפלטפורמת האינטרנט שמעכב את Excalidraw:
File System Access API הוא כלי נהדר, אבל אתם יודעים מה? רוב הקבצים שחשובים לי בימים אלה נמצאים ב-Dropbox או ב-Google Drive, ולא בדיסק הקשיח. הייתי רוצה שממשק File System Access API יכלול שכבת הפשטה לספקי מערכות קבצים מרוחקות כמו Dropbox או Google, כדי שאפשר יהיה לשלב אותן, ושמפתחים יוכלו לכתוב קוד נגדם. המשתמשים יכולים להיות רגועים ולדעת שהקבצים שלהם בטוחים אצל ספק הענן שהם סומכים עליו.
אני מסכים/ה לחלוטין עם lipis, גם אני חי/ה בענן. אני מקווה שהתכונה הזו תוטמע בקרוב.
מצב אפליקציה עם כרטיסיות
וואו! ראינו הרבה שילובים מצוינים של API ב-Excalidraw. מערכת קבצים, טיפול בקבצים, לוח גזירה, שיתוף באינטרנט ויעד שיתוף באינטרנט. אבל יש עוד דבר אחד. עד עכשיו, יכולתי לערוך רק מסמך אחד בכל פעם. לא יותר. אנחנו שמחים להציג לראשונה גרסה מוקדמת של מצב האפליקציה עם הכרטיסיות ב-Excalidraw. כך זה נראה.
יש לי קובץ קיים שפתוח באפליקציית PWA של Excalidraw שמותקנת ופועלת במצב עצמאי. עכשיו אני פותח כרטיסייה חדשה בחלון העצמאי. זו לא כרטיסייה רגילה בדפדפן, אלא כרטיסיית PWA. בכרטיסייה החדשה הזו אוכל לפתוח קובץ משני ולעבוד עליו בנפרד מחלון האפליקציה.
מצב האפליקציה עם הכרטיסיות נמצא בשלבי פיתוח מוקדמים, ולכן לא הכול סופי. אם אתם מעוניינים, כדאי לקרוא את המאמר שלי כדי להתעדכן בסטטוס הנוכחי של התכונה הזו.
סגירה
כדי להתעדכן בנושא הזה ובתכונות אחרות, כדאי לעקוב אחרי המעקב שלנו אחרי Fugu API. אנחנו נרגשים לקדם את האינטרנט ולאפשר לכם לעשות יותר בפלטפורמה. אנחנו מאחלים לכם שימוש מוצלח ב-Excalidraw, ומקווים שתבנו איתו אפליקציות מדהימות. כדי להתחיל ליצור, נכנסים אל excalidraw.com.
אני כבר לא יכול לחכות לראות חלק מהממשקי ה-API שהצגתי היום מופיעים באפליקציות שלך. שמי Tom, אפשר למצוא אותי ב-Twitter בכתובת @tomayac ובאינטרנט באופן כללי. תודה רבה שצפיתם, ושתהנו משאר האירועים ב-Google I/O.