הטמעת פאנל צדדי להרחבת Chrome (Chrome) במפתח מלא

חלונות קופצים של תוספי Chrome נסגרים כשמקליקים מחוץ להם, וזה קריטי לכלים שדורשים גישה מתמדת. אנחנו מפתחים Side Panel במפתח מלא—מהקונספט ועד היישום, תוך הבטחת פעילות יציבה ותמיכה מתמשכת. הצוות שלנו מספק פתרון אמין ששומר על הקשר בעת מעבר בין טאבים וגדל עם העסק שלך.

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

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

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

השירותים שאנו מציעים
מציג 1 מתוך 1כל 2062 השירותים
הטמעת פאנל צדדי להרחבת Chrome (Chrome) במפתח מלא
בינוני
~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

חלונות פופ-אפ של תוספי Chrome נסגרים כאשר לוחצים מחוץ להם — זה קריטי לכלים הדורשים גישה מתמדת. ממשק ה-Side Panel API פותר בעיה זו על ידי מתן פאנל צדדי קבוע. משתמשים בתוספים לרישום הערות, ניטור או כלי פיתוח מאבדים לעיתים קרובות נתונים כאשר הפופ-אפ נסגר בטעות. ה-Side Panel נשאר פתוח, שומר על המצב בעת מעבר בין טאבים. אנו מיישמים פאנלים כאלה במפתח מלא תוך 3–9 ימים. נבחן את הפרויקט שלך — צור קשר. הניסיון שלנו עם Chrome API הוא למעלה מ-5 שנים, ואנו מבטיחים תמיכה לאחר ההשקה. קבל ייעוץ בנושא אינטגרציה.

לפי Side Panel API, ניתן להגדיר את הפאנל בנפרד עבור כל טאב. בפרויקט אחד, החלפנו את הפופ-אפ ב-Side Panel עבור תוסף CRM. משתמשים הפסיקו לאבד הזמנות פעילות בעת מעבר בין טאבים, וזמן העבודה עם התוסף גדל ב-40%.

כיצד Side Panel פותר את בעיית אובדן ההקשר?

הפופ-אפ חי רק כל עוד הטאב פעיל והמשתמש לא לחץ מחוץ לחלון. ה-Side Panel נשאר פתוח בעת מעבר בין טאבים ואפילו בעבודה בחלון אחר. זה קריטי לתוספים דמויי DevTools, ניטור, רישום הערות וצ'אטים. מעבר בין טאבים אינו דורש טעינה מחדש של הפאנל — הנתונים נשמרים בזיכרון.

הבדלים בין Side Panel לפופ-אפ

מאפיין פופ-אפ Side Panel
רוחב מקסימום 800 פיקסלים ~400 פיקסלים (קבוע על ידי Chrome)
מחזור חיים עד אובדן פוקוס קבוע, שורד מעברי טאבים
הקשר טאב קשור לטאב הפעיל יכול להיות גלובלי או לכל טאב
זמינות מאז Chrome 4 מאז Chrome 114
Firefox/Safari אין אנלוג אין אנלוג

כיצד להגדיר Side Panel עבור טאבים שונים?

הפאנל יכול להיות שונה עבור כל טאב או משותף לכולם. זה מוגדר באמצעות chrome.sidePanel.setOptions עם הפרמטר tabId. לדוגמה, עבור GitHub אנו מציגים פאנל עם משימות, עבור Figma — עם תגובות, עבור אחרים — מנטרלים אותו. חיסכון במשאבים: הפאנל לא נטען באתרים מיותרים.

הגדרת Manifest V3

{
  "manifest_version": 3,
  "name": "My Side Panel Extension",
  "version": "1.0.0",
  "permissions": ["storage", "tabs", "activeTab", "scripting", "sidePanel"],
  "background": {
    "service_worker": "background.js"
  },
  "action": {
    "default_icon": "icons/icon48.png",
    "default_title": "Открыть панель"
  },
  "side_panel": {
    "default_path": "panel/panel.html"
  }
}
תצורת manifest.json מפורטת

