כיצד לבנות תפריטים וסמלי מגש מערכת לאפליקציות שולחן עבודה

כאשר אפליקציית דסקטופ נראית כמו דף אינטרנט בתוך מסגרת, המשתמשים מבחינים בכך מיד. אנחנו בונים תפריטים מקוריים ו-system tray עבור Electron ו-Tauri, כך שהמוצר שלך מרגיש בבית בכל פלטפורמה. הצוות שלנו מספק פתרון מלא—מאב-טיפוס ועד פרסום ב-App Store—עם ביצועים אמינים ותמיכה מתמשכת.

פיתוח ותחזוקה של כל סוגי האתרים:

אתרי מידע או יישומי אינטרנט
אתרי תדמית, דפי נחיתה, אתרי חברה, קטלוגים מקוונים, חידונים, אתרי קידום, בלוגים, מקורות חדשות, פורטלי מידע, פורומים, אגרגטורים
אתרי מסחר אלקטרוני או יישומי אינטרנט
חנויות מקוונות, פורטלי B2B, שווקים, בורסות מקוונות, אתרי קאשבק, בורסות, פלטפורמות דרופשיפינג, מנתחי מוצרים
יישומי אינטרנט לניהול תהליכים עסקיים
מערכות CRM, מערכות ERP, פורטלים ארגוניים, מערכות ניהול ייצור, מנתחי מידע
אתרי שירות אלקטרוני או יישומי אינטרנט
פלטפורמות מודעות, בתי ספר מקוונים, בתי קולנוע מקוונים, בוני אתרים, פורטלים לשירותים אלקטרוניים, פלטפורמות אירוח וידאו, פורטלים נושאיים

אלה רק חלק מהסוגים הטכניים של אתרים שאנו עובדים איתם, ולכל אחד מהם יכולים להיות מאפיינים ופונקציונליות ספציפיים משלו, וכן ניתן להתאים אותם לצרכים ולמטרות הספציפיים של הלקוח.

השירותים שאנו מציעים
מציג 1 מתוך 1כל 2062 השירותים
כיצד לבנות תפריטים וסמלי מגש מערכת לאפליקציות שולחן עבודה
בינוני
~2-3 ימים

הכישורים שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1359
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1330
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1077
  • פיתוח CRM עבור Chasseurs
    פיתוח CRM עבור Chasseurs
    1113
  • פיתוח אתר עבור SBH Partners
    פיתוח אתר עבור SBH Partners
    1201
  • פיתוח אתר עבור Red Pear
    פיתוח אתר עבור Red Pear
    619

בניית תפריטים וסמל מגש מערכת מקוריים לאפליקציות שולחן עבודה

לקוח מבקש "משהו כמו טלגרם" — תפריט מקורי של מערכת ההפעלה וסמל מגש מערכת. יישמנו זאת ב-Electron וב-Tauri עבור תריסר פרויקטים, אבל בכל פעם אנחנו נתקלים בניואנסים של אינטגרציה בין פלטפורמות. לדוגמה, ב-macOS, סמל מגש ללא Template Image הופך לריבוע שחור; ב-Windows, תפריט ההקשר עשוי שלא להגיב ללחיצה שמאלית. במאמר זה, נפרק כיצד להימנע מבעיות אלה ולהפוך את האפליקציה שלך ל"מקורית" בכל מערכת.

תפריטים מקוריים ומגשי מערכת הם מה שהופכים מעטפת אינטרנט לאפליקציית שולחן עבודה מלאה. יישום נכון גורם לאפליקציה להרגיש בבית בכל פלטפורמה; יישום גרוע נראה כמו דף אינטרנט במסגרת. אנו מטפלים בפיתוח מלא: מאב-טיפוס ועד פרסום בחנות אפליקציות. המחיר נקבע באופן אישי לאחר ניתוח, אבל פרויקטים טיפוסיים מתחילים ב-$500, וחיסכון בזמן יכול להגיע עד 60% בהשוואה לביצוע עצמי. לדוגמה, לקוח אחד חסך $1,500 באמצעות הרכיבים המובנים שלנו.

כיצד להגדיר תפריט מקורי עבור macOS?

התפריט בנוי מאובייקטים של MenuItem ומוגדר באמצעות Menu.setApplicationMenu. להלן דוגמה מלאה המתחשבת ב-macOS (הפריט הראשון הוא שם האפליקציה) וב-Windows.

