diff --git a/lzipus/README.md b/lzipus/README.md
new file mode 100644
index 0000000..b32aeb7
--- /dev/null
+++ b/lzipus/README.md
@@ -0,0 +1,166 @@
+# Izipus - SMS Support Templates Manager
+
+**Version:** 0.4.0
+**Type:** Browser Extension (Firefox/Chrome)
+
+## π― ΠΠΏΠΈΡΠ°Π½ΠΈΠ΅
+
+Izipus - Π±ΡΠ°ΡΠ·Π΅ΡΠ½ΠΎΠ΅ ΡΠ°ΡΡΠΈΡΠ΅Π½ΠΈΠ΅ Π΄Π»Ρ ΡΠΏΠ΅ΡΠΈΠ°Π»ΠΈΡΡΠΎΠ² ΡΠ΅Ρ
Π½ΠΈΡΠ΅ΡΠΊΠΎΠΉ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΊΠΈ SMS/ΡΠ΅Π»Π΅ΠΊΠΎΠΌ-ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡΠΎΠ². Π£ΠΏΡΠΎΡΠ°Π΅Ρ ΡΠ°Π±ΠΎΡΡ Ρ ΡΠ°Π±Π»ΠΎΠ½Π°ΠΌΠΈ ΠΎΡΠ²Π΅ΡΠΎΠ² Π½Π° ΡΠΈΠΏΠΎΠ²ΡΠ΅ Π·Π°ΠΏΡΠΎΡΡ ΠΊΠ»ΠΈΠ΅Π½ΡΠΎΠ² ΠΈ ΠΏΠ°ΡΡΠ½ΡΡΠΎΠ².
+
+## β¨ ΠΡΠ½ΠΎΠ²Π½ΡΠ΅ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΠΈ
+
+### Π€Π°Π·Π° 1 (v0.4.0) - ΠΠΠ’ΠΠΠ β
+
+#### π Π£ΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ ΡΠ°Π±Π»ΠΎΠ½Π°ΠΌΠΈ
+- **ΠΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠ° Π³ΠΎΡΠΎΠ²ΡΡ
ΡΠ°Π±Π»ΠΎΠ½ΠΎΠ²** Π½Π° ΡΡΡΡΠΊΠΎΠΌ ΠΈ Π°Π½Π³Π»ΠΈΠΉΡΠΊΠΎΠΌ ΡΠ·ΡΠΊΠ°Ρ
+- **Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΡΡΠΊΠΈΡ
ΡΠ°Π±Π»ΠΎΠ½ΠΎΠ²** Ρ RU/EN Π²Π΅ΡΡΠΈΡΠΌΠΈ
+- **Π Π΅Π΄Π°ΠΊΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ Π²ΡΡΡΠΎΠ΅Π½Π½ΡΡ
ΡΠ°Π±Π»ΠΎΠ½ΠΎΠ²** Ρ ΡΠΎΡ
ΡΠ°Π½Π΅Π½ΠΈΠ΅ΠΌ ΠΏΠ΅ΡΠ΅ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½ΠΈΠΉ
+- **ΠΠΌΠΏΠΎΡΡ/ΡΠΊΡΠΏΠΎΡΡ ΡΠ°Π±Π»ΠΎΠ½ΠΎΠ²** Π² JSON Π΄Π»Ρ ΠΎΠ±ΠΌΠ΅Π½Π° Ρ ΠΊΠΎΠ»Π»Π΅Π³Π°ΠΌΠΈ
+- **ΠΠΎΠΈΡΠΊ ΠΏΠΎ ΡΠ°Π±Π»ΠΎΠ½Π°ΠΌ** ΠΏΠΎ Π½Π°Π·Π²Π°Π½ΠΈΡ ΠΈ ΡΠΎΠ΄Π΅ΡΠΆΠΈΠΌΠΎΠΌΡ
+
+#### πΎ Π‘ΠΈΠ½Ρ
ΡΠΎΠ½ΠΈΠ·Π°ΡΠΈΡ
+- **Chrome Storage Sync API** - Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠ°Ρ ΡΠΈΠ½Ρ
ΡΠΎΠ½ΠΈΠ·Π°ΡΠΈΡ ΠΌΠ΅ΠΆΠ΄Ρ ΡΡΡΡΠΎΠΉΡΡΠ²Π°ΠΌΠΈ
+- **ΠΠ²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠ°Ρ ΠΌΠΈΠ³ΡΠ°ΡΠΈΡ** Π΄Π°Π½Π½ΡΡ
ΠΈΠ· localStorage
+- **Fallback Π½Π° localStorage** Π΄Π»Ρ Π»ΠΎΠΊΠ°Π»ΡΠ½ΠΎΠ³ΠΎ ΡΠ΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ
+
+#### π¨ ΠΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΡΡΠΊΠΈΠΉ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡ
+- **Toast ΡΠ²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΡ** ΠΏΡΠΈ ΠΊΠΎΠΏΠΈΡΠΎΠ²Π°Π½ΠΈΠΈ Π² Π±ΡΡΠ΅Ρ ΠΎΠ±ΠΌΠ΅Π½Π°
+- **Π’ΡΠΌΠ½Π°Ρ/ΡΠ²Π΅ΡΠ»Π°Ρ ΡΠ΅ΠΌΠ°** Ρ ΡΠΎΡ
ΡΠ°Π½Π΅Π½ΠΈΠ΅ΠΌ Π²ΡΠ±ΠΎΡΠ°
+- **ΠΡΠ³Π°Π½ΠΈΠ·Π°ΡΠΈΡ ΠΏΠΎ ΠΊΠ°ΡΠ΅Π³ΠΎΡΠΈΡΠΌ** Ρ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΡΡ ΡΠ²ΠΎΡΠ°ΡΠΈΠ²Π°Π½ΠΈΡ
+- **Π‘ΡΡΡΡΠΈΠΊ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΡ** Π΄Π»Ρ ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΡΠ°Π±Π»ΠΎΠ½Π°
+- **ΠΠ΄Π°ΠΏΡΠΈΠ²Π½ΡΠΉ Π΄ΠΈΠ·Π°ΠΉΠ½**
+
+## π Π£ΡΡΠ°Π½ΠΎΠ²ΠΊΠ°
+
+### Firefox
+1. Π‘ΠΊΠ°ΡΠ°ΠΉΡΠ΅ ΡΠ°ΡΡΠΈΡΠ΅Π½ΠΈΠ΅
+2. ΠΡΠΊΡΠΎΠΉΡΠ΅ `about:debugging#/runtime/this-firefox`
+3. ΠΠ°ΠΆΠΌΠΈΡΠ΅ "ΠΠ°Π³ΡΡΠ·ΠΈΡΡ Π²ΡΠ΅ΠΌΠ΅Π½Π½ΠΎΠ΅ Π΄ΠΎΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅"
+4. ΠΡΠ±Π΅ΡΠΈΡΠ΅ ΡΠ°ΠΉΠ» `manifest.json`
+
+### Chrome/Edge
+1. Π‘ΠΊΠ°ΡΠ°ΠΉΡΠ΅ ΡΠ°ΡΡΠΈΡΠ΅Π½ΠΈΠ΅
+2. ΠΡΠΊΡΠΎΠΉΡΠ΅ `chrome://extensions/`
+3. ΠΠΊΠ»ΡΡΠΈΡΠ΅ "Π Π΅ΠΆΠΈΠΌ ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊΠ°"
+4. ΠΠ°ΠΆΠΌΠΈΡΠ΅ "ΠΠ°Π³ΡΡΠ·ΠΈΡΡ ΡΠ°ΡΠΏΠ°ΠΊΠΎΠ²Π°Π½Π½ΠΎΠ΅ ΡΠ°ΡΡΠΈΡΠ΅Π½ΠΈΠ΅"
+5. ΠΡΠ±Π΅ΡΠΈΡΠ΅ ΠΏΠ°ΠΏΠΊΡ Ρ ΡΠ°ΡΡΠΈΡΠ΅Π½ΠΈΠ΅ΠΌ
+
+## π ΠΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅
+
+### ΠΡΠ½ΠΎΠ²Π½ΡΠ΅ Π΄Π΅ΠΉΡΡΠ²ΠΈΡ
+
+1. **ΠΠΎΠΏΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ ΡΠ°Π±Π»ΠΎΠ½Π°**: ΠΠ°ΠΆΠΌΠΈΡΠ΅ ΠΊΠ½ΠΎΠΏΠΊΡ RU ΠΈΠ»ΠΈ ENG ΡΡΠ΄ΠΎΠΌ Ρ Π½ΡΠΆΠ½ΡΠΌ ΡΠ°Π±Π»ΠΎΠ½ΠΎΠΌ
+2. **Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΡΠ°Π±Π»ΠΎΠ½Π°**: ΠΠ°ΠΆΠΌΠΈΡΠ΅ ΠΊΠ½ΠΎΠΏΠΊΡ "+" Π² Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠ΅
+3. **Π Π΅Π΄Π°ΠΊΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅**: ΠΠ°ΠΆΠΌΠΈΡΠ΅ ΠΈΠΊΠΎΠ½ΠΊΡ ΠΊΠ°ΡΠ°Π½Π΄Π°ΡΠ° ΡΡΠ΄ΠΎΠΌ Ρ ΡΠ°Π±Π»ΠΎΠ½ΠΎΠΌ
+4. **Π£Π΄Π°Π»Π΅Π½ΠΈΠ΅**: ΠΠ°ΠΆΠΌΠΈΡΠ΅ ΠΈΠΊΠΎΠ½ΠΊΡ ΠΊΠΎΡΠ·ΠΈΠ½Ρ
+5. **ΠΠΎΠΈΡΠΊ**: ΠΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ ΡΡΡΠΎΠΊΡ ΠΏΠΎΠΈΡΠΊΠ° Π² Π²Π΅ΡΡ
Π½Π΅ΠΉ ΡΠ°ΡΡΠΈ ΠΎΠΊΠ½Π°
+
+### ΠΠΌΠΏΠΎΡΡ/ΠΠΊΡΠΏΠΎΡΡ
+
+**ΠΠΊΡΠΏΠΎΡΡ:**
+- ΠΠ°ΠΆΠΌΠΈΡΠ΅ ΠΊΠ½ΠΎΠΏΠΊΡ ΡΠΊΡΠΏΠΎΡΡΠ° (π€)
+- Π€Π°ΠΉΠ» ΡΠΎΡ
ΡΠ°Π½ΠΈΡΡΡ ΠΊΠ°ΠΊ `izipus-templates-YYYY-MM-DD.json`
+
+**ΠΠΌΠΏΠΎΡΡ:**
+- ΠΠ°ΠΆΠΌΠΈΡΠ΅ ΠΊΠ½ΠΎΠΏΠΊΡ ΠΈΠΌΠΏΠΎΡΡΠ° (π₯)
+- ΠΡΠ±Π΅ΡΠΈΡΠ΅ JSON ΡΠ°ΠΉΠ» Ρ ΡΠ°Π±Π»ΠΎΠ½Π°ΠΌΠΈ
+- ΠΡΠ±Π»ΠΈΠΊΠ°ΡΡ (ΠΏΠΎ Π½Π°Π·Π²Π°Π½ΠΈΡ) Π±ΡΠ΄ΡΡ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ ΠΏΡΠΎΠΏΡΡΠ΅Π½Ρ
+
+### Π Π΅Π΄Π°ΠΊΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ Π²ΡΡΡΠΎΠ΅Π½Π½ΡΡ
ΡΠ°Π±Π»ΠΎΠ½ΠΎΠ²
+
+1. ΠΠ°ΠΆΠΌΠΈΡΠ΅ ΠΊΠ½ΠΎΠΏΠΊΡ ΡΠ΅Π΄Π°ΠΊΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ (ποΈ) Π½Π° Π²ΡΡΡΠΎΠ΅Π½Π½ΠΎΠΌ ΡΠ°Π±Π»ΠΎΠ½Π΅
+2. ΠΡΠ±Π΅ΡΠΈΡΠ΅ ΡΠ·ΡΠΊ (OK - RU, ΠΡΠΌΠ΅Π½Π° - EN)
+3. ΠΠ²Π΅Π΄ΠΈΡΠ΅ Π½ΠΎΠ²ΡΠΉ ΡΠ΅ΠΊΡΡ
+4. ΠΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΡ ΡΠΎΡ
ΡΠ°Π½ΡΡΡΡΡ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ
+
+## π Π‘ΡΡΡΠΊΡΡΡΠ° ΠΏΡΠΎΠ΅ΠΊΡΠ°
+
+```
+lzipus/
+βββ manifest.json # ΠΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΡ ΡΠ°ΡΡΠΈΡΠ΅Π½ΠΈΡ
+βββ icons/ # ΠΠΊΠΎΠ½ΠΊΠΈ ΡΠ°ΡΡΠΈΡΠ΅Π½ΠΈΡ
+β βββ icon16.png
+β βββ icon48.png
+β βββ icon128.png
+βββ src/
+ βββ popup.html # ΠΠ½ΡΠ΅ΡΡΠ΅ΠΉΡ ΡΠ°ΡΡΠΈΡΠ΅Π½ΠΈΡ
+ βββ popup.css # Π‘ΡΠΈΠ»ΠΈ
+ βββ popup.js # ΠΠΎΠ³ΠΈΠΊΠ° ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ
+```
+
+## π§ Π’Π΅Ρ
Π½ΠΎΠ»ΠΎΠ³ΠΈΠΈ
+
+- **Manifest V3** - ΡΠΎΠ²ΡΠ΅ΠΌΠ΅Π½Π½Π°Ρ Π²Π΅ΡΡΠΈΡ API ΡΠ°ΡΡΠΈΡΠ΅Π½ΠΈΠΉ
+- **Chrome Storage Sync API** - ΡΠΈΠ½Ρ
ΡΠΎΠ½ΠΈΠ·Π°ΡΠΈΡ Π΄Π°Π½Π½ΡΡ
+- **Bootstrap 5.3.1** - UI ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΡ
+- **Font Awesome 6.1.2** - ΠΈΠΊΠΎΠ½ΠΊΠΈ
+- **Vanilla JavaScript** - Π±Π΅Π· ΡΡΠ΅ΠΉΠΌΠ²ΠΎΡΠΊΠΎΠ²
+
+## π Π₯ΡΠ°Π½Π΅Π½ΠΈΠ΅ Π΄Π°Π½Π½ΡΡ
+
+ΠΡΠ΅ Π΄Π°Π½Π½ΡΠ΅ Ρ
ΡΠ°Π½ΡΡΡΡ Π² `chrome.storage.sync`:
+
+- `templates` - ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΡΡΠΊΠΈΠ΅ ΡΠ°Π±Π»ΠΎΠ½Ρ
+- `builtinOverrides` - ΠΏΠ΅ΡΠ΅ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½ΠΈΡ Π²ΡΡΡΠΎΠ΅Π½Π½ΡΡ
ΡΠ°Π±Π»ΠΎΠ½ΠΎΠ²
+- `usageStats` - ΡΡΠ°ΡΠΈΡΡΠΈΠΊΠ° ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΡ
+- `theme` - Π²ΡΠ±ΡΠ°Π½Π½Π°Ρ ΡΠ΅ΠΌΠ°
+- `categoryStates` - ΡΠΎΡΡΠΎΡΠ½ΠΈΡ ΠΊΠ°ΡΠ΅Π³ΠΎΡΠΈΠΉ (ΠΎΡΠΊΡΡΡΠΎ/Π·Π°ΠΊΡΡΡΠΎ)
+
+## πΊοΈ ΠΠΎΡΠΎΠΆΠ½Π°Ρ ΠΊΠ°ΡΡΠ°
+
+### Π€Π°Π·Π° 2: ΠΠΎΠ²Π°Ρ ΡΡΠ½ΠΊΡΠΈΠΎΠ½Π°Π»ΡΠ½ΠΎΡΡΡ
+- [ ] Π‘ΠΈΡΡΠ΅ΠΌΠ° ΠΏΠ΅ΡΠ΅ΠΌΠ΅Π½Π½ΡΡ
Π² ΡΠ°Π±Π»ΠΎΠ½Π°Ρ
(`{{client_name}}`, `{{date}}`)
+- [ ] ΠΠΎΠ½ΡΠ΅ΠΊΡΡΠ½ΠΎΠ΅ ΠΌΠ΅Π½Ρ Π΄Π»Ρ Π±ΡΡΡΡΠΎΠ³ΠΎ Π΄ΠΎΡΡΡΠΏΠ°
+- [ ] ΠΡΡΠΎΡΠΈΡ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΡ ΠΈ ΡΡΠ°ΡΠΈΡΡΠΈΠΊΠ°
+- [ ] ΠΡΠ»ΡΡΠΈΡΠ·ΡΡΠ½ΠΎΡΡΡ (ES, DE, FR)
+
+### Π€Π°Π·Π° 3: ΠΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΡ
+- [ ] ΠΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΡ Ρ CRM/ΡΠΈΠΊΠ΅Ρ-ΡΠΈΡΡΠ΅ΠΌΠ°ΠΌΠΈ (Zendesk, Jira)
+- [ ] AI-Π°ΡΡΠΈΡΡΠ΅Π½Ρ Π΄Π»Ρ ΠΏΡΠ΅Π΄Π»ΠΎΠΆΠ΅Π½ΠΈΡ ΡΠ°Π±Π»ΠΎΠ½ΠΎΠ²
+- [ ] ΠΠΎΠΌΠ°Π½Π΄Π½ΡΠ΅ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΠΈ (ΠΎΠ±Π»Π°ΡΠ½ΠΎΠ΅ Ρ
ΡΠ°Π½ΠΈΠ»ΠΈΡΠ΅)
+
+### Π€Π°Π·Π° 4: ΠΠ°ΡΠ΅ΡΡΠ²ΠΎ
+- [ ] Π Π΅ΡΠ°ΠΊΡΠΎΡΠΈΠ½Π³ (ΠΌΠΎΠ΄ΡΠ»ΠΈ, TypeScript)
+- [ ] Unit ΠΈ E2E ΡΠ΅ΡΡΡ
+- [ ] CI/CD pipeline
+- [ ] ΠΠΎΠ»Π½Π°Ρ Π΄ΠΎΠΊΡΠΌΠ΅Π½ΡΠ°ΡΠΈΡ
+
+## π€ ΠΠΊΠ»Π°Π΄ Π² ΠΏΡΠΎΠ΅ΠΊΡ
+
+ΠΡΠΎΠ΅ΠΊΡ ΠΎΡΠΊΡΡΡ Π΄Π»Ρ ΡΠ»ΡΡΡΠ΅Π½ΠΈΠΉ! ΠΡΠ»ΠΈ Ρ Π²Π°Ρ Π΅ΡΡΡ ΠΈΠ΄Π΅ΠΈ ΠΈΠ»ΠΈ Π²Ρ Π½Π°ΡΠ»ΠΈ Π±Π°Π³:
+
+1. Π‘ΠΎΠ·Π΄Π°ΠΉΡΠ΅ issue Π½Π° GitLab
+2. ΠΡΠ΅Π΄Π»ΠΎΠΆΠΈΡΠ΅ pull request
+3. ΠΠΏΠΈΡΠΈΡΠ΅ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΡ ΠΈ ΠΈΡ
Π½Π΅ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΠΌΠΎΡΡΡ
+
+## π Changelog
+
+### v0.4.0 (2025-10-26) - Π€Π°Π·Π° 1
+- β
Toast ΡΠ²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΡ ΠΏΡΠΈ ΠΊΠΎΠΏΠΈΡΠΎΠ²Π°Π½ΠΈΠΈ
+- β
ΠΠΎΠΈΡΠΊ ΠΏΠΎ ΡΠ°Π±Π»ΠΎΠ½Π°ΠΌ
+- β
ΠΠΌΠΏΠΎΡΡ/ΡΠΊΡΠΏΠΎΡΡ Π² JSON
+- β
Π‘ΡΡΡΡΠΈΠΊ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΡ ΡΠ°Π±Π»ΠΎΠ½ΠΎΠ²
+- β
ΠΠΈΠ³ΡΠ°ΡΠΈΡ Π½Π° chrome.storage.sync
+- β
Π Π΅Π΄Π°ΠΊΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ Π²ΡΡΡΠΎΠ΅Π½Π½ΡΡ
ΡΠ°Π±Π»ΠΎΠ½ΠΎΠ²
+- π ΠΡΠΏΡΠ°Π²Π»Π΅Π½Π° ΠΎΠΏΠ΅ΡΠ°ΡΠΊΠ° Π² HTML
+
+### v0.3.1
+- ΠΠ°Π·ΠΎΠ²Π°Ρ ΡΡΠ½ΠΊΡΠΈΠΎΠ½Π°Π»ΡΠ½ΠΎΡΡΡ
+- ΠΡΡΡΠΎΠ΅Π½Π½ΡΠ΅ ΡΠ°Π±Π»ΠΎΠ½Ρ
+- ΠΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΡΡΠΊΠΈΠ΅ ΡΠ°Π±Π»ΠΎΠ½Ρ
+- Π’ΡΠΌΠ½Π°Ρ ΡΠ΅ΠΌΠ°
+
+## π ΠΠΈΡΠ΅Π½Π·ΠΈΡ
+
+ΠΡΠΎΠ΅ΠΊΡ ΡΠ°ΡΠΏΡΠΎΡΡΡΠ°Π½ΡΠ΅ΡΡΡ "ΠΊΠ°ΠΊ Π΅ΡΡΡ" Π΄Π»Ρ Π²Π½ΡΡΡΠ΅Π½Π½Π΅Π³ΠΎ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΡ.
+
+## π€ ΠΠ²ΡΠΎΡ
+
+**Dmitriy Gorshenin**
+Email: dmitriy.gorshenin1@gmail.com
+GitLab: https://git.gorshenin.info/Dgors03/Answer_Templates
+
+---
+
+Made with β€οΈ for SMS Support Teams
+
diff --git a/lzipus/manifest.json b/lzipus/manifest.json
index 6c993f4..bb12e50 100644
--- a/lzipus/manifest.json
+++ b/lzipus/manifest.json
@@ -1,6 +1,6 @@
{
"name": "Izipus",
- "version": "0.3.1",
+ "version": "0.4.0",
"manifest_version": 3,
"description": "Lzipus - assists your workflow by simplifying interactions.",
"homepage_url": "https://git.gorshenin.info/Dgors03/Answer_Templates",
diff --git a/lzipus/src/popup.css b/lzipus/src/popup.css
index 2cdb32b..aabb60a 100644
--- a/lzipus/src/popup.css
+++ b/lzipus/src/popup.css
@@ -8,6 +8,28 @@ body {
box-sizing: border-box;
}
+/* ΠΠ»Π°Π²Π½ΠΎΠ΅ ΠΏΠΎΡΠ²Π»Π΅Π½ΠΈΠ΅ ΡΠ»Π΅ΠΌΠ΅Π½ΡΠΎΠ² */
+@keyframes fadeIn {
+ from {
+ opacity: 0;
+ }
+ to {
+ opacity: 1;
+ }
+}
+
+/* ΠΠ°Π³ΠΎΠ»ΠΎΠ²ΠΊΠΈ */
+h1, h3 {
+ padding: 6px;
+}
+
+h3 {
+ font-size: 16px; /* Π£ΠΌΠ΅Π½ΡΡΠ΅Π½ ΡΠ°Π·ΠΌΠ΅Ρ ΡΡΠΈΡΡΠ° */
+ font-weight: normal; /* Π£ΠΌΠ΅Π½ΡΡΠ΅Π½ Π²Π΅Ρ ΡΡΠΈΡΡΠ° Π΄Π»Ρ ΠΌΠΈΠ½ΠΈΠΌΠ°Π»ΠΈΡΡΠΈΡΠ½ΠΎΠ³ΠΎ Π²ΠΈΠ΄Π° */
+ color: #333; /* Π¦Π²Π΅Ρ ΡΡΠΈΡΡΠ° Π΄Π»Ρ ΠΊΠ°ΡΠ΅Π³ΠΎΡΠΈΠΉ */
+}
+
+/* ΠΠΎΠ½ΡΠ΅ΠΉΠ½Π΅ΡΡ */
div.container {
display: flex;
flex-direction: column;
@@ -18,26 +40,17 @@ div.container {
div.header {
display: flex;
flex-direction: row;
- justify-content: center;
+ justify-content: space-between;
+ align-items: center;
padding: 6px;
}
-h1 {
- padding: 6px;
-}
-
-h3 {
- padding: 6px;
- font-family: Helvetica, Arial, sans-serif; /* ΠΠΎΠ»Π΅Π΅ ΠΌΠΈΠ½ΠΈΠΌΠ°Π»ΠΈΡΡΠΈΡΠ½ΡΠΉ ΡΡΠΈΡΡ Π΄Π»Ρ ΠΊΠ°ΡΠ΅Π³ΠΎΡΠΈΠΉ */
- font-size: 16px; /* Π£ΠΌΠ΅Π½ΡΡΠ΅Π½ ΡΠ°Π·ΠΌΠ΅Ρ ΡΡΠΈΡΡΠ° */
- font-weight: normal; /* Π£ΠΌΠ΅Π½ΡΡΠ΅Π½ Π²Π΅Ρ ΡΡΠΈΡΡΠ° Π΄Π»Ρ ΠΌΠΈΠ½ΠΈΠΌΠ°Π»ΠΈΡΡΠΈΡΠ½ΠΎΠ³ΠΎ Π²ΠΈΠ΄Π° */
- color: #333; /* Π¦Π²Π΅Ρ ΡΡΠΈΡΡΠ° Π΄Π»Ρ ΠΊΠ°ΡΠ΅Π³ΠΎΡΠΈΠΉ */
-}
-
-i {
- width: 20px;
+.header-buttons {
+ display: flex;
+ gap: 5px;
}
+/* ΠΠ½ΠΎΠΏΠΊΠΈ */
button.template-add,
button.template-edit,
button.template-delete {
@@ -49,19 +62,19 @@ button.template-delete {
cursor: pointer;
font-size: 14px; /* ΠΠ΅Π½ΡΡΠΈΠΉ ΡΠ°Π·ΠΌΠ΅Ρ ΡΠ΅ΠΊΡΡΠ° */
border-radius: 5px; /* Π‘ΠΊΡΡΠ³Π»Π΅Π½Π½ΡΠ΅ ΡΠ³Π»Ρ */
- transition: background-color 0.3s, color 0.3s, border-color 0.3s; /* ΠΠ»Π°Π²Π½ΡΠ΅ ΠΏΠ΅ΡΠ΅Ρ
ΠΎΠ΄Ρ */
+ transition: background-color 0.3s, color 0.3s, border-color 0.3s, transform 0.3s; /* ΠΠ»Π°Π²Π½ΡΠ΅ ΠΏΠ΅ΡΠ΅Ρ
ΠΎΠ΄Ρ */
}
-/* ΠΡΡΠ΅ΠΊΡ ΠΏΡΠΈ Π½Π°Π²Π΅Π΄Π΅Π½ΠΈΠΈ */
+/* ΠΡΡΠ΅ΠΊΡΡ Π΄Π»Ρ ΠΊΠ½ΠΎΠΏΠΎΠΊ */
button.template-add:hover,
button.template-edit:hover,
button.template-delete:hover {
background-color: #abcef5; /* ΠΠΎΠ΄ΡΠ²Π΅ΡΠΊΠ° ΡΠΎΠ½ΠΎΠΌ */
color: #fff; /* ΠΠ΅Π»ΡΠΉ ΡΠ²Π΅Ρ ΡΠ΅ΠΊΡΡΠ° */
border-color: #88aee5; /* ΠΠ΅ΠΌΠ½ΠΎΠ³ΠΎ ΡΠ΅ΠΌΠ½Π΅Π΅ ΡΠ°ΠΌΠΊΠ° */
+ transform: scale(1.05); /* Π£Π²Π΅Π»ΠΈΡΠ΅Π½ΠΈΠ΅ ΠΊΠ½ΠΎΠΏΠΊΠΈ ΠΏΡΠΈ Π½Π°Π²Π΅Π΄Π΅Π½ΠΈΠΈ */
}
-/* ΠΡΡΠ΅ΠΊΡ ΠΏΡΠΈ ΡΠΎΠΊΡΡΠ΅ */
button.template-add:focus,
button.template-edit:focus,
button.template-delete:focus {
@@ -69,6 +82,7 @@ button.template-delete:focus {
box-shadow: 0 0 3px rgba(0, 0, 0, 0.2); /* ΠΠ΅Π³ΠΊΠ°Ρ ΡΠ΅Π½Ρ Π΄Π»Ρ ΡΠΎΠΊΡΡΠ° */
}
+/* Π¨Π°Π±Π»ΠΎΠ½Ρ */
div.templates {
display: flex;
flex-direction: column;
@@ -83,12 +97,16 @@ span.template {
justify-content: space-between;
height: fit-content;
padding: 8px 7px;
+ justify-content: space-between;
+ height: fit-content;
+ padding: 8px 7px;
border: 1px solid #8888c6; /* Π¦Π²Π΅Ρ ΡΠ°ΠΌΠΊΠΈ ΡΠΎΠ²ΠΏΠ°Π΄Π°Π΅Ρ Ρ ΡΠ°ΠΌΠΊΠΎΠΉ ΠΊΠ°ΡΠ΅Π³ΠΎΡΠΈΠΈ */
border-radius: 8px; /* Π‘ΠΊΡΡΠ³Π»Π΅Π½Π½ΡΠ΅ ΡΠ³Π»Ρ */
overflow: hidden;
width: 100%; /* Π¨Π°Π±Π»ΠΎΠ½Ρ Π΄ΠΎΠ»ΠΆΠ½Ρ ΡΠ°ΡΡΡΠ³ΠΈΠ²Π°ΡΡΡΡ Π½Π° Π²ΡΡ ΡΠΈΡΠΈΠ½Ρ */
box-sizing: border-box; /* Π§ΡΠΎΠ±Ρ ΠΏΠ°Π΄Π΄ΠΈΠ½Π³ΠΈ Π½Π΅ Π²Π»ΠΈΡΠ»ΠΈ Π½Π° ΡΠ°Π·ΠΌΠ΅Ρ */
transition: background-color 0.3s ease, color 0.3s ease, border-color 0.3s ease; /* ΠΠ»Π°Π²Π½ΡΠΉ ΠΏΠ΅ΡΠ΅Ρ
ΠΎΠ΄ ΠΏΡΠΈ Π½Π°Π²Π΅Π΄Π΅Π½ΠΈΠΈ */
+ animation: fadeIn 0.5s ease-in; /* ΠΡΠΈΠΌΠ΅Π½ΡΠ΅ΠΌ Π°Π½ΠΈΠΌΠ°ΡΠΈΡ ΠΊ ΡΠ»Π΅ΠΌΠ΅Π½ΡΠ°ΠΌ ΡΠ°Π±Π»ΠΎΠ½Π° */
}
/* ΠΠΎΠ΄ΡΠ²Π΅ΡΠΊΠ° ΡΠ°Π±Π»ΠΎΠ½ΠΎΠ² ΠΏΡΠΈ Π½Π°Π²Π΅Π΄Π΅Π½ΠΈΠΈ */
@@ -265,3 +283,112 @@ textarea {
resize: none;
}
+/* Toast ΡΠ²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΡ */
+.toast-container {
+ position: fixed;
+ top: 20px;
+ right: 20px;
+ z-index: 9999;
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+}
+
+.toast {
+ background: #4CAF50;
+ color: white;
+ padding: 12px 20px;
+ border-radius: 8px;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ min-width: 250px;
+ animation: slideIn 0.3s ease-out, fadeOut 0.3s ease-in 2.7s;
+ opacity: 0;
+ animation-fill-mode: forwards;
+}
+
+.toast.show {
+ opacity: 1;
+}
+
+.toast i {
+ font-size: 18px;
+}
+
+.toast-message {
+ flex: 1;
+ font-size: 14px;
+}
+
+@keyframes slideIn {
+ from {
+ transform: translateX(400px);
+ opacity: 0;
+ }
+ to {
+ transform: translateX(0);
+ opacity: 1;
+ }
+}
+
+@keyframes fadeOut {
+ from {
+ opacity: 1;
+ }
+ to {
+ opacity: 0;
+ }
+}
+
+.dark-theme .toast {
+ background: #388E3C;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
+}
+
+/* ΠΠΎΠΈΡΠΊ */
+.search-wrapper {
+ position: relative;
+ margin: 10px 0;
+ width: 100%;
+}
+
+.search-wrapper input {
+ width: 100%;
+ padding: 10px 40px 10px 15px;
+ border: 1px solid #8888c6;
+ border-radius: 8px;
+ font-size: 14px;
+ transition: border-color 0.3s;
+}
+
+.search-wrapper input:focus {
+ outline: none;
+ border-color: #a56fbf;
+ box-shadow: 0 0 5px rgba(165, 111, 191, 0.3);
+}
+
+.search-icon {
+ position: absolute;
+ right: 15px;
+ top: 50%;
+ transform: translateY(-50%);
+ color: #8888c6;
+ pointer-events: none;
+}
+
+.dark-theme .search-wrapper input {
+ background: #444;
+ color: #fff;
+ border-color: #555;
+}
+
+.dark-theme .search-icon {
+ color: #aaa;
+}
+
+/* Π‘ΠΊΡΡΡΠΈΠ΅ ΡΠ»Π΅ΠΌΠ΅Π½ΡΠΎΠ² ΠΏΡΠΈ ΠΏΠΎΠΈΡΠΊΠ΅ */
+.hidden-by-search {
+ display: none !important;
+}
diff --git a/lzipus/src/popup.html b/lzipus/src/popup.html
index b593ba2..a2a958e 100644
--- a/lzipus/src/popup.html
+++ b/lzipus/src/popup.html
@@ -11,16 +11,34 @@
+
-
+
+
+
+
+
+
+
+
ΠΡΠΎΠΌΠ΅ΠΆΡΡΠΎΡΠ½ΡΠ΅ ΠΎΡΠ²Π΅ΡΡ
@@ -28,12 +46,12 @@
-
+
ΠΡΠΈΠ½ΡΠ»ΠΈ Π² ΡΠ°Π±ΠΎΡΡ
RU
ENG
-
+
@@ -277,7 +295,7 @@
- 1--div>
+
diff --git a/lzipus/src/popup.js b/lzipus/src/popup.js
index 9921715..3f577b5 100644
--- a/lzipus/src/popup.js
+++ b/lzipus/src/popup.js
@@ -1,6 +1,124 @@
-document.addEventListener("DOMContentLoaded", function () {
+document.addEventListener("DOMContentLoaded", async () => {
+ // Storage Helper - ΠΎΠ±ΡΡΡΠΊΠ° Π΄Π»Ρ chrome.storage.sync Ρ fallback Π½Π° localStorage
+ const StorageHelper = {
+ async get(key) {
+ if (typeof chrome !== 'undefined' && chrome.storage && chrome.storage.sync) {
+ return new Promise((resolve) => {
+ chrome.storage.sync.get([key], (result) => {
+ resolve(result[key]);
+ });
+ });
+ } else {
+ // Fallback Π΄Π»Ρ Π»ΠΎΠΊΠ°Π»ΡΠ½ΠΎΠ³ΠΎ ΡΠ΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ
+ const value = localStorage.getItem(key);
+ return value ? JSON.parse(value) : null;
+ }
+ },
+
+ async set(key, value) {
+ if (typeof chrome !== 'undefined' && chrome.storage && chrome.storage.sync) {
+ return new Promise((resolve) => {
+ chrome.storage.sync.set({ [key]: value }, resolve);
+ });
+ } else {
+ // Fallback Π΄Π»Ρ Π»ΠΎΠΊΠ°Π»ΡΠ½ΠΎΠ³ΠΎ ΡΠ΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ
+ localStorage.setItem(key, JSON.stringify(value));
+ return Promise.resolve();
+ }
+ },
+
+ async remove(key) {
+ if (typeof chrome !== 'undefined' && chrome.storage && chrome.storage.sync) {
+ return new Promise((resolve) => {
+ chrome.storage.sync.remove(key, resolve);
+ });
+ } else {
+ localStorage.removeItem(key);
+ return Promise.resolve();
+ }
+ }
+ };
+
+ // ΠΠΈΠ³ΡΠ°ΡΠΈΡ Π΄Π°Π½Π½ΡΡ
ΠΈΠ· localStorage Π² chrome.storage.sync
+ async function migrateFromLocalStorage() {
+ const migrationKey = 'migrated_to_chrome_storage';
+ const alreadyMigrated = await StorageHelper.get(migrationKey);
+
+ if (!alreadyMigrated && typeof chrome !== 'undefined' && chrome.storage && chrome.storage.sync) {
+ console.log('ΠΠ°ΡΠΈΠ½Π°Π΅ΠΌ ΠΌΠΈΠ³ΡΠ°ΡΠΈΡ Π΄Π°Π½Π½ΡΡ
ΠΈΠ· localStorage Π² chrome.storage.sync...');
+
+ const keysToMigrate = ['templates', 'theme', 'usageStats'];
+
+ for (const key of keysToMigrate) {
+ const localValue = localStorage.getItem(key);
+ if (localValue) {
+ try {
+ const parsedValue = JSON.parse(localValue);
+ await StorageHelper.set(key, parsedValue);
+ console.log(`ΠΠΈΠ³ΡΠΈΡΠΎΠ²Π°Π½ ΠΊΠ»ΡΡ: ${key}`);
+ } catch (e) {
+ console.error(`ΠΡΠΈΠ±ΠΊΠ° ΠΏΡΠΈ ΠΌΠΈΠ³ΡΠ°ΡΠΈΠΈ ΠΊΠ»ΡΡΠ° ${key}:`, e);
+ }
+ }
+ }
+
+ // ΠΠΈΠ³ΡΠ°ΡΠΈΡ ΡΠΎΡΡΠΎΡΠ½ΠΈΠΉ ΠΊΠ°ΡΠ΅Π³ΠΎΡΠΈΠΉ
+ const categoryStates = {};
+ for (let i = 0; i < localStorage.length; i++) {
+ const key = localStorage.key(i);
+ if (key && !keysToMigrate.includes(key)) {
+ const value = localStorage.getItem(key);
+ if (value === 'true' || value === 'false') {
+ categoryStates[key] = value;
+ }
+ }
+ }
+
+ if (Object.keys(categoryStates).length > 0) {
+ await StorageHelper.set('categoryStates', categoryStates);
+ console.log('ΠΠΈΠ³ΡΠΈΡΠΎΠ²Π°Π½Ρ ΡΠΎΡΡΠΎΡΠ½ΠΈΡ ΠΊΠ°ΡΠ΅Π³ΠΎΡΠΈΠΉ');
+ }
+
+ await StorageHelper.set(migrationKey, true);
+ console.log('ΠΠΈΠ³ΡΠ°ΡΠΈΡ Π·Π°Π²Π΅ΡΡΠ΅Π½Π°!');
+ }
+ }
+
+ await migrateFromLocalStorage();
+
+ // Π‘ΡΠ°ΡΠΈΡΡΠΈΠΊΠ° ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΡ ΡΠ°Π±Π»ΠΎΠ½ΠΎΠ²
+ let usageStats = await StorageHelper.get('usageStats') || {};
+
+ async function updateUsageStats(templateId) {
+ usageStats[templateId] = (usageStats[templateId] || 0) + 1;
+ await StorageHelper.set('usageStats', usageStats);
+ }
+
+ function getUsageCount(templateId) {
+ return usageStats[templateId] || 0;
+ }
+
+ // Toast ΡΠ²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΡ
+ function showToast(message, duration = 3000) {
+ const toastContainer = document.getElementById('toast-container');
+ const toast = document.createElement('div');
+ toast.className = 'toast show';
+ toast.innerHTML = `
+
+
${message}
+ `;
+ toastContainer.appendChild(toast);
+
+ setTimeout(() => {
+ toast.remove();
+ }, duration);
+ }
+
+ // ΠΠ°Π³ΡΡΠΆΠ°Π΅ΠΌ ΠΏΠ΅ΡΠ΅ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½ΠΈΡ Π²ΡΡΡΠΎΠ΅Π½Π½ΡΡ
ΡΠ°Π±Π»ΠΎΠ½ΠΎΠ²
+ let builtinOverrides = await StorageHelper.get('builtinOverrides') || {};
+
// ΠΠ±ΡΠ΅ΠΊΡ Ρ ΡΠ΅ΠΊΡΡΠ°ΠΌΠΈ Π΄Π»Ρ ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΡΠ»Π΅ΠΌΠ΅Π½ΡΠ°
- const clipboardTexts = {
+ let clipboardTexts = {
"inWorkRu": "ΠΠΎΠ»Π»Π΅Π³ΠΈ, Π·Π΄ΡΠ°Π²ΡΡΠ²ΡΠΉΡΠ΅.\nΠΡΠΈΠ½ΡΠ»ΠΈ ΠΠ°Ρ Π·Π°ΠΏΡΠΎΡ Π² ΡΠ°Π±ΠΎΡΡ. Π‘ΠΎΠΎΠ±ΡΠΈΠΌ ΠΏΠΎ ΠΌΠ΅ΡΠ΅ ΠΏΠΎΡΡΡΠΏΠ»Π΅Π½ΠΈΡ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΠΈ.",
"inWorkEn": "Dear customer,\nWe are working on your request.",
"dialogueRu": "ΠΠΎΠ»Π»Π΅Π³ΠΈ, Π·Π΄ΡΠ°Π²ΡΡΠ²ΡΠΉΡΠ΅.\nΠ£Π²Π΅Π΄ΠΎΠΌΠ»ΡΠ΅ΠΌ Π²Π°Ρ ΠΎ ΡΠΎΠΌ, ΡΡΠΎ ΠΌΡ Π½Π°ΡΠ°Π»ΠΈ Π΄ΠΈΠ°Π»ΠΎΠ³ Ρ ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡΠΎΠΌ ΠΏΠΎ Π΄Π°Π½Π½ΠΎΠΌΡ Π·Π°ΠΏΡΠΎΡΡ. ΠΡ ΠΎΠΆΠΈΠ΄Π°Π΅ΠΌ ΠΎΡΠ²Π΅ΡΠ° ΠΈ Π±ΡΠ΄Π΅ΠΌ Π΄Π΅ΡΠΆΠ°ΡΡ Π²Π°Ρ Π² ΠΊΡΡΡΠ΅ Π»ΡΠ±ΡΡ
ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ.",
@@ -59,11 +177,59 @@ document.addEventListener("DOMContentLoaded", function () {
"HLREn": "Dear colleagues,\nPlease clarify the correctness of HLR statuses for the following subscriber numbers:",
"managerTemplate": "Π‘ΡΡΠ°Π½Π°: \nΠΠΏΠ΅ΡΠ°ΡΠΎΡ: \nmccMnc: \nΠ‘Π΅Π½Π΄Π΅Ρ: \nΠΠ»ΠΈΠ΅Π½Ρ: \nSource node: \nDestination node: "
};
+
+ // ΠΡΠΈΠΌΠ΅Π½ΡΠ΅ΠΌ ΠΏΠ΅ΡΠ΅ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½ΠΈΡ
+ Object.keys(builtinOverrides).forEach(key => {
+ if (clipboardTexts.hasOwnProperty(key)) {
+ clipboardTexts[key] = builtinOverrides[key];
+ }
+ });
+
+ // Π€ΡΠ½ΠΊΡΠΈΡ Π΄Π»Ρ ΡΠ΅Π΄Π°ΠΊΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ Π²ΡΡΡΠΎΠ΅Π½Π½ΡΡ
ΡΠ°Π±Π»ΠΎΠ½ΠΎΠ²
+ async function editBuiltinTemplate(templateId) {
+ const newText = prompt('ΠΠ²Π΅Π΄ΠΈΡΠ΅ Π½ΠΎΠ²ΡΠΉ ΡΠ΅ΠΊΡΡ ΡΠ°Π±Π»ΠΎΠ½Π°:', clipboardTexts[templateId]);
+ if (newText !== null && newText !== clipboardTexts[templateId]) {
+ clipboardTexts[templateId] = newText;
+ builtinOverrides[templateId] = newText;
+ await StorageHelper.set('builtinOverrides', builtinOverrides);
+ showToast('ΠΡΡΡΠΎΠ΅Π½Π½ΡΠΉ ΡΠ°Π±Π»ΠΎΠ½ ΠΎΠ±Π½ΠΎΠ²Π»ΡΠ½!');
+ }
+ }
+
+ // ΠΠ±ΡΠ°Π±ΠΎΡΡΠΈΠΊΠΈ Π΄Π»Ρ ΠΊΠ½ΠΎΠΏΠΎΠΊ ΡΠ΅Π΄Π°ΠΊΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ Π²ΡΡΡΠΎΠ΅Π½Π½ΡΡ
ΡΠ°Π±Π»ΠΎΠ½ΠΎΠ²
+ document.querySelectorAll('.template-edit-builtin').forEach(btn => {
+ const template = btn.closest('.template');
+ btn.addEventListener('click', () => {
+ // ΠΠ°Ρ
ΠΎΠ΄ΠΈΠΌ RU ΠΈ EN ΠΊΠ½ΠΎΠΏΠΊΠΈ
+ const ruBtn = template.querySelector('[id$="Ru"]');
+ const enBtn = template.querySelector('[id$="En"]');
+
+ if (ruBtn || enBtn) {
+ const templateName = template.querySelector('.template-title').textContent.trim();
+ const action = confirm(`Π Π΅Π΄Π°ΠΊΡΠΈΡΠΎΠ²Π°ΡΡ ΡΠ°Π±Π»ΠΎΠ½ "${templateName}"?\nΠΠ - Π Π΅Π΄Π°ΠΊΡΠΈΡΠΎΠ²Π°ΡΡ RU\nΠΡΠΌΠ΅Π½Π° - Π Π΅Π΄Π°ΠΊΡΠΈΡΠΎΠ²Π°ΡΡ EN`);
+
+ if (action && ruBtn) {
+ editBuiltinTemplate(ruBtn.id);
+ } else if (!action && enBtn) {
+ editBuiltinTemplate(enBtn.id);
+ }
+ }
+ });
+ });
// Π€ΡΠ½ΠΊΡΠΈΡ Π΄Π»Ρ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ ΠΊΠ»ΠΈΠΊΠΎΠ²
function handleClipboardClick(buttonId) {
if (clipboardTexts[buttonId]) {
- navigator.clipboard.writeText(clipboardTexts[buttonId]);
+ navigator.clipboard.writeText(clipboardTexts[buttonId])
+ .then(() => {
+ updateUsageStats(buttonId);
+ const count = getUsageCount(buttonId);
+ showToast(`Π’Π΅ΠΊΡΡ ΡΠΊΠΎΠΏΠΈΡΠΎΠ²Π°Π½! (ΠΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠΉ: ${count})`);
+ })
+ .catch(err => {
+ console.error('ΠΠ΅ ΡΠ΄Π°Π»ΠΎΡΡ ΡΠΊΠΎΠΏΠΈΡΠΎΠ²Π°ΡΡ ΡΠ΅ΠΊΡΡ: ', err);
+ showToast('ΠΡΠΈΠ±ΠΊΠ° ΠΊΠΎΠΏΠΈΡΠΎΠ²Π°Π½ΠΈΡ');
+ });
}
}
@@ -121,12 +287,12 @@ function createTemplate(title, RUText, ENText) {
});
// ΠΠ±ΡΠ°Π±ΠΎΡΡΠΈΠΊ Π΄Π»Ρ ΡΠ΄Π°Π»Π΅Π½ΠΈΡ
- deleteBtn.addEventListener('click', () => {
- const templates = JSON.parse(localStorage.getItem('templates')) || [];
+ deleteBtn.addEventListener('click', async () => {
+ const templates = await StorageHelper.get('templates') || [];
const templateIndex = templates.findIndex(template => template.title === titleEl.innerText);
if (templateIndex !== -1) {
templates.splice(templateIndex, 1);
- localStorage.setItem('templates', JSON.stringify(templates));
+ await StorageHelper.set('templates', templates);
}
templateEl.remove();
});
@@ -144,9 +310,18 @@ function createTemplate(title, RUText, ENText) {
// ΠΠ±ΡΠ°Π±ΠΎΡΡΠΈΠΊ Π΄Π»Ρ ΠΊΠΎΠΏΠΈΡΠΎΠ²Π°Π½ΠΈΡ ΡΠ΅ΠΊΡΡΠ° Π² Π±ΡΡΠ΅Ρ ΠΎΠ±ΠΌΠ΅Π½Π°
const handleCopyText = (e, key) => {
+ const templateId = `custom-${title}-${key}`;
navigator.clipboard.writeText(e.target.dataset[key])
- .then(() => console.log(`Π’Π΅ΠΊΡΡ ${key} ΡΠΊΠΎΠΏΠΈΡΠΎΠ²Π°Π½ Π² Π±ΡΡΠ΅Ρ ΠΎΠ±ΠΌΠ΅Π½Π°`))
- .catch(err => console.error(`ΠΠ΅ ΡΠ΄Π°Π»ΠΎΡΡ ΡΠΊΠΎΠΏΠΈΡΠΎΠ²Π°ΡΡ ΡΠ΅ΠΊΡΡ ${key}: `, err));
+ .then(() => {
+ updateUsageStats(templateId);
+ const count = getUsageCount(templateId);
+ showToast(`Π’Π΅ΠΊΡΡ ΡΠΊΠΎΠΏΠΈΡΠΎΠ²Π°Π½! (ΠΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠΉ: ${count})`);
+ console.log(`Π’Π΅ΠΊΡΡ ${key} ΡΠΊΠΎΠΏΠΈΡΠΎΠ²Π°Π½ Π² Π±ΡΡΠ΅Ρ ΠΎΠ±ΠΌΠ΅Π½Π°`);
+ })
+ .catch(err => {
+ console.error(`ΠΠ΅ ΡΠ΄Π°Π»ΠΎΡΡ ΡΠΊΠΎΠΏΠΈΡΠΎΠ²Π°ΡΡ ΡΠ΅ΠΊΡΡ ${key}: `, err);
+ showToast('ΠΡΠΈΠ±ΠΊΠ° ΠΊΠΎΠΏΠΈΡΠΎΠ²Π°Π½ΠΈΡ');
+ });
};
textRUEl.addEventListener('click', (e) => handleCopyText(e, 'ruText'));
@@ -155,19 +330,19 @@ function createTemplate(title, RUText, ENText) {
return templateEl;
}
-function saveTemplateToLocalStorage(title, RUText, ENText) {
+async function saveTemplateToLocalStorage(title, RUText, ENText) {
const template = { title, RUText, ENText };
- const templates = JSON.parse(localStorage.getItem('templates')) || [];
+ const templates = await StorageHelper.get('templates') || [];
templates.push(template);
- localStorage.setItem('templates', JSON.stringify(templates));
+ await StorageHelper.set('templates', templates);
}
-function updateTemplateInLocalStorage(title, key, value) {
- const templates = JSON.parse(localStorage.getItem('templates')) || [];
+async function updateTemplateInLocalStorage(title, key, value) {
+ const templates = await StorageHelper.get('templates') || [];
const templateIndex = templates.findIndex(template => template.title === title);
if (templateIndex !== -1) {
templates[templateIndex][key] = value;
- localStorage.setItem('templates', JSON.stringify(templates));
+ await StorageHelper.set('templates', templates);
}
}
@@ -181,8 +356,8 @@ addBtn.addEventListener('click', () => {
saveTemplateToLocalStorage(title, RUText, ENText);
});
-window.onload = function () {
- const templates = JSON.parse(localStorage.getItem('templates')) || [];
+window.onload = async function () {
+ const templates = await StorageHelper.get('templates') || [];
templates.forEach(template => {
const el = createTemplate(template.title, template.RUText, template.ENText);
templatesEl.appendChild(el);
@@ -195,8 +370,8 @@ const themeToggle = document.getElementById('theme-toggle');
const themeIcon = document.getElementById('theme-icon');
// ΠΡΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ ΡΠΎΡ
ΡΠ°Π½Π΅Π½Π½ΠΎΠΉ ΡΠ΅ΠΌΡ
-const applySavedTheme = () => {
- const savedTheme = localStorage.getItem('theme');
+const applySavedTheme = async () => {
+ const savedTheme = await StorageHelper.get('theme');
if (savedTheme === 'dark') {
document.body.classList.add('dark-theme');
if (themeIcon) {
@@ -212,10 +387,10 @@ const applySavedTheme = () => {
// ΠΠ΅ΡΠ΅ΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΡΠ΅ΠΌΡ
if (themeToggle && themeIcon) {
- themeToggle.addEventListener('click', () => {
+ themeToggle.addEventListener('click', async () => {
document.body.classList.toggle('dark-theme');
const theme = document.body.classList.contains('dark-theme') ? 'dark' : 'light';
- localStorage.setItem('theme', theme); // Π‘ΠΎΡ
ΡΠ°Π½ΡΠ΅ΠΌ Π²ΡΠ±ΡΠ°Π½Π½ΡΡ ΡΠ΅ΠΌΡ
+ await StorageHelper.set('theme', theme); // Π‘ΠΎΡ
ΡΠ°Π½ΡΠ΅ΠΌ Π²ΡΠ±ΡΠ°Π½Π½ΡΡ ΡΠ΅ΠΌΡ
themeIcon.classList.replace(theme === 'dark' ? 'fa-moon' : 'fa-sun', theme === 'dark' ? 'fa-sun' : 'fa-moon');
});
}
@@ -224,13 +399,14 @@ if (themeToggle && themeIcon) {
applySavedTheme();
// Π£ΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ ΠΊΠ°ΡΠ΅Π³ΠΎΡΠΈΡΠΌΠΈ
-document.querySelectorAll('.category h3').forEach(function(header) {
+document.querySelectorAll('.category h3').forEach(async function(header) {
const categoryId = header.textContent.trim(); // Π£Π½ΠΈΠΊΠ°Π»ΡΠ½ΡΠΉ ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡ ΠΊΠ°ΡΠ΅Π³ΠΎΡΠΈΠΈ ΠΏΠΎ Π½Π°Π·Π²Π°Π½ΠΈΡ
const content = header.nextElementSibling; // Π‘ΠΎΠ΄Π΅ΡΠΆΠΈΠΌΠΎΠ΅ ΠΊΠ°ΡΠ΅Π³ΠΎΡΠΈΠΈ
const icon = header.querySelector('.toggle-icon'); // ΠΠΊΠΎΠ½ΠΊΠ° ΡΡΡΠ΅Π»ΠΊΠΈ
// ΠΡΠΎΠ²Π΅ΡΠΊΠ° ΡΠΎΡΡΠΎΡΠ½ΠΈΡ ΠΊΠ°ΡΠ΅Π³ΠΎΡΠΈΠΈ ΠΏΡΠΈ Π·Π°Π³ΡΡΠ·ΠΊΠ΅ ΡΡΡΠ°Π½ΠΈΡΡ
- const isCategoryOpen = localStorage.getItem(categoryId) === 'true';
+ const categoryStates = await StorageHelper.get('categoryStates') || {};
+ const isCategoryOpen = categoryStates[categoryId] === 'true';
if (isCategoryOpen) {
content.classList.add('show');
@@ -245,12 +421,180 @@ document.querySelectorAll('.category h3').forEach(function(header) {
}
// ΠΠ±ΡΠ°Π±ΠΎΡΡΠΈΠΊ ΠΊΠ»ΠΈΠΊΠ° ΠΏΠΎ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΡ ΠΊΠ°ΡΠ΅Π³ΠΎΡΠΈΠΈ
- header.addEventListener('click', function() {
+ header.addEventListener('click', async function() {
content.classList.toggle('show'); // ΠΠ΅ΡΠ΅ΠΊΠ»ΡΡΠ°Π΅ΠΌ Π²ΠΈΠ΄ΠΈΠΌΠΎΡΡΡ ΠΊΠ°ΡΠ΅Π³ΠΎΡΠΈΠΈ
icon.classList.toggle('fa-chevron-down');
icon.classList.toggle('fa-chevron-up');
// Π‘ΠΎΡ
ΡΠ°Π½ΡΠ΅ΠΌ ΡΠΎΡΡΠΎΡΠ½ΠΈΠ΅ ΠΊΠ°ΡΠ΅Π³ΠΎΡΠΈΠΈ ΠΊΠ°ΠΊ ΠΎΡΠΊΡΡΡΠΎΠ΅ ΠΈΠ»ΠΈ Π·Π°ΠΊΡΡΡΠΎΠ΅
- localStorage.setItem(categoryId, content.classList.contains('show') ? 'true' : 'false');
+ const categoryStates = await StorageHelper.get('categoryStates') || {};
+ categoryStates[categoryId] = content.classList.contains('show') ? 'true' : 'false';
+ await StorageHelper.set('categoryStates', categoryStates);
});
});
+
+// ΠΠΌΠΏΠΎΡΡ/ΠΠΊΡΠΏΠΎΡΡ ΡΠ°Π±Π»ΠΎΠ½ΠΎΠ²
+const exportBtn = document.querySelector('.export-btn');
+const importBtn = document.querySelector('.import-btn');
+const importFileInput = document.getElementById('import-file-input');
+
+if (exportBtn) {
+ exportBtn.addEventListener('click', async () => {
+ const templates = await StorageHelper.get('templates') || [];
+ const dataStr = JSON.stringify(templates, null, 2);
+ const dataBlob = new Blob([dataStr], { type: 'application/json' });
+
+ const url = URL.createObjectURL(dataBlob);
+ const link = document.createElement('a');
+ link.href = url;
+ link.download = `izipus-templates-${new Date().toISOString().split('T')[0]}.json`;
+ document.body.appendChild(link);
+ link.click();
+ document.body.removeChild(link);
+ URL.revokeObjectURL(url);
+
+ showToast(`ΠΠΊΡΠΏΠΎΡΡΠΈΡΠΎΠ²Π°Π½ΠΎ ${templates.length} ΡΠ°Π±Π»ΠΎΠ½ΠΎΠ²`);
+ });
+}
+
+if (importBtn && importFileInput) {
+ importBtn.addEventListener('click', () => {
+ importFileInput.click();
+ });
+
+ importFileInput.addEventListener('change', (e) => {
+ const file = e.target.files[0];
+ if (!file) return;
+
+ const reader = new FileReader();
+ reader.onload = async (event) => {
+ try {
+ const importedTemplates = JSON.parse(event.target.result);
+
+ if (!Array.isArray(importedTemplates)) {
+ showToast('ΠΠ΅Π²Π΅ΡΠ½ΡΠΉ ΡΠΎΡΠΌΠ°Ρ ΡΠ°ΠΉΠ»Π°');
+ return;
+ }
+
+ // ΠΠ°Π»ΠΈΠ΄Π°ΡΠΈΡ ΡΠ°Π±Π»ΠΎΠ½ΠΎΠ²
+ const validTemplates = importedTemplates.filter(t =>
+ t.title && typeof t.title === 'string' &&
+ t.RUText && typeof t.RUText === 'string' &&
+ t.ENText && typeof t.ENText === 'string'
+ );
+
+ if (validTemplates.length === 0) {
+ showToast('ΠΠ΅Ρ Π²Π°Π»ΠΈΠ΄Π½ΡΡ
ΡΠ°Π±Π»ΠΎΠ½ΠΎΠ² Π΄Π»Ρ ΠΈΠΌΠΏΠΎΡΡΠ°');
+ return;
+ }
+
+ // ΠΠΎΠ»ΡΡΠ°Π΅ΠΌ ΡΡΡΠ΅ΡΡΠ²ΡΡΡΠΈΠ΅ ΡΠ°Π±Π»ΠΎΠ½Ρ
+ const existingTemplates = await StorageHelper.get('templates') || [];
+
+ // ΠΠ±ΡΠ΅Π΄ΠΈΠ½ΡΠ΅ΠΌ ΡΠ°Π±Π»ΠΎΠ½Ρ (ΠΈΠ·Π±Π΅Π³Π°Π΅ΠΌ Π΄ΡΠ±Π»ΠΈΠΊΠ°ΡΠΎΠ² ΠΏΠΎ Π½Π°Π·Π²Π°Π½ΠΈΡ)
+ const existingTitles = new Set(existingTemplates.map(t => t.title));
+ const newTemplates = validTemplates.filter(t => !existingTitles.has(t.title));
+
+ if (newTemplates.length === 0) {
+ showToast('ΠΡΠ΅ ΡΠ°Π±Π»ΠΎΠ½Ρ ΡΠΆΠ΅ ΡΡΡΠ΅ΡΡΠ²ΡΡΡ');
+ return;
+ }
+
+ const mergedTemplates = [...existingTemplates, ...newTemplates];
+ await StorageHelper.set('templates', mergedTemplates);
+
+ // ΠΠΎΠ±Π°Π²Π»ΡΠ΅ΠΌ Π½ΠΎΠ²ΡΠ΅ ΡΠ°Π±Π»ΠΎΠ½Ρ Π½Π° ΡΡΡΠ°Π½ΠΈΡΡ
+ newTemplates.forEach(template => {
+ const el = createTemplate(template.title, template.RUText, template.ENText);
+ templatesEl.appendChild(el);
+ });
+
+ showToast(`ΠΠΌΠΏΠΎΡΡΠΈΡΠΎΠ²Π°Π½ΠΎ ${newTemplates.length} Π½ΠΎΠ²ΡΡ
ΡΠ°Π±Π»ΠΎΠ½ΠΎΠ²`);
+ } catch (error) {
+ console.error('ΠΡΠΈΠ±ΠΊΠ° ΠΈΠΌΠΏΠΎΡΡΠ°:', error);
+ showToast('ΠΡΠΈΠ±ΠΊΠ° ΠΏΡΠΈ ΠΈΠΌΠΏΠΎΡΡΠ΅ ΡΠ°ΠΉΠ»Π°');
+ }
+
+ // Π‘Π±ΡΠ°ΡΡΠ²Π°Π΅ΠΌ input
+ importFileInput.value = '';
+ };
+
+ reader.readAsText(file);
+ });
+}
+
+// ΠΠΎΠΈΡΠΊ ΠΏΠΎ ΡΠ°Π±Π»ΠΎΠ½Π°ΠΌ
+const searchInput = document.getElementById('search-input');
+if (searchInput) {
+ searchInput.addEventListener('input', function(e) {
+ const searchTerm = e.target.value.toLowerCase().trim();
+ const categories = document.querySelectorAll('.category');
+
+ if (searchTerm === '') {
+ // ΠΡΠ»ΠΈ ΠΏΠΎΠΈΡΠΊ ΠΏΡΡΡ, ΠΏΠΎΠΊΠ°Π·ΡΠ²Π°Π΅ΠΌ Π²ΡΠ΅ ΡΠ°Π±Π»ΠΎΠ½Ρ
+ categories.forEach(category => {
+ category.classList.remove('hidden-by-search');
+ const templates = category.querySelectorAll('.template');
+ templates.forEach(template => {
+ template.classList.remove('hidden-by-search');
+ });
+ });
+ return;
+ }
+
+ // ΠΡΠ΅ΠΌ ΠΏΠΎ Π²ΡΠ΅ΠΌ ΠΊΠ°ΡΠ΅Π³ΠΎΡΠΈΡΠΌ
+ categories.forEach(category => {
+ const templates = category.querySelectorAll('.template');
+ let hasVisibleTemplates = false;
+
+ templates.forEach(template => {
+ // ΠΠΎΠ»ΡΡΠ°Π΅ΠΌ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ ΡΠ°Π±Π»ΠΎΠ½Π°
+ const titleEl = template.querySelector('.template-title, #template-title');
+ const title = titleEl ? titleEl.textContent.toLowerCase() : '';
+
+ // ΠΠΎΠ»ΡΡΠ°Π΅ΠΌ ΡΠΎΠ΄Π΅ΡΠΆΠΈΠΌΠΎΠ΅ ΡΠ°Π±Π»ΠΎΠ½ΠΎΠ² (RU ΠΈ EN)
+ const ruBtn = template.querySelector('[id$="Ru"], [data-ru-text]');
+ const enBtn = template.querySelector('[id$="En"], [data-en-text]');
+
+ let ruText = '';
+ let enText = '';
+
+ if (ruBtn) {
+ ruText = (ruBtn.dataset.ruText || clipboardTexts[ruBtn.id] || '').toLowerCase();
+ }
+
+ if (enBtn) {
+ enText = (enBtn.dataset.enText || clipboardTexts[enBtn.id] || '').toLowerCase();
+ }
+
+ // ΠΡΠΎΠ²Π΅ΡΡΠ΅ΠΌ ΡΠΎΠ²ΠΏΠ°Π΄Π΅Π½ΠΈΠ΅
+ const matches = title.includes(searchTerm) ||
+ ruText.includes(searchTerm) ||
+ enText.includes(searchTerm);
+
+ if (matches) {
+ template.classList.remove('hidden-by-search');
+ hasVisibleTemplates = true;
+ } else {
+ template.classList.add('hidden-by-search');
+ }
+ });
+
+ // Π‘ΠΊΡΡΠ²Π°Π΅ΠΌ ΠΊΠ°ΡΠ΅Π³ΠΎΡΠΈΡ, Π΅ΡΠ»ΠΈ Π² Π½Π΅ΠΉ Π½Π΅Ρ Π²ΠΈΠ΄ΠΈΠΌΡΡ
ΡΠ°Π±Π»ΠΎΠ½ΠΎΠ²
+ if (hasVisibleTemplates) {
+ category.classList.remove('hidden-by-search');
+ // ΠΡΠΊΡΡΠ²Π°Π΅ΠΌ ΠΊΠ°ΡΠ΅Π³ΠΎΡΠΈΡ ΠΏΡΠΈ ΠΏΠΎΠΈΡΠΊΠ΅
+ const content = category.querySelector('.category-content');
+ if (content && !content.classList.contains('show')) {
+ content.classList.add('show');
+ const icon = category.querySelector('.toggle-icon');
+ if (icon) {
+ icon.classList.replace('fa-chevron-down', 'fa-chevron-up');
+ }
+ }
+ } else {
+ category.classList.add('hidden-by-search');
+ }
+ });
+ });
+}
});
\ No newline at end of file