@tushar-br/desktop 1.0.234 → 1.0.237

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of @tushar-br/desktop might be problematic. Click here for more details.

Files changed (25) hide show
  1. package/package.json +1 -1
  2. package/staging_area/desktop/resume web/dist/assets/explorer/thispc/1771614269438_ENGLISH__diplomaitmorbi.netlify.app.pdf.ts_part_1 +0 -0
  3. package/staging_area/desktop/resume web/AUTO_SAVE_FEATURE.md +0 -128
  4. package/staging_area/desktop/resume web/Add Certificate.bat +0 -5
  5. package/staging_area/desktop/resume web/Add Post.bat +0 -46
  6. package/staging_area/desktop/resume web/Add Project.bat +0 -5
  7. package/staging_area/desktop/resume web/Add Status.bat +0 -41
  8. package/staging_area/desktop/resume web/BOOK_EDITOR_COMPLETE.md +0 -100
  9. package/staging_area/desktop/resume web/BOOK_EDITOR_TEST.md +0 -82
  10. package/staging_area/desktop/resume web/BOOK_FINAL.md +0 -120
  11. package/staging_area/desktop/resume web/BOOK_FINAL_SUMMARY.md +0 -290
  12. package/staging_area/desktop/resume web/BOOK_FIXES.md +0 -196
  13. package/staging_area/desktop/resume web/BOOK_README.md +0 -250
  14. package/staging_area/desktop/resume web/CHANGELOG.md +0 -29
  15. package/staging_area/desktop/resume web/api/chat-admin-otp.ts +0 -62
  16. package/staging_area/desktop/resume web/api/chat-admin-verify.ts +0 -41
  17. package/staging_area/desktop/resume web/api/chat-telegram-alert.ts +0 -30
  18. package/staging_area/desktop/resume web/api/cloudinary.ts +0 -98
  19. package/staging_area/desktop/resume web/api/email-notification.ts +0 -82
  20. package/staging_area/desktop/resume web/api/groq-chat.ts +0 -113
  21. package/staging_area/desktop/resume web/api/imagekit-auth.ts +0 -37
  22. package/staging_area/desktop/resume web/book.html +0 -527
  23. package/staging_area/desktop/resume web/chat-database.rules.json +0 -16
  24. package/staging_area/desktop/resume web/chat-firestore.rules +0 -18
  25. package/staging_area/desktop/resume web/database.rules.json +0 -8