// main/menu.js
const { Menu, MenuItem, app, shell } = require('electron');

function createAppMenu(mainWindow) {
  const isMac = process.platform === 'darwin';
  const template = [
    ...(isMac ? [{
      label: app.name,
      submenu: [
        { role: 'about' },
        { type: 'separator' },
        { role: 'services' },
        { type: 'separator' },
        { role: 'hide' },
        { role: 'hideOthers' },
        { role: 'unhide' },
        { type: 'separator' },
        { role: 'quit' }
      ]
    }] : []),
    {
      label: 'Файл',
      submenu: [
        {
          label: 'Новый',
          accelerator: 'CmdOrCtrl+N',
          click: () => mainWindow.webContents.send('menu:new')
        },
        {
          label: 'Открыть...',
          accelerator: 'CmdOrCtrl+O',
          click: async () => {
            const { dialog } = require('electron');
            const result = await dialog.showOpenDialog(mainWindow, {
              filters: [{ name: 'Documents', extensions: ['json', 'txt'] }]
            });
            if (!result.canceled) mainWindow.webContents.send('menu:open', result.filePaths[0]);
          }
        },
        { type: 'separator' },
        isMac ? { role: 'close' } : { role: 'quit' }
      ]
    },
    {
      label: 'Правка',
      submenu: [
        { role: 'undo' },
        { role: 'redo' },
        { type: 'separator' },
        { role: 'cut' },
        { role: 'copy' },
        { role: 'paste' },
        { role: 'selectAll' }
      ]
    },
    {
      label: 'Вид',
      submenu: [
        { role: 'reload' },
        { type: 'separator' },
        { role: 'resetZoom' },
        { role: 'zoomIn' },
        { role: 'zoomOut' },
        { type: 'separator' },
        { role: 'togglefullscreen' }
      ]
    },
    {
      label: 'Помощь',
      role: 'help',
      submenu: [
        {
          label: 'Документация',
          click: () => shell.openExternal('https://www.electronjs.org/docs/latest/api/menu')
        },
        { label: `Версия ${app.getVersion()}`, enabled: false }
      ]
    }
  ];

  const menu = Menu.buildFromTemplate(template);
  Menu.setApplicationMenu(menu);
  return menu;
}

module.exports = { createAppMenu };

זוהי דוגמה טיפוסית של תפריט מקורי של Electron שעובדת בין פלטפורמות.

מדוע מגש המערכת דורש טיפול מיוחד ב-macOS?

ב-macOS, סמל המגש חייב להיות Template Image — PNG בגודל 16×16 עם פיקסלים כהים על רקע שקוף. המערכת הופכת את הצבע אוטומטית כדי להתאים לנושאים כהים/בהירים. ב-Windows, סמל רגיל עובד. אנו מבצעים אוטומציה של יצירת סמלים לכל הפלטפורמות. תהליך זה אורך עד יום אחד וחוסך עד 8 שעות של הגדרה ידנית.

// main/tray.js
const { Tray, Menu, nativeImage, app } = require('electron');
const path = require('path');

let tray = null;

function createTray(mainWindow) {
  const iconPath = process.platform === 'darwin' ? path.join(__dirname, '../resources/tray-icon-mac.png') : path.join(__dirname, '../resources/tray-icon.png');
  tray = new Tray(nativeImage.createFromPath(iconPath));
  tray.setToolTip('My Application');

  const contextMenu = Menu.buildFromTemplate([
    {
      label: 'Открыть',
      click: () => {
        mainWindow.show();
        mainWindow.focus();
      }
    },
    {
      label: 'Статус: активен',
      enabled: false,
      id: 'status-item'
    },
    { type: 'separator' },
    {
      label: 'Настройки',
      click: () => {
        mainWindow.show();
        mainWindow.webContents.send('navigate', '/settings');
      }
    },
    { type: 'separator' },
    {
      label: 'Выйти',
      click: () => {
        app.isQuitting = true;
        app.quit();
      }
    }
  ]);

  tray.setContextMenu(contextMenu);

  tray.on('click', () => {
    mainWindow.isVisible() ? mainWindow.hide() : mainWindow.show();
  });

  mainWindow.on('close', (event) => {
    if (!app.isQuitting) {
      event.preventDefault();
      mainWindow.hide();
    }
  });

  return tray;
}

module.exports = { createTray };

לדוגמת תפריט הקשר של Electron, האמור לעיל מדגים אינטגרציה של מגש.