ודא שכללת את כל ההרשאות הנדרשות. ההרשאה { "manifest_version": 3, "name": "My Side Panel Extension", "version": "1.0.0", "permissions": ["storage", "tabs", "activeTab", "scripting", "sidePanel"], "background": { "service_worker": "background.js" }, "action": { "default_icon": "icons/icon48.png", "default_title": "Открыть панель" }, "side_panel": { "default_path": "panel/panel.html" } } היא חובה. בנוסף, sidePanel נדרשת אם אתה שומר נתונים. לגישה לתוכן הטאב, הוסף storage ו-activeTab.

פתיחת פאנל ולוגיקת טאבים (background.js מלא)

// background.js — объединённый Service Worker

// Открытие по клику на иконку
chrome.sidePanel.setPanelBehavior({ openPanelOnActionClick: true }).catch(console.error);

// Per-tab панели (разные для GitHub и Figma)
chrome.tabs.onUpdated.addListener(async (tabId, info, tab) => {
  if (info.status !== 'complete') return;
  if (tab.url?.includes('github.com')) {
    await chrome.sidePanel.setOptions({ tabId, path: 'panel/github-panel.html', enabled: true });
  } else if (tab.url?.includes('figma.com')) {
    await chrome.sidePanel.setOptions({ tabId, path: 'panel/design-panel.html', enabled: true });
  } else {
    await chrome.sidePanel.setOptions({ tabId, enabled: false });
  }
});

// Постоянное соединение с Side Panel через Port
const sidePanelPorts = new Map();
chrome.runtime.onConnect.addListener((port) => {
  if (port.name !== 'side-panel') return;
  chrome.tabs.query({ active: true, currentWindow: true }, ([tab]) => {
    sidePanelPorts.set(tab.id, port);
    port.onDisconnect.addListener(() => sidePanelPorts.delete(tab.id));
  });
});

// Пересылка сообщений от content script в панель
chrome.runtime.onMessage.addListener((msg, sender) => {
  if (msg.type === 'SELECTION_CHANGED') {
    const port = sidePanelPorts.get(sender.tab?.id);
    port?.postMessage({ type: 'SELECTION_CHANGED', text: msg.text });
  }
});

// Отслеживание смены вкладок
chrome.tabs.onActivated.addListener(async ({ tabId }) => {
  const tab = await chrome.tabs.get(tabId);
  const port = sidePanelPorts.get(tabId);
  port?.postMessage({ type: 'PAGE_CHANGED', url: tab.url, title: tab.title });
});

chrome.tabs.onUpdated.addListener((tabId, info, tab) => {
  if (info.status !== 'complete') return;
  const port = sidePanelPorts.get(tabId);
  port?.postMessage({ type: 'PAGE_CHANGED', url: tab.url, title: tab.title });
});

יישום React ב-Side Panel

המבנה של scripting דומה לפופ-אפ, אך יש יותר מקום. אנו משתמשים ב-React לבניית הממשק — זה מאפשר שימוש חוזר ברכיבים ומפשט את התחזוקה.

// panel/App.tsx
import { useEffect, useState, useRef } from 'react';
import browser from 'webextension-polyfill';

