Commit ·
afdf449
1
Parent(s): d4d18df
feat: 12 UI improvements batch - 1. Editor surface flush (no margin/border, Google Docs style) - 2. Custom styled summary slider (gradient thumb) - 3. Empty states with icons for suggestions - 4. Enhanced status bar (chars, sentences, reading time) - 5. Mobile scrollable formatting toolbar - 6. Summary word count + compression ratio - 7. Document search bar with filter - 8. Text color + highlight color pickers - 9. Lists (bullet/ordered) + indent/outdent + clear format - 10. Animated sun/moon theme toggle - 11. Summary bullet points mode toggle - 12. Print styles (only editor content)
Browse files- src/css/components.css +368 -10
- src/index.html +108 -8
- src/js/editor.js +4 -0
- src/js/format.js +114 -0
- src/js/theme.js +1 -4
- src/js/ui.js +7 -6
src/css/components.css
CHANGED
|
@@ -286,12 +286,19 @@
|
|
| 286 |
/* ── Formatting Toolbar ── */
|
| 287 |
.format-toolbar {
|
| 288 |
display: flex;
|
| 289 |
-
flex-wrap:
|
| 290 |
align-items: center;
|
| 291 |
gap: 6px;
|
| 292 |
padding: 8px var(--spacing-md);
|
| 293 |
border-bottom: 1px solid var(--color-border);
|
| 294 |
background: var(--color-surface);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 295 |
}
|
| 296 |
|
| 297 |
.fmt-group {
|
|
@@ -475,7 +482,7 @@
|
|
| 475 |
background: var(--color-editor);
|
| 476 |
color: var(--color-text-primary);
|
| 477 |
min-height: 50vh;
|
| 478 |
-
padding: var(--spacing-lg);
|
| 479 |
font-size: var(--font-size-editor);
|
| 480 |
font-weight: var(--font-weight-regular);
|
| 481 |
line-height: var(--line-height-editor);
|
|
@@ -485,11 +492,13 @@
|
|
| 485 |
white-space: pre-wrap;
|
| 486 |
word-wrap: break-word;
|
| 487 |
overflow-y: auto;
|
| 488 |
-
border-radius:
|
| 489 |
-
margin:
|
| 490 |
-
border:
|
| 491 |
-
|
| 492 |
-
|
|
|
|
|
|
|
| 493 |
}
|
| 494 |
|
| 495 |
@media (min-width: 768px) {
|
|
@@ -502,8 +511,6 @@
|
|
| 502 |
|
| 503 |
.editor-surface:focus {
|
| 504 |
outline: none;
|
| 505 |
-
border-color: var(--color-border-strong);
|
| 506 |
-
box-shadow: var(--shadow-editor), 0 0 0 3px var(--focus-ring);
|
| 507 |
}
|
| 508 |
|
| 509 |
.editor-surface[data-empty="true"]::before {
|
|
@@ -515,7 +522,7 @@
|
|
| 515 |
}
|
| 516 |
|
| 517 |
.editor-surface.analyzing {
|
| 518 |
-
opacity: 0.
|
| 519 |
}
|
| 520 |
|
| 521 |
.editor-footer {
|
|
@@ -2104,3 +2111,354 @@ input[type="range"]::-webkit-slider-thumb {
|
|
| 2104 |
margin-top: var(--spacing-sm);
|
| 2105 |
}
|
| 2106 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 286 |
/* ── Formatting Toolbar ── */
|
| 287 |
.format-toolbar {
|
| 288 |
display: flex;
|
| 289 |
+
flex-wrap: nowrap;
|
| 290 |
align-items: center;
|
| 291 |
gap: 6px;
|
| 292 |
padding: 8px var(--spacing-md);
|
| 293 |
border-bottom: 1px solid var(--color-border);
|
| 294 |
background: var(--color-surface);
|
| 295 |
+
overflow-x: auto;
|
| 296 |
+
-webkit-overflow-scrolling: touch;
|
| 297 |
+
scrollbar-width: none;
|
| 298 |
+
}
|
| 299 |
+
|
| 300 |
+
.format-toolbar::-webkit-scrollbar {
|
| 301 |
+
display: none;
|
| 302 |
}
|
| 303 |
|
| 304 |
.fmt-group {
|
|
|
|
| 482 |
background: var(--color-editor);
|
| 483 |
color: var(--color-text-primary);
|
| 484 |
min-height: 50vh;
|
| 485 |
+
padding: var(--spacing-lg) var(--spacing-xl);
|
| 486 |
font-size: var(--font-size-editor);
|
| 487 |
font-weight: var(--font-weight-regular);
|
| 488 |
line-height: var(--line-height-editor);
|
|
|
|
| 492 |
white-space: pre-wrap;
|
| 493 |
word-wrap: break-word;
|
| 494 |
overflow-y: auto;
|
| 495 |
+
border-radius: 0;
|
| 496 |
+
margin: 0;
|
| 497 |
+
border: none;
|
| 498 |
+
border-top: 1px solid var(--color-border);
|
| 499 |
+
box-shadow: none;
|
| 500 |
+
transition: none;
|
| 501 |
+
flex: 1;
|
| 502 |
}
|
| 503 |
|
| 504 |
@media (min-width: 768px) {
|
|
|
|
| 511 |
|
| 512 |
.editor-surface:focus {
|
| 513 |
outline: none;
|
|
|
|
|
|
|
| 514 |
}
|
| 515 |
|
| 516 |
.editor-surface[data-empty="true"]::before {
|
|
|
|
| 522 |
}
|
| 523 |
|
| 524 |
.editor-surface.analyzing {
|
| 525 |
+
opacity: 0.92;
|
| 526 |
}
|
| 527 |
|
| 528 |
.editor-footer {
|
|
|
|
| 2111 |
margin-top: var(--spacing-sm);
|
| 2112 |
}
|
| 2113 |
|
| 2114 |
+
/* ── Item 2: Custom Summary Slider ── */
|
| 2115 |
+
.summarize-panel input[type="range"] {
|
| 2116 |
+
-webkit-appearance: none;
|
| 2117 |
+
appearance: none;
|
| 2118 |
+
width: 100%;
|
| 2119 |
+
height: 6px;
|
| 2120 |
+
border-radius: 3px;
|
| 2121 |
+
background: var(--color-border);
|
| 2122 |
+
outline: none;
|
| 2123 |
+
direction: ltr;
|
| 2124 |
+
cursor: pointer;
|
| 2125 |
+
}
|
| 2126 |
+
|
| 2127 |
+
.summarize-panel input[type="range"]::-webkit-slider-thumb {
|
| 2128 |
+
-webkit-appearance: none;
|
| 2129 |
+
width: 22px;
|
| 2130 |
+
height: 22px;
|
| 2131 |
+
border-radius: 50%;
|
| 2132 |
+
background: linear-gradient(135deg, var(--color-primary), var(--color-secondary));
|
| 2133 |
+
cursor: pointer;
|
| 2134 |
+
border: 3px solid var(--color-surface);
|
| 2135 |
+
box-shadow: 0 2px 8px rgba(0,0,0,0.25);
|
| 2136 |
+
transition: transform 0.15s ease;
|
| 2137 |
+
}
|
| 2138 |
+
|
| 2139 |
+
.summarize-panel input[type="range"]::-webkit-slider-thumb:hover {
|
| 2140 |
+
transform: scale(1.15);
|
| 2141 |
+
}
|
| 2142 |
+
|
| 2143 |
+
.summarize-panel input[type="range"]::-moz-range-thumb {
|
| 2144 |
+
width: 22px;
|
| 2145 |
+
height: 22px;
|
| 2146 |
+
border-radius: 50%;
|
| 2147 |
+
background: linear-gradient(135deg, var(--color-primary), var(--color-secondary));
|
| 2148 |
+
cursor: pointer;
|
| 2149 |
+
border: 3px solid var(--color-surface);
|
| 2150 |
+
box-shadow: 0 2px 8px rgba(0,0,0,0.25);
|
| 2151 |
+
}
|
| 2152 |
+
|
| 2153 |
+
/* ── Item 3: Empty States ── */
|
| 2154 |
+
.empty-state {
|
| 2155 |
+
display: flex;
|
| 2156 |
+
flex-direction: column;
|
| 2157 |
+
align-items: center;
|
| 2158 |
+
justify-content: center;
|
| 2159 |
+
padding: var(--spacing-xl) var(--spacing-md);
|
| 2160 |
+
text-align: center;
|
| 2161 |
+
gap: var(--spacing-md);
|
| 2162 |
+
}
|
| 2163 |
+
|
| 2164 |
+
.empty-state__icon {
|
| 2165 |
+
width: 48px;
|
| 2166 |
+
height: 48px;
|
| 2167 |
+
border-radius: 50%;
|
| 2168 |
+
background: var(--color-surface-elevated);
|
| 2169 |
+
display: flex;
|
| 2170 |
+
align-items: center;
|
| 2171 |
+
justify-content: center;
|
| 2172 |
+
color: var(--color-text-muted);
|
| 2173 |
+
}
|
| 2174 |
+
|
| 2175 |
+
.empty-state__title {
|
| 2176 |
+
font-size: var(--font-size-caption);
|
| 2177 |
+
font-weight: var(--font-weight-semibold);
|
| 2178 |
+
color: var(--color-text-secondary);
|
| 2179 |
+
}
|
| 2180 |
+
|
| 2181 |
+
.empty-state__desc {
|
| 2182 |
+
font-size: var(--font-size-label);
|
| 2183 |
+
color: var(--color-text-muted);
|
| 2184 |
+
line-height: 1.6;
|
| 2185 |
+
}
|
| 2186 |
+
|
| 2187 |
+
/* ── Item 4: Enhanced Status Bar ── */
|
| 2188 |
+
.editor-stats {
|
| 2189 |
+
display: flex;
|
| 2190 |
+
flex-wrap: wrap;
|
| 2191 |
+
gap: var(--spacing-sm);
|
| 2192 |
+
align-items: center;
|
| 2193 |
+
}
|
| 2194 |
+
|
| 2195 |
+
.stat-item {
|
| 2196 |
+
display: flex;
|
| 2197 |
+
align-items: center;
|
| 2198 |
+
gap: 4px;
|
| 2199 |
+
font-size: var(--font-size-label);
|
| 2200 |
+
color: var(--color-text-muted);
|
| 2201 |
+
}
|
| 2202 |
+
|
| 2203 |
+
.stat-item--sep {
|
| 2204 |
+
width: 1px;
|
| 2205 |
+
height: 14px;
|
| 2206 |
+
background: var(--color-border);
|
| 2207 |
+
}
|
| 2208 |
+
|
| 2209 |
+
/* ── Item 6: Summary Stats ── */
|
| 2210 |
+
.summary-stats {
|
| 2211 |
+
display: flex;
|
| 2212 |
+
flex-wrap: wrap;
|
| 2213 |
+
gap: var(--spacing-md);
|
| 2214 |
+
padding: var(--spacing-sm) 0;
|
| 2215 |
+
margin-bottom: var(--spacing-md);
|
| 2216 |
+
border-bottom: 1px solid var(--color-border);
|
| 2217 |
+
}
|
| 2218 |
+
|
| 2219 |
+
.summary-stat {
|
| 2220 |
+
display: flex;
|
| 2221 |
+
align-items: center;
|
| 2222 |
+
gap: 6px;
|
| 2223 |
+
font-size: var(--font-size-label);
|
| 2224 |
+
color: var(--color-text-secondary);
|
| 2225 |
+
}
|
| 2226 |
+
|
| 2227 |
+
.summary-stat__value {
|
| 2228 |
+
font-weight: var(--font-weight-bold);
|
| 2229 |
+
color: var(--color-primary);
|
| 2230 |
+
}
|
| 2231 |
+
|
| 2232 |
+
/* ── Item 7: Document Search ── */
|
| 2233 |
+
.docs-search {
|
| 2234 |
+
display: flex;
|
| 2235 |
+
align-items: center;
|
| 2236 |
+
gap: 8px;
|
| 2237 |
+
padding: 6px 10px;
|
| 2238 |
+
border: 1px solid var(--color-border);
|
| 2239 |
+
border-radius: 6px;
|
| 2240 |
+
background: var(--color-surface);
|
| 2241 |
+
margin-bottom: var(--spacing-md);
|
| 2242 |
+
transition: border-color 0.15s ease;
|
| 2243 |
+
}
|
| 2244 |
+
|
| 2245 |
+
.docs-search:focus-within {
|
| 2246 |
+
border-color: var(--color-primary);
|
| 2247 |
+
}
|
| 2248 |
+
|
| 2249 |
+
.docs-search__input {
|
| 2250 |
+
flex: 1;
|
| 2251 |
+
border: none;
|
| 2252 |
+
background: transparent;
|
| 2253 |
+
color: var(--color-text-primary);
|
| 2254 |
+
font-family: inherit;
|
| 2255 |
+
font-size: var(--font-size-caption);
|
| 2256 |
+
outline: none;
|
| 2257 |
+
direction: rtl;
|
| 2258 |
+
}
|
| 2259 |
+
|
| 2260 |
+
.docs-search__input::placeholder {
|
| 2261 |
+
color: var(--color-text-muted);
|
| 2262 |
+
}
|
| 2263 |
+
|
| 2264 |
+
.docs-search__icon {
|
| 2265 |
+
color: var(--color-text-muted);
|
| 2266 |
+
flex-shrink: 0;
|
| 2267 |
+
}
|
| 2268 |
+
|
| 2269 |
+
.doc-item-meta {
|
| 2270 |
+
font-size: 0.65rem;
|
| 2271 |
+
color: var(--color-text-muted);
|
| 2272 |
+
margin-top: 2px;
|
| 2273 |
+
}
|
| 2274 |
+
|
| 2275 |
+
/* ── Item 8: Color Picker ── */
|
| 2276 |
+
.fmt-color-btn {
|
| 2277 |
+
display: flex;
|
| 2278 |
+
align-items: center;
|
| 2279 |
+
justify-content: center;
|
| 2280 |
+
width: 34px;
|
| 2281 |
+
height: 34px;
|
| 2282 |
+
border: none;
|
| 2283 |
+
background: var(--color-surface);
|
| 2284 |
+
cursor: pointer;
|
| 2285 |
+
position: relative;
|
| 2286 |
+
transition: background 0.15s ease;
|
| 2287 |
+
}
|
| 2288 |
+
|
| 2289 |
+
.fmt-color-btn:hover {
|
| 2290 |
+
background: var(--color-surface-elevated);
|
| 2291 |
+
}
|
| 2292 |
+
|
| 2293 |
+
.fmt-color-indicator {
|
| 2294 |
+
position: absolute;
|
| 2295 |
+
bottom: 4px;
|
| 2296 |
+
left: 50%;
|
| 2297 |
+
transform: translateX(-50%);
|
| 2298 |
+
width: 14px;
|
| 2299 |
+
height: 3px;
|
| 2300 |
+
border-radius: 2px;
|
| 2301 |
+
}
|
| 2302 |
+
|
| 2303 |
+
.fmt-color-grid {
|
| 2304 |
+
display: grid;
|
| 2305 |
+
grid-template-columns: repeat(6, 1fr);
|
| 2306 |
+
gap: 4px;
|
| 2307 |
+
padding: 8px;
|
| 2308 |
+
}
|
| 2309 |
+
|
| 2310 |
+
.fmt-color-swatch {
|
| 2311 |
+
width: 24px;
|
| 2312 |
+
height: 24px;
|
| 2313 |
+
border-radius: 4px;
|
| 2314 |
+
border: 2px solid transparent;
|
| 2315 |
+
cursor: pointer;
|
| 2316 |
+
transition: transform 0.12s ease, border-color 0.12s ease;
|
| 2317 |
+
}
|
| 2318 |
+
|
| 2319 |
+
.fmt-color-swatch:hover {
|
| 2320 |
+
transform: scale(1.15);
|
| 2321 |
+
border-color: var(--color-text-primary);
|
| 2322 |
+
}
|
| 2323 |
+
|
| 2324 |
+
.fmt-color-swatch--active {
|
| 2325 |
+
border-color: var(--color-primary);
|
| 2326 |
+
box-shadow: 0 0 0 2px var(--color-primary);
|
| 2327 |
+
}
|
| 2328 |
+
|
| 2329 |
+
/* ── Item 10: Animated Theme Toggle ── */
|
| 2330 |
+
.theme-toggle-animated {
|
| 2331 |
+
display: flex;
|
| 2332 |
+
align-items: center;
|
| 2333 |
+
justify-content: center;
|
| 2334 |
+
width: 40px;
|
| 2335 |
+
height: 40px;
|
| 2336 |
+
border: none;
|
| 2337 |
+
border-radius: 50%;
|
| 2338 |
+
background: var(--color-surface-elevated);
|
| 2339 |
+
color: var(--color-text-secondary);
|
| 2340 |
+
cursor: pointer;
|
| 2341 |
+
transition: background 0.3s ease, transform 0.3s ease, color 0.3s ease;
|
| 2342 |
+
position: relative;
|
| 2343 |
+
overflow: hidden;
|
| 2344 |
+
}
|
| 2345 |
+
|
| 2346 |
+
.theme-toggle-animated:hover {
|
| 2347 |
+
background: var(--color-primary);
|
| 2348 |
+
color: #fff;
|
| 2349 |
+
transform: rotate(15deg);
|
| 2350 |
+
}
|
| 2351 |
+
|
| 2352 |
+
.theme-toggle-animated svg {
|
| 2353 |
+
transition: transform 0.4s ease, opacity 0.3s ease;
|
| 2354 |
+
}
|
| 2355 |
+
|
| 2356 |
+
.theme-toggle-animated .theme-icon-sun,
|
| 2357 |
+
.theme-toggle-animated .theme-icon-moon {
|
| 2358 |
+
position: absolute;
|
| 2359 |
+
transition: transform 0.4s ease, opacity 0.3s ease;
|
| 2360 |
+
}
|
| 2361 |
+
|
| 2362 |
+
[data-theme="dark"] .theme-icon-sun {
|
| 2363 |
+
transform: rotate(90deg) scale(0);
|
| 2364 |
+
opacity: 0;
|
| 2365 |
+
}
|
| 2366 |
+
|
| 2367 |
+
[data-theme="dark"] .theme-icon-moon {
|
| 2368 |
+
transform: rotate(0) scale(1);
|
| 2369 |
+
opacity: 1;
|
| 2370 |
+
}
|
| 2371 |
+
|
| 2372 |
+
[data-theme="light"] .theme-icon-moon {
|
| 2373 |
+
transform: rotate(-90deg) scale(0);
|
| 2374 |
+
opacity: 0;
|
| 2375 |
+
}
|
| 2376 |
+
|
| 2377 |
+
[data-theme="light"] .theme-icon-sun {
|
| 2378 |
+
transform: rotate(0) scale(1);
|
| 2379 |
+
opacity: 1;
|
| 2380 |
+
}
|
| 2381 |
+
|
| 2382 |
+
/* ── Item 11: Summary Mode Toggle ── */
|
| 2383 |
+
.summary-mode-toggle {
|
| 2384 |
+
display: flex;
|
| 2385 |
+
border: 1px solid var(--color-border);
|
| 2386 |
+
border-radius: 8px;
|
| 2387 |
+
overflow: hidden;
|
| 2388 |
+
margin-bottom: var(--spacing-md);
|
| 2389 |
+
}
|
| 2390 |
+
|
| 2391 |
+
.summary-mode-btn {
|
| 2392 |
+
flex: 1;
|
| 2393 |
+
padding: 8px 12px;
|
| 2394 |
+
border: none;
|
| 2395 |
+
background: transparent;
|
| 2396 |
+
color: var(--color-text-secondary);
|
| 2397 |
+
font-family: inherit;
|
| 2398 |
+
font-size: var(--font-size-caption);
|
| 2399 |
+
font-weight: var(--font-weight-semibold);
|
| 2400 |
+
cursor: pointer;
|
| 2401 |
+
transition: all 0.2s ease;
|
| 2402 |
+
display: flex;
|
| 2403 |
+
align-items: center;
|
| 2404 |
+
justify-content: center;
|
| 2405 |
+
gap: 6px;
|
| 2406 |
+
}
|
| 2407 |
+
|
| 2408 |
+
.summary-mode-btn.active {
|
| 2409 |
+
background: linear-gradient(135deg, var(--color-primary), var(--color-secondary));
|
| 2410 |
+
color: #fff;
|
| 2411 |
+
}
|
| 2412 |
+
|
| 2413 |
+
.summary-mode-btn:hover:not(.active) {
|
| 2414 |
+
background: var(--color-surface-elevated);
|
| 2415 |
+
}
|
| 2416 |
+
|
| 2417 |
+
/* ── Item 12: Print Styles ── */
|
| 2418 |
+
@media print {
|
| 2419 |
+
body * {
|
| 2420 |
+
visibility: hidden;
|
| 2421 |
+
}
|
| 2422 |
+
|
| 2423 |
+
#editor-container,
|
| 2424 |
+
#editor-container * {
|
| 2425 |
+
visibility: visible;
|
| 2426 |
+
}
|
| 2427 |
+
|
| 2428 |
+
#editor-container {
|
| 2429 |
+
position: absolute;
|
| 2430 |
+
top: 0;
|
| 2431 |
+
left: 0;
|
| 2432 |
+
right: 0;
|
| 2433 |
+
width: 100%;
|
| 2434 |
+
min-height: auto;
|
| 2435 |
+
padding: 2cm;
|
| 2436 |
+
font-size: 14pt;
|
| 2437 |
+
line-height: 2;
|
| 2438 |
+
color: #000;
|
| 2439 |
+
background: #fff;
|
| 2440 |
+
border: none;
|
| 2441 |
+
box-shadow: none;
|
| 2442 |
+
}
|
| 2443 |
+
|
| 2444 |
+
.spelling-error,
|
| 2445 |
+
.grammar-error,
|
| 2446 |
+
.punctuation-suggestion {
|
| 2447 |
+
border: none;
|
| 2448 |
+
background: transparent;
|
| 2449 |
+
text-decoration: none;
|
| 2450 |
+
}
|
| 2451 |
+
|
| 2452 |
+
.site-nav,
|
| 2453 |
+
.format-toolbar,
|
| 2454 |
+
.editor-toolbar,
|
| 2455 |
+
.editor-footer,
|
| 2456 |
+
.sidebar-panel,
|
| 2457 |
+
.docs-sidebar,
|
| 2458 |
+
.bottom-sheet,
|
| 2459 |
+
.suggestion-popover,
|
| 2460 |
+
#analyzing-indicator {
|
| 2461 |
+
display: none !important;
|
| 2462 |
+
}
|
| 2463 |
+
}
|
| 2464 |
+
|
src/index.html
CHANGED
|
@@ -86,7 +86,10 @@
|
|
| 86 |
</div>
|
| 87 |
</div>
|
| 88 |
</div>
|
| 89 |
-
<button id="theme-toggle" class="theme-toggle" aria-label="تبديل السمة" aria-pressed="true" type="button">
|
|
|
|
|
|
|
|
|
|
| 90 |
|
| 91 |
</div>
|
| 92 |
</div>
|
|
@@ -461,6 +464,10 @@
|
|
| 461 |
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"/></svg>
|
| 462 |
مستند جديد
|
| 463 |
</button>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 464 |
<div id="docs-list" role="list" aria-label="قائمة المستندات"></div>
|
| 465 |
</div>
|
| 466 |
</div>
|
|
@@ -556,6 +563,51 @@
|
|
| 556 |
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 10H11a5 5 0 00-5 5v2M21 10l-4-4M21 10l-4 4"/></svg>
|
| 557 |
</button>
|
| 558 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 559 |
</div>
|
| 560 |
<input type="file" id="doc-import-input" class="sr-only" accept=".txt,.docx,text/plain,application/vnd.openxmlformats-officedocument.wordprocessingml.document" aria-hidden="true">
|
| 561 |
<div id="write-area">
|
|
@@ -573,6 +625,17 @@
|
|
| 573 |
</div>
|
| 574 |
</div>
|
| 575 |
<div id="summarize-area" class="summarize-panel is-hidden">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 576 |
<div class="mb-6">
|
| 577 |
<label class="block text-base font-bold mb-3" for="summary-length">طول الملخص</label>
|
| 578 |
<div class="flex items-center gap-4">
|
|
@@ -591,6 +654,11 @@
|
|
| 591 |
<button id="generate-summary-btn" onclick="generateSummary(event)" class="btn-primary w-full py-4 text-lg mb-6" type="button">توليد الملخص</button>
|
| 592 |
<div id="summary-preview" class="summary-preview">
|
| 593 |
<div class="summary-card">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 594 |
<div class="flex items-center justify-between mb-4">
|
| 595 |
<h3 class="text-lg font-bold summary-card__title">الملخص</h3>
|
| 596 |
<button onclick="copySummary()" class="btn-ghost" type="button">نسخ</button>
|
|
@@ -600,14 +668,23 @@
|
|
| 600 |
</div>
|
| 601 |
</div>
|
| 602 |
<div class="editor-footer">
|
| 603 |
-
<div class="editor-stats" role="status" aria-label="إحصائيات
|
| 604 |
<div class="flex items-center gap-2"><span class="stat-dot stat-dot--spelling" aria-hidden="true"></span><span class="text-sm text-secondary"><span id="spelling-count">٠</span> إملائي</span></div>
|
| 605 |
<div class="flex items-center gap-2"><span class="stat-dot stat-dot--grammar" aria-hidden="true"></span><span class="text-sm text-secondary"><span id="grammar-count">٠</span> نحوي</span></div>
|
| 606 |
<div class="flex items-center gap-2"><span class="stat-dot stat-dot--punctuation" aria-hidden="true"></span><span class="text-sm text-secondary"><span id="punctuation-count">٠</span> ترقيم</span></div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 607 |
</div>
|
| 608 |
<div class="editor-actions">
|
| 609 |
-
<button onclick="clearEditor()" class="btn-ghost" type="button"
|
| 610 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 611 |
</div>
|
| 612 |
</div>
|
| 613 |
</div>
|
|
@@ -926,10 +1003,32 @@
|
|
| 926 |
}
|
| 927 |
|
| 928 |
if (data.status === 'success' && data.summary) {
|
| 929 |
-
|
| 930 |
-
|
| 931 |
-
|
| 932 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 933 |
} else {
|
| 934 |
throw new Error(data.error || 'لم يتم توليد ملخص');
|
| 935 |
}
|
|
@@ -1065,6 +1164,7 @@
|
|
| 1065 |
initUI();
|
| 1066 |
initEditor();
|
| 1067 |
if (typeof initFormatToolbar === 'function') initFormatToolbar();
|
|
|
|
| 1068 |
initDocuments();
|
| 1069 |
updateSuggestionsList([]);
|
| 1070 |
// Phase 7 — Sync System
|
|
|
|
| 86 |
</div>
|
| 87 |
</div>
|
| 88 |
</div>
|
| 89 |
+
<button id="theme-toggle" class="theme-toggle-animated" aria-label="تبديل السمة" aria-pressed="true" type="button">
|
| 90 |
+
<svg class="theme-icon-sun" width="20" height="20" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"/></svg>
|
| 91 |
+
<svg class="theme-icon-moon" width="20" height="20" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"/></svg>
|
| 92 |
+
</button>
|
| 93 |
|
| 94 |
</div>
|
| 95 |
</div>
|
|
|
|
| 464 |
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"/></svg>
|
| 465 |
مستند جديد
|
| 466 |
</button>
|
| 467 |
+
<div class="docs-search">
|
| 468 |
+
<svg class="docs-search__icon" width="14" height="14" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/></svg>
|
| 469 |
+
<input type="text" class="docs-search__input" id="docs-search-input" placeholder="بحث في المستندات..." autocomplete="off">
|
| 470 |
+
</div>
|
| 471 |
<div id="docs-list" role="list" aria-label="قائمة المستندات"></div>
|
| 472 |
</div>
|
| 473 |
</div>
|
|
|
|
| 563 |
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 10H11a5 5 0 00-5 5v2M21 10l-4-4M21 10l-4 4"/></svg>
|
| 564 |
</button>
|
| 565 |
</div>
|
| 566 |
+
<div class="fmt-divider"></div>
|
| 567 |
+
<!-- Item 8: Color pickers -->
|
| 568 |
+
<div class="fmt-group fmt-group--font">
|
| 569 |
+
<div class="fmt-dropdown" id="fmt-textcolor-wrap">
|
| 570 |
+
<button class="fmt-color-btn" type="button" id="fmt-textcolor-trigger" title="لون النص">
|
| 571 |
+
<svg width="16" height="16" fill="currentColor" viewBox="0 0 24 24"><path d="M11 2L5.5 16h2.25l1.12-3h6.25l1.12 3h2.25L13 2h-2zm-1.38 9L12 4.67 14.38 11H9.62z"/></svg>
|
| 572 |
+
<span class="fmt-color-indicator" id="fmt-textcolor-bar" style="background:#ECEEF2"></span>
|
| 573 |
+
</button>
|
| 574 |
+
<div class="fmt-dropdown__menu" id="fmt-textcolor-menu" role="menu">
|
| 575 |
+
<div class="fmt-color-grid" id="fmt-textcolor-grid"></div>
|
| 576 |
+
</div>
|
| 577 |
+
</div>
|
| 578 |
+
<div class="fmt-dropdown" id="fmt-highlight-wrap">
|
| 579 |
+
<button class="fmt-color-btn" type="button" id="fmt-highlight-trigger" title="لون التظليل">
|
| 580 |
+
<svg width="16" height="16" fill="currentColor" viewBox="0 0 24 24"><path d="M16.56 8.94L7.62 0 6.21 1.41l2.38 2.38-5.15 5.15a1.49 1.49 0 000 2.12l5.5 5.5c.29.29.68.44 1.06.44s.77-.15 1.06-.44l5.5-5.5c.59-.58.59-1.53 0-2.12zM5.21 10L10 5.21 14.79 10H5.21zM19 11.5s-2 2.17-2 3.5c0 1.1.9 2 2 2s2-.9 2-2c0-1.33-2-3.5-2-3.5zM2 20h20v4H2v-4z"/></svg>
|
| 581 |
+
<span class="fmt-color-indicator" id="fmt-highlight-bar" style="background:transparent"></span>
|
| 582 |
+
</button>
|
| 583 |
+
<div class="fmt-dropdown__menu" id="fmt-highlight-menu" role="menu">
|
| 584 |
+
<div class="fmt-color-grid" id="fmt-highlight-grid"></div>
|
| 585 |
+
</div>
|
| 586 |
+
</div>
|
| 587 |
+
</div>
|
| 588 |
+
<div class="fmt-divider"></div>
|
| 589 |
+
<!-- Item 9: Lists + Indent -->
|
| 590 |
+
<div class="fmt-group">
|
| 591 |
+
<button class="fmt-btn" onclick="execFormat('insertUnorderedList')" type="button" title="قائمة نقطية">
|
| 592 |
+
<svg width="16" height="16" fill="currentColor" viewBox="0 0 24 24"><path d="M4 6h2v2H4V6zm4 0h12v2H8V6zM4 11h2v2H4v-2zm4 0h12v2H8v-2zm-4 5h2v2H4v-2zm4 0h12v2H8v-2z"/></svg>
|
| 593 |
+
</button>
|
| 594 |
+
<button class="fmt-btn" onclick="execFormat('insertOrderedList')" type="button" title="قائمة مرقمة">
|
| 595 |
+
<svg width="16" height="16" fill="currentColor" viewBox="0 0 24 24"><path d="M2 17h2v.5H3v1h1v.5H2v1h3v-4H2v1zm1-9h1V4H2v1h1v3zm-1 3h1.8L2 13.1v.9h3v-1H3.2L5 10.9V10H2v1zm5-6v2h14V5H7zm0 14h14v-2H7v2zm0-6h14v-2H7v2z"/></svg>
|
| 596 |
+
</button>
|
| 597 |
+
<button class="fmt-btn" onclick="execFormat('indent')" type="button" title="مسافة بادئة">
|
| 598 |
+
<svg width="16" height="16" fill="currentColor" viewBox="0 0 24 24"><path d="M3 21h18v-2H3v2zM3 8v8l4-4-4-4zm8 9h10v-2H11v2zM3 3v2h18V3H3zm8 6h10V7H11v2zm0 4h10v-2H11v2z"/></svg>
|
| 599 |
+
</button>
|
| 600 |
+
<button class="fmt-btn" onclick="execFormat('outdent')" type="button" title="إزالة المسافة البادئة">
|
| 601 |
+
<svg width="16" height="16" fill="currentColor" viewBox="0 0 24 24"><path d="M11 17h10v-2H11v2zm-8-5l4 4V8l-4 4zm0 9h18v-2H3v2zM3 3v2h18V3H3zm8 6h10V7H11v2zm0 4h10v-2H11v2z"/></svg>
|
| 602 |
+
</button>
|
| 603 |
+
</div>
|
| 604 |
+
<div class="fmt-divider"></div>
|
| 605 |
+
<!-- Clear formatting -->
|
| 606 |
+
<div class="fmt-group">
|
| 607 |
+
<button class="fmt-btn" onclick="execFormat('removeFormat')" type="button" title="مسح التنسيق">
|
| 608 |
+
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 2L2 22h20L12 2z"/><path stroke-linecap="round" stroke-width="2" d="M4 4l16 16"/></svg>
|
| 609 |
+
</button>
|
| 610 |
+
</div>
|
| 611 |
</div>
|
| 612 |
<input type="file" id="doc-import-input" class="sr-only" accept=".txt,.docx,text/plain,application/vnd.openxmlformats-officedocument.wordprocessingml.document" aria-hidden="true">
|
| 613 |
<div id="write-area">
|
|
|
|
| 625 |
</div>
|
| 626 |
</div>
|
| 627 |
<div id="summarize-area" class="summarize-panel is-hidden">
|
| 628 |
+
<!-- Item 11: Mode Toggle -->
|
| 629 |
+
<div class="summary-mode-toggle">
|
| 630 |
+
<button type="button" class="summary-mode-btn active" id="summary-mode-paragraph" onclick="setSummaryMode('paragraph')">
|
| 631 |
+
<svg width="14" height="14" fill="currentColor" viewBox="0 0 24 24"><path d="M3 5h18v2H3V5zm0 8h18v2H3v-2zm0 4h12v2H3v-2z"/></svg>
|
| 632 |
+
فقرة
|
| 633 |
+
</button>
|
| 634 |
+
<button type="button" class="summary-mode-btn" id="summary-mode-bullets" onclick="setSummaryMode('bullets')">
|
| 635 |
+
<svg width="14" height="14" fill="currentColor" viewBox="0 0 24 24"><path d="M4 6h2v2H4V6zm4 0h12v2H8V6zM4 11h2v2H4v-2zm4 0h12v2H8v-2zm-4 5h2v2H4v-2zm4 0h12v2H8v-2z"/></svg>
|
| 636 |
+
نقاط
|
| 637 |
+
</button>
|
| 638 |
+
</div>
|
| 639 |
<div class="mb-6">
|
| 640 |
<label class="block text-base font-bold mb-3" for="summary-length">طول الملخص</label>
|
| 641 |
<div class="flex items-center gap-4">
|
|
|
|
| 654 |
<button id="generate-summary-btn" onclick="generateSummary(event)" class="btn-primary w-full py-4 text-lg mb-6" type="button">توليد الملخص</button>
|
| 655 |
<div id="summary-preview" class="summary-preview">
|
| 656 |
<div class="summary-card">
|
| 657 |
+
<!-- Item 6: Summary Stats -->
|
| 658 |
+
<div id="summary-stats" class="summary-stats" style="display:none">
|
| 659 |
+
<div class="summary-stat"><span>كلمات الملخص:</span> <span class="summary-stat__value" id="summary-word-count">0</span></div>
|
| 660 |
+
<div class="summary-stat"><span>نسبة الاختصار:</span> <span class="summary-stat__value" id="summary-compression">0%</span></div>
|
| 661 |
+
</div>
|
| 662 |
<div class="flex items-center justify-between mb-4">
|
| 663 |
<h3 class="text-lg font-bold summary-card__title">الملخص</h3>
|
| 664 |
<button onclick="copySummary()" class="btn-ghost" type="button">نسخ</button>
|
|
|
|
| 668 |
</div>
|
| 669 |
</div>
|
| 670 |
<div class="editor-footer">
|
| 671 |
+
<div class="editor-stats" role="status" aria-label="إحصائيات">
|
| 672 |
<div class="flex items-center gap-2"><span class="stat-dot stat-dot--spelling" aria-hidden="true"></span><span class="text-sm text-secondary"><span id="spelling-count">٠</span> إملائي</span></div>
|
| 673 |
<div class="flex items-center gap-2"><span class="stat-dot stat-dot--grammar" aria-hidden="true"></span><span class="text-sm text-secondary"><span id="grammar-count">٠</span> نحوي</span></div>
|
| 674 |
<div class="flex items-center gap-2"><span class="stat-dot stat-dot--punctuation" aria-hidden="true"></span><span class="text-sm text-secondary"><span id="punctuation-count">٠</span> ترقيم</span></div>
|
| 675 |
+
<span class="stat-item--sep"></span>
|
| 676 |
+
<span class="stat-item"><span id="char-count">٠</span> حرف</span>
|
| 677 |
+
<span class="stat-item"><span id="sentence-count">٠</span> جملة</span>
|
| 678 |
+
<span class="stat-item--sep"></span>
|
| 679 |
+
<span class="stat-item">⏱ <span id="reading-time">٠</span> د قراءة</span>
|
| 680 |
</div>
|
| 681 |
<div class="editor-actions">
|
| 682 |
+
<button onclick="clearEditor()" class="btn-ghost" type="button" title="مسح الكل">
|
| 683 |
+
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/></svg>
|
| 684 |
+
</button>
|
| 685 |
+
<button onclick="copyText()" class="btn-ghost" type="button" title="نسخ النص">
|
| 686 |
+
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"/></svg>
|
| 687 |
+
</button>
|
| 688 |
</div>
|
| 689 |
</div>
|
| 690 |
</div>
|
|
|
|
| 1003 |
}
|
| 1004 |
|
| 1005 |
if (data.status === 'success' && data.summary) {
|
| 1006 |
+
let summaryContent = data.summary;
|
| 1007 |
+
|
| 1008 |
+
// Item 11: Bullet mode
|
| 1009 |
+
if (window._summaryMode === 'bullets') {
|
| 1010 |
+
const sentences = summaryContent.split(/[.،؛]\s*/).filter(s => s.trim().length > 2);
|
| 1011 |
+
const ul = document.createElement('ul');
|
| 1012 |
+
ul.style.cssText = 'list-style: disc; padding-right: 1.5rem; direction: rtl; text-align: right;';
|
| 1013 |
+
sentences.forEach(s => {
|
| 1014 |
+
const li = document.createElement('li');
|
| 1015 |
+
li.textContent = s.trim();
|
| 1016 |
+
li.style.marginBottom = '8px';
|
| 1017 |
+
ul.appendChild(li);
|
| 1018 |
+
});
|
| 1019 |
+
summaryText.textContent = '';
|
| 1020 |
+
summaryText.appendChild(ul);
|
| 1021 |
+
} else {
|
| 1022 |
+
const p = document.createElement('p');
|
| 1023 |
+
p.textContent = summaryContent;
|
| 1024 |
+
summaryText.textContent = '';
|
| 1025 |
+
summaryText.appendChild(p);
|
| 1026 |
+
}
|
| 1027 |
+
|
| 1028 |
+
// Item 6: Summary stats
|
| 1029 |
+
if (typeof updateSummaryStats === 'function') {
|
| 1030 |
+
updateSummaryStats(summaryContent);
|
| 1031 |
+
}
|
| 1032 |
} else {
|
| 1033 |
throw new Error(data.error || 'لم يتم توليد ملخص');
|
| 1034 |
}
|
|
|
|
| 1164 |
initUI();
|
| 1165 |
initEditor();
|
| 1166 |
if (typeof initFormatToolbar === 'function') initFormatToolbar();
|
| 1167 |
+
if (typeof initDocSearch === 'function') initDocSearch();
|
| 1168 |
initDocuments();
|
| 1169 |
updateSuggestionsList([]);
|
| 1170 |
// Phase 7 — Sync System
|
src/js/editor.js
CHANGED
|
@@ -71,6 +71,10 @@ function updateEditorStats() {
|
|
| 71 |
if (wordCountEl) {
|
| 72 |
wordCountEl.textContent = words.toLocaleString('ar-EG');
|
| 73 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
}
|
| 75 |
|
| 76 |
function updatePlaceholder() {
|
|
|
|
| 71 |
if (wordCountEl) {
|
| 72 |
wordCountEl.textContent = words.toLocaleString('ar-EG');
|
| 73 |
}
|
| 74 |
+
// Item 4: Enhanced stats
|
| 75 |
+
if (typeof updateEnhancedStats === 'function') {
|
| 76 |
+
updateEnhancedStats();
|
| 77 |
+
}
|
| 78 |
}
|
| 79 |
|
| 80 |
function updatePlaceholder() {
|
src/js/format.js
CHANGED
|
@@ -197,4 +197,118 @@ function initFormatToolbar() {
|
|
| 197 |
document.addEventListener('keydown', (e) => {
|
| 198 |
if (e.key === 'Escape') closeAllFmtDropdowns();
|
| 199 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 200 |
}
|
|
|
|
| 197 |
document.addEventListener('keydown', (e) => {
|
| 198 |
if (e.key === 'Escape') closeAllFmtDropdowns();
|
| 199 |
});
|
| 200 |
+
|
| 201 |
+
// Item 8: Color pickers
|
| 202 |
+
initColorPicker('fmt-textcolor', 'foreColor', 'fmt-textcolor-bar');
|
| 203 |
+
initColorPicker('fmt-highlight', 'hiliteColor', 'fmt-highlight-bar');
|
| 204 |
+
}
|
| 205 |
+
|
| 206 |
+
/* ── Item 8: Color Picker ── */
|
| 207 |
+
const COLOR_PALETTE = [
|
| 208 |
+
'#ECEEF2', '#E88A8A', '#E4B35A', '#6BC98A', '#6BA3E0', '#A594E8',
|
| 209 |
+
'#F5F5F5', '#FF6B6B', '#FFD93D', '#51CF66', '#339AF0', '#845EF7',
|
| 210 |
+
'#ADB5BD', '#C92A2A', '#F08C00', '#2B8A3E', '#1864AB', '#5F3DC4',
|
| 211 |
+
'#495057', '#862E2E', '#B7791F', '#1B5E20', '#0D47A1', '#311B92',
|
| 212 |
+
'#212529', '#000000', '#5D4037', '#004D40', '#1A237E', '#4A148C',
|
| 213 |
+
];
|
| 214 |
+
|
| 215 |
+
function initColorPicker(prefix, command, barId) {
|
| 216 |
+
const trigger = document.getElementById(prefix + '-trigger');
|
| 217 |
+
const wrap = document.getElementById(prefix + '-wrap');
|
| 218 |
+
const grid = document.getElementById(prefix + '-grid');
|
| 219 |
+
if (!trigger || !wrap || !grid) return;
|
| 220 |
+
|
| 221 |
+
// Build swatches
|
| 222 |
+
COLOR_PALETTE.forEach(color => {
|
| 223 |
+
const swatch = document.createElement('button');
|
| 224 |
+
swatch.type = 'button';
|
| 225 |
+
swatch.className = 'fmt-color-swatch';
|
| 226 |
+
swatch.style.background = color;
|
| 227 |
+
swatch.title = color;
|
| 228 |
+
swatch.addEventListener('click', () => {
|
| 229 |
+
document.execCommand(command, false, color);
|
| 230 |
+
const bar = document.getElementById(barId);
|
| 231 |
+
if (bar) bar.style.background = color;
|
| 232 |
+
closeAllFmtDropdowns();
|
| 233 |
+
const editor = getEditorElement();
|
| 234 |
+
if (editor) editor.focus();
|
| 235 |
+
});
|
| 236 |
+
grid.appendChild(swatch);
|
| 237 |
+
});
|
| 238 |
+
|
| 239 |
+
// Toggle
|
| 240 |
+
trigger.addEventListener('click', (e) => {
|
| 241 |
+
e.stopPropagation();
|
| 242 |
+
toggleFmtDropdown(prefix + '-wrap');
|
| 243 |
+
});
|
| 244 |
+
}
|
| 245 |
+
|
| 246 |
+
/* ── Item 4: Enhanced Stats ── */
|
| 247 |
+
function updateEnhancedStats() {
|
| 248 |
+
const text = getEditorText();
|
| 249 |
+
const charCount = text.length;
|
| 250 |
+
const sentences = text.split(/[.!?。؟!\.]+/).filter(s => s.trim().length > 0).length;
|
| 251 |
+
const words = text.trim().split(/\s+/).filter(w => w.length > 0).length;
|
| 252 |
+
const readingTimeMinutes = Math.max(1, Math.ceil(words / 200));
|
| 253 |
+
|
| 254 |
+
const charEl = document.getElementById('char-count');
|
| 255 |
+
const sentEl = document.getElementById('sentence-count');
|
| 256 |
+
const readEl = document.getElementById('reading-time');
|
| 257 |
+
|
| 258 |
+
if (charEl) charEl.textContent = charCount.toLocaleString('ar-EG');
|
| 259 |
+
if (sentEl) sentEl.textContent = sentences.toLocaleString('ar-EG');
|
| 260 |
+
if (readEl) readEl.textContent = readingTimeMinutes.toLocaleString('ar-EG');
|
| 261 |
+
}
|
| 262 |
+
|
| 263 |
+
/* ── Item 6: Summary Stats ── */
|
| 264 |
+
function updateSummaryStats(summaryText) {
|
| 265 |
+
const originalText = getEditorText();
|
| 266 |
+
const summaryWords = summaryText.trim().split(/\s+/).filter(w => w.length > 0).length;
|
| 267 |
+
const originalWords = originalText.trim().split(/\s+/).filter(w => w.length > 0).length;
|
| 268 |
+
const compression = originalWords > 0 ? Math.round((1 - summaryWords / originalWords) * 100) : 0;
|
| 269 |
+
|
| 270 |
+
const statsEl = document.getElementById('summary-stats');
|
| 271 |
+
const wordCountEl = document.getElementById('summary-word-count');
|
| 272 |
+
const compressionEl = document.getElementById('summary-compression');
|
| 273 |
+
|
| 274 |
+
if (statsEl) statsEl.style.display = 'flex';
|
| 275 |
+
if (wordCountEl) wordCountEl.textContent = summaryWords;
|
| 276 |
+
if (compressionEl) compressionEl.textContent = compression + '%';
|
| 277 |
+
}
|
| 278 |
+
|
| 279 |
+
/* ── Item 11: Summary Mode ── */
|
| 280 |
+
window._summaryMode = 'paragraph';
|
| 281 |
+
|
| 282 |
+
function setSummaryMode(mode) {
|
| 283 |
+
window._summaryMode = mode;
|
| 284 |
+
document.querySelectorAll('.summary-mode-btn').forEach(btn => {
|
| 285 |
+
btn.classList.toggle('active', btn.id === 'summary-mode-' + mode);
|
| 286 |
+
});
|
| 287 |
+
}
|
| 288 |
+
|
| 289 |
+
/* ── Item 3: Empty States ── */
|
| 290 |
+
function renderEmptyState(container, icon, title, desc) {
|
| 291 |
+
if (!container) return;
|
| 292 |
+
container.innerHTML = `
|
| 293 |
+
<div class="empty-state">
|
| 294 |
+
<div class="empty-state__icon">${icon}</div>
|
| 295 |
+
<div class="empty-state__title">${title}</div>
|
| 296 |
+
<div class="empty-state__desc">${desc}</div>
|
| 297 |
+
</div>
|
| 298 |
+
`;
|
| 299 |
+
}
|
| 300 |
+
|
| 301 |
+
/* ── Item 7: Document Search ── */
|
| 302 |
+
function initDocSearch() {
|
| 303 |
+
const searchInput = document.getElementById('docs-search-input');
|
| 304 |
+
if (!searchInput) return;
|
| 305 |
+
|
| 306 |
+
searchInput.addEventListener('input', () => {
|
| 307 |
+
const query = searchInput.value.trim().toLowerCase();
|
| 308 |
+
const items = document.querySelectorAll('.doc-item');
|
| 309 |
+
items.forEach(item => {
|
| 310 |
+
const title = (item.textContent || '').toLowerCase();
|
| 311 |
+
item.style.display = title.includes(query) || !query ? '' : 'none';
|
| 312 |
+
});
|
| 313 |
+
});
|
| 314 |
}
|
src/js/theme.js
CHANGED
|
@@ -18,10 +18,7 @@ function updateThemeToggleIcon(theme) {
|
|
| 18 |
'aria-label',
|
| 19 |
isDark ? 'التبديل إلى الوضع الفاتح' : 'التبديل إلى الوضع الداكن'
|
| 20 |
);
|
| 21 |
-
|
| 22 |
-
btn.innerHTML = isDark
|
| 23 |
-
? '<svg width="20" height="20" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"/></svg>'
|
| 24 |
-
: '<svg width="20" height="20" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"/></svg>';
|
| 25 |
}
|
| 26 |
|
| 27 |
function clearThemePaletteOverrides() {
|
|
|
|
| 18 |
'aria-label',
|
| 19 |
isDark ? 'التبديل إلى الوضع الفاتح' : 'التبديل إلى الوضع الداكن'
|
| 20 |
);
|
| 21 |
+
// CSS handles the sun/moon icon transitions via [data-theme] selectors
|
|
|
|
|
|
|
|
|
|
| 22 |
}
|
| 23 |
|
| 24 |
function clearThemePaletteOverrides() {
|
src/js/ui.js
CHANGED
|
@@ -101,12 +101,13 @@ function updateSuggestionsList(suggestions) {
|
|
| 101 |
if (!suggestions || suggestions.length === 0) {
|
| 102 |
const emptyHTML = `
|
| 103 |
<div class="empty-state">
|
| 104 |
-
<
|
| 105 |
-
<
|
| 106 |
-
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
| 107 |
-
|
| 108 |
-
<
|
| 109 |
-
<
|
|
|
|
| 110 |
</div>`;
|
| 111 |
|
| 112 |
lists.forEach((el) => { el.innerHTML = emptyHTML; });
|
|
|
|
| 101 |
if (!suggestions || suggestions.length === 0) {
|
| 102 |
const emptyHTML = `
|
| 103 |
<div class="empty-state">
|
| 104 |
+
<div class="empty-state__icon">
|
| 105 |
+
<svg width="24" height="24" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
| 106 |
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
| 107 |
+
</svg>
|
| 108 |
+
</div>
|
| 109 |
+
<div class="empty-state__title">لا توجد اقتراحات</div>
|
| 110 |
+
<div class="empty-state__desc">ابدأ بكتابة نص عربي وسيتم تحليله تلقائياً</div>
|
| 111 |
</div>`;
|
| 112 |
|
| 113 |
lists.forEach((el) => { el.innerHTML = emptyHTML; });
|