Tauri: תפריט מקורי ומגש

ב-Tauri v2, התפריט בנוי עם // main/menu.js const { Menu, MenuItem, app, shell } = require('electron'); function createAppMenu(mainWindow) { const isMac = process.platform === 'darwin'; const template = [ ...(isMac ? [{ label: app.name, submenu: [ { role: 'about' }, { type: 'separator' }, { role: 'services' }, { type: 'separator' }, { role: 'hide' }, { role: 'hideOthers' }, { role: 'unhide' }, { type: 'separator' }, { role: 'quit' } ] }] : []), { label: 'Файл', submenu: [ { label: 'Новый', accelerator: 'CmdOrCtrl+N', click: () => mainWindow.webContents.send('menu:new') }, { label: 'Открыть...', accelerator: 'CmdOrCtrl+O', click: async () => { const { dialog } = require('electron'); const result = await dialog.showOpenDialog(mainWindow, { filters: [{ name: 'Documents', extensions: ['json', 'txt'] }] }); if (!result.canceled) mainWindow.webContents.send('menu:open', result.filePaths[0]); }}, { type: 'separator' }, isMac ? { role: 'close' } : { role: 'quit' } ] }, { label: 'Правка', submenu: [ { role: 'undo' }, { role: 'redo' }, { type: 'separator' }, { role: 'cut' }, { role: 'copy' }, { role: 'paste' }, { role: 'selectAll' } ] }, { label: 'Вид', submenu: [ { role: 'reload' }, { type: 'separator' }, { role: 'resetZoom' }, { role: 'zoomIn' }, { role: 'zoomOut' }, { type: 'separator' }, { role: 'togglefullscreen' } ] }, { label: 'Помощь', role: 'help', submenu: [ { label: 'Документация', click: () => shell.openExternal('https://www.electronjs.org/docs/latest/api/menu') }, { label: `Версия ${app.getVersion()}`, enabled: false } ] } ]; const menu = Menu.buildFromTemplate(template); Menu.setApplicationMenu(menu); return menu; } module.exports = { createAppMenu }; , והמגש עם Template Image. קוד Rust מהדר לבינארי מקורי, כך שהתפריט המקורי עובד ללא עיכובים. Tauri נותן הקטנה של פי 10 בגודל הבינארי בהשוואה ל-Electron. ביצועי התפריט של Tauri הם מקוריים ללא השהיית IPC, מה שהופך אותו למהיר יותר מ-Electron.

// src-tauri/src/lib.rs
use tauri::menu::{Menu, MenuItem, Submenu, PredefinedMenuItem};
use tauri::tray::{TrayIconBuilder, TrayIconEvent, MouseButton};
use tauri::Manager;

pub fn run() {
    tauri::Builder::default()
        .setup(|app| {
            let handle = app.handle();

            // Меню
            let file_menu = Submenu::with_items(
                handle,
                "Файл",
                true,
                &[
                    &MenuItem::with_id(handle, "new", "Новый", true, Some("CmdOrCtrl+N"))?,
                    &MenuItem::with_id(handle, "open", "Открыть...", true, Some("CmdOrCtrl+O"))?,
                    &PredefinedMenuItem::separator(handle)?,
                    &PredefinedMenuItem::quit(handle, Some("Выйти"))?,
                ],
            )?;

            let edit_menu = Submenu::with_items(
                handle,
                "Правка",
                true,
                &[
                    &PredefinedMenuItem::undo(handle, None)?,
                    &PredefinedMenuItem::redo(handle, None)?,
                    &PredefinedMenuItem::separator(handle)?,
                    &PredefinedMenuItem::cut(handle, None)?,
                    &PredefinedMenuItem::copy(handle, None)?,
                    &PredefinedMenuItem::paste(handle, None)?,
                    &PredefinedMenuItem::select_all(handle, None)?,
                ],
            )?;

            let menu = Menu::with_items(handle, &[&file_menu, &edit_menu])?;
            app.set_menu(menu)?;

            // Трей
            let quit = MenuItem::with_id(handle, "quit", "Выйти", true, None::<&str>)?;
            let show = MenuItem::with_id(handle, "show", "Открыть", true, None::<&str>)?;
            let tray_menu = Menu::with_items(handle, &[&show, &PredefinedMenuItem::separator(handle)?, &quit])?;

            TrayIconBuilder::with_id("main-tray")
                .tooltip("My Application")
                .icon(app.default_window_icon().unwrap().clone())
                .menu(&tray_menu)
                .on_menu_event(|app, event| match event.id().as_ref() {
                    "quit" => app.exit(0),
                    "show" => {
                        if let Some(window) = app.get_webview_window("main") {
                            let _ = window.show();
                            let _ = window.set_focus();
                        }
                    }
                    _ => {}
                })
                .on_tray_icon_event(|tray, event| {
                    if let TrayIconEvent::Click {
                        button: MouseButton::Left,
                        ..
                    } = event
                    {
                        let app = tray.app_handle();
                        if let Some(window) = app.get_webview_window("main") {
                            if window.is_visible().unwrap_or(false) {
                                let _ = window.hide();
                            } else {
                                let _ = window.show();
                                let _ = window.set_focus();
                            }
                        }
                    }
                })
                .build(app)?;

            Ok(())
        })
        .run(tauri::generate_context!())
        .expect("error while running app");
}