export function SidePanel() {
  const [notes, setNotes] = useState<string[]>([]);
  const [currentUrl, setCurrentUrl] = useState('');
  const portRef = useRef<browser.Runtime.Port | null>(null);

  useEffect(() => {
    portRef.current = browser.runtime.connect({ name: 'side-panel' });
    portRef.current.onMessage.addListener((msg) => {
      if (msg.type === 'PAGE_CHANGED') {
        setCurrentUrl(msg.url);
        loadNotesForUrl(msg.url);
      }
      if (msg.type === 'SELECTION_CHANGED') {
        handleNewSelection(msg.text);
      }
    });

    browser.tabs.query({ active: true, currentWindow: true }).then(([tab]) => {
      if (tab.url) {
        setCurrentUrl(tab.url);
        loadNotesForUrl(tab.url);
      }
    });

    return () => portRef.current?.disconnect();
  }, []);

  async function loadNotesForUrl(url: string) {
    const domain = new URL(url).hostname;
    const { notes } = await browser.storage.local.get(`notes_${domain}`);
    setNotes(notes ?? []);
  }

  async function addNote(text: string) {
    const domain = new URL(currentUrl).hostname;
    const updated = [...notes, text];
    setNotes(updated);
    await browser.storage.local.set({ [`notes_${domain}`]: updated });
  }

  return (
    <div className="side-panel">
      <header className="side-panel__header">
        <h2>Заметки</h2>
        <span className="side-panel__url">{new URL(currentUrl).hostname}</span>
      </header>
      <div className="side-panel__notes">
        {notes.map((note, i) => (
          <div key={i} className="note">{note}</div>
        ))}
      </div>
      <NoteInput onAdd={addNote} />
    </div>
  );
}

תקשורת עם Content Script דרך Port

ה-Side Panel חי זמן רב — נוח להשתמש בחיבורים קבועים במקום sendMessage חד-פעמי. ה-Content Script עוקב אחר בחירת טקסט ושולח אותו ל-background, שמעביר אותו לפאנל.

// content.js — следит за выделением текста
document.addEventListener('mouseup', () => {
  const selection = window.getSelection()?.toString().trim();
  if (selection && selection.length > 3) {
    chrome.runtime.sendMessage({ type: 'SELECTION_CHANGED', text: selection });
  }
});

למה לבחור ב-React עבור Side Panel?

React מאפשר פירוק הממשק לרכיבים, ניהול מצב בקלות ושימוש חוזר בלוגיקה. בשילוב עם Port API, אנו מקבלים פאנל ראקטיבי שמגיב מיידית לפעולות המשתמש בדף. לדוגמה, כאשר טקסט נבחר בדף, הפאנל מציג אותו מיד — עיכוב מתחת ל-50 אלפיות השנייה. ה-Side Panel צורך פחות זיכרון מדפי background ואינו משפיע על LCP. אנו מייעלים טעינה: פיצול חבילות, tree-shake, מיניפיקציה של רכיבי React. זמן פתיחת הפאנל הוא מתחת ל-200 אלפיות השנייה.

השוואה: React לעומת Vanilla JS עבור Side Panel

מאפיין Vanilla JS React
ניהול מצב ידני מובנה (useState)
מדרגיות מוגבלת מבוסס רכיבים
מהירות פיתוח בינונית גבוהה (שימוש חוזר)

