דילוג לתוכן
  • חוקי הפורום
  • פופולרי
  • לא נפתר
  • משתמשים
  • חיפוש גוגל בפורום
  • צור קשר
עיצובים
  • בהיר
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • כהה
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • ברירת מחדל (ללא עיצוב (ברירת מחדל))
  • ללא עיצוב (ברירת מחדל)
כיווץ
מתמחים טופ
ל

לב טוב

@לב טוב
הפסקת מעקב מעקב
אודות
פוסטים
248
נושאים
24
שיתופים
0
קבוצות
0
עוקבים
9
עוקב אחרי
0

פוסטים

פוסטים אחרונים הגבוה ביותר שנוי במחלוקת

  • שיתוף | מרכז הערוצים - תוסף לצפייה בהודעות מכל ערוצי ChatFree
    ל לב טוב

    @הדובדבן-שבקצפת נסה ותראה
    הבדלים רבים מאוד
    עי' היטב בפוסט הראשון

    עזרה הדדית - מחשבים וטכנולוגיה

  • שיתוף | מרכז הערוצים - תוסף לצפייה בהודעות מכל ערוצי ChatFree
    ל לב טוב

    @לשכת-הרב עדכנתי בפוסט הראשון,
    בעדכון הבא יתווסף גם אותנטי ניוז ועוד

    עזרה הדדית - מחשבים וטכנולוגיה

  • שיתוף | מרכז הערוצים - תוסף לצפייה בהודעות מכל ערוצי ChatFree
    ל לב טוב

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

    עזרה הדדית - מחשבים וטכנולוגיה

  • שיתוף | נפתחו סימן הלייק והדיסלייק בפורום בסינון אתרוג!
    ל לב טוב

    @שניאור-שמח פתוח, חוץ משתי האימוג'ים השני והשלישי שחסומים גם בגלישה רגילה

    אתרוג

  • בירור | התייעצות על הקמת שרשור של קודי הצטרפות ל4 חודשים חינם פרו בגוגל/גמיני
    ל לב טוב

    @לנציצ אם כבר, אזכיר את התוסף שלי שאפשר להעתיק איתו
    תיקיות שלימות מהדרייב עם כל תכולתן בקלות רבה

    עזרה הדדית - מחשבים וטכנולוגיה

  • שיתוף | מרכז הערוצים - תוסף לצפייה בהודעות מכל ערוצי ChatFree
    ל לב טוב

    עדכון גירסה
    נוספו שיפורים שונים

    • כפתור לחזרה למיקום האחרון שצפיתם בערוץ (יש באג זמני והוא רק בחלק מן הערוצים)
    • הוספתי צלילים שונים, @לנציצ
    • הוספתי בהגדרות אופציה לשנות את האייקון בגי'מייל ללבן, @לשכת-הרב
    עזרה הדדית - מחשבים וטכנולוגיה

  • להורדה | תוסף לפתיחת חלון תצוגה מקדימה בעת רפרוף על קישור
    ל לב טוב

    @יוחנן-יוחננוביץ ממליץ שהתצוגה מקדימה תופיע צמוד לסמן העכבר, מה שיאפשר [לכאורה] גם גלילה בתוך התצוגה לפני שהיא נעלמת

    עזרה הדדית - מחשבים וטכנולוגיה

  • שיתוף | מרכז הערוצים - תוסף לצפייה בהודעות מכל ערוצי ChatFree
    ל לב טוב

    @לנציצ בהגדרות יש ביטול התראות, ואופציה לשינוי הצליל או ללא צליל וכו'

    עזרה הדדית - מחשבים וטכנולוגיה

  • שיתוף | מרכז הערוצים - תוסף לצפייה בהודעות מכל ערוצי ChatFree
    ל לב טוב

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

    עזרה הדדית - מחשבים וטכנולוגיה

  • שיתוף | מרכז הערוצים - תוסף לצפייה בהודעות מכל ערוצי ChatFree
    ל לב טוב

    @לשכת-הרב ובחשבון הגוגל ברירת המחדל אין לך גישה לערוצים הללו?

    עזרה הדדית - מחשבים וטכנולוגיה

  • שיתוף | מרכז הערוצים - תוסף לצפייה בהודעות מכל ערוצי ChatFree
    ל לב טוב

    @לשכת-הרב כנראה ערוצים הללו לא הגדירו שצריך התחברות בחשבון גוגל.
    אין סיכוי בעולם שהתוסף הוא זה שעושה מעקף שכזה. בעולם. לדעתי הענייה.

    עזרה הדדית - מחשבים וטכנולוגיה

  • שיתוף | מרכז הערוצים - תוסף לצפייה בהודעות מכל ערוצי ChatFree
    ל לב טוב

    @לשכת-הרב לא, התחברות גוגל הכרחית

    עזרה הדדית - מחשבים וטכנולוגיה

  • שיתוף | מרכז הערוצים - תוסף לצפייה בהודעות מכל ערוצי ChatFree
    ל לב טוב

    @לשכת-הרב רק כפי שניתן לראות, הוא עדיין לא גמור...

    עזרה הדדית - מחשבים וטכנולוגיה

  • שיתוף | מרכז הערוצים - תוסף לצפייה בהודעות מכל ערוצי ChatFree
    ל לב טוב

    מרכז הערוצים

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

    להתקנה מחנות כרום

    צילום מסך 2026-06-28 202958.png

    ערוצים נתמכים בתוסף
    עיצוב ללא שם (2).png

    האפשרויות בתוסף:

    • בחירת ערוצים לקבלת הודעות
    • דף הבית לקריאת ההודעות האחרונות ברצף מכל הערוצים
    • אפשרות לגלילה אוטומטית של ההודעות!
    • בחירת גודל הטקסט, מצב בהיר/כהה, ועוד אפשרויות להתאמה אישית.
    • לאחר ההתקנה ורענון Gmail התוסף יופיע בסרגל הצד של Gmail:
      צילום מסך 2026-07ע-02 010229.png

    תודה ליוצרי התוספים הבאים, שמהם קיבלתי לא מעט השראה במהלך הפיתוח:

    • הערוץ
    • אתרים במייל
    • חדשות הגיזרה

    אשמח מאוד לשמוע הצעות לשיפור!
    מכירים ערוץ שכדאי להוסיף? כתבו כאן או פנו אליי ואבדוק להוסיף אותו.
    התוסף נמצא בפיתוח פעיל, ועדכונים ותכונות חדשות יתווספו בהמשך.

    לחצו כאן להתקנת התוסף

    עזרה הדדית - מחשבים וטכנולוגיה

  • שיתוף | העתקה אוטומטית של כל המייל אל הדרייב
    ל לב טוב

    @יוסף-מאיר-וייס ב''ה אני לא משועמם... בעקבות בקשה של כמה אנשים.
    פשוט ככה הכל יורד אוטומטי למחשב לשימוש גם כשאין רשת? להורדה מהירה בחדרי מחשבים?
    וכו'

    עזרה הדדית - מחשבים וטכנולוגיה

  • שיתוף | העתקה אוטומטית של כל המייל אל הדרייב
    ל לב טוב

    צריכים גיבוי מסודר של המיילים שלכם?

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

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

    /**
     * Gmail to Google Drive Sync - Advanced Interface & Automation
     * -----------------------------------------------------------------
     * גרסה הפתוחה למשתמשים אחרים (דורש פריסה כ-User Accessing)
     */
    
    const RULES_PROP_KEY = "GMAIL_TO_DRIVE_RULES";
    const LOGS_PROP_KEY = "GMAIL_TO_DRIVE_LOGS";
    const PROCESSED_LABEL_NAME = "System/SavedToDrive";
    const MAX_EXECUTION_TIME_MS = 5 * 60 * 1000; // 5 minutes limit
    
    function doGet() {
      const htmlContent = getHtmlPage();
      return HtmlService.createHtmlOutput(htmlContent)
        .setTitle("מנהל סנכרון Gmail ל-Drive")
        // אבטחה: מונע Clickjacking (חשוב לערעור מול גוגל)
        .setXFrameOptionsMode(HtmlService.XFrameOptionsMode.DEFAULT)
        .addMetaTag('viewport', 'width=device-width, initial-scale=1');
    }
    
    function getRules() {
      const props = PropertiesService.getUserProperties();
      const rulesJson = props.getProperty(RULES_PROP_KEY);
      return rulesJson ? JSON.parse(rulesJson) : [];
    }
    
    function saveRules(rules) {
      const props = PropertiesService.getUserProperties();
      props.setProperty(RULES_PROP_KEY, JSON.stringify(rules));
      return { success: true };
    }
    
    function getLogs() {
      const props = PropertiesService.getUserProperties();
      const logsJson = props.getProperty(LOGS_PROP_KEY);
      return logsJson ? JSON.parse(logsJson) : [];
    }
    
    function addLog(ruleName, count, status) {
      const props = PropertiesService.getUserProperties();
      let logs = getLogs();
      const newLog = {
        date: Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "yyyy-MM-dd HH:mm:ss"),
        rule: ruleName,
        count: count,
        status: status
      };
      logs.unshift(newLog);
      if (logs.length > 50) logs.pop();
      props.setProperty(LOGS_PROP_KEY, JSON.stringify(logs));
    }
    
    function clearLogs() {
      const props = PropertiesService.getUserProperties();
      props.deleteProperty(LOGS_PROP_KEY);
      return { success: true };
    }
    
    // קבלת מצב האוטומציה השמור (כעת כולל גם את השעות והתדירות)
    function getTriggerStatus() {
      const props = PropertiesService.getUserProperties();
      const configStr = props.getProperty("AUTO_CONFIG");
      
      // הגדרות ברירת מחדל אם טרם הוגדר
      let config = { active: false, mode: 'daily', time: 0, hours: [] };
      if (configStr) {
        try { config = JSON.parse(configStr); } catch (e) {}
      }
    
      const triggers = ScriptApp.getProjectTriggers();
      let hasTrigger = false;
      for (let i = 0; i < triggers.length; i++) {
        if (triggers[i].getHandlerFunction() === 'runAutomations') {
          hasTrigger = true;
          break;
        }
      }
      
      // סנכרון מצב במידה וטריגרים נמחקו ידנית
      config.active = hasTrigger; 
      return config;
    }
    
    // שמירת והפעלת אוטומציה לפי הגדרות משתמש מורחבות
    function toggleAutomation(config) {
      cleanUpAllTriggers();
      const props = PropertiesService.getUserProperties();
      
      if (config.active) {
        if (config.mode === 'daily') {
          // פעם ביום בשעה מסוימת
          ScriptApp.newTrigger('runAutomations')
            .timeBased()
            .everyDays(1)
            .atHour(parseInt(config.time))
            .create();
        } else if (config.mode === 'interval') {
          // כל X שעות
          ScriptApp.newTrigger('runAutomations')
            .timeBased()
            .everyHours(parseInt(config.intervalHours))
            .create();
        } else if (config.mode === 'specific') {
          // בשעות ספציפיות ביום (ייצור מספר טריגרים)
          config.hours.forEach(hour => {
            ScriptApp.newTrigger('runAutomations')
              .timeBased()
              .everyDays(1)
              .atHour(parseInt(hour))
              .create();
          });
        }
      }
      
      props.setProperty("AUTO_CONFIG", JSON.stringify(config));
      return { success: true, config: config };
    }
    
    function cleanUpAllTriggers() {
      const triggers = ScriptApp.getProjectTriggers();
      for (let i = 0; i < triggers.length; i++) {
        const handler = triggers[i].getHandlerFunction();
        if (handler === 'runAutomations' || handler === 'runAutomations_Continuation') {
          ScriptApp.deleteTrigger(triggers[i]);
        }
      }
    }
    
    function getBaseFolderUrl(folderPath) {
      try {
        const folderNames = folderPath.split('/');
        let currentFolder = DriveApp.getRootFolder();
        for (let i = 0; i < folderNames.length; i++) {
          const name = folderNames[i].trim();
          if (name === "") continue;
          const folders = currentFolder.getFoldersByName(name);
          if (folders.hasNext()) {
            currentFolder = folders.next();
          } else {
            currentFolder = currentFolder.createFolder(name);
          }
        }
        return currentFolder.getUrl();
      } catch (e) {
        return "https://drive.google.com";
      }
    }
    
    function runAutomations() {
      cleanUpContinuationTriggersOnly();
      const startTime = Date.now();
      ensureLabelExists(PROCESSED_LABEL_NAME);
      
      const rules = getRules();
      let timeExceeded = false;
      let totalSavedCount = 0;
      let summaryDetails = [];
      
      for (let i = 0; i < rules.length; i++) {
        if (!rules[i].active) continue;
        
        const result = processRule(rules[i], startTime);
        
        if (result.processedCount > 0) {
          totalSavedCount += result.processedCount;
          const folderUrl = getBaseFolderUrl(rules[i].folder);
          summaryDetails.push(
            "<div style='margin-bottom:10px;'><b>" + rules[i].name + "</b>: סונכרנו " + result.processedCount + " הודעות חדשות.<br>" +
            "<a href='" + folderUrl + "' style='color: #2563eb; text-decoration: none;'>📂 פתח את התיקייה בדרייב</a></div>"
          );
        }
    
        if (result.timeUp) {
          timeExceeded = true;
          break;
        }
      }
      
      if (timeExceeded) {
        createContinuationTrigger();
        addLog("מערכת (אזהרה)", 0, "מגבלת זמן מתקרבת. מתזמן המשך בעוד דקה.");
      }
    
      if (totalSavedCount > 0) {
        sendSummaryEmail(totalSavedCount, summaryDetails, timeExceeded);
      }
    
      return { success: true, continuation: timeExceeded };
    }
    
    function sendSummaryEmail(totalCount, detailsArray, isPartial) {
      const userEmail = Session.getActiveUser().getEmail();
      let subject = "סיכום גיבוי מ-Gmail ל-Drive (" + totalCount + " הודעות חדשות)";
      if (isPartial) subject += " [סנכרון חלקי - ימשיך בדקה הבאה]";
    
      let htmlBody = '<div dir="rtl" style="font-family: Arial, sans-serif; color: #333; max-width: 600px; margin: auto; padding: 20px; border: 1px solid #e2e8f0; border-radius: 10px;">';
      htmlBody += '<h2 style="color: #2563eb; margin-top: 0;">סנכרון ה-Gmail פעל בהצלחה! 🎉</h2>';
      htmlBody += '<p>המערכת סיימה לסרוק ולשמור את המיילים שלך לתיקיות המוגדרות. להלן הפירוט:</p>';
      htmlBody += '<div style="background-color: #f8fafc; padding: 15px; border-radius: 8px; margin-bottom: 20px;">' + detailsArray.join('') + '</div>';
      
      if (isPartial) {
        htmlBody += '<div style="background-color: #fef3c7; border: 1px solid #f59e0b; padding: 10px; border-radius: 5px; margin-top: 15px;">';
        htmlBody += '<strong style="color: #d97706;">שימו לב:</strong> עקב עומס, הריצה הופסקה זמנית ותמשיך אוטומטית בעוד כדקה. לא נדרשת פעולה מצידך.';
        htmlBody += '</div>';
      }
      htmlBody += '<hr style="margin-top: 30px; border: 0; border-top: 1px solid #eee;" />';
      htmlBody += '<p style="font-size: 11px; color: #888;">הודעה זו נשלחה אוטומטית ממערכת הגיבוי החכמה שהגדרת ב-Google Apps Script.</p>';
      htmlBody += '</div>';
    
      MailApp.sendEmail({
        to: userEmail,
        subject: subject,
        htmlBody: htmlBody
      });
    }
    
    function processRule(rule, startTime) {
      const fullQuery = rule.query ? rule.query + " -label:" + PROCESSED_LABEL_NAME : "-label:" + PROCESSED_LABEL_NAME;
      const threads = GmailApp.search(fullQuery, 0, 30);
      
      if (threads.length === 0) return { timeUp: false, processedCount: 0 };
    
      const processedLabel = GmailApp.getUserLabelByName(PROCESSED_LABEL_NAME);
      let savedCount = 0;
    
      for (let i = 0; i < threads.length; i++) {
        if (Date.now() - startTime > MAX_EXECUTION_TIME_MS) {
          if (savedCount > 0) addLog(rule.name, savedCount, "הושלם חלקית - זמן נגמר");
          return { timeUp: true, processedCount: savedCount };
        }
    
        const thread = threads[i];
        try {
          saveThreadToDrive(thread, rule);
          thread.addLabel(processedLabel);
          savedCount++;
        } catch (error) {
          addLog(rule.name, 0, "שגיאה במייל: " + error.toString());
        }
      }
    
      if (savedCount > 0) addLog(rule.name, savedCount, "סונכרן בהצלחה");
      return { timeUp: false, processedCount: savedCount };
    }
    
    function saveThreadToDrive(thread, rule) {
      const messages = thread.getMessages();
      const firstMessage = messages[0];
      const dateStr = Utilities.formatDate(firstMessage.getDate(), Session.getScriptTimeZone(), "yyyy-MM-dd_HH-mm");
      const cleanSubject = thread.getFirstMessageSubject().replace(/[\/\\?%*:|"<>]/g, '-');
      const baseFileName = dateStr + " - " + cleanSubject;
    
      const rawFrom = firstMessage.getFrom();
      let senderEmail = rawFrom;
      const emailMatch = rawFrom.match(/<([^>]+)>/);
      if (emailMatch) {
        senderEmail = emailMatch[1];
      }
      const cleanSenderEmail = senderEmail.replace(/[\/\\?%*:|"<>]/g, '_');
    
      let dynamicPath = rule.folder;
      const msgDate = firstMessage.getDate();
      const yearMonth = Utilities.formatDate(msgDate, Session.getScriptTimeZone(), "yyyy/MM");
      const yearMonthDay = Utilities.formatDate(msgDate, Session.getScriptTimeZone(), "yyyy/MM/dd");
      const justDay = Utilities.formatDate(msgDate, Session.getScriptTimeZone(), "dd");
    
      // התאמת יצירת התיקיות החדשה
      if (rule.orgMethod === 'date') {
        dynamicPath += "/" + yearMonth;
      } else if (rule.orgMethod === 'date_day') {
        dynamicPath += "/" + yearMonthDay;
      } else if (rule.orgMethod === 'sender') {
        dynamicPath += "/" + cleanSenderEmail;
      } else if (rule.orgMethod === 'sender_date') {
        dynamicPath += "/" + cleanSenderEmail + "/" + yearMonth;
      } else if (rule.orgMethod === 'sender_date_day') {
        dynamicPath += "/" + cleanSenderEmail + "/" + yearMonth + "/" + justDay;
      }
    
      const targetFolder = getOrCreateDriveFolder(dynamicPath);
    
      if (!rule.attachmentsOnly) {
        let emailContent = "";
        for (let j = 0; j < messages.length; j++) {
          const msg = messages[j];
          emailContent += "From: " + msg.getFrom() + "\n";
          emailContent += "To: " + msg.getTo() + "\n";
          emailContent += "Date: " + msg.getDate() + "\n";
          emailContent += "Subject: " + msg.getSubject() + "\n\n";
          emailContent += msg.getPlainBody() + "\n";
          emailContent += "--------------------------------------------------\n\n";
        }
        targetFolder.createFile(baseFileName + ".txt", emailContent, MimeType.PLAIN_TEXT);
      }
    
      for (let j = 0; j < messages.length; j++) {
        const attachments = messages[j].getAttachments();
        for (let k = 0; k < attachments.length; k++) {
          const attachment = attachments[k];
          const attachmentBlob = attachment.copyBlob();
          attachmentBlob.setName(baseFileName + " - " + attachment.getName());
          targetFolder.createFile(attachmentBlob);
        }
      }
    }
    
    function getOrCreateDriveFolder(path) {
      const folderNames = path.split('/');
      let currentFolder = DriveApp.getRootFolder();
      
      for (let i = 0; i < folderNames.length; i++) {
        const name = folderNames[i].trim();
        if (name === "") continue;
        
        const folders = currentFolder.getFoldersByName(name);
        if (folders.hasNext()) {
          currentFolder = folders.next();
        } else {
          currentFolder = currentFolder.createFolder(name);
        }
      }
      return currentFolder;
    }
    
    function ensureLabelExists(labelName) {
      let label = GmailApp.getUserLabelByName(labelName);
      if (!label) GmailApp.createLabel(labelName);
    }
    
    function createContinuationTrigger() {
      ScriptApp.newTrigger('runAutomations_Continuation').timeBased().after(60 * 1000).create();
    }
    function runAutomations_Continuation() { runAutomations(); }
    function cleanUpContinuationTriggersOnly() {
      const triggers = ScriptApp.getProjectTriggers();
      for (let i = 0; i < triggers.length; i++) {
        if (triggers[i].getHandlerFunction() === 'runAutomations_Continuation') ScriptApp.deleteTrigger(triggers[i]);
      }
    }
    
    function getHtmlPage() {
      return '<!DOCTYPE html>\n' +
    '<html lang="he" dir="rtl">\n' +
    '<head>\n' +
    '    <meta charset="UTF-8">\n' +
    '    <title>מנהל סנכרון Gmail ל-Drive</title>\n' +
    '    <script src="https://cdn.tailwindcss.com"></script>\n' +
    '    <link href="https://fonts.googleapis.com/css2?family=Assistant:wght@300;400;600;700;800&display=swap" rel="stylesheet">\n' +
    '    <script src="https://unpkg.com/@phosphor-icons/web"></script>\n' +
    '    <style>\n' +
    '        body { font-family: \'Assistant\', sans-serif; }\n' +
    '        .tab-content { display: none; }\n' +
    '        .tab-content.active { display: block; }\n' +
    '        .tab-btn.active { border-bottom: 2px solid #2563eb; color: #2563eb; font-weight: 700; }\n' +
    '        /* עיצוב גלילה */\n' +
    '        .custom-scrollbar::-webkit-scrollbar { width: 6px; }\n' +
    '        .custom-scrollbar::-webkit-scrollbar-track { background: #f1f5f9; border-radius: 10px; }\n' +
    '        .custom-scrollbar::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 10px; }\n' +
    '        .custom-scrollbar::-webkit-scrollbar-thumb:hover { background: #94a3b8; }\n' +
    '    </style>\n' +
    '</head>\n' +
    '<body class="bg-slate-50 text-slate-800 min-h-screen relative pb-16 flex flex-col">\n' +
    '    <div class="max-w-6xl mx-auto p-4 sm:p-6 lg:p-8 flex-1 w-full">\n' +
    '        <header class="flex flex-col sm:flex-row items-center justify-between mb-6 pb-4 border-b border-slate-200 gap-4">\n' +
    '            <div class="flex items-center gap-4">\n' +
    '                <div class="bg-gradient-to-br from-blue-600 to-indigo-600 text-white p-3.5 rounded-2xl shadow-lg shadow-blue-200">\n' +
    '                    <i class="ph ph-google-drive-logo text-3xl"></i>\n' +
    '                </div>\n' +
    '                <div>\n' +
    '                    <h1 class="text-3xl font-extrabold text-slate-900 leading-none mb-1">סנכרון מיילים חכם</h1>\n' +
    '                    <p class="text-sm text-slate-500">ניהול אוטומציות וגיבוי ג\'ימייל לדרייב</p>\n' +
    '                </div>\n' +
    '            </div>\n' +
    '            <div class="flex items-center gap-3">\n' +
    '                <div class="bg-white border border-slate-200 rounded-xl px-4 py-2.5 flex items-center gap-3 shadow-sm">\n' +
    '                    <div class="flex flex-col">\n' +
    '                         <span class="text-sm font-semibold text-slate-600">אוטומציה ברקע</span>\n' +
    '                         <button onclick="openAutomationSettings()" class="text-[10px] text-blue-500 hover:text-blue-700 text-right underline decoration-dotted">הגדרות מתקדמות</button>\n' +
    '                    </div>\n' +
    '                    <button id="automationToggleBtn" onclick="toggleAutomationState()" class="relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none bg-slate-200 ml-2">\n' +
    '                        <span id="toggleCircle" class="pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out translate-x-0"></span>\n' +
    '                    </button>\n' +
    '                </div>\n' +
    '                <button id="syncNowBtn" onclick="triggerManualSync()" class="bg-blue-600 hover:bg-blue-700 text-white text-sm font-bold px-5 py-2.5 rounded-xl shadow-md transition flex items-center gap-2">\n' +
    '                    <i id="syncIcon" class="ph ph-play-circle text-lg"></i> הפעל עכשיו\n' +
    '                </button>\n' +
    '            </div>\n' +
    '        </header>\n' +
    '        \n' +
    '        <!-- Navigation Tabs -->\n' +
    '        <div class="flex items-center gap-6 mb-6 px-2 border-b border-slate-200">\n' +
    '            <button onclick="switchTab(\'dashboard\')" id="tab-dashboard" class="tab-btn active pb-3 text-slate-500 hover:text-slate-800 transition text-sm flex items-center gap-2">\n' +
    '                <i class="ph ph-squares-four text-lg"></i> פאנל ניהול\n' +
    '            </button>\n' +
    '            <button onclick="switchTab(\'guide\')" id="tab-guide" class="tab-btn pb-3 text-slate-500 hover:text-slate-800 transition text-sm flex items-center gap-2">\n' +
    '                <i class="ph ph-book-open-text text-lg"></i> הדרכה ומדריך למשתמש\n' +
    '            </button>\n' +
    '        </div>\n' +
    '\n' +
    '        <!-- Dashboard Tab -->\n' +
    '        <div id="content-dashboard" class="tab-content active">\n' +
    '            <div class="grid grid-cols-1 xl:grid-cols-12 gap-6">\n' +
    '                <!-- Left Panel: Create Rule -->\n' +
    '                <div class="xl:col-span-7">\n' +
    '                    <div class="bg-white rounded-3xl p-6 sm:p-8 shadow-sm border border-slate-200">\n' +
    '                        <h2 class="text-xl font-bold mb-6 flex items-center gap-2 text-slate-800">\n' +
    '                            <div class="p-2 bg-blue-50 text-blue-600 rounded-lg"><i class="ph ph-plus text-xl"></i></div>\n' +
    '                            יצירת חוק סנכרון חדש\n' +
    '                        </h2>\n' +
    '                        <form id="ruleForm" onsubmit="createNewRule(event)" class="space-y-6">\n' +
    '                            <div>\n' +
    '                                <label class="block text-sm font-bold text-slate-700 mb-1.5">שם החוק (לזיהוי אישי)</label>\n' +
    '                                <input type="text" id="ruleName" required placeholder="לדוגמה: גיבוי חשבוניות מספקים" class="w-full border border-slate-200 rounded-xl p-3 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none bg-slate-50 focus:bg-white transition">\n' +
    '                            </div>\n' +
    '                            \n' +
    '                            <!-- Filter Options -->\n' +
    '                            <div class="bg-slate-50 p-5 rounded-2xl border border-slate-200">\n' +
    '                                <h3 class="text-sm font-bold text-slate-800 flex items-center gap-2 mb-4">\n' +
    '                                    <i class="ph ph-funnel text-blue-500 text-lg"></i> אפשרויות סינון (כמו בג\'ימייל)\n' +
    '                                </h3>\n' +
    '                                <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">\n' +
    '                                    <div>\n' +
    '                                        <label class="block text-xs font-bold text-slate-600 mb-1">מאת (כתובת שולח)</label>\n' +
    '                                        <input type="text" id="filterFrom" placeholder="example@mail.com" class="w-full border border-slate-200 rounded-lg p-2.5 text-sm focus:ring-2 focus:ring-blue-500" dir="ltr">\n' +
    '                                    </div>\n' +
    '                                    <div>\n' +
    '                                        <label class="block text-xs font-bold text-slate-600 mb-1">תווית ב-Gmail (Label)</label>\n' +
    '                                        <input type="text" id="filterLabel" placeholder="למשל: עבודה/חשבוניות" class="w-full border border-slate-200 rounded-lg p-2.5 text-sm focus:ring-2 focus:ring-blue-500">\n' +
    '                                    </div>\n' +
    '                                    <div>\n' +
    '                                        <label class="block text-xs font-bold text-slate-600 mb-1">נושא המייל מכיל</label>\n' +
    '                                        <input type="text" id="filterSubject" placeholder="למשל: קבלה" class="w-full border border-slate-200 rounded-lg p-2.5 text-sm focus:ring-2 focus:ring-blue-500">\n' +
    '                                    </div>\n' +
    '                                    <div>\n' +
    '                                        <label class="block text-xs font-bold text-slate-600 mb-1">מילים בגוף ההודעה</label>\n' +
    '                                        <input type="text" id="filterIncludes" placeholder="מילים לחיפוש" class="w-full border border-slate-200 rounded-lg p-2.5 text-sm focus:ring-2 focus:ring-blue-500">\n' +
    '                                    </div>\n' +
    '                                </div>\n' +
    '                                \n' +
    '                                <div class="mt-4 flex flex-wrap gap-4 pt-3 border-t border-slate-200">\n' +
    '                                    <label class="flex items-center gap-2 cursor-pointer bg-white px-3 py-1.5 rounded-lg border border-slate-200 hover:bg-blue-50 transition">\n' +
    '                                        <input type="checkbox" id="filterHasAttachment" class="rounded text-blue-600 w-4 h-4">\n' +
    '                                        <span class="text-xs font-bold text-slate-700">רק עם קבצים מצורפים</span>\n' +
    '                                    </label>\n' +
    '                                    <label class="flex items-center gap-2 cursor-pointer bg-white px-3 py-1.5 rounded-lg border border-slate-200 hover:bg-blue-50 transition">\n' +
    '                                        <input type="checkbox" id="filterUnread" class="rounded text-blue-600 w-4 h-4">\n' +
    '                                        <span class="text-xs font-bold text-slate-700">רק הודעות שלא נקראו</span>\n' +
    '                                    </label>\n' +
    '                                    <label class="flex items-center gap-2 cursor-pointer bg-white px-3 py-1.5 rounded-lg border border-slate-200 hover:bg-blue-50 transition">\n' +
    '                                        <input type="checkbox" id="filterStarred" class="rounded text-blue-600 w-4 h-4">\n' +
    '                                        <span class="text-xs font-bold text-slate-700">רק מסומנים בכוכב</span>\n' +
    '                                    </label>\n' +
    '                                </div>\n' +
    '                            </div>\n' +
    '\n' +
    '                            <!-- Drive Settings -->\n' +
    '                            <div class="grid grid-cols-1 sm:grid-cols-2 gap-5">\n' +
    '                                <div>\n' +
    '                                    <label class="block text-sm font-bold text-slate-800 mb-1">שם תיקיית האב ב-Drive</label>\n' +
    '                                    <input type="text" id="ruleFolder" required placeholder="למשל: גיבוי מיילים" class="w-full border border-slate-200 rounded-xl p-3 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none">\n' +
    '                                </div>\n' +
    '                                <div>\n' +
    '                                    <label class="block text-sm font-bold text-slate-800 mb-1">סידור תתי-תיקיות</label>\n' +
    '                                    <select id="ruleOrgMethod" class="w-full border border-slate-200 rounded-xl p-3 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none bg-white">\n' +
    '                                        <option value="sender_date_day">לפי שולח > שנה > חודש > יום (מומלץ)</option>\n' +
    '                                        <option value="sender_date">לפי שולח > שנה > חודש</option>\n' +
    '                                        <option value="sender">סדר רק לפי שולח (ללא תאריכים)</option>\n' +
    '                                        <option value="date_day">לפי שנה > חודש > יום (ללא שולח)</option>\n' +
    '                                        <option value="date">לפי שנה > חודש</option>\n' +
    '                                        <option value="flat">ללא תתי תיקיות (הכל בתיקייה אחת)</option>\n' +
    '                                    </select>\n' +
    '                                </div>\n' +
    '                            </div>\n' +
    '                            \n' +
    '                            <label class="flex items-center gap-3 cursor-pointer p-4 bg-slate-50 rounded-xl border border-slate-200 hover:border-blue-300 transition">\n' +
    '                                <input type="checkbox" id="ruleAttachmentsOnly" class="rounded text-blue-600 w-5 h-5 focus:ring-blue-500">\n' +
    '                                <span class="text-sm font-bold text-slate-700">שמור קבצים מצורפים בלבד (אל תייצר קובץ טקסט של המייל)</span>\n' +
    '                            </label>\n' +
    '\n' +
    '                            <button type="submit" class="w-full bg-slate-900 hover:bg-slate-800 text-white text-sm font-bold py-3.5 rounded-xl transition shadow-lg">\n' +
    '                                הוסף חוק סנכרון\n' +
    '                            </button>\n' +
    '                        </form>\n' +
    '                    </div>\n' +
    '                </div>\n' +
    '                \n' +
    '                <!-- Right Panel: Rules & Logs -->\n' +
    '                <div class="xl:col-span-5 space-y-6">\n' +
    '                    <div class="bg-white rounded-3xl p-6 shadow-sm border border-slate-200">\n' +
    '                        <h2 class="text-lg font-bold mb-4 flex items-center gap-2 text-slate-800">\n' +
    '                            <div class="p-1.5 bg-indigo-50 text-indigo-600 rounded-lg"><i class="ph ph-list-checks text-lg"></i></div>\n' +
    '                            חוקים פעילים\n' +
    '                        </h2>\n' +
    '                        <div id="rulesList" class="space-y-3 max-h-[350px] overflow-y-auto pr-1 custom-scrollbar"></div>\n' +
    '                        <div id="noRulesMsg" class="text-center py-10 text-slate-400 hidden bg-slate-50 rounded-xl border border-dashed border-slate-200 mt-2">\n' +
    '                            <i class="ph ph-wind text-3xl mb-2"></i>\n' +
    '                            <p class="text-sm">טרם הגדרת חוקי סנכרון.</p>\n' +
    '                        </div>\n' +
    '                    </div>\n' +
    '                    \n' +
    '                    <div class="bg-white rounded-3xl p-6 shadow-sm border border-slate-200">\n' +
    '                        <div class="flex items-center justify-between mb-4">\n' +
    '                            <h2 class="text-lg font-bold flex items-center gap-2 text-slate-800">\n' +
    '                                <div class="p-1.5 bg-slate-100 text-slate-600 rounded-lg"><i class="ph ph-clock-counter-clockwise text-lg"></i></div>\n' +
    '                                יומן פעולות\n' +
    '                            </h2>\n' +
    '                            <button onclick="clearSystemLogs()" class="text-xs text-slate-400 hover:text-red-500 font-bold transition">\n' +
    '                                נקה יומן\n' +
    '                            </button>\n' +
    '                        </div>\n' +
    '                        <div class="overflow-hidden rounded-xl border border-slate-200">\n' +
    '                            <div class="max-h-[250px] overflow-y-auto custom-scrollbar">\n' +
    '                                <table class="w-full text-right text-xs">\n' +
    '                                    <thead class="bg-slate-50 border-b border-slate-200 text-slate-500 font-bold sticky top-0">\n' +
    '                                        <tr>\n' +
    '                                            <th class="px-3 py-2.5">תאריך</th>\n' +
    '                                            <th class="px-3 py-2.5">חוק</th>\n' +
    '                                            <th class="px-3 py-2.5">סטטוס</th>\n' +
    '                                        </tr>\n' +
    '                                    </thead>\n' +
    '                                    <tbody id="logsList" class="divide-y divide-slate-100"></tbody>\n' +
    '                                </table>\n' +
    '                            </div>\n' +
    '                        </div>\n' +
    '                    </div>\n' +
    '                </div>\n' +
    '            </div>\n' +
    '        </div>\n' +
    '\n' +
    '        <!-- Guide Tab -->\n' +
    '        <div id="content-guide" class="tab-content max-w-4xl mx-auto">\n' +
    '            <div class="bg-white rounded-3xl p-6 sm:p-10 shadow-sm border border-slate-200 prose prose-slate max-w-none text-slate-700 leading-relaxed">\n' +
    '                <h2 class="text-2xl font-extrabold text-slate-900 mb-6 border-b border-slate-100 pb-4">מדריך מלא לשימוש במערכת 📖</h2>\n' +
    '                \n' +
    '                <h3 class="text-xl font-bold text-blue-600 mt-8 mb-3 flex items-center gap-2"><i class="ph ph-magic-wand"></i> איך המערכת עובדת?</h3>\n' +
    '                <p class="text-sm">המערכת הזו פועלת ישירות על השרתים המאובטחים של גוגל. המשמעות היא שברגע שהגדרת את החוקים והפעלת את ה"אוטומציה ברקע", <strong>המחשב שלך לא צריך להיות דולק והדפדפן לא צריך להיות פתוח</strong>. המערכת תסרוק את התיבה שלך בהתאם לזמנים שהגדרת באופן אוטומטי ותגבה את הקבצים.</p>\n' +
    '                \n' +
    '                <h3 class="text-xl font-bold text-blue-600 mt-8 mb-3 flex items-center gap-2"><i class="ph ph-folder-arrow-down"></i> איך להוריד הכל למחשב באופן אוטומטי?</h3>\n' +
    '                <p class="text-sm bg-blue-50 p-4 rounded-xl border border-blue-100 mb-4">הרבה משתמשים רוצים שכל הקבצים ירדו אוטומטית לתיקייה מקומית במחשב שלהם. מכיוון שהסנכרון מתבצע בענן, הדרך הנכונה לעשות זאת היא באמצעות תוכנת הסנכרון של גוגל.</p>\n' +
    '                <ol class="text-sm space-y-2 list-decimal list-inside ml-4">\n' +
    '                    <li>הורד והתקן את התוכנה הרשמית <strong><a href="https://www.google.com/drive/download/" target="_blank" class="text-blue-600 font-bold underline">Google Drive למחשב</a></strong>.</li>\n' +
    '                    <li>התחבר לאותו חשבון גוגל שבו אתה משתמש כעת.</li>\n' +
    '                    <li>בהגדרות התוכנה, בחר שהתיקיות שנוצרו על ידי מערכת זו יהיו ב-<strong>"שיקוף מלא" (Mirror files)</strong> או גש אליהן דרך הכונן הווירטואלי (G:).</li>\n' +
    '                </ol>\n' +
    '                \n' +
    '                <h3 class="text-xl font-bold text-blue-600 mt-8 mb-3 flex items-center gap-2"><i class="ph ph-play-circle"></i> כפתור "הפעל עכשיו"</h3>\n' +
    '                <p class="text-sm">בלחיצה על כפתור זה, תחל פעולת סנכרון מיידית המופעלת בשרתי גוגל. <strong>ברגע שקפצה הודעת האישור ש"התהליך החל", אתה יכול לסגור את חלון הדפדפן בבטחה.</strong> השרת ימשיך לעבוד ברקע. בסיום, תקבל הודעת אימייל מפורטת לתיבה שלך.</p>\n' +
    '            </div>\n' +
    '        </div>\n' +
    '    </div>\n' +
    '\n' +
    '    <!-- Credit Footer -->\n' +
    '    <footer class="mt-auto py-6 text-center">\n' +
    '        <a href="https://lev-good.github.io/Good-heart/" target="_blank" rel="noopener noreferrer" class="inline-flex flex-col items-center group">\n' +
    '            <span class="text-xs text-slate-400 group-hover:text-blue-500 transition-colors duration-300">פותח ע"י</span>\n' +
    '            <span class="font-bold text-sm text-slate-500 group-hover:text-blue-600 transition-colors duration-300 flex items-center gap-1.5 mt-0.5">\n' +
    '                <i class="ph-fill ph-heart text-red-400 group-hover:animate-pulse"></i>\n' +
    '                לב טוב\n' +
    '            </span>\n' +
    '        </a>\n' +
    '    </footer>\n' +
    '\n' +
    '    <!-- Automation Settings Modal -->\n' +
    '    <div id="automationModal" class="fixed inset-0 bg-slate-900/40 backdrop-blur-sm z-50 flex items-center justify-center hidden">\n' +
    '        <div class="bg-white rounded-2xl p-6 max-w-md w-full mx-4 shadow-xl border border-slate-200">\n' +
    '            <div class="flex items-center justify-between mb-5">\n' +
    '                <h3 class="text-lg font-bold text-slate-900 flex items-center gap-2">\n' +
    '                    <i class="ph ph-gear text-blue-600"></i> הגדרות תזמון אוטומציה\n' +
    '                </h3>\n' +
    '                <button onclick="closeAutomationModal()" class="text-slate-400 hover:text-slate-600"><i class="ph ph-x text-xl"></i></button>\n' +
    '            </div>\n' +
    '            \n' +
    '            <div class="space-y-4">\n' +
    '                <div>\n' +
    '                    <label class="block text-sm font-bold text-slate-700 mb-1">סוג תזמון</label>\n' +
    '                    <select id="autoMode" onchange="updateAutoUI()" class="w-full border border-slate-200 rounded-lg p-2.5 text-sm focus:ring-2 focus:ring-blue-500 bg-white">\n' +
    '                        <option value="daily">פעם ביום בשעה קבועה</option>\n' +
    '                        <option value="interval">כל מספר שעות</option>\n' +
    '                        <option value="specific">שעות ספציפיות במהלך היום</option>\n' +
    '                    </select>\n' +
    '                </div>\n' +
    '                \n' +
    '                <div id="ui-daily" class="auto-ui-section">\n' +
    '                    <label class="block text-sm font-bold text-slate-700 mb-1">בחר שעה (0-23)</label>\n' +
    '                    <select id="autoDailyTime" class="w-full border border-slate-200 rounded-lg p-2.5 text-sm focus:ring-2 focus:ring-blue-500 bg-white">\n' +
    '                        <option value="0">00:00 (חצות)</option>\n' +
    '                        <option value="2">02:00 בלילה</option>\n' +
    '                        <option value="6">06:00 בבוקר</option>\n' +
    '                        <option value="12">12:00 בצהריים</option>\n' +
    '                        <option value="18">18:00 בערב</option>\n' +
    '                    </select>\n' +
    '                </div>\n' +
    '                \n' +
    '                <div id="ui-interval" class="auto-ui-section hidden">\n' +
    '                    <label class="block text-sm font-bold text-slate-700 mb-1">כל כמה שעות לסנכרן?</label>\n' +
    '                    <select id="autoIntervalHours" class="w-full border border-slate-200 rounded-lg p-2.5 text-sm focus:ring-2 focus:ring-blue-500 bg-white">\n' +
    '                        <option value="1">כל שעה</option>\n' +
    '                        <option value="2">כל שעתיים</option>\n' +
    '                        <option value="4">כל 4 שעות</option>\n' +
    '                        <option value="6">כל 6 שעות</option>\n' +
    '                        <option value="12">כל 12 שעות</option>\n' +
    '                    </select>\n' +
    '                </div>\n' +
    '                \n' +
    '                <div id="ui-specific" class="auto-ui-section hidden">\n' +
    '                    <label class="block text-sm font-bold text-slate-700 mb-1">בחר שעות (ניתן לבחור מרובים)</label>\n' +
    '                    <div class="grid grid-cols-4 gap-2 max-h-40 overflow-y-auto p-2 border border-slate-200 rounded-lg custom-scrollbar">\n' +
    '                        <!-- ירונדר ב-JS -->\n' +
    '                    </div>\n' +
    '                </div>\n' +
    '            </div>\n' +
    '            \n' +
    '            <div class="mt-6 flex justify-end gap-3">\n' +
    '                <button onclick="closeAutomationModal()" class="px-4 py-2 bg-slate-100 hover:bg-slate-200 text-slate-700 text-sm font-bold rounded-lg transition">ביטול</button>\n' +
    '                <button onclick="saveAutomationSettings()" class="px-5 py-2 bg-blue-600 hover:bg-blue-700 text-white text-sm font-bold rounded-lg transition shadow-sm">שמור הגדרות</button>\n' +
    '            </div>\n' +
    '        </div>\n' +
    '    </div>\n' +
    '\n' +
    '    <!-- Sync Modal Notification -->\n' +
    '    <div id="syncModal" class="fixed inset-0 bg-slate-900/60 backdrop-blur-sm z-50 flex items-center justify-center hidden opacity-0 transition-opacity duration-300">\n' +
    '        <div class="bg-white rounded-3xl p-8 max-w-md w-full mx-4 shadow-2xl transform scale-95 transition-transform duration-300" id="syncModalContent">\n' +
    '            <div class="text-center">\n' +
    '                <div class="w-20 h-20 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-5 relative">\n' +
    '                    <i class="ph ph-cloud-arrow-up text-4xl text-blue-600 animate-bounce"></i>\n' +
    '                    <div class="absolute inset-0 border-4 border-blue-400 border-dashed rounded-full animate-[spin_4s_linear_infinite] opacity-50"></div>\n' +
    '                </div>\n' +
    '                <h3 class="text-2xl font-extrabold text-slate-900 mb-2">הסנכרון יצא לדרך! 🚀</h3>\n' +
    '                <p class="text-sm text-slate-600 mb-6 leading-relaxed">הפקודה נשלחה בהצלחה לשרתי גוגל.<br><strong>אפשר כעת לסגור את הדפדפן ולהמשיך בשגרת יומך.</strong><br>המערכת תשלח אליך למייל דוח מסודר בסיום התהליך.</p>\n' +
    '                <button onclick="closeSyncModal()" class="w-full bg-slate-100 hover:bg-slate-200 text-slate-800 font-bold py-3 rounded-xl transition">\n' +
    '                    הבנתי, תודה\n' +
    '                </button>\n' +
    '            </div>\n' +
    '        </div>\n' +
    '    </div>\n' +
    '\n' +
    '    <!-- Delete Modal -->\n' +
    '    <div id="deleteModal" class="fixed inset-0 bg-slate-900/40 backdrop-blur-sm z-50 flex items-center justify-center hidden">\n' +
    '        <div class="bg-white rounded-2xl p-6 max-w-sm w-full mx-4 shadow-xl border border-slate-150">\n' +
    '            <div class="flex items-center gap-3 mb-3 text-red-600">\n' +
    '                <i class="ph ph-trash text-2xl bg-red-50 p-2 rounded-xl"></i>\n' +
    '                <h3 class="text-base font-bold text-slate-900">מחיקת חוק</h3>\n' +
    '            </div>\n' +
    '            <p class="text-sm text-slate-500 mb-6">למחוק חוק זה לצמיתות?</p>\n' +
    '            <div class="flex items-center justify-end gap-2">\n' +
    '                <button onclick="closeDeleteModal()" class="px-4 py-2 bg-slate-100 hover:bg-slate-200 text-slate-700 text-sm font-bold rounded-lg transition">ביטול</button>\n' +
    '                <button id="confirmDeleteBtn" class="px-4 py-2 bg-red-600 hover:bg-red-700 text-white text-sm font-bold rounded-lg transition">מחק</button>\n' +
    '            </div>\n' +
    '        </div>\n' +
    '    </div>\n' +
    '\n' +
    '    <div id="toast" class="fixed bottom-5 left-5 bg-slate-900 text-white text-sm font-semibold px-5 py-3.5 rounded-xl shadow-2xl z-50 transform translate-y-20 opacity-0 transition duration-300 flex items-center gap-3">\n' +
    '        <i class="ph ph-check-circle text-green-400 text-lg"></i> <span id="toastMsg"></span>\n' +
    '    </div>\n' +
    '\n' +
    '    <script>\n' +
    '        let rules = [];\n' +
    '        let autoConfig = { active: false, mode: \'daily\', time: 0, hours: [] };\n' +
    '        let ruleIndexToDelete = null;\n' +
    '        \n' +
    '        document.addEventListener("DOMContentLoaded", () => {\n' +
    '            initHoursGrid();\n' +
    '            loadInitialData();\n' +
    '        });\n' +
    '        \n' +
    '        function initHoursGrid() {\n' +
    '            const container = document.querySelector(\'#ui-specific .grid\');\n' +
    '            for (let i = 0; i < 24; i++) {\n' +
    '                const val = i.toString().padStart(2, \'0\');\n' +
    '                container.innerHTML += \n' +
    '                    \'<label class="flex items-center gap-1.5 p-1 hover:bg-slate-50 rounded cursor-pointer">\' +\n' +
    '                    \'<input type="checkbox" value="\' + i + \'" class="hour-cb rounded text-blue-600 w-3.5 h-3.5">\' +\n' +
    '                    \'<span class="text-xs">\' + val + \':00</span></label>\';\n' +
    '            }\n' +
    '        }\n' +
    '        \n' +
    '        function switchTab(tabId) {\n' +
    '            document.querySelectorAll(\'.tab-btn\').forEach(btn => btn.classList.remove(\'active\'));\n' +
    '            document.querySelectorAll(\'.tab-content\').forEach(content => content.classList.remove(\'active\'));\n' +
    '            document.getElementById(\'tab-\' + tabId).classList.add(\'active\');\n' +
    '            document.getElementById(\'content-\' + tabId).classList.add(\'active\');\n' +
    '        }\n' +
    '\n' +
    '        function loadInitialData() {\n' +
    '            google.script.run.withSuccessHandler((r) => { rules = r; renderRules(); }).getRules();\n' +
    '            google.script.run.withSuccessHandler((l) => renderLogs(l)).getLogs();\n' +
    '            google.script.run.withSuccessHandler((conf) => { \n' +
    '                autoConfig = conf;\n' +
    '                updateToggleUI(); \n' +
    '                populateAutoModal();\n' +
    '            }).getTriggerStatus();\n' +
    '        }\n' +
    '\n' +
    '        function renderRules() {\n' +
    '            const list = document.getElementById("rulesList");\n' +
    '            const noRules = document.getElementById("noRulesMsg");\n' +
    '            list.innerHTML = "";\n' +
    '            if (rules.length === 0) { noRules.classList.remove("hidden"); return; }\n' +
    '            noRules.classList.add("hidden");\n' +
    '            rules.forEach((rule, index) => {\n' +
    '                const card = document.createElement("div");\n' +
    '                card.className = "flex items-center justify-between p-4 border border-slate-200 rounded-2xl bg-slate-50 hover:bg-white hover:shadow-md transition duration-200";\n' +
    '                const orgLabel = \n' +
    '                    rule.orgMethod === "sender_date_day" ? "שולח>שנה>חודש>יום" :\n' +
    '                    rule.orgMethod === "sender_date" ? "שולח>שנה>חודש" :\n' +
    '                    rule.orgMethod === "sender" ? "שולח" :\n' +
    '                    rule.orgMethod === "date_day" ? "שנה>חודש>יום" :\n' +
    '                    rule.orgMethod === "date" ? "שנה>חודש" : "תיקייה אחת";\n' +
    '                    \n' +
    '                const displayQuery = rule.query ? rule.query : "כל המיילים";\n' +
    '                card.innerHTML = \n' +
    '                    \'<div class="flex-1 min-w-0 pr-1">\' +\n' +
    '                    \'    <div class="flex items-center gap-2 mb-1.5">\' +\n' +
    '                    \'        <h3 class="font-extrabold text-slate-800 text-sm truncate">\' + rule.name + \'</h3>\' +\n' +
    '                    \'        \' + (rule.attachmentsOnly ? \'<span class="text-[10px] bg-amber-100 text-amber-800 px-2 py-0.5 rounded-md font-bold border border-amber-200">קבצים בלבד</span>\' : \'\') +\n' +
    '                    \'    </div>\' +\n' +
    '                    \'    <div class="text-[11px] text-indigo-700 bg-indigo-50 font-bold w-max px-2.5 py-1 rounded-md mb-2 border border-indigo-100" dir="ltr">\' + displayQuery + \'</div>\' +\n' +
    '                    \'    <div class="text-xs text-slate-500 flex items-center gap-1.5">\' +\n' +
    '                    \'        <i class="ph ph-folder-open text-blue-500 text-sm"></i> <b>\' + rule.folder + \'</b> <span class="text-slate-300">|</span> <span>סידור: \' + orgLabel + \'</span>\' +\n' +
    '                    \'    </div>\' +\n' +
    '                    \'</div>\' +\n' +
    '                    \'<div class="flex items-center gap-2 mr-3">\' +\n' +
    '                    \'    <button onclick="toggleRuleActive(\' + index + \')" class="p-2 bg-white hover:bg-slate-100 rounded-xl border border-slate-200 transition shadow-sm \' + (!rule.active ? \'text-slate-400\' : \'text-blue-600\') + \'">\' +\n' +
    '                    \'        <i class="ph \' + (rule.active ? \'ph-pause\' : \'ph-play\') + \' text-base"></i>\' +\n' +
    '                    \'    </button>\' +\n' +
    '                    \'    <button onclick="openDeleteModal(\' + index + \')" class="p-2 bg-white hover:bg-red-50 hover:text-red-600 hover:border-red-200 rounded-xl border border-slate-200 transition shadow-sm text-slate-400">\' +\n' +
    '                    \'        <i class="ph ph-trash text-base"></i>\' +\n' +
    '                    \'    </button>\' +\n' +
    '                    \'</div>\';\n' +
    '                list.appendChild(card);\n' +
    '            });\n' +
    '        }\n' +
    '        \n' +
    '        function renderLogs(logs) {\n' +
    '            const tbody = document.getElementById("logsList");\n' +
    '            tbody.innerHTML = "";\n' +
    '            if (!logs || logs.length === 0) { tbody.innerHTML = \'<tr><td colspan="3" class="text-center py-6 text-slate-400 text-sm">אין פעולות ביומן.</td></tr>\'; return; }\n' +
    '            logs.forEach(log => {\n' +
    '                const isError = log.status.includes("שגיאה");\n' +
    '                const statusClass = isError ? "text-red-500 bg-red-50" : "text-slate-600";\n' +
    '                const tr = document.createElement("tr");\n' +
    '                tr.innerHTML = \n' +
    '                    \'<td class="px-3 py-2 border-t border-slate-100 text-slate-500" dir="ltr">\' + log.date.split(" ")[0] + \'</td>\' +\n' +
    '                    \'<td class="px-3 py-2 border-t border-slate-100 font-bold text-slate-700">\' + log.rule + \'</td>\' +\n' +
    '                    \'<td class="px-3 py-2 border-t border-slate-100 \' + statusClass + \'">\' + log.status + \' <span class="text-[10px] bg-slate-200 text-slate-700 px-1.5 rounded-full ml-1">\' + log.count + \'</span></td>\';\n' +
    '                tbody.appendChild(tr);\n' +
    '            });\n' +
    '        }\n' +
    '\n' +
    '        function createNewRule(e) {\n' +
    '            e.preventDefault();\n' +
    '            const from = document.getElementById("filterFrom").value.trim();\n' +
    '            const label = document.getElementById("filterLabel").value.trim();\n' +
    '            const subject = document.getElementById("filterSubject").value.trim();\n' +
    '            const includes = document.getElementById("filterIncludes").value.trim();\n' +
    '            const hasAttachment = document.getElementById("filterHasAttachment").checked;\n' +
    '            const unread = document.getElementById("filterUnread").checked;\n' +
    '            const starred = document.getElementById("filterStarred").checked;\n' +
    '            \n' +
    '            let queryParts = [];\n' +
    '            if (from) queryParts.push("from:(" + from + ")");\n' +
    '            if (label) queryParts.push("label:(" + label.replace(/ /g,"-") + ")"); // ג\'ימייל דורש מקפים במקום רווחים\n' +
    '            if (subject) queryParts.push("subject:(" + subject + ")");\n' +
    '            if (includes) queryParts.push("(" + includes + ")");\n' +
    '            if (hasAttachment) queryParts.push("has:attachment");\n' +
    '            if (unread) queryParts.push("is:unread");\n' +
    '            if (starred) queryParts.push("is:starred");\n' +
    '            \n' +
    '            const compiledQuery = queryParts.join(" ");\n' +
    '            const newRule = {\n' +
    '                name: document.getElementById("ruleName").value,\n' +
    '                query: compiledQuery,\n' +
    '                folder: document.getElementById("ruleFolder").value,\n' +
    '                orgMethod: document.getElementById("ruleOrgMethod").value,\n' +
    '                attachmentsOnly: document.getElementById("ruleAttachmentsOnly").checked,\n' +
    '                active: true\n' +
    '            };\n' +
    '            rules.push(newRule);\n' +
    '            google.script.run.withSuccessHandler(() => {\n' +
    '                showToast("החוק נשמר בהצלחה!");\n' +
    '                document.getElementById("ruleForm").reset();\n' +
    '                renderRules();\n' +
    '            }).saveRules(rules);\n' +
    '        }\n' +
    '\n' +
    '        function openDeleteModal(index) { ruleIndexToDelete = index; document.getElementById("deleteModal").classList.remove("hidden"); }\n' +
    '        function closeDeleteModal() { ruleIndexToDelete = null; document.getElementById("deleteModal").classList.add("hidden"); }\n' +
    '        \n' +
    '        document.getElementById("confirmDeleteBtn").addEventListener("click", () => {\n' +
    '            if (ruleIndexToDelete !== null) {\n' +
    '                rules.splice(ruleIndexToDelete, 1);\n' +
    '                google.script.run.withSuccessHandler(() => { showToast("החוק נמחק."); closeDeleteModal(); renderRules(); }).saveRules(rules);\n' +
    '            }\n' +
    '        });\n' +
    '\n' +
    '        function toggleRuleActive(index) {\n' +
    '            rules[index].active = !rules[index].active;\n' +
    '            google.script.run.withSuccessHandler(() => { renderRules(); }).saveRules(rules);\n' +
    '        }\n' +
    '\n' +
    '        // --- טיפול בהגדרות אוטומציה ---\n' +
    '        function openAutomationSettings() {\n' +
    '            populateAutoModal();\n' +
    '            document.getElementById("automationModal").classList.remove("hidden");\n' +
    '        }\n' +
    '        function closeAutomationModal() {\n' +
    '            document.getElementById("automationModal").classList.add("hidden");\n' +
    '        }\n' +
    '        function updateAutoUI() {\n' +
    '            document.querySelectorAll(".auto-ui-section").forEach(el => el.classList.add("hidden"));\n' +
    '            const mode = document.getElementById("autoMode").value;\n' +
    '            document.getElementById("ui-" + mode).classList.remove("hidden");\n' +
    '        }\n' +
    '        function populateAutoModal() {\n' +
    '            document.getElementById("autoMode").value = autoConfig.mode || "daily";\n' +
    '            document.getElementById("autoDailyTime").value = autoConfig.time || 0;\n' +
    '            if (autoConfig.intervalHours) document.getElementById("autoIntervalHours").value = autoConfig.intervalHours;\n' +
    '            \n' +
    '            document.querySelectorAll(".hour-cb").forEach(cb => {\n' +
    '                cb.checked = (autoConfig.hours && autoConfig.hours.includes(cb.value));\n' +
    '            });\n' +
    '            updateAutoUI();\n' +
    '        }\n' +
    '        function saveAutomationSettings() {\n' +
    '            autoConfig.mode = document.getElementById("autoMode").value;\n' +
    '            autoConfig.time = document.getElementById("autoDailyTime").value;\n' +
    '            autoConfig.intervalHours = document.getElementById("autoIntervalHours").value;\n' +
    '            \n' +
    '            const selectedHours = Array.from(document.querySelectorAll(".hour-cb:checked")).map(cb => cb.value);\n' +
    '            autoConfig.hours = selectedHours;\n' +
    '            \n' +
    '            if (autoConfig.mode === "specific" && selectedHours.length === 0) {\n' +
    '                showToast("יש לבחור לפחות שעה אחת!");\n' +
    '                return;\n' +
    '            }\n' +
    '\n' +
    '            // רק שומרים, לא משנים את סטטוס ההפעלה (פעיל/כבוי)\n' +
    '            google.script.run.withSuccessHandler((res) => { \n' +
    '                autoConfig = res.config;\n' +
    '                closeAutomationModal();\n' +
    '                showToast("הגדרות תזמון נשמרו."); \n' +
    '            }).toggleAutomation(autoConfig);\n' +
    '        }\n' +
    '\n' +
    '        function toggleAutomationState() {\n' +
    '            autoConfig.active = !autoConfig.active;\n' +
    '            google.script.run.withSuccessHandler((res) => { \n' +
    '                autoConfig = res.config; \n' +
    '                updateToggleUI(); \n' +
    '                showToast(autoConfig.active ? "אוטומציה הופעלה בהצלחה!" : "האוטומציה כובתה."); \n' +
    '            }).toggleAutomation(autoConfig);\n' +
    '        }\n' +
    '\n' +
    '        function updateToggleUI() {\n' +
    '            const t = document.getElementById("automationToggleBtn"), c = document.getElementById("toggleCircle");\n' +
    '            if (autoConfig.active) { t.classList.remove("bg-slate-200"); t.classList.add("bg-blue-600"); c.className = "pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow transition translate-x-5"; }\n' +
    '            else { t.classList.remove("bg-blue-600"); t.classList.add("bg-slate-200"); c.className = "pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow transition translate-x-0"; }\n' +
    '        }\n' +
    '\n' +
    '        function triggerManualSync() {\n' +
    '            const modal = document.getElementById("syncModal");\n' +
    '            const content = document.getElementById("syncModalContent");\n' +
    '            modal.classList.remove("hidden");\n' +
    '            setTimeout(() => { modal.classList.remove("opacity-0"); content.classList.remove("scale-95"); }, 10);\n' +
    '            \n' +
    '            // Start server process without waiting for it to finish UI-wise so user can close tab\n' +
    '            google.script.run.runAutomations();\n' +
    '        }\n' +
    '\n' +
    '        function closeSyncModal() {\n' +
    '            const modal = document.getElementById("syncModal");\n' +
    '            const content = document.getElementById("syncModalContent");\n' +
    '            modal.classList.add("opacity-0"); content.classList.add("scale-95");\n' +
    '            setTimeout(() => { modal.classList.add("hidden"); }, 300);\n' +
    '        }\n' +
    '\n' +
    '        function clearSystemLogs() { google.script.run.withSuccessHandler(() => { showToast("היומן נוקה."); loadInitialData(); }).clearLogs(); }\n' +
    '        \n' +
    '        function showToast(msg) {\n' +
    '            const t = document.getElementById("toast"); document.getElementById("toastMsg").innerText = msg;\n' +
    '            t.classList.remove("translate-y-20", "opacity-0"); setTimeout(() => t.classList.add("translate-y-20", "opacity-0"), 4000);\n' +
    '        }\n' +
    '    </script>\n' +
    '</body>\n' +
    '</html>';
    }
    

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

    מדריך א.png
    מדריך ב.png
    מדריך ג.png
    מדריך ד.png
    מדריך ה.png
    מדריך ו.png

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

    עזרה הדדית - מחשבים וטכנולוגיה

  • שיתוף | הפלאפון חצי טאצ הכי זול שמצאתי
    ל לב טוב

    @חייא-שיאומי כתב:

    אחד החרטות של אליאקספרס זה דיל ברוך בואך אני האמנתי לזה

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

    עזרה הדדית - אנדרואיד

  • להורדה | נגן מוזיקה מתקדם למחשב - GoodMusic Desktop | (+גרסת לייט 3MB!) + גרסה מקוונת ללא הורדה!
    ל לב טוב

    @ישראל-דיין נכון מאוד, כבר העירו על זה שכדאי להדגיש את אפשרויות היציאה מהתוכנה, סגירה מלאה או רק מיזעור למגש המערכת.

    עזרה הדדית - מחשבים וטכנולוגיה

  • להורדה | נגן מוזיקה מתקדם למחשב - GoodMusic Desktop | (+גרסת לייט 3MB!) + גרסה מקוונת ללא הורדה!
    ל לב טוב

    @106 לא יודע

    עזרה הדדית - מחשבים וטכנולוגיה

  • להורדה | נגן מוזיקה מתקדם למחשב - GoodMusic Desktop | (+גרסת לייט 3MB!) + גרסה מקוונת ללא הורדה!
    ל לב טוב

    @עזיז אני גם לא... https://lev-good.github.io/Good-heart/

    עזרה הדדית - מחשבים וטכנולוגיה
  • התחברות

  • אין לך חשבון עדיין? הרשמה

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