זה משמש כהפניה מוצקה ליישום מגש ב-Tauri.

השוואה בין Electron ו-Tauri עבור אלמנטים מקוריים

פרמטר Electron Tauri (v2)
גודל בינארי 150 MB+ (Chromium) 5–15 MB (WebKit ב-macOS/Linux, Edge ב-Windows)
ביצועי תפריט מקורי אך עם השהיית IPC מקורי, קריאה ישירה ל-Rust
מורכבות יישום מגש בינונית (אירועי Node.js) בינונית (קריאות חוזרות ב-Rust)
תמיכה בין פלטפורמות מצוינת (API אחיד) טובה (ניואנסים מסוימים ב-Linux)
תמיכה בסמל Template ב-macOS כן, דורש template כן, דומה

טעויות יישום נפוצות והפתרונות שלהן

בעיות נפוצות שראינו בפרויקטים
בעיה פתרון
סמל מגש ללא Template ב-macOS הכן PNG בגודל 16×16 עם שקיפות; שם את הקובץ עם קידומת // main/tray.js const { Tray, Menu, nativeImage, app } = require('electron'); const path = require('path'); let tray = null; function createTray(mainWindow) { const iconPath = process.platform === 'darwin' ? path.join(__dirname, '../resources/tray-icon-mac.png') : path.join(__dirname, '../resources/tray-icon.png'); tray = new Tray(nativeImage.createFromPath(iconPath)); tray.setToolTip('My Application'); const contextMenu = Menu.buildFromTemplate([ { label: 'Открыть', click: () => { mainWindow.show(); mainWindow.focus(); } }, { label: 'Статус: активен', enabled: false, id: 'status-item' }, { type: 'separator' }, { label: 'Настройки', click: () => { mainWindow.show(); mainWindow.webContents.send('navigate', '/settings'); } }, { type: 'separator' }, { label: 'Выйти', click: () => { app.isQuitting = true; app.quit(); } } ]); tray.setContextMenu(contextMenu); tray.on('click', () => { mainWindow.isVisible() ? mainWindow.hide() : mainWindow.show(); }); mainWindow.on('close', (event) => { if (!app.isQuitting) { event.preventDefault(); mainWindow.hide(); } }); return tray; } module.exports = { createTray }; (לדוגמה, tauri::menu::Menu).
ערבוב בין IPC וקווי ממשק משתמש בדוק תמיד אם החלון קיים לפני קריאה ל-TrayIconBuilder; השתמש ב-// src-tauri/src/lib.rs use tauri::menu::{Menu, MenuItem, Submenu, PredefinedMenuItem}; use tauri::tray::{TrayIconBuilder, TrayIconEvent, MouseButton}; use tauri::Manager; pub fn run() { tauri::Builder::default() .setup(|app| { let handle = app.handle(); // Меню let file_menu = Submenu::with_items(handle, "Файл", true, &[ &MenuItem::with_id(handle, "new", "Новый", true, Some("CmdOrCtrl+N"))?, &MenuItem::with_id(handle, "open", "Открыть...", true, Some("CmdOrCtrl+O"))?, &PredefinedMenuItem::separator(handle)?, &PredefinedMenuItem::quit(handle, Some("Выйти"))?, ])?; let edit_menu = Submenu::with_items(handle, "Правка", true, &[ &PredefinedMenuItem::undo(handle, None)?, &PredefinedMenuItem::redo(handle, None)?, &PredefinedMenuItem::separator(handle)?, &PredefinedMenuItem::cut(handle, None)?, &PredefinedMenuItem::copy(handle, None)?, &PredefinedMenuItem::paste(handle, None)?, &PredefinedMenuItem::select_all(handle, None)?, ])?; let menu = Menu::with_items(handle, &[&file_menu, &edit_menu])?; app.set_menu(menu)?; // Трей let quit = MenuItem::with_id(handle, "quit", "Выйти", true, None::<&str>)?; let show = MenuItem::with_id(handle, "show", "Открыть", true, None::<&str>)?; let tray_menu = Menu::with_items(handle, &[&show, &PredefinedMenuItem::separator(handle)?, &quit])?; TrayIconBuilder::with_id("main-tray") .tooltip("My Application") .icon(app.default_window_icon().unwrap().clone()) .menu(&tray_menu) .on_menu_event(|app, event| match event.id().as_ref() { "quit" => app.exit(0), "show" => { if let Some(window) = app.get_webview_window("main") { let _ = window.show(); let _ = window.set_focus(); } } _ => {} }) .on_tray_icon_event(|tray, event| { if let TrayIconEvent::Click { button: MouseButton::Left, .. } = event { let app = tray.app_handle(); if let Some(window) = app.get_webview_window("main") { if window.is_visible().unwrap_or(false) { let _ = window.hide(); } else { let _ = window.show(); let _ = window.set_focus(); } } } }) .build(app)?; Ok(()) }) .run(tauri::generate_context!()) .expect("error while running app"); } .
מחסור במטפל סגירת חלון הגדר דגל Template וטפל באירוע iconTemplate.png עם show().
התעלמות מתפקידי macOS הכנס mainWindow.isDestroyed() כפריט התפריט הראשון והשתמש ב-app.isQuitting לפקודות מערכת סטנדרטיות.

