Reorganize: skills/ directory + move memory to docs/
skill-legal-decision/ → skills/decision/ skill-legal-assistant/ → skills/assistant/ skill-legal-docx/ → skills/docx/ memory/*.md → docs/ Also removed: TASKS.md (use TaskMaster), classifier.py (replaced by local_classifier.py) Updated all references in CLAUDE.md, scripts, PRDs, docs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
976
skills/docx/SKILL.md
Normal file
976
skills/docx/SKILL.md
Normal file
@@ -0,0 +1,976 @@
|
||||
---
|
||||
name: legal-docx
|
||||
description: >
|
||||
יצירת מסמכים משפטיים בעברית בפורמט DOCX עם תמיכה מלאה ב-RTL, עקוב אחר שינויים,
|
||||
והערות. משתמש בסקיל הבסיסי docx ומוסיף התמחות בתחום המשפטי הישראלי.
|
||||
|
||||
טריגרים: "מסמך משפטי", "הסכם", "כתב הגנה", "כתב תביעה", "בקשה", "תצהיר",
|
||||
"מכתב התראה", "חוזה", "הסכם שירותים", "ייפוי כוח", "פרוטוקול", "החלטה",
|
||||
"צו", "פסק דין", "כתב טענות", בקשה ליצור מסמך DOCX בעברית, מסמך RTL,
|
||||
"tracked changes בעברית", "הערות שוליים משפטיות", "עקוב אחר שינויים".
|
||||
|
||||
גם מתאים כאשר המשתמש מבקש מסמך Word בעברית עם פונט David/FrankRuehl/Miriam,
|
||||
שוליים 2.5 ס"מ, או כל מסמך מקצועי בעברית שדורש עיצוב משפטי מדויק.
|
||||
|
||||
פיצ'רים: טבלאות RTL, הערות שוליים, תוכן עניינים, היפרלינקים,
|
||||
לוגו/נייר פירמה, עריכת DOCX קיים, tracked changes, comments,
|
||||
מרווח שורות, קו תחתי, מספר סקשנים, זיהוי אוטומטי של סוג מסמך.
|
||||
---
|
||||
|
||||
# Legal DOCX v3.0 — מסמכים משפטיים בעברית
|
||||
|
||||
סקיל זה מרחיב את סקיל docx הבסיסי עם התמחות במסמכים משפטיים ישראליים.
|
||||
|
||||
**תמיד לקרוא קודם** את `/mnt/skills/public/docx/SKILL.md` — הסקיל הזה מניח שאתה מכיר את תהליך העבודה הבסיסי (docx-js, unpack/pack, tracked changes, comments).
|
||||
|
||||
---
|
||||
|
||||
## 🔴 קריטי: כללי RTL שחייבים לזכור
|
||||
|
||||
### הכלל המרכזי: START/END במקום LEFT/RIGHT
|
||||
|
||||
**במסמך עברי עם `bidirectional: true`, לעולם אל תשתמש ב-`AlignmentType.LEFT` או `AlignmentType.RIGHT` לפסקאות ומספור!**
|
||||
|
||||
| רוצה יישור ל... | ❌ לא להשתמש | ✅ להשתמש |
|
||||
|-----------------|-------------|----------|
|
||||
| **ימין** | `LEFT` או `RIGHT` | `AlignmentType.START` |
|
||||
| **שמאל** | `LEFT` או `RIGHT` | `AlignmentType.END` |
|
||||
| **מרכז** | — | `AlignmentType.CENTER` |
|
||||
| **שני צדדים** | — | `AlignmentType.BOTH` |
|
||||
|
||||
> **למה?** כש-`bidirectional: true`, Word מתבלבל עם LEFT/RIGHT. `START` = התחלה = ימין ב-RTL, `END` = סוף = שמאל ב-RTL.
|
||||
|
||||
### שלוש הגדרות RTL חובה
|
||||
|
||||
כל מסמך עברי חייב את **שלושת** ההגדרות הבאות בכל הרמות:
|
||||
|
||||
```javascript
|
||||
// 1. ברמת ה-Section
|
||||
sections: [{
|
||||
properties: {
|
||||
bidi: true // ← חובה!
|
||||
}
|
||||
}]
|
||||
|
||||
// 2. ברמת כל Paragraph
|
||||
new Paragraph({
|
||||
bidirectional: true, // ← חובה!
|
||||
alignment: AlignmentType.BOTH, // או START/CENTER/END
|
||||
})
|
||||
|
||||
// 3. ברמת כל TextRun
|
||||
new TextRun({
|
||||
text: "טקסט בעברית",
|
||||
rightToLeft: true, // ← חובה!
|
||||
font: "David",
|
||||
})
|
||||
```
|
||||
|
||||
**חוסר באחת מהן = יישור שגוי או טקסט הפוך!**
|
||||
|
||||
---
|
||||
|
||||
## זיהוי סוג מסמך — Document Type Detection
|
||||
|
||||
**לפני יצירת מסמך, זהה את סוגו.** לכל סוג יש מבנה שונה:
|
||||
|
||||
| סוג מסמך | דוגמאות | Header בית משפט? | מבנה מיוחד |
|
||||
|----------|---------|------------------|------------|
|
||||
| **כתב טענות** | תביעה, הגנה, בקשה, ערעור, תצהיר, בר"ע | ✅ כן | טבלת Header עם בית משפט + מספר תיק |
|
||||
| **מכתב התראה** | התראה, דרישה, מכתב עו"ד | ❌ לא | לוגו/פרטי משרד, "הנדון:", חתימה |
|
||||
| **הסכם/חוזה** | הסכם שירותים, NDA, חוזה שכירות | ❌ לא | הואילים, צדדים, חתימות בשני טורים |
|
||||
| **מסמך כללי** | חוות דעת, מזכר, סיכום | ❌ לא | לפי הצורך |
|
||||
|
||||
### טריגרים לזיהוי
|
||||
|
||||
```
|
||||
כתב טענות ← "בית משפט", "בית הדין", "תביעה", "הגנה", "בקשה",
|
||||
"ערעור", "תצהיר", "המבקש", "המשיב", "התובע", "הנתבע", "בר\"ע"
|
||||
|
||||
מכתב התראה ← "התראה", "דרישה", "לכבוד", "הנדון:", "נשלח מבלי לפגוע"
|
||||
|
||||
הסכם/חוזה ← "הסכם", "חוזה", "בין:", "לבין:", "הואיל", "צד א'", "צד ב'",
|
||||
"ולראיה באו הצדדים"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## פונטים ומידות
|
||||
|
||||
### פונטים משפטיים
|
||||
|
||||
| פונט | שימוש | size (half-points) |
|
||||
|------|-------|-------------------|
|
||||
| **David** | ברירת מחדל, גוף טקסט | 24 (12pt) |
|
||||
| **FrankRuehl** | פורמלי/שמרני | 24 (12pt) |
|
||||
| **Miriam** | מודרני יותר | 24 (12pt) |
|
||||
|
||||
**חשוב:** תמיד להגדיר גם `w:cs` (Complex Script) וגם `w:ascii`/`w:hAnsi`:
|
||||
```javascript
|
||||
new TextRun({ text: "...", font: "David", rightToLeft: true })
|
||||
// docx-js מייצר: <w:rFonts w:ascii="David" w:cs="David" w:eastAsia="David" w:hAnsi="David"/>
|
||||
```
|
||||
|
||||
### מידות ושוליים
|
||||
|
||||
```
|
||||
2.5 ס"מ = 1417 DXA (ברירת מחדל משפטי)
|
||||
3.0 ס"מ = 1701 DXA
|
||||
2.0 ס"מ = 1134 DXA
|
||||
1.0 אינץ' = 1440 DXA
|
||||
|
||||
A4 = 11906 × 16838 DXA
|
||||
רוחב תוכן (A4, שוליים 2.5 ס"מ) = 9072 DXA
|
||||
רוחב תוכן (A4, שוליים 2.0 ס"מ) = 9638 DXA
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## מספור סעיפים משפטיים
|
||||
|
||||
**⚠️ שים לב: `alignment: AlignmentType.START` — לא LEFT ולא RIGHT!**
|
||||
|
||||
```javascript
|
||||
numbering: {
|
||||
config: [{
|
||||
reference: "legal-clauses",
|
||||
levels: [
|
||||
{
|
||||
level: 0,
|
||||
format: LevelFormat.DECIMAL,
|
||||
text: "%1.",
|
||||
alignment: AlignmentType.START, // ✅ START — לא RIGHT!
|
||||
suffix: "tab",
|
||||
style: { paragraph: { indent: { left: 720, hanging: 360 } } }
|
||||
},
|
||||
{
|
||||
level: 1,
|
||||
format: LevelFormat.DECIMAL,
|
||||
text: "%1.%2",
|
||||
alignment: AlignmentType.START, // ✅ START — לא RIGHT!
|
||||
suffix: "tab",
|
||||
style: { paragraph: { indent: { left: 1440, hanging: 500 } } }
|
||||
},
|
||||
{
|
||||
level: 2,
|
||||
format: LevelFormat.DECIMAL,
|
||||
text: "%1.%2.%3",
|
||||
alignment: AlignmentType.START, // ✅ START
|
||||
suffix: "tab",
|
||||
style: { paragraph: { indent: { left: 2160, hanging: 640 } } }
|
||||
}
|
||||
]
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
**שימוש:**
|
||||
```javascript
|
||||
new Paragraph({
|
||||
bidirectional: true,
|
||||
numbering: { reference: "legal-clauses", level: 0 },
|
||||
children: [new TextRun({ text: "תוכן הסעיף", font: "David", size: 24, rightToLeft: true })]
|
||||
})
|
||||
```
|
||||
|
||||
> **הבעיה שנפתרה:** בלי `AlignmentType.START`, המספור מופיע כ-".1" במקום "1."
|
||||
|
||||
---
|
||||
|
||||
## טבלאות RTL
|
||||
|
||||
**⚠️ קריטי: `visuallyRightToLeft: true` — בלי זה העמודות יהיו הפוכות!**
|
||||
|
||||
```javascript
|
||||
const { Table, TableRow, TableCell, BorderStyle, WidthType, ShadingType } = require('docx');
|
||||
|
||||
const CONTENT_WIDTH = 9072; // A4 עם שוליים 2.5 ס"מ (11906 - 1417×2)
|
||||
const border = { style: BorderStyle.SINGLE, size: 1, color: "999999" };
|
||||
const borders = { top: border, bottom: border, left: border, right: border };
|
||||
const noBorders = {
|
||||
top: { style: BorderStyle.NONE, size: 0, color: "FFFFFF" },
|
||||
bottom: { style: BorderStyle.NONE, size: 0, color: "FFFFFF" },
|
||||
left: { style: BorderStyle.NONE, size: 0, color: "FFFFFF" },
|
||||
right: { style: BorderStyle.NONE, size: 0, color: "FFFFFF" }
|
||||
};
|
||||
|
||||
// Helper function לתאים בעברית
|
||||
const rtlCell = (text, width, opts = {}) => new TableCell({
|
||||
borders: opts.noBorders ? noBorders : borders,
|
||||
width: { size: width, type: WidthType.DXA },
|
||||
margins: { top: 80, bottom: 80, left: 120, right: 120 },
|
||||
...(opts.shading ? { shading: { fill: opts.shading, type: ShadingType.CLEAR } } : {}),
|
||||
children: [new Paragraph({
|
||||
bidirectional: true,
|
||||
alignment: opts.alignment || AlignmentType.CENTER,
|
||||
children: [new TextRun({
|
||||
text, font: "David", size: 24, rightToLeft: true, bold: opts.bold
|
||||
})]
|
||||
})]
|
||||
});
|
||||
|
||||
// טבלה עם גבולות
|
||||
new Table({
|
||||
visuallyRightToLeft: true, // ✅ קריטי! בלי זה העמודות הפוכות
|
||||
width: { size: CONTENT_WIDTH, type: WidthType.DXA },
|
||||
columnWidths: [4536, 2268, 2268], // חייב להסתכם ל-CONTENT_WIDTH
|
||||
rows: [
|
||||
new TableRow({ children: [
|
||||
rtlCell("סוג שירות", 4536, { bold: true, shading: "D5E8F0" }),
|
||||
rtlCell("תעריף", 2268, { bold: true, shading: "D5E8F0" }),
|
||||
rtlCell("הערות", 2268, { bold: true, shading: "D5E8F0" }),
|
||||
]}),
|
||||
new TableRow({ children: [
|
||||
rtlCell("ייעוץ משפטי", 4536),
|
||||
rtlCell("850 ש״ח", 2268),
|
||||
rtlCell("בתוספת מע״מ", 2268),
|
||||
]}),
|
||||
]
|
||||
})
|
||||
|
||||
// טבלה ללא גבולות (לחתימות / header)
|
||||
new Table({
|
||||
visuallyRightToLeft: true,
|
||||
width: { size: CONTENT_WIDTH, type: WidthType.DXA },
|
||||
columnWidths: [CONTENT_WIDTH / 2, CONTENT_WIDTH / 2],
|
||||
rows: [
|
||||
new TableRow({ children: [
|
||||
rtlCell("חתימה: ________", CONTENT_WIDTH / 2, { noBorders: true, alignment: AlignmentType.CENTER }),
|
||||
rtlCell("חתימה: ________", CONTENT_WIDTH / 2, { noBorders: true, alignment: AlignmentType.CENTER }),
|
||||
]})
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
**כללים:**
|
||||
- **`visuallyRightToLeft: true`** — חובה! בלי זה העמודות משמאל לימין
|
||||
- **`WidthType.DXA`** — לא PERCENTAGE (פחות אמין ב-RTL)
|
||||
- **`columnWidths`** — סכום חייב להיות שווה ל-`CONTENT_WIDTH`
|
||||
- **`bidirectional: true` + `rightToLeft: true`** — בכל תא
|
||||
|
||||
---
|
||||
|
||||
## Tracked Changes — עקוב אחר שינויים
|
||||
|
||||
### שם מחבר בעברית
|
||||
```xml
|
||||
<w:del w:id="10" w:author="עו"ד כהן" w:date="2026-02-06T09:00:00Z">
|
||||
```
|
||||
|
||||
### שינוי ערך (סכום, תאריך, תקופה)
|
||||
פצל את הטקסט ועטוף רק את הערך שמשתנה:
|
||||
```xml
|
||||
<w:r><w:rPr>...RTL PROPS...</w:rPr>
|
||||
<w:t xml:space="preserve">שכר הטרחה יעמוד על סך של </w:t></w:r>
|
||||
<w:del w:id="10" w:author="עו"ד כהן" w:date="...">
|
||||
<w:r><w:rPr>...RTL PROPS...</w:rPr><w:delText>750</w:delText></w:r>
|
||||
</w:del>
|
||||
<w:ins w:id="11" w:author="עו"ד כהן" w:date="...">
|
||||
<w:r><w:rPr>...RTL PROPS...</w:rPr><w:t>850</w:t></w:r>
|
||||
</w:ins>
|
||||
<w:r><w:rPr>...RTL PROPS...</w:rPr>
|
||||
<w:t xml:space="preserve"> ש״ח לשעת עבודה</w:t></w:r>
|
||||
```
|
||||
|
||||
### מחיקת סעיף שלם
|
||||
סמן גם את ה-paragraph mark כ-deleted:
|
||||
```xml
|
||||
<w:p>
|
||||
<w:pPr>
|
||||
<w:bidi/>
|
||||
<w:jc w:val="both"/>
|
||||
<w:rPr>
|
||||
<w:del w:id="20" w:author="עו"ד כהן" w:date="..."/>
|
||||
</w:rPr>
|
||||
</w:pPr>
|
||||
<w:del w:id="21" w:author="עו"ד כהן" w:date="...">
|
||||
<w:r><w:rPr>...RTL PROPS...</w:rPr>
|
||||
<w:delText>הסעיף שנמחק</w:delText></w:r>
|
||||
</w:del>
|
||||
</w:p>
|
||||
```
|
||||
|
||||
### RTL PROPS — בלוק rPr מלא לכל run
|
||||
```xml
|
||||
<w:rPr>
|
||||
<w:rFonts w:ascii="David" w:cs="David" w:eastAsia="David" w:hAnsi="David"/>
|
||||
<w:sz w:val="24"/>
|
||||
<w:szCs w:val="24"/>
|
||||
<w:rtl/>
|
||||
</w:rPr>
|
||||
```
|
||||
|
||||
### קבלה/דחייה של שינויים
|
||||
|
||||
**קבלת Insertion:**
|
||||
```
|
||||
לפני: <w:ins w:id="5" w:author="..."><w:r>...<w:t>טקסט חדש</w:t></w:r></w:ins>
|
||||
אחרי: <w:r>...<w:t>טקסט חדש</w:t></w:r>
|
||||
→ הסר את תגית <w:ins> ושמור את התוכן הפנימי.
|
||||
```
|
||||
|
||||
**דחיית Insertion:**
|
||||
```
|
||||
לפני: <w:ins w:id="5" w:author="..."><w:r>...<w:t>טקסט חדש</w:t></w:r></w:ins>
|
||||
אחרי: (הסר לחלוטין)
|
||||
→ מחק את כל בלוק ה-<w:ins> כולל תוכנו.
|
||||
```
|
||||
|
||||
**קבלת מחיקה:**
|
||||
```
|
||||
לפני: <w:del w:id="10" w:author="..."><w:r>...<w:delText>טקסט שנמחק</w:delText></w:r></w:del>
|
||||
אחרי: (הסר לחלוטין)
|
||||
→ מחק את כל בלוק ה-<w:del> כולל תוכנו — המחיקה מתקבלת.
|
||||
```
|
||||
|
||||
**שחזור טקסט מקורי (דחיית מחיקה):**
|
||||
```
|
||||
לפני: <w:del w:id="10" w:author="..."><w:r>...<w:delText>טקסט מקורי</w:delText></w:r></w:del>
|
||||
אחרי: <w:r>...<w:t>טקסט מקורי</w:t></w:r>
|
||||
→ הסר <w:del>, החלף <w:delText> ב-<w:t>, הסר <w:del> מ-rPr אם קיים.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## הערות (Comments)
|
||||
|
||||
הערות משמשות בסקירה משפטית להסביר *למה* בוצע שינוי:
|
||||
|
||||
```bash
|
||||
python /mnt/skills/public/docx/scripts/comment.py unpacked/ 0 "הערה בעברית" --author "עו״ד כהן"
|
||||
```
|
||||
|
||||
שימושים נפוצים:
|
||||
- הסבר לשינוי סכום או תאריך
|
||||
- דגל על סעיף בעייתי
|
||||
- הפניה לפסיקה או חקיקה
|
||||
- שאלה ללקוח / לצד השני
|
||||
|
||||
> **הערה:** `comment.py` מטפל אוטומטית ב-Content_Types ו-relationships.
|
||||
|
||||
---
|
||||
|
||||
## עריכת DOCX קיים (Unpack → Edit → Pack)
|
||||
|
||||
### תהליך מאומת
|
||||
```bash
|
||||
# 1. פתיחת הקובץ
|
||||
python /mnt/skills/public/docx/scripts/unpack.py input.docx unpacked/
|
||||
|
||||
# 2. עריכת word/document.xml (או קבצי XML אחרים)
|
||||
|
||||
# 3. ארגון מחדש
|
||||
python /mnt/skills/public/docx/scripts/pack.py unpacked/ output.docx --original input.docx
|
||||
```
|
||||
|
||||
### מיקום הוספת תוכן — כלל קריטי
|
||||
```
|
||||
⚠️ פסקאות חדשות חייבות להיכנס *לפני* <w:sectPr> האחרון בגוף המסמך.
|
||||
הוספה *אחרי* sectPr תיכשל בוולידציה.
|
||||
|
||||
מבנה תקין:
|
||||
<w:body>
|
||||
<w:p>...</w:p> ← פסקאות קיימות
|
||||
<w:p>...</w:p> ← פסקה חדשה כאן ✅
|
||||
<w:sectPr>...</w:sectPr> ← תמיד אחרון
|
||||
</w:body>
|
||||
```
|
||||
|
||||
### דוגמה — הוספת פסקה בעברית
|
||||
```xml
|
||||
<w:p>
|
||||
<w:pPr>
|
||||
<w:bidi/>
|
||||
<w:jc w:val="both"/>
|
||||
</w:pPr>
|
||||
<w:r>
|
||||
<w:rPr>
|
||||
<w:rFonts w:ascii="David" w:cs="David" w:eastAsia="David" w:hAnsi="David"/>
|
||||
<w:sz w:val="24"/>
|
||||
<w:szCs w:val="24"/>
|
||||
<w:rtl/>
|
||||
</w:rPr>
|
||||
<w:t>הטקסט החדש</w:t>
|
||||
</w:r>
|
||||
</w:p>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## הערות שוליים (Footnotes)
|
||||
|
||||
**השימוש המרכזי:** הפניות לחקיקה ופסיקה.
|
||||
|
||||
```javascript
|
||||
const { FootnoteReferenceRun } = require('docx');
|
||||
|
||||
// 1. הגדרה ב-Document:
|
||||
const doc = new Document({
|
||||
footnotes: {
|
||||
1: { children: [new Paragraph({
|
||||
bidirectional: true, alignment: AlignmentType.START, // ✅ START
|
||||
children: [new TextRun({
|
||||
text: "חוק החוזים (חלק כללי), התשל״ג-1973, סעיף 12.",
|
||||
font: "David", size: 20, rightToLeft: true // 10pt להערות שוליים
|
||||
})]
|
||||
})] },
|
||||
2: { children: [new Paragraph({
|
||||
bidirectional: true, alignment: AlignmentType.START,
|
||||
children: [new TextRun({
|
||||
text: "ע״א 1234/20 כהן נ׳ לוי, פסקה 15 (פורסם בנבו, 1.1.2024).",
|
||||
font: "David", size: 20, rightToLeft: true
|
||||
})]
|
||||
})] },
|
||||
},
|
||||
// ...sections
|
||||
});
|
||||
|
||||
// 2. הפניה בגוף הטקסט:
|
||||
new Paragraph({
|
||||
bidirectional: true, alignment: AlignmentType.BOTH,
|
||||
children: [
|
||||
new TextRun({ text: "חובת תום הלב", font: "David", size: 24, rightToLeft: true }),
|
||||
new FootnoteReferenceRun(1),
|
||||
new TextRun({ text: " חלה על כל שלבי המשא ומתן", font: "David", size: 24, rightToLeft: true }),
|
||||
new FootnoteReferenceRun(2),
|
||||
new TextRun({ text: ".", font: "David", size: 24, rightToLeft: true }),
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
### תיקון RTL בהערות שוליים (post-unpack)
|
||||
docx-js לא מגדיר RTL מלא בהערות שוליים. אחרי unpack, צריך לתקן ב-`word/footnotes.xml`:
|
||||
```xml
|
||||
<!-- 1. הוסף pStyle + bidi לכל הערת שוליים: -->
|
||||
<w:footnote w:id="1">
|
||||
<w:p>
|
||||
<w:pPr>
|
||||
<w:pStyle w:val="FootnoteText"/>
|
||||
<w:bidi/>
|
||||
<w:jc w:val="start"/>
|
||||
</w:pPr>
|
||||
...
|
||||
|
||||
<!-- 2. הוסף rtl ל-footnoteRef run: -->
|
||||
<w:r>
|
||||
<w:rPr>
|
||||
<w:rStyle w:val="FootnoteReference"/>
|
||||
<w:rtl/>
|
||||
</w:rPr>
|
||||
<w:footnoteRef/>
|
||||
</w:r>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## מרווח שורות (Line Spacing)
|
||||
|
||||
**דרישת בתי המשפט:** בדרך כלל 1.5 שורות.
|
||||
|
||||
```javascript
|
||||
const { LineRuleType } = require('docx');
|
||||
|
||||
// LineRuleType.AUTO — הערך הוא ב-1/240 שורה
|
||||
spacing: { line: 240, lineRule: LineRuleType.AUTO } // 1.0 — צפוף
|
||||
spacing: { line: 276, lineRule: LineRuleType.AUTO } // 1.15 — ברירת מחדל Word
|
||||
spacing: { line: 360, lineRule: LineRuleType.AUTO } // 1.5 — נדרש בבתי משפט
|
||||
spacing: { line: 480, lineRule: LineRuleType.AUTO } // 2.0 — כפול
|
||||
|
||||
// שילוב עם before/after:
|
||||
spacing: { line: 360, lineRule: LineRuleType.AUTO, before: 120, after: 120 }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## תוכן עניינים (TOC)
|
||||
|
||||
**⚠️ חובה: TOC ידני (לא TableOfContents).**
|
||||
`TableOfContents` של docx-js מייצר שדה שוורד מעדכן ב-F9 ומאבד הגדרות RTL.
|
||||
|
||||
```javascript
|
||||
const { Tab, TabStopType, LeaderType, PageBreak } = require('docx');
|
||||
|
||||
// שורת TOC ידנית
|
||||
const tocEntry = (text, pageNum, opts = {}) => new Paragraph({
|
||||
bidirectional: true,
|
||||
spacing: { after: 60, line: 276, lineRule: LineRuleType.AUTO },
|
||||
...(opts.indent ? { indent: { right: opts.indent } } : {}),
|
||||
tabStops: [{ type: TabStopType.RIGHT, position: 9026, leader: LeaderType.DOT }],
|
||||
children: [
|
||||
new TextRun({
|
||||
text, font: "David", size: 24, rightToLeft: true,
|
||||
bold: opts.bold || false,
|
||||
}),
|
||||
new TextRun({ children: [new Tab()], font: "David", rightToLeft: true }),
|
||||
new TextRun({
|
||||
text: String(pageNum), font: "David", size: 24, rightToLeft: true,
|
||||
}),
|
||||
]
|
||||
});
|
||||
|
||||
// שימוש:
|
||||
new Paragraph({
|
||||
bidirectional: true, alignment: AlignmentType.CENTER,
|
||||
spacing: { after: 200 },
|
||||
children: [new TextRun({
|
||||
text: "תוכן עניינים", font: "David", size: 32, bold: true, rightToLeft: true
|
||||
})]
|
||||
}),
|
||||
tocEntry("פרק א׳ — הגדרות כלליות", 2, { bold: true }),
|
||||
tocEntry("1. הגדרות יסוד", 2, { indent: 400 }),
|
||||
tocEntry("פרק ב׳ — השירותים", 3, { bold: true }),
|
||||
new Paragraph({ children: [new PageBreak()] }),
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## קו תחתי (Underline)
|
||||
|
||||
```javascript
|
||||
const { UnderlineType } = require('docx');
|
||||
|
||||
// קו תחתי רגיל:
|
||||
new TextRun({
|
||||
text: "נושא: הסכם שירותים",
|
||||
font: "David", size: 24, rightToLeft: true,
|
||||
underline: { type: UnderlineType.SINGLE }
|
||||
})
|
||||
|
||||
// קו תחתי כפול (לכותרות חשובות):
|
||||
underline: { type: UnderlineType.DOUBLE }
|
||||
|
||||
// סוגים שימושיים: SINGLE, DOUBLE, THICK, DOTTED, DASH, WAVE
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## מספר סקשנים (Multiple Sections)
|
||||
|
||||
**שימוש:** כותרות שונות לנספחים, עמוד לרוחב לטבלאות, שוליים שונים.
|
||||
|
||||
```javascript
|
||||
const doc = new Document({
|
||||
sections: [
|
||||
// סקשן 1 — גוף ההסכם
|
||||
{
|
||||
properties: {
|
||||
page: { size: { width: 11906, height: 16838 },
|
||||
margin: { top: 1417, right: 1417, bottom: 1417, left: 1417 } },
|
||||
bidi: true,
|
||||
},
|
||||
headers: {
|
||||
default: new Header({ children: [new Paragraph({
|
||||
bidirectional: true, alignment: AlignmentType.CENTER,
|
||||
children: [new TextRun({ text: "הסכם שירותים", font: "David", size: 20, bold: true, rightToLeft: true })]
|
||||
})] })
|
||||
},
|
||||
children: [ /* ... */ ]
|
||||
},
|
||||
// סקשן 2 — נספח עם כותרת שונה
|
||||
{
|
||||
properties: {
|
||||
page: { size: { width: 11906, height: 16838 },
|
||||
margin: { top: 1417, right: 1417, bottom: 1417, left: 1417 } },
|
||||
bidi: true,
|
||||
},
|
||||
headers: {
|
||||
default: new Header({ children: [new Paragraph({
|
||||
bidirectional: true, alignment: AlignmentType.START, // ✅ START
|
||||
children: [new TextRun({ text: "נספח א׳ — לוח תעריפים", font: "David", size: 20, bold: true, rightToLeft: true })]
|
||||
})] })
|
||||
},
|
||||
children: [ /* ... */ ]
|
||||
}
|
||||
]
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## לוגו/תמונה בכותרת (Letterhead)
|
||||
|
||||
```javascript
|
||||
const { ImageRun } = require('docx');
|
||||
|
||||
const logoBuffer = fs.readFileSync('/path/to/logo.png');
|
||||
|
||||
headers: {
|
||||
default: new Header({
|
||||
children: [
|
||||
new Paragraph({
|
||||
alignment: AlignmentType.CENTER,
|
||||
children: [
|
||||
new ImageRun({
|
||||
data: logoBuffer,
|
||||
transformation: { width: 200, height: 60 }, // pixels
|
||||
type: "png",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new Paragraph({
|
||||
bidirectional: true, alignment: AlignmentType.CENTER,
|
||||
children: [new TextRun({
|
||||
text: "משרד עורכי דין ישראלי ושות׳",
|
||||
font: "David", size: 20, bold: true, rightToLeft: true
|
||||
})],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
}
|
||||
```
|
||||
|
||||
**הערה:** תמונה חייבת להיות קובץ אמיתי — לבקש מהמשתמש אם אין.
|
||||
|
||||
---
|
||||
|
||||
## היפרלינקים
|
||||
|
||||
```javascript
|
||||
const { ExternalHyperlink, UnderlineType } = require('docx');
|
||||
|
||||
new Paragraph({
|
||||
bidirectional: true,
|
||||
children: [
|
||||
new TextRun({ text: "ראה: ", font: "David", size: 24, rightToLeft: true }),
|
||||
new ExternalHyperlink({
|
||||
link: "https://www.nevo.co.il/law_html/law01/073_002.htm",
|
||||
children: [new TextRun({
|
||||
text: "חוק החוזים באתר נבו",
|
||||
font: "David", size: 24, rightToLeft: true,
|
||||
color: "0563C1",
|
||||
underline: { type: UnderlineType.SINGLE },
|
||||
})],
|
||||
}),
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
**⚠️ אזהרות:**
|
||||
- **לא להשתמש ב-`style: "Hyperlink"`** — מפריע ל-RTL!
|
||||
- **לא להוסיף `alignment: AlignmentType.RIGHT`** — `bidirectional: true` מספיק
|
||||
|
||||
---
|
||||
|
||||
## תבניות מסמכים — Document Templates
|
||||
|
||||
### תבנית 1: כתב טענות (בקשה, תביעה, הגנה, ערעור)
|
||||
|
||||
```javascript
|
||||
const { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell,
|
||||
AlignmentType, LevelFormat, BorderStyle, WidthType } = require('docx');
|
||||
|
||||
const PAGE_WIDTH = 11906;
|
||||
const MARGINS = { top: 1134, right: 1134, bottom: 1134, left: 1134 };
|
||||
const CONTENT_WIDTH = PAGE_WIDTH - MARGINS.left - MARGINS.right;
|
||||
|
||||
const noBorder = { style: BorderStyle.NONE, size: 0, color: "FFFFFF" };
|
||||
const noBorders = { top: noBorder, bottom: noBorder, left: noBorder, right: noBorder };
|
||||
|
||||
// Header בית משפט — טבלה עם שם בית המשפט (ימין) ומספר תיק (שמאל)
|
||||
function courtHeader(courtName, caseNumber) {
|
||||
return new Table({
|
||||
width: { size: CONTENT_WIDTH, type: WidthType.DXA },
|
||||
columnWidths: [CONTENT_WIDTH / 2, CONTENT_WIDTH / 2],
|
||||
visuallyRightToLeft: true,
|
||||
rows: [
|
||||
new TableRow({
|
||||
children: [
|
||||
new TableCell({
|
||||
width: { size: CONTENT_WIDTH / 2, type: WidthType.DXA },
|
||||
borders: noBorders,
|
||||
children: [new Paragraph({
|
||||
bidirectional: true, alignment: AlignmentType.START,
|
||||
children: [new TextRun({ text: courtName, bold: true, font: "David", size: 26, rightToLeft: true })]
|
||||
})]
|
||||
}),
|
||||
new TableCell({
|
||||
width: { size: CONTENT_WIDTH / 2, type: WidthType.DXA },
|
||||
borders: noBorders,
|
||||
children: [new Paragraph({
|
||||
bidirectional: true, alignment: AlignmentType.END,
|
||||
children: [new TextRun({ text: caseNumber, bold: true, font: "David", size: 26, rightToLeft: true })]
|
||||
})]
|
||||
})
|
||||
]
|
||||
})
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
// כותרת ראשית ממורכזת עם קו תחתון
|
||||
function mainTitle(text) {
|
||||
return new Paragraph({
|
||||
bidirectional: true, alignment: AlignmentType.CENTER,
|
||||
spacing: { before: 300, after: 300 },
|
||||
children: [new TextRun({ text, bold: true, font: "David", size: 28, rightToLeft: true, underline: {} })]
|
||||
});
|
||||
}
|
||||
|
||||
// כותרת משנה מיושרת לימין עם קו תחתון
|
||||
function subHeading(text) {
|
||||
return new Paragraph({
|
||||
bidirectional: true, alignment: AlignmentType.START,
|
||||
spacing: { before: 240, after: 120 },
|
||||
children: [new TextRun({ text, bold: true, font: "David", size: 24, rightToLeft: true, underline: {} })]
|
||||
});
|
||||
}
|
||||
|
||||
// שימוש:
|
||||
const doc = new Document({
|
||||
numbering: {
|
||||
config: [{
|
||||
reference: "legal-clauses",
|
||||
levels: [{
|
||||
level: 0, format: LevelFormat.DECIMAL, text: "%1.",
|
||||
alignment: AlignmentType.START, suffix: "tab",
|
||||
style: { paragraph: { indent: { left: 360, hanging: 360 } } }
|
||||
}]
|
||||
}]
|
||||
},
|
||||
sections: [{
|
||||
properties: {
|
||||
page: { size: { width: PAGE_WIDTH, height: 16838 }, margin: MARGINS },
|
||||
bidi: true
|
||||
},
|
||||
children: [
|
||||
courtHeader("בית המשפט המחוזי בתל אביב", "ת\"א 12345-01-26"),
|
||||
mainTitle("כתב תביעה"),
|
||||
// ... פרטי צדדים, סעיפים, חתימה
|
||||
]
|
||||
}]
|
||||
});
|
||||
```
|
||||
|
||||
### תבנית 2: מכתב התראה
|
||||
|
||||
```javascript
|
||||
// מכתב התראה — ללא header בית משפט, עם פרטי משרד
|
||||
|
||||
function letterHeader(firmName, address, phone, email) {
|
||||
return [
|
||||
new Paragraph({
|
||||
bidirectional: true, alignment: AlignmentType.START,
|
||||
children: [new TextRun({ text: firmName, bold: true, font: "David", size: 28, rightToLeft: true })]
|
||||
}),
|
||||
new Paragraph({
|
||||
bidirectional: true, alignment: AlignmentType.START,
|
||||
children: [new TextRun({ text: address, font: "David", size: 22, rightToLeft: true })]
|
||||
}),
|
||||
new Paragraph({
|
||||
bidirectional: true, alignment: AlignmentType.START,
|
||||
spacing: { after: 300 },
|
||||
children: [new TextRun({ text: `טל': ${phone} | ${email}`, font: "David", size: 22, rightToLeft: true })]
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
function subjectLine(text) {
|
||||
return new Paragraph({
|
||||
bidirectional: true, alignment: AlignmentType.CENTER,
|
||||
spacing: { before: 200, after: 200 },
|
||||
children: [
|
||||
new TextRun({ text: "הנדון: ", bold: true, font: "David", size: 24, rightToLeft: true }),
|
||||
new TextRun({ text, bold: true, font: "David", size: 24, rightToLeft: true, underline: {} })
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
// שימוש:
|
||||
sections: [{
|
||||
properties: { page: { ... }, bidi: true },
|
||||
children: [
|
||||
...letterHeader("משרד עו\"ד כהן ושות'", "רח' הרצל 1, תל אביב", "03-1234567", "office@cohen-law.co.il"),
|
||||
new Paragraph({
|
||||
bidirectional: true, alignment: AlignmentType.START,
|
||||
children: [new TextRun({ text: "תאריך: 10.2.2026", font: "David", size: 24, rightToLeft: true })]
|
||||
}),
|
||||
new Paragraph({
|
||||
bidirectional: true, alignment: AlignmentType.START,
|
||||
spacing: { before: 200 },
|
||||
children: [new TextRun({ text: "לכבוד: [שם הנמען]", font: "David", size: 24, rightToLeft: true })]
|
||||
}),
|
||||
subjectLine("התראה בטרם נקיטת הליכים משפטיים"),
|
||||
// ... גוף המכתב
|
||||
]
|
||||
}]
|
||||
```
|
||||
|
||||
### תבנית 3: הסכם/חוזה
|
||||
|
||||
```javascript
|
||||
// הסכם — הואילים, צדדים, חתימות בשני טורים
|
||||
|
||||
function contractTitle(text) {
|
||||
return new Paragraph({
|
||||
bidirectional: true, alignment: AlignmentType.CENTER,
|
||||
spacing: { after: 300 },
|
||||
children: [new TextRun({ text, bold: true, font: "David", size: 32, rightToLeft: true })]
|
||||
});
|
||||
}
|
||||
|
||||
function partyClause(label, name, id, address, alias) {
|
||||
return new Paragraph({
|
||||
bidirectional: true, alignment: AlignmentType.BOTH,
|
||||
spacing: { after: 120 },
|
||||
children: [
|
||||
new TextRun({ text: `${label}: `, bold: true, font: "David", size: 24, rightToLeft: true }),
|
||||
new TextRun({ text: `${name}, ח.פ./ת.ז. ${id}, מ${address} (להלן: "`, font: "David", size: 24, rightToLeft: true }),
|
||||
new TextRun({ text: alias, bold: true, font: "David", size: 24, rightToLeft: true }),
|
||||
new TextRun({ text: '")', font: "David", size: 24, rightToLeft: true }),
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
function signatureTable() {
|
||||
return new Table({
|
||||
width: { size: CONTENT_WIDTH, type: WidthType.DXA },
|
||||
columnWidths: [CONTENT_WIDTH / 2, CONTENT_WIDTH / 2],
|
||||
visuallyRightToLeft: true,
|
||||
rows: [
|
||||
new TableRow({
|
||||
children: [
|
||||
new TableCell({
|
||||
borders: noBorders,
|
||||
children: [
|
||||
new Paragraph({ bidirectional: true, alignment: AlignmentType.CENTER,
|
||||
children: [new TextRun({ text: "_________________", font: "David", size: 24, rightToLeft: true })] }),
|
||||
new Paragraph({ bidirectional: true, alignment: AlignmentType.CENTER,
|
||||
children: [new TextRun({ text: "צד א'", font: "David", size: 24, rightToLeft: true })] })
|
||||
]
|
||||
}),
|
||||
new TableCell({
|
||||
borders: noBorders,
|
||||
children: [
|
||||
new Paragraph({ bidirectional: true, alignment: AlignmentType.CENTER,
|
||||
children: [new TextRun({ text: "_________________", font: "David", size: 24, rightToLeft: true })] }),
|
||||
new Paragraph({ bidirectional: true, alignment: AlignmentType.CENTER,
|
||||
children: [new TextRun({ text: "צד ב'", font: "David", size: 24, rightToLeft: true })] })
|
||||
]
|
||||
})
|
||||
]
|
||||
})
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
// שימוש:
|
||||
sections: [{
|
||||
properties: { page: { ... }, bidi: true },
|
||||
children: [
|
||||
contractTitle("הסכם שירותים"),
|
||||
new Paragraph({
|
||||
bidirectional: true, alignment: AlignmentType.CENTER,
|
||||
children: [new TextRun({ text: "נערך ונחתם בתל אביב ביום __________", font: "David", size: 24, rightToLeft: true })]
|
||||
}),
|
||||
partyClause("מצד אחד", "[שם]", "[מספר]", "[כתובת]", "המזמין"),
|
||||
partyClause("מצד שני", "[שם]", "[מספר]", "[כתובת]", "הספק"),
|
||||
// הואילים...
|
||||
// סעיפים...
|
||||
new Paragraph({
|
||||
bidirectional: true, alignment: AlignmentType.CENTER,
|
||||
spacing: { before: 400, after: 300 },
|
||||
children: [new TextRun({ text: "ולראיה באו הצדדים על החתום:", bold: true, font: "David", size: 24, rightToLeft: true })]
|
||||
}),
|
||||
signatureTable()
|
||||
]
|
||||
}]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference — טבלת עזר מהיר
|
||||
|
||||
### יישור
|
||||
|
||||
| רוצה | השתמש ב... | ❌ לא להשתמש |
|
||||
|------|-----------|-------------|
|
||||
| ימין | `AlignmentType.START` | `LEFT`, `RIGHT` |
|
||||
| שמאל | `AlignmentType.END` | `LEFT`, `RIGHT` |
|
||||
| מרכז | `AlignmentType.CENTER` | — |
|
||||
| שני צדדים | `AlignmentType.BOTH` | `JUSTIFIED` |
|
||||
|
||||
### גדלי טקסט (half-points)
|
||||
|
||||
| שימוש | size | נקודות |
|
||||
|-------|------|--------|
|
||||
| גוף טקסט | 24 | 12pt |
|
||||
| כותרת משנה | 26 | 13pt |
|
||||
| כותרת ראשית | 28-32 | 14-16pt |
|
||||
| הערות שוליים | 20 | 10pt |
|
||||
| Header/Footer | 18-20 | 9-10pt |
|
||||
|
||||
### מרווחי שורות
|
||||
|
||||
| רווח | line value |
|
||||
|------|-----------|
|
||||
| 1.0 | 240 |
|
||||
| 1.15 | 276 |
|
||||
| 1.5 | 360 |
|
||||
| 2.0 | 480 |
|
||||
|
||||
### Checklist — הגדרות חובה
|
||||
|
||||
```
|
||||
☐ Section: bidi: true
|
||||
☐ Paragraph: bidirectional: true
|
||||
☐ TextRun: rightToLeft: true
|
||||
☐ Numbering: alignment: AlignmentType.START
|
||||
☐ Table: visuallyRightToLeft: true
|
||||
☐ Footnotes: alignment: AlignmentType.START
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Troubleshooting
|
||||
|
||||
**מספור מופיע הפוך (.1 במקום 1.):**
|
||||
→ וודא `alignment: AlignmentType.START` במספור (לא RIGHT!)
|
||||
|
||||
**טקסט מופיע משמאל לימין:**
|
||||
→ וודא את שלושת ההגדרות: Section `bidi`, Paragraph `bidirectional`, TextRun `rightToLeft`
|
||||
|
||||
**עמודות טבלה הפוכות:**
|
||||
→ הוסף `visuallyRightToLeft: true` לטבלה
|
||||
|
||||
**columnWidths לא מסתכם:**
|
||||
→ וודא שסכום כל הרוחבים = CONTENT_WIDTH (9072 לשוליים 2.5 ס"מ, חישוב: 11906 - 1417×2)
|
||||
|
||||
**המסמך לא נפתח / שגיאה ב-Word:**
|
||||
→ בדוק שלא הוספת פסקה אחרי `<w:sectPr>` (חייב להיות אחרון ב-body)
|
||||
→ וודא `npm list docx` >= 8.0.0
|
||||
|
||||
**הערות שוליים לא ב-RTL:**
|
||||
→ אחרי unpack, תקן ידנית ב-word/footnotes.xml (ראה סעיף הערות שוליים)
|
||||
|
||||
---
|
||||
|
||||
## טעויות נפוצות — Common Pitfalls
|
||||
|
||||
| ❌ טעות | ✅ תיקון |
|
||||
|--------|---------|
|
||||
| `AlignmentType.RIGHT` במספור | `AlignmentType.START` |
|
||||
| `AlignmentType.LEFT` ליישור שמאלי | `AlignmentType.END` |
|
||||
| טבלה בלי `visuallyRightToLeft` | הוסף `visuallyRightToLeft: true` |
|
||||
| שכחת `bidirectional: true` בפסקה | הוסף לכל פסקה |
|
||||
| שכחת `rightToLeft: true` ב-TextRun | הוסף לכל TextRun |
|
||||
| שכחת `bidi: true` ב-Section | הוסף ל-properties |
|
||||
| הוספת פסקה אחרי `sectPr` | הוסף לפני `sectPr` |
|
||||
| שימוש ב-`style: "Hyperlink"` | הגדר ידנית `color` + `underline` |
|
||||
| `columnWidths` לא מסתכם נכון | וודא שהסכום = `CONTENT_WIDTH` |
|
||||
|
||||
---
|
||||
|
||||
## קבצי עזר
|
||||
|
||||
- **`references/document-types.md`** — מבנים מפורטים ל-9 סוגי מסמכים משפטיים
|
||||
- **`scripts/create-legal-doc.js`** — סקריפט בסיסי עם כל הגדרות ה-RTL המתוקנות
|
||||
|
||||
---
|
||||
|
||||
## Dependencies
|
||||
|
||||
```bash
|
||||
npm install docx
|
||||
```
|
||||
|
||||
**גרסה מומלצת:** docx >= 8.0.0
|
||||
271
skills/docx/references/document-types.md
Normal file
271
skills/docx/references/document-types.md
Normal file
@@ -0,0 +1,271 @@
|
||||
# סוגי מסמכים משפטיים — מבנים ותבניות
|
||||
|
||||
## תוכן עניינים
|
||||
1. [הסכם / חוזה](#הסכם--חוזה)
|
||||
2. [מכתב התראה](#מכתב-התראה)
|
||||
3. [כתב תביעה](#כתב-תביעה)
|
||||
4. [כתב הגנה](#כתב-הגנה)
|
||||
5. [בקשה לבית משפט](#בקשה-לבית-משפט)
|
||||
6. [תצהיר](#תצהיר)
|
||||
7. [ייפוי כוח](#ייפוי-כוח)
|
||||
8. [פרוטוקול ישיבה](#פרוטוקול-ישיבה)
|
||||
9. [חוות דעת משפטית](#חוות-דעת-משפטית)
|
||||
|
||||
---
|
||||
|
||||
## הסכם / חוזה
|
||||
|
||||
### מבנה
|
||||
```
|
||||
כותרת: "הסכם [סוג]" (מרכז, bold, 16pt)
|
||||
תאריך ומקום: "נערך ונחתם ב[עיר] ביום [תאריך]"
|
||||
צדדים:
|
||||
"מצד אחד: [שם], ח.פ./ת.ז. [מספר], מ[כתובת] (להלן: "[כינוי]")"
|
||||
"מצד שני: [שם], ח.פ./ת.ז. [מספר], מ[כתובת] (להלן: "[כינוי]")"
|
||||
הואילים (מוספרים):
|
||||
"1. והואיל ו[תנאי ראשון];"
|
||||
"2. והואיל ו[תנאי שני];"
|
||||
מעבר: "לפיכך הוסכם, הותנה והוצהר בין הצדדים כדלקמן:" (מרכז, bold)
|
||||
סעיפים ממוספרים: 1., 1.1, 1.2, 2., 2.1...
|
||||
חתימות: "ולראיה באו הצדדים על החתום:" + שורות חתימה
|
||||
```
|
||||
|
||||
### סעיפים נפוצים
|
||||
- היקף השירותים / הגדרות
|
||||
- תמורה ותשלום
|
||||
- תקופת ההסכם
|
||||
- סודיות
|
||||
- קניין רוחני
|
||||
- אחריות ושיפוי
|
||||
- סיום ההתקשרות
|
||||
- שונות (דין חל, סמכות שיפוט, כתובות)
|
||||
|
||||
### כותרות heading
|
||||
- כותרת ראשית: Heading1, center, 16pt
|
||||
- "בין הצדדים", "הואיל:": Heading2, center, 14pt
|
||||
- כותרות סעיפים ("1. היקף השירותים"): Heading2, right/justified, 14pt
|
||||
|
||||
---
|
||||
|
||||
## מכתב התראה
|
||||
|
||||
### מבנה
|
||||
```
|
||||
Header: לוגו/שם משרד, כתובת, טלפון, פקס, דוא"ל
|
||||
תאריך: "ב[עיר], [תאריך]"
|
||||
סימוכין: "סימוכין: [מספר תיק]"
|
||||
נמען: "לכבוד [שם]\n[כתובת]"
|
||||
שורת נדון: "הנדון: [נושא]" (bold, underline)
|
||||
סיווג: "מכתב זה נשלח מבלי לפגוע בזכויות מרשי/תי" (bold)
|
||||
גוף: פסקאות ללא מספור — תיאור עובדות, עילה, דרישה
|
||||
סיום: "בכבוד רב," + חתימה
|
||||
העתק: "העתק: [נמענים]"
|
||||
```
|
||||
|
||||
### טון
|
||||
- פורמלי ותקיף
|
||||
- עובדתי ומדויק
|
||||
- מציין מועד אחרון לתגובה
|
||||
|
||||
---
|
||||
|
||||
## כתב תביעה
|
||||
|
||||
### מבנה
|
||||
```
|
||||
Header: "בבית המשפט [סוג] ב[עיר]"
|
||||
מספר תיק: "ת"א [מספר]"
|
||||
צדדים:
|
||||
"התובע: [שם], ת.ז. [מספר]"
|
||||
"ע"י ב"כ עו"ד [שם], [כתובת]"
|
||||
"-נגד-"
|
||||
"הנתבע: [שם], ת.ז. [מספר]"
|
||||
כותרת: "כתב תביעה" (מרכז, bold, 16pt)
|
||||
מבוא / הצדדים
|
||||
עילות (סעיפים ממוספרים):
|
||||
1. עובדות (בפסקאות ממוספרות)
|
||||
2. הנזק
|
||||
3. העילות המשפטיות
|
||||
הסעדים המבוקשים
|
||||
חתימה
|
||||
אימות (תצהיר מצורף)
|
||||
```
|
||||
|
||||
### דגשים
|
||||
- כל עובדה בסעיף נפרד
|
||||
- הפניות לסעיפי חוק
|
||||
- סכום התביעה בסוף
|
||||
|
||||
---
|
||||
|
||||
## כתב הגנה
|
||||
|
||||
### מבנה
|
||||
```
|
||||
Header: "בבית המשפט [סוג] ב[עיר]"
|
||||
מספר תיק: "ת"א [מספר]"
|
||||
צדדים: (כמו בכתב התביעה, עם "הנתבע/הנתבעת")
|
||||
כותרת: "כתב הגנה" (מרכז, bold, 16pt)
|
||||
מבוא
|
||||
תשובה לכתב התביעה:
|
||||
- התייחסות סעיף-סעיף ("לסעיף X — מוכחש/מאושר/אין ידיעה")
|
||||
- טענות הגנה
|
||||
- טענות מקדמיות (התיישנות, חוסר סמכות, חוסר עילה)
|
||||
סיכום
|
||||
חתימה
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## בקשה לבית משפט
|
||||
|
||||
### מבנה
|
||||
```
|
||||
Header: "בבית המשפט [סוג] ב[עיר]"
|
||||
מספר תיק
|
||||
צדדים
|
||||
כותרת: "בקשה ל[סוג הבקשה]" (מרכז, bold, 16pt)
|
||||
לדוגמה: "בקשה למתן צו מניעה זמני"
|
||||
מבוא
|
||||
הרקע העובדתי (ממוספר)
|
||||
הנימוקים המשפטיים (ממוספר)
|
||||
הסעד המבוקש
|
||||
חתימה
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## תצהיר
|
||||
|
||||
### מבנה
|
||||
```
|
||||
Header: "בבית המשפט [סוג] ב[עיר]" (אם מוגש לבימ"ש)
|
||||
כותרת: "תצהיר" / "תצהיר עדות ראשית" (מרכז, bold, 16pt)
|
||||
פתיחה: "אני, [שם], ת.ז. [מספר], לאחר שהוזהרתי כי עלי לומר את
|
||||
האמת וכי אהיה צפוי/ה לעונשים הקבועים בחוק אם לא אעשה כן,
|
||||
מצהיר/ה בזה כדלקמן:"
|
||||
גוף: סעיפים ממוספרים (עובדות בגוף ראשון)
|
||||
נספחים: "מצ"ב מסמך... מסומן כנספח [א']"
|
||||
סיום: "[שם המצהיר/ה]"
|
||||
אימות: "אישור עורך דין"
|
||||
"אני, עו"ד [שם], מאשר/ת בזה כי ביום [תאריך] התייצב/ה בפני
|
||||
[שם], שזיהה/תה עצמו/ה באמצעות ת.ז. [מספר], ולאחר שהזהרתיו/ה
|
||||
כי עליו/ה להצהיר אמת וכי יהיה/תהיה צפוי/ה לעונשים הקבועים בחוק
|
||||
אם לא יעשה/תעשה כן, אישר/ה את נכונות הצהרתו/ה וחתם/ה עליה
|
||||
בפני."
|
||||
חתימת עו"ד
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ייפוי כוח
|
||||
|
||||
### מבנה
|
||||
```
|
||||
כותרת: "ייפוי כוח" / "ייפוי כוח כללי" / "ייפוי כוח מיוחד"
|
||||
מייפה הכוח: "[שם], ת.ז. [מספר], מ[כתובת]"
|
||||
מיופה הכוח: "עו"ד [שם], רישיון [מספר]"
|
||||
ההרשאה: פירוט הפעולות המורשות
|
||||
- ייפוי כוח כללי: "לייצגני בכל עניין ולפעול בשמי..."
|
||||
- ייפוי כוח מיוחד: פירוט ספציפי של הפעולה
|
||||
תוקף: תאריך תחילה וסיום (אם רלוונטי)
|
||||
חתימה + אימות נוטריוני (אם נדרש)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## פרוטוקול ישיבה
|
||||
|
||||
### מבנה
|
||||
```
|
||||
כותרת: "פרוטוקול ישיבת [סוג] מס' [מספר]"
|
||||
פרטים:
|
||||
"תאריך: [תאריך]"
|
||||
"שעה: [שעה]"
|
||||
"מקום: [מקום]"
|
||||
"נוכחים: [רשימה]"
|
||||
"חסרים: [רשימה]"
|
||||
"מנהל הישיבה: [שם]"
|
||||
"מזכיר: [שם]"
|
||||
סדר יום (ממוספר)
|
||||
דיון (לפי סעיפי סדר היום)
|
||||
החלטות (ממוספרות, bold)
|
||||
חתימה: מנהל הישיבה + מזכיר
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## חוות דעת משפטית
|
||||
|
||||
### מבנה
|
||||
```
|
||||
כותרת: "חוות דעת משפטית" (מרכז, bold, 16pt)
|
||||
"לכבוד: [שם הלקוח]"
|
||||
"הנדון: [נושא]"
|
||||
"סימוכין: [מספר תיק]"
|
||||
תקציר מנהלים (אופציונלי)
|
||||
רקע עובדתי
|
||||
השאלה המשפטית
|
||||
הדין החל
|
||||
ניתוח משפטי
|
||||
מסקנות והמלצות
|
||||
הסתייגויות: "חוות דעת זו מבוססת על העובדות שנמסרו לי..."
|
||||
חתימה
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## החלטת ועדת ערר לתכנון ובניה
|
||||
|
||||
### מבנה
|
||||
```
|
||||
כותרת מוסדית: טבלה ללא גבולות, 2 טורים
|
||||
ימין: "מדינת ישראל" (bold), "ועדת ערר לתכנון ובניה", "מחוז ירושלים"
|
||||
שמאל: "מס' תיק:" + מספרים (bold), מספרנו, "מס' בקשה:"/"מס' תכנית:"
|
||||
הרכב: "בפני:" (bold), יו"ר + חברים
|
||||
צדדים: "העורר/ים:" + שמות + ב"כ, "-נגד-" (מרכז, bold), "המשיבים:" + שמות + ב"כ
|
||||
כותרת: "החלטה" (16pt, bold, מרכז)
|
||||
פתיחה: 1-2 סעיפים ללא כותרת ("לפנינו...")
|
||||
פתח דבר / רקע: מקרקעין, היסטוריה תכנונית, מהות הבקשה, ציטוט מפרוטוקול, תמונות
|
||||
תמצית טענות הצדדים: (14pt, bold, קו תחתון, מרכז)
|
||||
טענות העוררים (12pt, bold, מרכז)
|
||||
עמדת הוועדה המקומית (12pt, bold, מרכז)
|
||||
עמדת מבקשי ההיתר / מגישי התכנית (12pt, bold, מרכז)
|
||||
ההליכים בפני ועדת הערר: (14pt, bold, קו תחתון, מרכז) — דיון, סיור, השלמות טיעון
|
||||
התכניות החלות על המקרקעין: (אופציונלי, 14pt, bold, קו תחתון, מרכז)
|
||||
דיון והכרעה: (14pt, bold, קו תחתון, מרכז) — אסה רציפה ללא כותרות משנה
|
||||
סיכום / סוף דבר: (14pt, bold, קו תחתון, מרכז)
|
||||
חתימות: טבלה ללא גבולות, 2 טורים (יו"ר + מזכירה)
|
||||
```
|
||||
|
||||
### דגשים
|
||||
- מספור סעיפים רציף לאורך כל המסמך (לא מתאפס בין חלקים)
|
||||
- מספר הסעיף bold (run נפרד), הטקסט רגיל
|
||||
- ציטוטים בהזחה משני הצדדים (~1 ס"מ), פונט זהה לגוף
|
||||
- תמונות ותשריטים משולבים בטקסט עם הפניה מילולית לפניהם
|
||||
- "ניתנה פה אחד, [תאריך עברי], [תאריך לועזי]." לפני חתימות
|
||||
- מספור עמודים: "עמוד X מתוך Y" תחתון מרכזי
|
||||
- **ראה** `.claude/skills/legal-decision/SKILL.md` סעיפים 11-12 למבנה מלא ותהליך עבודה
|
||||
|
||||
---
|
||||
|
||||
## עקרונות עיצוב משותפים
|
||||
|
||||
### כל מסמך משפטי
|
||||
- **פונט**: David 12pt (ברירת מחדל), FrankRuehl לפורמלי
|
||||
- **שוליים**: 2.5 ס"מ (1417 DXA) מכל הצדדים
|
||||
- **יישור**: Justified (משני צדדים)
|
||||
- **מרווח שורות**: 1.15 או 1.5 (לפי בית המשפט)
|
||||
- **מספור עמודים**: תחתון מרכזי
|
||||
- **כיוון**: RTL מלא (bidi בכל הרמות)
|
||||
|
||||
### כתבי בית דין (תביעה, הגנה, בקשה)
|
||||
- Header עם שם בית המשפט ומספר תיק
|
||||
- צדדים בפורמט סטנדרטי עם "-נגד-"
|
||||
- מספור סעיפים רציף (לא מתאפס בכל חלק)
|
||||
- Footer עם מספר עמוד
|
||||
|
||||
### הסכמים חוזיים
|
||||
- "הואילים" לפני הסעיפים
|
||||
- "ולראיה באו הצדדים על החתום" לפני חתימות
|
||||
- חתימות בשני טורים
|
||||
261
skills/docx/scripts/create-legal-doc.js
Normal file
261
skills/docx/scripts/create-legal-doc.js
Normal file
@@ -0,0 +1,261 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* create-legal-doc.js — תבנית בסיסית למסמך משפטי בעברית
|
||||
*
|
||||
* שימוש: העתק לתיקיית העבודה, ערוך את CONTENT, הרץ עם node.
|
||||
*
|
||||
* הסקריפט כולל את כל הגדרות ה-RTL הנדרשות ב-5 רמות:
|
||||
* 1. Document defaults (styles)
|
||||
* 2. Section properties (bidi: true)
|
||||
* 3. Per-paragraph (bidirectional + alignment)
|
||||
* 4. Per-run (rightToLeft + font)
|
||||
* 5. Numbering (alignment: START, not RIGHT!)
|
||||
*
|
||||
* שינוי פונט: החלף "David" ב-"FrankRuehl" או "Miriam"
|
||||
* שינוי שוליים: שנה MARGIN_CM
|
||||
*
|
||||
* v3.0 — תיקון באג: AlignmentType.START במקום RIGHT במספור
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const { Document, Packer, Paragraph, TextRun, Header, Footer,
|
||||
AlignmentType, HeadingLevel, PageNumber, LevelFormat,
|
||||
Table, TableRow, TableCell, WidthType, BorderStyle,
|
||||
LineRuleType } = require('docx');
|
||||
|
||||
// ═══════════════════════════════════════════════
|
||||
// CONFIGURATION — שנה כאן
|
||||
// ═══════════════════════════════════════════════
|
||||
const FONT = "David";
|
||||
const FONT_SIZE = 24; // half-points (24 = 12pt)
|
||||
const HEADING1_SIZE = 32; // 16pt
|
||||
const HEADING2_SIZE = 28; // 14pt
|
||||
const MARGIN_CM = 2.5;
|
||||
const MARGIN_DXA = Math.round(MARGIN_CM / 2.54 * 1440);
|
||||
const OUTPUT_FILE = "legal-document.docx";
|
||||
|
||||
const HEADER_TEXT = ""; // שם המשרד — השאר ריק אם לא צריך
|
||||
const FOOTER_CONFIDENTIAL = "";
|
||||
|
||||
// ═══════════════════════════════════════════════
|
||||
// HELPERS — פונקציות עזר
|
||||
// ═══════════════════════════════════════════════
|
||||
|
||||
// TextRun עם RTL
|
||||
const rtlRun = (text, opts = {}) => new TextRun({
|
||||
text,
|
||||
...opts,
|
||||
font: opts.font || FONT,
|
||||
size: opts.size || FONT_SIZE,
|
||||
rightToLeft: true, // ← חובה! תמיד אחרון — לא ניתן לדריסה
|
||||
});
|
||||
|
||||
// Paragraph עם RTL
|
||||
const rtlPara = (children, opts = {}) => new Paragraph({
|
||||
bidirectional: true, // ← חובה!
|
||||
alignment: opts.alignment || AlignmentType.BOTH, // ✅ BOTH, לא JUSTIFIED
|
||||
spacing: opts.spacing,
|
||||
children: Array.isArray(children) ? children : [children],
|
||||
...(opts.heading ? { heading: opts.heading } : {}),
|
||||
...(opts.numbering ? { numbering: opts.numbering } : {}),
|
||||
});
|
||||
|
||||
// כותרת ראשית
|
||||
const heading1 = (text) => rtlPara(
|
||||
rtlRun(text, { bold: true, size: HEADING1_SIZE }),
|
||||
{ heading: HeadingLevel.HEADING_1, alignment: AlignmentType.CENTER }
|
||||
);
|
||||
|
||||
// כותרת משנה
|
||||
const heading2 = (text) => rtlPara(
|
||||
rtlRun(text, { bold: true, size: HEADING2_SIZE }),
|
||||
{ heading: HeadingLevel.HEADING_2, alignment: AlignmentType.START } // ✅ START
|
||||
);
|
||||
|
||||
// רווח
|
||||
const spacer = (after = 200) => rtlPara(rtlRun(""), { spacing: { after } });
|
||||
|
||||
// ═══════════════════════════════════════════════
|
||||
// CONTENT — ערוך כאן את תוכן המסמך
|
||||
// ═══════════════════════════════════════════════
|
||||
|
||||
const CONTENT = [
|
||||
// כותרת
|
||||
heading1("הסכם שירותים משפטיים"),
|
||||
|
||||
// תאריך
|
||||
rtlPara(rtlRun("נערך ונחתם בתל אביב ביום ___________"), { spacing: { after: 200 } }),
|
||||
|
||||
// צדדים
|
||||
heading2("בין הצדדים"),
|
||||
|
||||
rtlPara([
|
||||
rtlRun("מצד אחד: ", { bold: true }),
|
||||
rtlRun('[שם], ח.פ./ת.ז. [מספר], מ[כתובת] (להלן: "'),
|
||||
rtlRun("המזמין", { bold: true }),
|
||||
rtlRun('")'),
|
||||
], { spacing: { after: 120 } }),
|
||||
|
||||
rtlPara([
|
||||
rtlRun("מצד שני: ", { bold: true }),
|
||||
rtlRun('[שם], ח.פ./ת.ז. [מספר], מ[כתובת] (להלן: "'),
|
||||
rtlRun("הספק", { bold: true }),
|
||||
rtlRun('")'),
|
||||
], { spacing: { after: 200 } }),
|
||||
|
||||
// הואילים
|
||||
heading2("הואיל:"),
|
||||
rtlPara(rtlRun("1. והואיל ו[תנאי ראשון];"), { spacing: { after: 120 } }),
|
||||
rtlPara(rtlRun("2. והואיל ו[תנאי שני];"), { spacing: { after: 120 } }),
|
||||
rtlPara(rtlRun("3. והואיל והצדדים מעוניינים להסדיר את תנאי ההתקשרות ביניהם;"),
|
||||
{ spacing: { after: 200 } }),
|
||||
|
||||
// מעבר
|
||||
rtlPara(rtlRun("לפיכך הוסכם, הותנה והוצהר בין הצדדים כדלקמן:", { bold: true }),
|
||||
{ alignment: AlignmentType.CENTER, spacing: { before: 200, after: 200 } }),
|
||||
|
||||
// סעיפים
|
||||
heading2("1. היקף השירותים"),
|
||||
rtlPara(rtlRun("1.1 [תוכן הסעיף]"), { spacing: { after: 120 } }),
|
||||
rtlPara(rtlRun("1.2 [תוכן הסעיף]"), { spacing: { after: 120 } }),
|
||||
|
||||
heading2("2. התמורה"),
|
||||
rtlPara(rtlRun("2.1 [תוכן הסעיף]"), { spacing: { after: 120 } }),
|
||||
|
||||
// חתימות
|
||||
rtlPara(rtlRun("ולראיה באו הצדדים על החתום:", { bold: true }),
|
||||
{ alignment: AlignmentType.CENTER, spacing: { before: 600, after: 400 } }),
|
||||
|
||||
// טבלת חתימות
|
||||
new Table({
|
||||
visuallyRightToLeft: true, // ✅ קריטי!
|
||||
width: { size: 9072, type: WidthType.DXA },
|
||||
columnWidths: [4536, 4536],
|
||||
rows: [
|
||||
new TableRow({
|
||||
children: [
|
||||
new TableCell({
|
||||
borders: {
|
||||
top: { style: BorderStyle.NONE },
|
||||
bottom: { style: BorderStyle.NONE },
|
||||
left: { style: BorderStyle.NONE },
|
||||
right: { style: BorderStyle.NONE }
|
||||
},
|
||||
children: [
|
||||
rtlPara(rtlRun("________________________"), { alignment: AlignmentType.CENTER }),
|
||||
rtlPara(rtlRun("המזמין"), { alignment: AlignmentType.CENTER })
|
||||
]
|
||||
}),
|
||||
new TableCell({
|
||||
borders: {
|
||||
top: { style: BorderStyle.NONE },
|
||||
bottom: { style: BorderStyle.NONE },
|
||||
left: { style: BorderStyle.NONE },
|
||||
right: { style: BorderStyle.NONE }
|
||||
},
|
||||
children: [
|
||||
rtlPara(rtlRun("________________________"), { alignment: AlignmentType.CENTER }),
|
||||
rtlPara(rtlRun("הספק"), { alignment: AlignmentType.CENTER })
|
||||
]
|
||||
})
|
||||
]
|
||||
})
|
||||
]
|
||||
})
|
||||
];
|
||||
|
||||
// ═══════════════════════════════════════════════
|
||||
// DOCUMENT GENERATION — לא לשנות (אלא אם יודע מה עושים)
|
||||
// ═══════════════════════════════════════════════
|
||||
|
||||
const doc = new Document({
|
||||
// רמה 1: Document defaults
|
||||
styles: {
|
||||
default: {
|
||||
document: {
|
||||
run: { font: FONT, size: FONT_SIZE, rightToLeft: true },
|
||||
paragraph: { bidirectional: true, alignment: AlignmentType.BOTH }
|
||||
}
|
||||
},
|
||||
paragraphStyles: [
|
||||
{
|
||||
id: "Heading1", name: "Heading 1", basedOn: "Normal", next: "Normal",
|
||||
quickFormat: true,
|
||||
run: { size: HEADING1_SIZE, bold: true, font: FONT, rightToLeft: true },
|
||||
paragraph: { spacing: { before: 240, after: 240 }, outlineLevel: 0,
|
||||
bidirectional: true, alignment: AlignmentType.CENTER }
|
||||
},
|
||||
{
|
||||
id: "Heading2", name: "Heading 2", basedOn: "Normal", next: "Normal",
|
||||
quickFormat: true,
|
||||
run: { size: HEADING2_SIZE, bold: true, font: FONT, rightToLeft: true },
|
||||
paragraph: { spacing: { before: 200, after: 200 }, outlineLevel: 1,
|
||||
bidirectional: true, alignment: AlignmentType.START } // ✅ START
|
||||
},
|
||||
]
|
||||
},
|
||||
// מספור סעיפים
|
||||
numbering: {
|
||||
config: [{
|
||||
reference: "legal-clauses",
|
||||
levels: [
|
||||
{
|
||||
level: 0,
|
||||
format: LevelFormat.DECIMAL,
|
||||
text: "%1.",
|
||||
alignment: AlignmentType.START, // ✅ START — לא RIGHT!
|
||||
suffix: "tab",
|
||||
style: { paragraph: { indent: { left: 720, hanging: 360 } } }
|
||||
},
|
||||
{
|
||||
level: 1,
|
||||
format: LevelFormat.DECIMAL,
|
||||
text: "%1.%2",
|
||||
alignment: AlignmentType.START, // ✅ START — לא RIGHT!
|
||||
suffix: "tab",
|
||||
style: { paragraph: { indent: { left: 1440, hanging: 500 } } }
|
||||
},
|
||||
]
|
||||
}]
|
||||
},
|
||||
sections: [{
|
||||
// רמה 2: Section properties
|
||||
properties: {
|
||||
page: {
|
||||
size: { width: 11906, height: 16838 }, // A4
|
||||
margin: { top: MARGIN_DXA, right: MARGIN_DXA, bottom: MARGIN_DXA, left: MARGIN_DXA }
|
||||
},
|
||||
bidi: true, // ← חובה!
|
||||
},
|
||||
headers: HEADER_TEXT ? {
|
||||
default: new Header({
|
||||
children: [rtlPara(rtlRun(HEADER_TEXT, { bold: true, size: 20 }),
|
||||
{ alignment: AlignmentType.CENTER })]
|
||||
})
|
||||
} : undefined,
|
||||
footers: {
|
||||
default: new Footer({
|
||||
children: [new Paragraph({
|
||||
bidirectional: true,
|
||||
alignment: AlignmentType.CENTER,
|
||||
children: [
|
||||
rtlRun("עמוד ", { size: 18 }),
|
||||
new TextRun({ children: [PageNumber.CURRENT], font: FONT, size: 18 }),
|
||||
...(FOOTER_CONFIDENTIAL ? [rtlRun(` | ${FOOTER_CONFIDENTIAL}`, { size: 18 })] : []),
|
||||
]
|
||||
})]
|
||||
})
|
||||
},
|
||||
children: CONTENT
|
||||
}]
|
||||
});
|
||||
|
||||
Packer.toBuffer(doc).then(buffer => {
|
||||
fs.writeFileSync(OUTPUT_FILE, buffer);
|
||||
console.log(`✅ ${OUTPUT_FILE} created successfully`);
|
||||
console.log(` Font: ${FONT} ${FONT_SIZE/2}pt`);
|
||||
console.log(` Margins: ${MARGIN_CM}cm (${MARGIN_DXA} DXA)`);
|
||||
console.log(` Size: ${(buffer.length / 1024).toFixed(1)} KB`);
|
||||
console.log(` RTL: bidi + bidirectional + rightToLeft ✓`);
|
||||
console.log(` Alignment: START/END (not LEFT/RIGHT) ✓`);
|
||||
});
|
||||
Reference in New Issue
Block a user