כיצד להוסיף Side Panel לתוסף שלך

  1. הוסף הרשאת // background.js — объединённый Service Worker // Открытие по клику на иконку chrome.sidePanel.setPanelBehavior({ openPanelOnActionClick: true }).catch(console.error); // Per-tab панели (разные для GitHub и Figma) chrome.tabs.onUpdated.addListener(async (tabId, info, tab) => { if (info.status !== 'complete') return; if (tab.url?.includes('github.com')) { await chrome.sidePanel.setOptions({ tabId, path: 'panel/github-panel.html', enabled: true }); } else if (tab.url?.includes('figma.com')) { await chrome.sidePanel.setOptions({ tabId, path: 'panel/design-panel.html', enabled: true }); } else { await chrome.sidePanel.setOptions({ tabId, enabled: false }); } }); // Постоянное соединение с Side Panel через Port const sidePanelPorts = new Map(); chrome.runtime.onConnect.addListener((port) => { if (port.name !== 'side-panel') return; chrome.tabs.query({ active: true, currentWindow: true }, ([tab]) => { sidePanelPorts.set(tab.id, port); port.onDisconnect.addListener(() => sidePanelPorts.delete(tab.id)); }); }); // Пересылка сообщений от content script в панель chrome.runtime.onMessage.addListener((msg, sender) => { if (msg.type === 'SELECTION_CHANGED') { const port = sidePanelPorts.get(sender.tab?.id); port?.postMessage({ type: 'SELECTION_CHANGED', text: msg.text }); } }); // Отслеживание смены вкладок chrome.tabs.onActivated.addListener(async ({ tabId }) => { const tab = await chrome.tabs.get(tabId); const port = sidePanelPorts.get(tabId); port?.postMessage({ type: 'PAGE_CHANGED', url: tab.url, title: tab.title }); }); chrome.tabs.onUpdated.addListener((tabId, info, tab) => { if (info.status !== 'complete') return; const port = sidePanelPorts.get(tabId); port?.postMessage({ type: 'PAGE_CHANGED', url: tab.url, title: tab.title }); }); ב-manifest.json.
  2. צור קובץ HTML לפאנל (לדוגמה, panel.html).
  3. ב-service worker, קרא ל-panel/panel.html.
  4. הגדר לוגיקת טאבים דרך // panel/App.tsx import { useEffect, useState, useRef } from 'react'; import browser from 'webextension-polyfill'; export function SidePanel() { const [notes, setNotes] = useState<string[]>([]); const [currentUrl, setCurrentUrl] = useState(''); const portRef = useRef<browser.Runtime.Port | null>(null); useEffect(() => { portRef.current = browser.runtime.connect({ name: 'side-panel' }); portRef.current.onMessage.addListener((msg) => { if (msg.type === 'PAGE_CHANGED') { setCurrentUrl(msg.url); loadNotesForUrl(msg.url); } if (msg.type === 'SELECTION_CHANGED') { handleNewSelection(msg.text); } }); browser.tabs.query({ active: true, currentWindow: true }).then(([tab]) => { if (tab.url) { setCurrentUrl(tab.url); loadNotesForUrl(tab.url); } }); return () => portRef.current?.disconnect(); }, []); async function loadNotesForUrl(url: string) { const domain = new URL(url).hostname; const { notes } = await browser.storage.local.get(`notes_${domain}`); setNotes(notes ?? []); } async function addNote(text: string) { const domain = new URL(currentUrl).hostname; const updated = [...notes, text]; setNotes(updated); await browser.storage.local.set({ [`notes_${domain}`]: updated }); } return ( <div className="side-panel"> <header className="side-panel__header"> <h2>Заметки</h2> <span className="side-panel__url">{new URL(currentUrl).hostname}</span> </header> <div className="side-panel__notes"> {notes.map((note, i) => ( <div key={i} className="note">{note}</div> ))} </div> <NoteInput onAdd={addNote} /> </div> ); } .
  5. הגדר React וקבע את Port API לתקשורת עם התוכן.

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

  • ארכיטקטורה והגדרת Manifest V3
  • יישום Side Panel עם React (או פריימוורק אחר)
  • הגדרת לוגיקת טאבים (פאנלים שונים לאתרים שונים)
  • אינטגרציה עם Content Script דרך Port API
  • אחסון נתונים ב-chrome.storage
  • בדיקות ואופטימיזציה (Core Web Vitals, LCP, CLS)

לוח זמנים

Side Panel בסיסי עם React, חיבור קבוע ל-background, סנכרון טאבים ואחסון נתונים — 3–5 ימי עסקים. פאנל עם אינטראקציה בזמן אמת עם תוכן הדף, היסטוריה וחיפוש — 6–9 ימים. העלות מחושבת בנפרד.

נבחן את הפרויקט שלך — צור קשר. אנו מבטיחים תמיכה לאחר ההשקה ותיקוני באגים תוך 30 יום. קבל ייעוץ בנושא אינטגרציה של Side Panel לתוסף שלך.