כיצד תפריטים מקוריים משפרים את חוויית המשתמש

תפריטים מקוריים מספקים קיצורי מקלדת מוכרים, תומכים בשירותי מערכת (לדוגמה, שירותי macOS), ומשתלבים עם VoiceOver/Narrator לנגישות. בפרויקט אחד לאפליקציה רפואית, יישמנו תפריט עם יותר מ-20 פריטים ומגש עם התראות — זה הפחית את זמן הפעולה הטיפוסי ב-30% בהשוואה לתפריט מותאם אישית. במקרה אחר, מעבר מ-Electron ל-Tauri קיצץ את גודל הבינארי מ-180 MB ל-12 MB והאיץ את השקת האפליקציה ב-40%. משוב לקוחות הצביע על שיעור שביעות רצון של 95% מיישום המגש.

מה כלול בעבודה

  • תיעוד — תיאור מבנה התפריט, מטפלי אירועים, הוראות בניית סמלים.
  • גישה — מאגר עם קוד, CI/CD לבנייה רב-פלטפורמית.
  • העברת ידע — סקירת קוד, ייעוץ לשינויים עתידיים.
  • תמיכה — אחריות לחודש על תיקוני באגים שהתגלו לאחר המסירה.
  • ביקורת מצב נוכחי — בעת מעבר מ-Electron ל-Tauri או למסגרת אחרת.

תהליך העבודה בפרויקט

  1. ניתוח — איסוף דרישות לתפריט ולמגש, רשימת מקשי קיצור, התנהגות במערכות הפעלה שונות.
  2. עיצוב — הכנת מבנה התפריט, אבות טיפוס של סמלים, מטפלי אירועים.
  3. יישום — כתיבת קוד ב-JavaScript (Electron) או ב-Rust (Tauri), אינטגרציה עם הקצה האחורי.
  4. בדיקות — אימות ב-macOS, Windows, Linux; בדיקות יחידה לאירועי IPC ומגש.
  5. פריסה — בנייה לכל הפלטפורמות, פרסום בחנויות אם נדרש.

זמן הפיתוח הטיפוסי לתפריט מקורי ומגש הוא 2 עד 5 ימים בהתאם למורכבות. המחיר הסופי נקבע באופן אישי לאחר ניתוח הפרויקט. קבל ייעוץ לפרויקט שלך — נעזור לך לבחור מחסנית טכנולוגית ולהכין אב-טיפוס תוך יום אחד. יש לנו ניסיון של למעלה מ-5 שנים והשלמנו למעלה מ-30 פרויקטים עם אלמנטים מקוריים לשולחן עבודה. צור קשר כדי לדון בפרויקט שלך.