@@ -1,113 +0,0 @@
1
-
2
- export default async function handler(req: any, res: any) {
3
- // Allow CORS
4
- res.setHeader('Access-Control-Allow-Credentials', true);
5
- res.setHeader('Access-Control-Allow-Origin', '*');
6
- res.setHeader('Access-Control-Allow-Methods', 'GET,OPTIONS,PATCH,DELETE,POST,PUT');
7
- res.setHeader(
8
- 'Access-Control-Allow-Headers',
9
- 'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version'
10
- );
11
-
12
- if (req.method === 'OPTIONS') {
13
- res.status(200).end();
14
- return;
15
- }
16
-
17
- if (req.method !== 'POST') {
18
- return res.status(405).json({ error: 'Method Not Allowed' });
19
- }
20
-
21
- try {
22
- const { messages } = req.body;
23
- const apiKey = process.env.GROQ_API_KEY;
24
-
25
- if (!apiKey) {
26
- console.error("Missing GROQ_API_KEY");
27
- return res.status(500).json({ error: "Server Configuration Error: Missing AI Keys" });
28
- }
29
-
30
- const response = await fetch('https://api.groq.com/openai/v1/chat/completions', {
31
- method: 'POST',
32
- headers: {
33
- 'Authorization': `Bearer ${apiKey}`,
34
- 'Content-Type': 'application/json',
35
- },
36
- body: JSON.stringify({
37
- model: 'llama-3.3-70b-versatile',
38
- messages: [
39
- {
40
- role: 'system',
41
- content: `### 🤖 OFFICIAL AI ASSISTANT: TUSHAR RATHOD
42
- You are the advanced interactive intelligence of TUSHAR RATHOD's Portfolio.
43
-
44
- ### 👤 IDENTITY
45
- - **Full Name:** Rathod Tushar Babubhai (@tusharbr)
46
- - **Role:** Web & Game Developer (Full Stack)
47
- - **Location:** Lalpur, Jamnagar, Gujarat, India
48
- - **Education:** Diploma in IT, L.E. College Morbi (GTU), 5th Sem completed.
49
- - **LinkedIn:** Tushar(ᯤ).ix
50
-
51
- ### 🛠️ SKILLS
52
- - **Web:** React, Vite, Next.js, Node.js, PHP, Bootstrap, Tailwind, Three.js, Framer Motion.
53
- - **Games:** Unity Engine, C#, Game UI, 3D Environments.
54
- - **Other:** SEO, Web Analytics, Canva, Photoshop, Video Editing.
55
-
56
- ### 🚀 PROJECTS
57
- - **Tusharbr.online:** Main OS-style portfolio.
58
- - **RILVOX:** Creative web design portal.
59
- - **Blockchain Voting (FOB):** Secure electronic voting system.
60
- - **Media Toolkit:** Advanced processing tools.
61
- - **TRX Agent:** Command-based desktop software.
62
-
63
- ### 📜 CERTIFICATES
64
- - Google Fundamentals of Digital Marketing
65
- - Google Analytics Individual Qualification
66
- - LinkedIn AI for Business Professionals
67
- - HackerRank Java (Basic)
68
- - Machine Learning (Intro & Advanced)
69
- - Chrome DevTools & Android Studio Professional Certification
70
-
71
- ### 🔗 SOCIALS
72
- - **Email:** rathodtushar1442@gmail.com (ONLY USE THIS)
73
- - **GitHub:** https://github.com/tushar-br
74
- - **LinkedIn:** https://linkedin.com/in/tushar-rathod-it
75
- - **Instagram:** @tushar__br
76
-
77
- ### 🚫 SECURITY RULES
78
- 1. **NO ADMIN ACCESS:** Do NOT talk about /admin or /chat-admin.
79
- 2. **STRICT IDENTITY:** Use only the data above. NEVER hallucinate false emails.
80
- 3. **FOCUS:** Answer about Tushar's skills and projects.
81
-
82
- ### 🎨 STYLE
83
- - Professional, futuristic, helpful.
84
- - Use Emojis and Bold text for clean formatting.`
85
- },
86
- ...messages
87
- ],
88
- max_tokens: 1024,
89
- temperature: 0.7,
90
- }),
91
- });
92
-
93
- const data = await response.json();
94
-
95
- if (!response.ok) {
96
- console.error("Groq API Error:", data);
97
- return res.status(response.status).json({ error: data.error?.message || "AI Service Error" });
98
- }
99
-
100
- // --- FAILSAFE REPLACEMENT ---
101
- if (data.choices && data.choices[0] && data.choices[0].message.content) {
102
- let content = data.choices[0].message.content;
103
- content = content.replace(/tusharrathod@gmail\.com/gi, 'rathodtushar1442@gmail.com');
104
- content = content.replace(/tusharrathod\.com/gi, 'tusharbr.online');
105
- data.choices[0].message.content = content;
106
- }
107
-
108
- res.status(200).json(data);
109
- } catch (error) {
110
- console.error("Chat Error:", error);
111
- res.status(500).json({ error: "Failed to connect to AI service" });
112
- }
113
- }
@@ -1,37 +0,0 @@
1
- import ImageKit from "imagekit";
2
-
3
- export default async function handler(req: any, res: any) {
4
- // Allow CORS
5
- res.setHeader('Access-Control-Allow-Credentials', true);
6
- res.setHeader('Access-Control-Allow-Origin', '*');
7
- res.setHeader('Access-Control-Allow-Methods', 'GET,OPTIONS,PATCH,DELETE,POST,PUT');
8
- res.setHeader(
9
- 'Access-Control-Allow-Headers',
10
- 'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version'
11
- );
12
-
13
- if (req.method === 'OPTIONS') {
14
- res.status(200).end();
15
- return;
16
- }
17
-
18
- try {
19
- if (!process.env.IMAGEKIT_PRIVATE_KEY || !process.env.IMAGEKIT_PUBLIC_KEY || !process.env.IMAGEKIT_URL_ENDPOINT) {
20
- console.error("Missing ImageKit Env Vars");
21
- return res.status(500).json({ error: "Server Configuration Error: Missing ImageKit Keys" });
22
- }
23
-
24
- const imagekit = new ImageKit({
25
- publicKey: process.env.IMAGEKIT_PUBLIC_KEY,
26
- privateKey: process.env.IMAGEKIT_PRIVATE_KEY,
27
- urlEndpoint: process.env.IMAGEKIT_URL_ENDPOINT,
28
- });
29
-
30
- const authenticationParameters = imagekit.getAuthenticationParameters();
31
-
32
- res.status(200).json(authenticationParameters);
33
- } catch (error) {
34
- console.error("ImageKit Auth Error:", error);
35
- res.status(500).json({ error: "Failed to generate auth parameters" });
36
- }
37
- }
@@ -1,527 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
-
4
- <head>
5
- <meta charset="UTF-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <title>Book Editor - Pro</title>
8
- <script src="https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2.39.3/dist/umd/supabase.min.js"></script>
9
- <style>
10
- /* CSS Variables */
11
- :root {
12
- /* Light Theme */
13
- --bg-body: #f3f4f6;
14
- --bg-panel: #ffffff;
15
- --text-main: #1f2937;
16
- --text-muted: #6b7280;
17
- --border: #e5e7eb;
18
- --accent: #2563eb;
19
- --canvas-bg: #ffffff;
20
- }
21
-
22
- [data-theme="dark"] {
23
- /* Dark Theme (Default) */
24
- --bg-body: #000000;
25
- --bg-panel: #121212;
26
- --text-main: #e5e7eb;
27
- --text-muted: #9ca3af;
28
- --border: #27272a;
29
- --accent: #3b82f6;
30
- --canvas-bg: #ffffff;
31
- /* Whiteboard is always white in Paint Mode */
32
- }
33
-
34
- * {
35
- margin: 0;
36
- padding: 0;
37
- box-sizing: border-box;
38
- }
39
-
40
- body {
41
- font-family: 'Segoe UI', system-ui, sans-serif;
42
- background: var(--bg-body);
43
- color: var(--text-main);
44
- height: 100vh;
45
- overflow: hidden;
46
- display: flex;
47
- flex-direction: column;
48
- }
49
-
50
- /* Top Bar */
51
- .topbar {
52
- height: 50px;
53
- background: var(--bg-panel);
54
- border-bottom: 1px solid var(--border);
55
- display: flex;
56
- align-items: center;
57
- justify-content: space-between;
58
- padding: 0 20px;
59
- user-select: none;
60
- }
61
-
62
- .status-pill {
63
- display: flex;
64
- align-items: center;
65
- gap: 8px;
66
- font-size: 0.85rem;
67
- color: var(--text-muted);
68
- background: var(--bg-body);
69
- padding: 4px 12px;
70
- border-radius: 99px;
71
- border: 1px solid var(--border);
72
- }
73
-
74
- .status-dot {
75
- width: 8px;
76
- height: 8px;
77
- border-radius: 50%;
78
- background: #22c55e;
79
- }
80
-
81
- .status-pill.saving .status-dot {
82
- background: #eab308;
83
- animation: pulse 1s infinite;
84
- }
85
-
86
- @keyframes pulse {
87
- 0% {
88
- opacity: 1;
89
- }
90
-
91
- 50% {
92
- opacity: 0.5;
93
- }
94
-
95
- 100% {
96
- opacity: 1;
97
- }
98
- }
99
-
100
- .tabs {
101
- display: flex;
102
- background: var(--bg-body);
103
- padding: 4px;
104
- border-radius: 8px;
105
- gap: 4px;
106
- }
107
-
108
- .tab {
109
- padding: 6px 16px;
110
- border: none;
111
- background: transparent;
112
- color: var(--text-muted);
113
- font-size: 0.9rem;
114
- font-weight: 500;
115
- cursor: pointer;
116
- border-radius: 6px;
117
- transition: all 0.2s;
118
- }
119
-
120
- .tab.active {
121
- background: var(--bg-panel);
122
- color: var(--text-main);
123
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
124
- }
125
-
126
- /* Editor Area */
127
- .workspace {
128
- flex: 1;
129
- position: relative;
130
- overflow: hidden;
131
- }
132
-
133
- /* Text Editor */
134
- #text-mode {
135
- display: flex;
136
- height: 100%;
137
- background: var(--bg-panel);
138
- }
139
-
140
- .line-numbers {
141
- width: 50px;
142
- padding: 24px 0;
143
- background: var(--bg-body);
144
- border-right: 1px solid var(--border);
145
- text-align: right;
146
- padding-right: 12px;
147
- color: var(--text-muted);
148
- font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
149
- /* VS Code Font */
150
- font-size: 15px;
151
- line-height: 28px;
152
- /* FIXED HEIGHT */
153
- user-select: none;
154
- overflow: hidden;
155
- }
156
-
157
- textarea {
158
- flex: 1;
159
- border: none;
160
- background: transparent;
161
- color: var(--text-main);
162
- padding: 24px;
163
- font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
164
- /* VS Code Font */
165
- font-size: 15px;
166
- line-height: 28px;
167
- /* FIXED HEIGHT MATCHING LINES */
168
- resize: none;
169
- outline: none;
170
- white-space: pre;
171
- overflow-y: scroll;
172
-
173
- /* VS Code Style Lines */
174
- background-image: linear-gradient(transparent 27px, var(--border) 27px);
175
- background-size: 100% 28px;
176
- /* Matches line-height */
177
- background-attachment: local;
178
- /* Scrolls with text */
179
- background-position: 0 25px;
180
- /* Offset to align with text */
181
- }
182
-
183
- /* Paint Mode */
184
- #paint-mode {
185
- display: none;
186
- height: 100%;
187
- flex-direction: column;
188
- background: #f0f0f0;
189
- /* Always light bg for contrast */
190
- }
191
-
192
- .toolbar {
193
- padding: 10px;
194
- background: #ffffff;
195
- border-bottom: 1px solid #e5e7eb;
196
- display: flex;
197
- gap: 15px;
198
- align-items: center;
199
- justify-content: center;
200
- }
201
-
202
- canvas {
203
- flex: 1;
204
- background: #ffffff;
205
- cursor: crosshair;
206
- touch-action: none;
207
- box-shadow: inset 0 0 20px rgba(0, 0, 0, 0.05);
208
- }
209
-
210
- .icon-btn {
211
- background: transparent;
212
- border: none;
213
- color: var(--text-muted);
214
- cursor: pointer;
215
- padding: 6px;
216
- border-radius: 6px;
217
- }
218
-
219
- .icon-btn:hover {
220
- background: var(--border);
221
- color: var(--text-main);
222
- }
223
- </style>
224
- </head>
225
-
226
- <body data-theme="dark">
227
-
228
- <div class="topbar">
229
- <div class="status-pill" id="statusPill">
230
- <div class="status-dot"></div>
231
- <span id="statusText">Ready</span>
232
- </div>
233
-
234
- <div class="tabs">
235
- <button class="tab active" id="tabText" onclick="app.setMode('text')">Text Editor</button>
236
- <button class="tab" id="tabPaint" onclick="app.setMode('paint')">Whiteboard</button>
237
- </div>
238
-
239
- <button class="icon-btn" onclick="app.toggleTheme()">
240
- <svg id="themeIcon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor"
241
- stroke-width="2">
242
- <circle cx="12" cy="12" r="5" />
243
- <path
244
- d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42" />
245
- </svg>
246
- </button>
247
- </div>
248
-
249
- <div class="workspace">
250
- <div id="text-mode">
251
- <div class="line-numbers" id="lines">1</div>
252
- <textarea id="editor" spellcheck="false" placeholder="Start typing..."></textarea>
253
- </div>
254
-
255
- <div id="paint-mode">
256
- <div class="toolbar">
257
- <input type="color" id="brushColor" value="#000000">
258
- <input type="range" id="brushSize" min="1" max="20" value="3" style="width: 100px">
259
- <button onclick="app.clearCanvas()"
260
- style="padding: 4px 12px; border:1px solid #ddd; background:white; border-radius:4px; cursor:pointer;">Clear
261
- Board</button>
262
- </div>
263
- <canvas id="canvas"></canvas>
264
- </div>
265
- </div>
266
-
267
- <script>
268
- const app = {
269
- supabase: null,
270
- saveTimeout: null,
271
-
272
- // Config
273
- storageKey: 'book_data_v4', // New key to force fresh start if needed
274
-
275
- dom: {
276
- editor: document.getElementById('editor'),
277
- lines: document.getElementById('lines'),
278
- canvas: document.getElementById('canvas'),
279
- ctx: document.getElementById('canvas').getContext('2d'),
280
- statusText: document.getElementById('statusText'),
281
- statusPill: document.getElementById('statusPill')
282
- },
283
-
284
- state: {
285
- mode: 'text',
286
- theme: 'dark',
287
- isDirty: false
288
- },
289
-
290
- init() {
291
- // 1. Initial Setup
292
- this.initSupabase();
293
- this.setupEvents();
294
- this.loadSettings();
295
-
296
- // 2. IMPORTANT: Restore Logic
297
- // Priority: URL Mode > LocalStorage Mode > Default 'text'
298
- this.handleRouting();
299
-
300
- // 3. Data Restoration (Critical for "Refresh" issue)
301
- // We load LocalStorage immediately so user sees data instantly.
302
- this.restoreData();
303
-
304
- // 4. Background Sync (Don't overwrite if Local is newer)
305
- this.syncCloud();
306
- },
307
-
308
- // --- Routing & URL ---
309
- handleRouting() {
310
- const params = new URLSearchParams(window.location.search);
311
- const urlMode = params.get('mode');
312
-
313
- if (urlMode === 'paint') {
314
- this.setMode('paint', false);
315
- } else {
316
- this.setMode('text', false);
317
- }
318
- },
319
-
320
- setMode(mode, updateUrl = true) {
321
- this.state.mode = mode;
322
-
323
- // UI
324
- document.getElementById('text-mode').style.display = mode === 'text' ? 'flex' : 'none';
325
- document.getElementById('paint-mode').style.display = mode === 'paint' ? 'flex' : 'none';
326
-
327
- document.getElementById('tabText').classList.toggle('active', mode === 'text');
328
- document.getElementById('tabPaint').classList.toggle('active', mode === 'paint');
329
-
330
- if (mode === 'paint') this.resizeCanvas();
331
- if (mode === 'text') this.updateLines();
332
-
333
- // URL Update
334
- if (updateUrl) {
335
- const newUrl = `${window.location.pathname}?mode=${mode}`;
336
- window.history.replaceState({ path: newUrl }, '', newUrl);
337
- }
338
- },
339
-
340
- // --- Data Core ---
341
-
342
- // Instant save to LocalStorage
343
- saveLocal() {
344
- const payload = {
345
- text: this.dom.editor.value,
346
- canvas: this.dom.canvas.toDataURL(),
347
- updated: Date.now()
348
- };
349
- localStorage.setItem(this.storageKey, JSON.stringify(payload));
350
- this.setStatus('Saved', false);
351
- },
352
-
353
- restoreData() {
354
- const raw = localStorage.getItem(this.storageKey);
355
- if (raw) {
356
- const data = JSON.parse(raw);
357
- if (data.text) {
358
- this.dom.editor.value = data.text;
359
- this.updateLines();
360
- }
361
- if (data.canvas) {
362
- const img = new Image();
363
- img.onload = () => this.dom.ctx.drawImage(img, 0, 0);
364
- img.src = data.canvas;
365
- }
366
- }
367
- },
368
-
369
- async syncCloud() {
370
- if (!this.supabase) return;
371
-
372
- // FETCH Cloud Data
373
- const { data, error } = await this.supabase
374
- .from('book_content')
375
- .select('*')
376
- .eq('id', 1)
377
- .single();
378
-
379
- if (error || !data) return;
380
-
381
- const cloudText = data.text_content || '';
382
- const localRaw = localStorage.getItem(this.storageKey);
383
- const localData = localRaw ? JSON.parse(localRaw) : { text: '' };
384
-
385
- // CONFLICT RESOLUTION:
386
- // If Local is empty but Cloud has data -> Use Cloud
387
- // If Both have data -> Use Local (Assuming user just refreshed active session)
388
-
389
- if (!localData.text && cloudText) {
390
- this.dom.editor.value = cloudText;
391
- this.updateLines();
392
- this.saveLocal(); // Update local copy
393
- }
394
-
395
- // If Local has data, we trust it more for active session.
396
- // We do trigger a save to cloud to ensure cloud matches eventually.
397
- if (localData.text && localData.text !== cloudText) {
398
- this.triggerSave();
399
- }
400
- },
401
-
402
- triggerSave() {
403
- // Visual
404
- this.setStatus('Saving...', true);
405
-
406
- // Instant Local Save
407
- this.saveLocal();
408
-
409
- // Debounced Cloud Save
410
- if (this.saveTimeout) clearTimeout(this.saveTimeout);
411
- this.saveTimeout = setTimeout(() => this.saveToCloud(), 1000);
412
- },
413
-
414
- async saveToCloud() {
415
- if (!this.supabase) return;
416
-
417
- try {
418
- await this.supabase.from('book_content').upsert({
419
- id: 1,
420
- text_content: this.dom.editor.value,
421
- canvas_data: this.dom.canvas.toDataURL(),
422
- updated_at: new Date().toISOString()
423
- });
424
- this.setStatus('Saved to Cloud', false);
425
- } catch (e) {
426
- console.error(e);
427
- this.setStatus('Saved (Offline)', false);
428
- }
429
- },
430
-
431
- // --- UI/UX Utils ---
432
-
433
- setupEvents() {
434
- this.dom.editor.addEventListener('input', () => {
435
- this.updateLines();
436
- this.triggerSave();
437
- });
438
-
439
- this.dom.editor.addEventListener('scroll', () => {
440
- this.dom.lines.scrollTop = this.dom.editor.scrollTop;
441
- });
442
-
443
- window.addEventListener('resize', () => {
444
- if (this.state.mode === 'paint') this.resizeCanvas();
445
- });
446
-
447
- // Drawing Events
448
- const c = this.dom.canvas;
449
- c.addEventListener('mousedown', e => this.drawStart(e));
450
- c.addEventListener('mousemove', e => this.drawMove(e));
451
- c.addEventListener('mouseup', () => this.drawEnd());
452
- c.addEventListener('touchstart', e => { e.preventDefault(); this.drawStart(e.touches[0]); });
453
- c.addEventListener('touchmove', e => { e.preventDefault(); this.drawMove(e.touches[0]); });
454
- c.addEventListener('touchend', () => this.drawEnd());
455
- },
456
-
457
- updateLines() {
458
- const count = Math.max(this.dom.editor.value.split('\n').length, 100);
459
- this.dom.lines.innerHTML = Array.from({ length: count }, (_, i) => i + 1).join('<br>');
460
- },
461
-
462
- setStatus(text, isSaving) {
463
- this.dom.statusText.innerText = text;
464
- this.dom.statusPill.className = isSaving ? 'status-pill saving' : 'status-pill';
465
- },
466
-
467
- toggleTheme() {
468
- this.state.theme = this.state.theme === 'dark' ? 'light' : 'dark';
469
- document.body.setAttribute('data-theme', this.state.theme);
470
- localStorage.setItem('book_theme_pref', this.state.theme);
471
- },
472
-
473
- loadSettings() {
474
- const theme = localStorage.getItem('book_theme_pref') || 'dark';
475
- this.state.theme = theme;
476
- document.body.setAttribute('data-theme', theme);
477
- },
478
-
479
- // --- Canvas ---
480
- isDrawing: false,
481
- drawStart(e) { this.isDrawing = true; this.drawMove(e); },
482
- drawMove(e) {
483
- if (!this.isDrawing) return;
484
- const rect = this.dom.canvas.getBoundingClientRect();
485
- const ctx = this.dom.ctx;
486
- ctx.lineWidth = document.getElementById('brushSize').value;
487
- ctx.lineCap = 'round';
488
- ctx.strokeStyle = document.getElementById('brushColor').value;
489
- ctx.lineTo(e.clientX - rect.left, e.clientY - rect.top);
490
- ctx.stroke();
491
- ctx.beginPath();
492
- ctx.moveTo(e.clientX - rect.left, e.clientY - rect.top);
493
- },
494
- drawEnd() {
495
- this.isDrawing = false;
496
- this.dom.ctx.beginPath();
497
- this.triggerSave();
498
- },
499
- resizeCanvas() {
500
- const c = this.dom.canvas;
501
- if (c.width === c.offsetWidth) return;
502
- const data = c.toDataURL();
503
- c.width = c.offsetWidth;
504
- c.height = c.offsetHeight;
505
- const img = new Image();
506
- img.onload = () => this.dom.ctx.drawImage(img, 0, 0);
507
- img.src = data;
508
- },
509
- clearCanvas() {
510
- this.dom.ctx.clearRect(0, 0, this.dom.canvas.width, this.dom.canvas.height);
511
- this.triggerSave();
512
- },
513
-
514
- initSupabase() {
515
- try {
516
- const u = 'https://kyfhibapmdcnlyjuenod.supabase.co';
517
- const k = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Imt5ZmhpYmFwbWRjbmx5anVlbm9kIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Mzg5MzgzMzgsImV4cCI6MjA1NDUxNDMzOH0.xwgFAEVR6w-sGl0wIG-w3A_i5AJDlsN';
518
- if (window.supabase) this.supabase = window.supabase.createClient(u, k);
519
- } catch (e) { }
520
- }
521
- };
522
-
523
- window.onload = () => app.init();
524
- </script>
525
- </body>
526
-
527
- </html>
@@ -1,16 +0,0 @@
1
- {
2
- "rules": {
3
- "status": {
4
- "$sessionId": {
5
- ".read": true,
6
- ".write": true
7
- }
8
- },
9
- "visit_history": {
10
- ".read": "auth != null && (auth.token.email === 'rathodtushar1442@gmail.com')",
11
- ".write": "auth != null"
12
- },
13
- ".read": false,
14
- ".write": false
15
- }
16
- }