Spaces:
Running
Running
Upload 4 files
Browse files- Apache License.txt +17 -0
- README.md +90 -0
- index.html +2142 -0
- 📘 Educator & Student Guide CodeTut.txt +76 -0
Apache License.txt
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Apache License
|
| 2 |
+
Version 2.0, January 2004
|
| 3 |
+
http://www.apache.org/licenses/
|
| 4 |
+
|
| 5 |
+
Copyright 2025 Shift Mind AI Labs
|
| 6 |
+
|
| 7 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
| 8 |
+
you may not use this file except in compliance with the License.
|
| 9 |
+
You may obtain a copy of the License at
|
| 10 |
+
|
| 11 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
| 12 |
+
|
| 13 |
+
Unless required by applicable law or agreed to in writing, software
|
| 14 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
| 15 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 16 |
+
See the License for the specific language governing permissions and
|
| 17 |
+
limitations under the License.
|
README.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: "🧠 CodeTutor Pro – Intelligent Code Explanation Platform"
|
| 3 |
+
emoji: "💡"
|
| 4 |
+
colorFrom: "blue"
|
| 5 |
+
colorTo: "purple"
|
| 6 |
+
sdk: "static"
|
| 7 |
+
sdk_version: "0.1.0"
|
| 8 |
+
app_file: "index.html"
|
| 9 |
+
pinned: false
|
| 10 |
+
---
|
| 11 |
+
|
| 12 |
+
# 🧠 CodeTutor Pro – Intelligent Code Explanation Platform
|
| 13 |
+
**Developed by Shift Mind AI Labs**
|
| 14 |
+
|
| 15 |
+
CodeTutor Pro is an open-source, privacy-first platform that transforms code into clear, beginner-friendly, and multi-language explanations—instantly powered by AI. Whether you are a student, teacher, or developer, this tool helps demystify code, deepen understanding, and accelerate your programming learning journey.
|
| 16 |
+
|
| 17 |
+
---
|
| 18 |
+
|
| 19 |
+
## 🚀 Features
|
| 20 |
+
|
| 21 |
+
- **Plain-Language Explanations:** Converts complex code into easy, jargon-free text.
|
| 22 |
+
- **Line-by-Line & Conceptual Analysis:** Detailed, sectioned explanations (no code snippets) with stepwise logic and key concepts.
|
| 23 |
+
- **Multi-Level Output:** Choose from “Complete Beginner” to “Advanced” for the right depth.
|
| 24 |
+
- **Supports All Languages:** Works with Python, Java, C++, JS, HTML, SQL, and more.
|
| 25 |
+
- **Full Multilingual UI:** 90+ languages, RTL/LTR support, instant translation (OpenAI API required).
|
| 26 |
+
- **Editable Explanations:** Output is content-editable for class notes, customization, or portfolio building.
|
| 27 |
+
- **Privacy-First:** API key and all data stored locally; never leaves your device.
|
| 28 |
+
|
| 29 |
+
---
|
| 30 |
+
|
| 31 |
+
## 🛠 How to Use
|
| 32 |
+
|
| 33 |
+
1. **Open the tool** in your browser or on Hugging Face Spaces (no install/login).
|
| 34 |
+
2. **Select your interface language** (auto-translate supported).
|
| 35 |
+
3. **Enter your OpenAI API key** (kept private in your browser).
|
| 36 |
+
4. **Paste or type your code** (any language; up to 1 million characters).
|
| 37 |
+
5. *(Optional)* Select your programming language and explanation level.
|
| 38 |
+
6. **Click “🧠 Generate Explanation”.**
|
| 39 |
+
7. **Read, edit, and copy** your customized, sectioned explanation for class, homework, or sharing.
|
| 40 |
+
8. **Switch languages or clear cache** anytime for updated UI and output.
|
| 41 |
+
|
| 42 |
+
---
|
| 43 |
+
|
| 44 |
+
## 👩🏫 For Educators: Classroom Applications
|
| 45 |
+
|
| 46 |
+
- **Instant Code Explanation:** Great for assignments, flipped learning, and project walkthroughs.
|
| 47 |
+
- **Student Differentiation:** Match output depth to learner level; use in ELL/multilingual classes.
|
| 48 |
+
- **Editable Output:** Use in LMS, printouts, or digital portfolios.
|
| 49 |
+
- **PD & Training:** Onboard new teachers to unfamiliar codebases or languages.
|
| 50 |
+
|
| 51 |
+
---
|
| 52 |
+
|
| 53 |
+
## 👨🎓 For Students: Benefits
|
| 54 |
+
|
| 55 |
+
- **Learn Any Code:** Instantly understand code in your preferred language and depth.
|
| 56 |
+
- **Practice Reflection:** Edit and personalize explanations for deeper learning.
|
| 57 |
+
- **Safe Exploration:** No accounts or data sharing—perfect for minors and privacy-sensitive contexts.
|
| 58 |
+
|
| 59 |
+
---
|
| 60 |
+
|
| 61 |
+
## 🔐 Data Privacy
|
| 62 |
+
|
| 63 |
+
- Your OpenAI API key, code, and all data are stored only on your device.
|
| 64 |
+
- Nothing is transmitted to Shift Mind AI Labs, Hugging Face, or third parties.
|
| 65 |
+
|
| 66 |
+
---
|
| 67 |
+
|
| 68 |
+
## 📄 License
|
| 69 |
+
|
| 70 |
+
Licensed under the [Apache License 2.0](./LICENSE).
|
| 71 |
+
|
| 72 |
+
---
|
| 73 |
+
|
| 74 |
+
## 🧠 About Shift Mind AI Labs
|
| 75 |
+
|
| 76 |
+
Shift Mind AI Labs builds open-source, ethical AI tools for global education, digital skills, and lifelong learning.
|
| 77 |
+
|
| 78 |
+
🌐 https://www.shiftmind.io
|
| 79 |
+
✉️ info@shiftmind.io
|
| 80 |
+
|
| 81 |
+
---
|
| 82 |
+
|
| 83 |
+
## 🙌 Contributing
|
| 84 |
+
|
| 85 |
+
Feedback, pull requests, and pilots welcome!
|
| 86 |
+
For partnerships, research, or school programs: **info@shiftmind.io**
|
| 87 |
+
|
| 88 |
+
---
|
| 89 |
+
|
| 90 |
+
*Bringing expert code explanations to every learner, everywhere, in every language.*
|
index.html
ADDED
|
@@ -0,0 +1,2142 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<title>CodeTutor Pro - Intelligent Code Explanation Platform</title>
|
| 6 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
| 7 |
+
<style>
|
| 8 |
+
:root {
|
| 9 |
+
--primary: #7c3aed;
|
| 10 |
+
--secondary: #8b5cf6;
|
| 11 |
+
--accent: #c4b5fd;
|
| 12 |
+
--background: #f8fafc;
|
| 13 |
+
--surface: #ffffff;
|
| 14 |
+
--text: #1e293b;
|
| 15 |
+
--text-secondary: #64748b;
|
| 16 |
+
--border: #e2e8f0;
|
| 17 |
+
--success: #10b981;
|
| 18 |
+
--warning: #f59e0b;
|
| 19 |
+
--error: #ef4444;
|
| 20 |
+
--shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
| 21 |
+
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
* {
|
| 25 |
+
box-sizing: border-box;
|
| 26 |
+
margin: 0;
|
| 27 |
+
padding: 0;
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
body {
|
| 31 |
+
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
| 32 |
+
background: linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 100%);
|
| 33 |
+
color: var(--text);
|
| 34 |
+
line-height: 1.6;
|
| 35 |
+
min-height: 100vh;
|
| 36 |
+
padding: 15px;
|
| 37 |
+
direction: ltr;
|
| 38 |
+
text-align: left;
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
/* RTL Support - Comprehensive */
|
| 42 |
+
body.rtl {
|
| 43 |
+
direction: rtl;
|
| 44 |
+
text-align: right;
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
body.rtl .form-grid {
|
| 48 |
+
direction: rtl;
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
body.rtl .header {
|
| 52 |
+
direction: rtl;
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
body.rtl .features-grid {
|
| 56 |
+
direction: rtl;
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
body.rtl .settings-bar {
|
| 60 |
+
direction: rtl;
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
body.rtl .language-info {
|
| 64 |
+
flex-direction: row-reverse;
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
body.rtl .form-group {
|
| 68 |
+
text-align: right;
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
body.rtl .landing-form {
|
| 72 |
+
text-align: right;
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
body.rtl .landing-form h2 {
|
| 76 |
+
text-align: center;
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
body.rtl .api-key-section {
|
| 80 |
+
right: 15px;
|
| 81 |
+
left: auto;
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
body.rtl .char-counter {
|
| 85 |
+
text-align: left;
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
body.rtl .form-section h3 {
|
| 89 |
+
flex-direction: row-reverse;
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
body.rtl .output-section h2 {
|
| 93 |
+
flex-direction: row-reverse;
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
body.rtl .generate-btn {
|
| 97 |
+
direction: rtl;
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
body.rtl .spinner {
|
| 101 |
+
margin-right: 0;
|
| 102 |
+
margin-left: 8px;
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
body.rtl .feature-card .icon {
|
| 106 |
+
direction: ltr; /* Keep emojis in LTR */
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
body.rtl .edit-notice {
|
| 110 |
+
direction: rtl;
|
| 111 |
+
}
|
| 112 |
+
|
| 113 |
+
body.rtl .footer {
|
| 114 |
+
direction: rtl;
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
/* Ensure code areas remain LTR for readability */
|
| 118 |
+
body.rtl #codeInput,
|
| 119 |
+
body.rtl .output-area,
|
| 120 |
+
body.rtl pre,
|
| 121 |
+
body.rtl code {
|
| 122 |
+
direction: ltr;
|
| 123 |
+
text-align: left;
|
| 124 |
+
}
|
| 125 |
+
|
| 126 |
+
/* API key inputs should remain LTR */
|
| 127 |
+
body.rtl #apiKey,
|
| 128 |
+
body.rtl #landingApiKey {
|
| 129 |
+
direction: ltr;
|
| 130 |
+
text-align: left;
|
| 131 |
+
}
|
| 132 |
+
|
| 133 |
+
/* RTL List Formatting - Fix numbered lists positioning */
|
| 134 |
+
body.rtl ol {
|
| 135 |
+
padding-right: 20px;
|
| 136 |
+
padding-left: 0;
|
| 137 |
+
margin-right: 0;
|
| 138 |
+
margin-left: 0;
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
body.rtl ul {
|
| 142 |
+
padding-right: 20px;
|
| 143 |
+
padding-left: 0;
|
| 144 |
+
margin-right: 0;
|
| 145 |
+
margin-left: 0;
|
| 146 |
+
}
|
| 147 |
+
|
| 148 |
+
body.rtl li {
|
| 149 |
+
text-align: right;
|
| 150 |
+
direction: rtl;
|
| 151 |
+
margin-right: 0;
|
| 152 |
+
margin-left: 0;
|
| 153 |
+
padding-right: 0;
|
| 154 |
+
padding-left: 0;
|
| 155 |
+
}
|
| 156 |
+
|
| 157 |
+
/* Fix numbered list markers positioning in RTL */
|
| 158 |
+
body.rtl ol li {
|
| 159 |
+
list-style-position: inside;
|
| 160 |
+
text-align: right;
|
| 161 |
+
}
|
| 162 |
+
|
| 163 |
+
body.rtl ul li {
|
| 164 |
+
list-style-position: inside;
|
| 165 |
+
text-align: right;
|
| 166 |
+
}
|
| 167 |
+
|
| 168 |
+
/* Ensure proper spacing for RTL lists */
|
| 169 |
+
body.rtl .output-area ol,
|
| 170 |
+
body.rtl .output-area ul {
|
| 171 |
+
margin: 10px 0;
|
| 172 |
+
padding-right: 25px;
|
| 173 |
+
padding-left: 0;
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
+
body.rtl .output-area li {
|
| 177 |
+
margin-bottom: 5px;
|
| 178 |
+
text-align: right;
|
| 179 |
+
direction: rtl;
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
.container {
|
| 183 |
+
max-width: 1200px;
|
| 184 |
+
margin: 0 auto;
|
| 185 |
+
background: var(--surface);
|
| 186 |
+
border-radius: 16px;
|
| 187 |
+
box-shadow: var(--shadow-lg);
|
| 188 |
+
overflow: hidden;
|
| 189 |
+
position: relative;
|
| 190 |
+
}
|
| 191 |
+
|
| 192 |
+
/* Landing Page Styles */
|
| 193 |
+
.landing-page {
|
| 194 |
+
display: block;
|
| 195 |
+
padding: 40px;
|
| 196 |
+
text-align: center;
|
| 197 |
+
min-height: 80vh;
|
| 198 |
+
display: flex;
|
| 199 |
+
flex-direction: column;
|
| 200 |
+
justify-content: center;
|
| 201 |
+
align-items: center;
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
.landing-page.hidden {
|
| 205 |
+
display: none;
|
| 206 |
+
}
|
| 207 |
+
|
| 208 |
+
.landing-header {
|
| 209 |
+
margin-bottom: 40px;
|
| 210 |
+
}
|
| 211 |
+
|
| 212 |
+
.landing-header h1 {
|
| 213 |
+
font-size: 3rem;
|
| 214 |
+
font-weight: 800;
|
| 215 |
+
background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
|
| 216 |
+
-webkit-background-clip: text;
|
| 217 |
+
-webkit-text-fill-color: transparent;
|
| 218 |
+
background-clip: text;
|
| 219 |
+
margin-bottom: 16px;
|
| 220 |
+
}
|
| 221 |
+
|
| 222 |
+
.landing-header .subtitle {
|
| 223 |
+
font-size: 1.3rem;
|
| 224 |
+
color: var(--text-secondary);
|
| 225 |
+
font-weight: 500;
|
| 226 |
+
margin-bottom: 12px;
|
| 227 |
+
}
|
| 228 |
+
|
| 229 |
+
.landing-header .description {
|
| 230 |
+
font-size: 1.1rem;
|
| 231 |
+
color: var(--text-secondary);
|
| 232 |
+
max-width: 600px;
|
| 233 |
+
margin: 0 auto;
|
| 234 |
+
}
|
| 235 |
+
|
| 236 |
+
.landing-form {
|
| 237 |
+
background: var(--surface);
|
| 238 |
+
border: 2px solid var(--border);
|
| 239 |
+
border-radius: 16px;
|
| 240 |
+
padding: 40px;
|
| 241 |
+
max-width: 500px;
|
| 242 |
+
width: 100%;
|
| 243 |
+
box-shadow: var(--shadow-lg);
|
| 244 |
+
}
|
| 245 |
+
|
| 246 |
+
.landing-form h2 {
|
| 247 |
+
color: var(--primary);
|
| 248 |
+
font-size: 1.5rem;
|
| 249 |
+
font-weight: 700;
|
| 250 |
+
margin-bottom: 30px;
|
| 251 |
+
text-align: center;
|
| 252 |
+
}
|
| 253 |
+
|
| 254 |
+
.form-group {
|
| 255 |
+
margin-bottom: 25px;
|
| 256 |
+
text-align: left;
|
| 257 |
+
}
|
| 258 |
+
|
| 259 |
+
.form-group label {
|
| 260 |
+
display: block;
|
| 261 |
+
margin-bottom: 8px;
|
| 262 |
+
font-weight: 600;
|
| 263 |
+
color: var(--text);
|
| 264 |
+
font-size: 1rem;
|
| 265 |
+
}
|
| 266 |
+
|
| 267 |
+
.form-group input,
|
| 268 |
+
.form-group select {
|
| 269 |
+
width: 100%;
|
| 270 |
+
padding: 14px 16px;
|
| 271 |
+
border: 2px solid var(--border);
|
| 272 |
+
border-radius: 8px;
|
| 273 |
+
font-size: 1rem;
|
| 274 |
+
font-family: inherit;
|
| 275 |
+
background: var(--surface);
|
| 276 |
+
transition: all 0.2s ease;
|
| 277 |
+
}
|
| 278 |
+
|
| 279 |
+
.form-group input:focus,
|
| 280 |
+
.form-group select:focus {
|
| 281 |
+
outline: none;
|
| 282 |
+
border-color: var(--primary);
|
| 283 |
+
box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.1);
|
| 284 |
+
}
|
| 285 |
+
|
| 286 |
+
.start-btn {
|
| 287 |
+
background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
|
| 288 |
+
color: white;
|
| 289 |
+
padding: 16px 32px;
|
| 290 |
+
border: none;
|
| 291 |
+
border-radius: 12px;
|
| 292 |
+
font-size: 1.2rem;
|
| 293 |
+
font-weight: 700;
|
| 294 |
+
cursor: pointer;
|
| 295 |
+
transition: all 0.3s ease;
|
| 296 |
+
width: 100%;
|
| 297 |
+
margin-top: 10px;
|
| 298 |
+
}
|
| 299 |
+
|
| 300 |
+
.start-btn:hover {
|
| 301 |
+
transform: translateY(-2px);
|
| 302 |
+
box-shadow: 0 12px 24px -8px rgba(124, 58, 237, 0.4);
|
| 303 |
+
}
|
| 304 |
+
|
| 305 |
+
.start-btn:disabled {
|
| 306 |
+
opacity: 0.7;
|
| 307 |
+
cursor: not-allowed;
|
| 308 |
+
transform: none;
|
| 309 |
+
}
|
| 310 |
+
|
| 311 |
+
/* Main App Styles */
|
| 312 |
+
.main-app {
|
| 313 |
+
display: none;
|
| 314 |
+
}
|
| 315 |
+
|
| 316 |
+
.main-app.active {
|
| 317 |
+
display: block;
|
| 318 |
+
}
|
| 319 |
+
|
| 320 |
+
/* Language and Settings Bar */
|
| 321 |
+
.settings-bar {
|
| 322 |
+
background: rgba(124, 58, 237, 0.05);
|
| 323 |
+
border-bottom: 1px solid var(--border);
|
| 324 |
+
padding: 15px 30px;
|
| 325 |
+
display: flex;
|
| 326 |
+
justify-content: space-between;
|
| 327 |
+
align-items: center;
|
| 328 |
+
flex-wrap: wrap;
|
| 329 |
+
gap: 15px;
|
| 330 |
+
}
|
| 331 |
+
|
| 332 |
+
.language-info {
|
| 333 |
+
display: flex;
|
| 334 |
+
align-items: center;
|
| 335 |
+
gap: 15px;
|
| 336 |
+
font-size: 0.9rem;
|
| 337 |
+
color: var(--text-secondary);
|
| 338 |
+
}
|
| 339 |
+
|
| 340 |
+
.change-language-btn,
|
| 341 |
+
.clear-cache-btn {
|
| 342 |
+
background: var(--primary);
|
| 343 |
+
color: white;
|
| 344 |
+
border: none;
|
| 345 |
+
padding: 8px 16px;
|
| 346 |
+
border-radius: 6px;
|
| 347 |
+
font-size: 0.85rem;
|
| 348 |
+
cursor: pointer;
|
| 349 |
+
transition: all 0.2s ease;
|
| 350 |
+
}
|
| 351 |
+
|
| 352 |
+
.change-language-btn:hover,
|
| 353 |
+
.clear-cache-btn:hover {
|
| 354 |
+
background: var(--secondary);
|
| 355 |
+
transform: translateY(-1px);
|
| 356 |
+
}
|
| 357 |
+
|
| 358 |
+
.clear-cache-btn {
|
| 359 |
+
background: var(--warning);
|
| 360 |
+
}
|
| 361 |
+
|
| 362 |
+
.clear-cache-btn:hover {
|
| 363 |
+
background: #d97706;
|
| 364 |
+
}
|
| 365 |
+
|
| 366 |
+
/* API Key Section - Static Position Top Left */
|
| 367 |
+
.api-key-section {
|
| 368 |
+
background: rgba(124, 58, 237, 0.05);
|
| 369 |
+
border: 1px solid rgba(124, 58, 237, 0.1);
|
| 370 |
+
border-radius: 8px;
|
| 371 |
+
padding: 12px;
|
| 372 |
+
margin: 15px;
|
| 373 |
+
max-width: 280px;
|
| 374 |
+
}
|
| 375 |
+
|
| 376 |
+
.api-key-section label {
|
| 377 |
+
font-size: 12px;
|
| 378 |
+
font-weight: 600;
|
| 379 |
+
color: var(--primary);
|
| 380 |
+
margin-bottom: 6px;
|
| 381 |
+
display: block;
|
| 382 |
+
}
|
| 383 |
+
|
| 384 |
+
.api-key-section input {
|
| 385 |
+
width: 100%;
|
| 386 |
+
padding: 8px 12px;
|
| 387 |
+
border: 1px solid var(--border);
|
| 388 |
+
border-radius: 6px;
|
| 389 |
+
font-size: 14px;
|
| 390 |
+
background: var(--surface);
|
| 391 |
+
transition: all 0.2s ease;
|
| 392 |
+
font-family: 'Courier New', monospace;
|
| 393 |
+
}
|
| 394 |
+
|
| 395 |
+
.api-key-section input:focus {
|
| 396 |
+
outline: none;
|
| 397 |
+
border-color: var(--primary);
|
| 398 |
+
box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.1);
|
| 399 |
+
}
|
| 400 |
+
|
| 401 |
+
/* Main Content */
|
| 402 |
+
.main-content {
|
| 403 |
+
padding: 20px 30px 30px;
|
| 404 |
+
}
|
| 405 |
+
|
| 406 |
+
/* Header */
|
| 407 |
+
.header {
|
| 408 |
+
text-align: center;
|
| 409 |
+
margin-bottom: 25px;
|
| 410 |
+
padding-bottom: 20px;
|
| 411 |
+
border-bottom: 2px solid var(--border);
|
| 412 |
+
}
|
| 413 |
+
|
| 414 |
+
.header h1 {
|
| 415 |
+
font-size: 2.5rem;
|
| 416 |
+
font-weight: 800;
|
| 417 |
+
background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
|
| 418 |
+
-webkit-background-clip: text;
|
| 419 |
+
-webkit-text-fill-color: transparent;
|
| 420 |
+
background-clip: text;
|
| 421 |
+
margin-bottom: 8px;
|
| 422 |
+
}
|
| 423 |
+
|
| 424 |
+
.header .subtitle {
|
| 425 |
+
font-size: 1.1rem;
|
| 426 |
+
color: var(--text-secondary);
|
| 427 |
+
font-weight: 500;
|
| 428 |
+
}
|
| 429 |
+
|
| 430 |
+
.header .description {
|
| 431 |
+
font-size: 1rem;
|
| 432 |
+
color: var(--text-secondary);
|
| 433 |
+
margin-top: 12px;
|
| 434 |
+
max-width: 700px;
|
| 435 |
+
margin-left: auto;
|
| 436 |
+
margin-right: auto;
|
| 437 |
+
}
|
| 438 |
+
|
| 439 |
+
/* Code Explanation Features Overview */
|
| 440 |
+
.features-overview {
|
| 441 |
+
background: rgba(124, 58, 237, 0.05);
|
| 442 |
+
border: 1px solid rgba(124, 58, 237, 0.1);
|
| 443 |
+
border-radius: 12px;
|
| 444 |
+
padding: 20px;
|
| 445 |
+
margin-bottom: 25px;
|
| 446 |
+
}
|
| 447 |
+
|
| 448 |
+
.features-overview h3 {
|
| 449 |
+
color: var(--primary);
|
| 450 |
+
font-size: 1.2rem;
|
| 451 |
+
font-weight: 700;
|
| 452 |
+
margin-bottom: 15px;
|
| 453 |
+
text-align: center;
|
| 454 |
+
}
|
| 455 |
+
|
| 456 |
+
.features-grid {
|
| 457 |
+
display: grid;
|
| 458 |
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
| 459 |
+
gap: 15px;
|
| 460 |
+
}
|
| 461 |
+
|
| 462 |
+
.feature-card {
|
| 463 |
+
background: rgba(124, 58, 237, 0.02);
|
| 464 |
+
border: 1px solid rgba(124, 58, 237, 0.1);
|
| 465 |
+
border-radius: 8px;
|
| 466 |
+
padding: 15px;
|
| 467 |
+
text-align: center;
|
| 468 |
+
transition: all 0.3s ease;
|
| 469 |
+
}
|
| 470 |
+
|
| 471 |
+
.feature-card:hover {
|
| 472 |
+
background: rgba(124, 58, 237, 0.05);
|
| 473 |
+
border-color: var(--primary);
|
| 474 |
+
transform: translateY(-2px);
|
| 475 |
+
}
|
| 476 |
+
|
| 477 |
+
.feature-card .icon {
|
| 478 |
+
font-size: 1.5rem;
|
| 479 |
+
margin-bottom: 8px;
|
| 480 |
+
}
|
| 481 |
+
|
| 482 |
+
.feature-card h4 {
|
| 483 |
+
color: var(--primary);
|
| 484 |
+
font-size: 0.9rem;
|
| 485 |
+
font-weight: 700;
|
| 486 |
+
margin-bottom: 6px;
|
| 487 |
+
}
|
| 488 |
+
|
| 489 |
+
.feature-card p {
|
| 490 |
+
font-size: 0.8rem;
|
| 491 |
+
color: var(--text-secondary);
|
| 492 |
+
line-height: 1.4;
|
| 493 |
+
}
|
| 494 |
+
|
| 495 |
+
/* Progress Bar */
|
| 496 |
+
.progress-container {
|
| 497 |
+
background: var(--border);
|
| 498 |
+
height: 6px;
|
| 499 |
+
border-radius: 3px;
|
| 500 |
+
margin: 15px 0;
|
| 501 |
+
overflow: hidden;
|
| 502 |
+
}
|
| 503 |
+
|
| 504 |
+
.progress-bar {
|
| 505 |
+
width: 0%;
|
| 506 |
+
height: 100%;
|
| 507 |
+
background: linear-gradient(90deg, var(--primary) 0%, var(--secondary) 100%);
|
| 508 |
+
transition: width 0.3s ease;
|
| 509 |
+
border-radius: 3px;
|
| 510 |
+
}
|
| 511 |
+
|
| 512 |
+
/* Form Section */
|
| 513 |
+
.form-section {
|
| 514 |
+
background: var(--surface);
|
| 515 |
+
border: 1px solid var(--border);
|
| 516 |
+
border-radius: 12px;
|
| 517 |
+
padding: 25px;
|
| 518 |
+
margin-bottom: 25px;
|
| 519 |
+
transition: all 0.3s ease;
|
| 520 |
+
box-shadow: var(--shadow);
|
| 521 |
+
}
|
| 522 |
+
|
| 523 |
+
.form-section:hover {
|
| 524 |
+
border-color: var(--primary);
|
| 525 |
+
box-shadow: 0 8px 25px -8px rgba(124, 58, 237, 0.3);
|
| 526 |
+
}
|
| 527 |
+
|
| 528 |
+
.form-section h3 {
|
| 529 |
+
font-size: 1.2rem;
|
| 530 |
+
font-weight: 700;
|
| 531 |
+
color: var(--primary);
|
| 532 |
+
margin-bottom: 15px;
|
| 533 |
+
display: flex;
|
| 534 |
+
align-items: center;
|
| 535 |
+
gap: 8px;
|
| 536 |
+
}
|
| 537 |
+
|
| 538 |
+
/* Form Elements */
|
| 539 |
+
label {
|
| 540 |
+
display: block;
|
| 541 |
+
margin-bottom: 8px;
|
| 542 |
+
font-weight: 600;
|
| 543 |
+
color: var(--text);
|
| 544 |
+
font-size: 0.95rem;
|
| 545 |
+
}
|
| 546 |
+
|
| 547 |
+
input[type="text"],
|
| 548 |
+
textarea,
|
| 549 |
+
select {
|
| 550 |
+
width: 100%;
|
| 551 |
+
padding: 12px 16px;
|
| 552 |
+
border: 2px solid var(--border);
|
| 553 |
+
border-radius: 8px;
|
| 554 |
+
font-size: 1rem;
|
| 555 |
+
font-family: inherit;
|
| 556 |
+
background: var(--surface);
|
| 557 |
+
transition: all 0.2s ease;
|
| 558 |
+
resize: vertical;
|
| 559 |
+
}
|
| 560 |
+
|
| 561 |
+
input[type="text"]:focus,
|
| 562 |
+
textarea:focus,
|
| 563 |
+
select:focus {
|
| 564 |
+
outline: none;
|
| 565 |
+
border-color: var(--primary);
|
| 566 |
+
box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.1);
|
| 567 |
+
}
|
| 568 |
+
|
| 569 |
+
textarea {
|
| 570 |
+
min-height: 200px;
|
| 571 |
+
line-height: 1.6;
|
| 572 |
+
font-family: 'Fira Code', 'Courier New', monospace;
|
| 573 |
+
}
|
| 574 |
+
|
| 575 |
+
.char-counter {
|
| 576 |
+
font-size: 0.8rem;
|
| 577 |
+
color: var(--text-secondary);
|
| 578 |
+
text-align: right;
|
| 579 |
+
margin-top: 4px;
|
| 580 |
+
}
|
| 581 |
+
|
| 582 |
+
.form-grid {
|
| 583 |
+
display: grid;
|
| 584 |
+
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
| 585 |
+
gap: 15px;
|
| 586 |
+
margin-top: 15px;
|
| 587 |
+
}
|
| 588 |
+
|
| 589 |
+
.form-field {
|
| 590 |
+
display: flex;
|
| 591 |
+
flex-direction: column;
|
| 592 |
+
}
|
| 593 |
+
|
| 594 |
+
/* Generate Button */
|
| 595 |
+
.generate-btn {
|
| 596 |
+
background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
|
| 597 |
+
color: white;
|
| 598 |
+
padding: 18px 40px;
|
| 599 |
+
border: none;
|
| 600 |
+
border-radius: 12px;
|
| 601 |
+
font-size: 1.2rem;
|
| 602 |
+
font-weight: 700;
|
| 603 |
+
cursor: pointer;
|
| 604 |
+
transition: all 0.3s ease;
|
| 605 |
+
display: block;
|
| 606 |
+
margin: 30px auto;
|
| 607 |
+
min-width: 320px;
|
| 608 |
+
position: relative;
|
| 609 |
+
overflow: hidden;
|
| 610 |
+
}
|
| 611 |
+
|
| 612 |
+
.generate-btn:hover {
|
| 613 |
+
transform: translateY(-2px);
|
| 614 |
+
box-shadow: 0 12px 24px -8px rgba(124, 58, 237, 0.4);
|
| 615 |
+
}
|
| 616 |
+
|
| 617 |
+
.generate-btn:active {
|
| 618 |
+
transform: translateY(0);
|
| 619 |
+
}
|
| 620 |
+
|
| 621 |
+
.generate-btn:disabled {
|
| 622 |
+
opacity: 0.7;
|
| 623 |
+
cursor: not-allowed;
|
| 624 |
+
transform: none;
|
| 625 |
+
}
|
| 626 |
+
|
| 627 |
+
/* Loading Spinner */
|
| 628 |
+
.spinner {
|
| 629 |
+
display: none;
|
| 630 |
+
width: 20px;
|
| 631 |
+
height: 20px;
|
| 632 |
+
border: 2px solid rgba(255, 255, 255, 0.3);
|
| 633 |
+
border-radius: 50%;
|
| 634 |
+
border-top-color: white;
|
| 635 |
+
animation: spin 1s ease-in-out infinite;
|
| 636 |
+
margin-right: 8px;
|
| 637 |
+
}
|
| 638 |
+
|
| 639 |
+
@keyframes spin {
|
| 640 |
+
to { transform: rotate(360deg); }
|
| 641 |
+
}
|
| 642 |
+
|
| 643 |
+
/* Output Section */
|
| 644 |
+
.output-section {
|
| 645 |
+
margin-top: 30px;
|
| 646 |
+
}
|
| 647 |
+
|
| 648 |
+
.output-section h2 {
|
| 649 |
+
font-size: 1.5rem;
|
| 650 |
+
font-weight: 700;
|
| 651 |
+
color: var(--primary);
|
| 652 |
+
margin-bottom: 15px;
|
| 653 |
+
display: flex;
|
| 654 |
+
align-items: center;
|
| 655 |
+
gap: 8px;
|
| 656 |
+
text-align: center;
|
| 657 |
+
justify-content: center;
|
| 658 |
+
}
|
| 659 |
+
|
| 660 |
+
.output-area {
|
| 661 |
+
background: var(--surface);
|
| 662 |
+
border: 2px solid var(--border);
|
| 663 |
+
border-radius: 12px;
|
| 664 |
+
padding: 25px;
|
| 665 |
+
min-height: 300px;
|
| 666 |
+
transition: all 0.3s ease;
|
| 667 |
+
position: relative;
|
| 668 |
+
overflow-x: auto;
|
| 669 |
+
font-family: 'Georgia', serif;
|
| 670 |
+
line-height: 1.8;
|
| 671 |
+
white-space: pre-wrap;
|
| 672 |
+
word-wrap: break-word;
|
| 673 |
+
}
|
| 674 |
+
|
| 675 |
+
.output-area:empty::before {
|
| 676 |
+
content: "Your detailed code explanation will appear here...";
|
| 677 |
+
color: var(--text-secondary);
|
| 678 |
+
font-style: italic;
|
| 679 |
+
font-family: 'Inter', sans-serif;
|
| 680 |
+
}
|
| 681 |
+
|
| 682 |
+
.output-area:focus {
|
| 683 |
+
outline: none;
|
| 684 |
+
border-color: var(--primary);
|
| 685 |
+
box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.1);
|
| 686 |
+
}
|
| 687 |
+
|
| 688 |
+
.output-area h2, .output-area h3 {
|
| 689 |
+
color: var(--primary);
|
| 690 |
+
margin: 25px 0 15px 0;
|
| 691 |
+
font-family: 'Inter', sans-serif;
|
| 692 |
+
}
|
| 693 |
+
|
| 694 |
+
.output-area h2 {
|
| 695 |
+
border-bottom: 2px solid var(--primary);
|
| 696 |
+
padding-bottom: 8px;
|
| 697 |
+
font-size: 1.4rem;
|
| 698 |
+
}
|
| 699 |
+
|
| 700 |
+
.output-area h3 {
|
| 701 |
+
font-size: 1.2rem;
|
| 702 |
+
}
|
| 703 |
+
|
| 704 |
+
/* Section Headers with Decorative Underlines - Matching Example Format */
|
| 705 |
+
.output-area .section-header {
|
| 706 |
+
color: #e67e22; /* Orange color like in the example */
|
| 707 |
+
font-size: 1.3rem;
|
| 708 |
+
font-weight: 700;
|
| 709 |
+
margin: 30px 0 20px 0;
|
| 710 |
+
padding-bottom: 10px;
|
| 711 |
+
border-bottom: 3px solid #e67e22;
|
| 712 |
+
text-align: right; /* RTL alignment */
|
| 713 |
+
direction: rtl;
|
| 714 |
+
font-family: 'Inter', sans-serif;
|
| 715 |
+
}
|
| 716 |
+
|
| 717 |
+
/* For LTR languages */
|
| 718 |
+
body:not(.rtl) .output-area .section-header {
|
| 719 |
+
text-align: left;
|
| 720 |
+
direction: ltr;
|
| 721 |
+
}
|
| 722 |
+
|
| 723 |
+
/* Section content paragraphs */
|
| 724 |
+
.output-area .section-content {
|
| 725 |
+
margin: 15px 0 25px 0;
|
| 726 |
+
line-height: 1.8;
|
| 727 |
+
font-size: 1rem;
|
| 728 |
+
text-align: right;
|
| 729 |
+
direction: rtl;
|
| 730 |
+
}
|
| 731 |
+
|
| 732 |
+
/* For LTR languages */
|
| 733 |
+
body:not(.rtl) .output-area .section-content {
|
| 734 |
+
text-align: left;
|
| 735 |
+
direction: ltr;
|
| 736 |
+
}
|
| 737 |
+
|
| 738 |
+
/* Better paragraph spacing for the new format */
|
| 739 |
+
.output-area .section-content p {
|
| 740 |
+
margin: 12px 0;
|
| 741 |
+
line-height: 1.8;
|
| 742 |
+
}
|
| 743 |
+
|
| 744 |
+
.output-area p {
|
| 745 |
+
margin: 12px 0;
|
| 746 |
+
}
|
| 747 |
+
|
| 748 |
+
.output-area strong {
|
| 749 |
+
color: var(--primary);
|
| 750 |
+
}
|
| 751 |
+
|
| 752 |
+
.output-area ul, .output-area ol {
|
| 753 |
+
margin: 12px 0 12px 20px;
|
| 754 |
+
}
|
| 755 |
+
|
| 756 |
+
.output-area li {
|
| 757 |
+
margin: 6px 0;
|
| 758 |
+
}
|
| 759 |
+
|
| 760 |
+
.output-area code {
|
| 761 |
+
background: rgba(124, 58, 237, 0.1);
|
| 762 |
+
padding: 2px 6px;
|
| 763 |
+
border-radius: 4px;
|
| 764 |
+
font-family: 'Fira Code', 'Courier New', monospace;
|
| 765 |
+
color: var(--primary);
|
| 766 |
+
font-size: 0.9em;
|
| 767 |
+
}
|
| 768 |
+
|
| 769 |
+
.output-area pre {
|
| 770 |
+
background: rgba(124, 58, 237, 0.05);
|
| 771 |
+
border: 1px solid rgba(124, 58, 237, 0.2);
|
| 772 |
+
border-radius: 8px;
|
| 773 |
+
padding: 16px;
|
| 774 |
+
margin: 16px 0;
|
| 775 |
+
overflow-x: auto;
|
| 776 |
+
font-family: 'Fira Code', 'Courier New', monospace;
|
| 777 |
+
font-size: 0.9em;
|
| 778 |
+
line-height: 1.5;
|
| 779 |
+
}
|
| 780 |
+
|
| 781 |
+
.output-area pre code {
|
| 782 |
+
background: none;
|
| 783 |
+
padding: 0;
|
| 784 |
+
border-radius: 0;
|
| 785 |
+
color: var(--text);
|
| 786 |
+
font-size: inherit;
|
| 787 |
+
}
|
| 788 |
+
|
| 789 |
+
/* Edit Notice */
|
| 790 |
+
.edit-notice {
|
| 791 |
+
background: rgba(124, 58, 237, 0.1);
|
| 792 |
+
border: 1px solid rgba(124, 58, 237, 0.2);
|
| 793 |
+
color: var(--primary);
|
| 794 |
+
padding: 8px 12px;
|
| 795 |
+
border-radius: 6px;
|
| 796 |
+
margin-bottom: 10px;
|
| 797 |
+
font-size: 0.85rem;
|
| 798 |
+
text-align: center;
|
| 799 |
+
font-weight: 500;
|
| 800 |
+
}
|
| 801 |
+
|
| 802 |
+
/* Error Messages */
|
| 803 |
+
.error-message {
|
| 804 |
+
background: rgba(239, 68, 68, 0.1);
|
| 805 |
+
border: 1px solid rgba(239, 68, 68, 0.2);
|
| 806 |
+
color: var(--error);
|
| 807 |
+
padding: 12px 16px;
|
| 808 |
+
border-radius: 8px;
|
| 809 |
+
margin: 10px 0;
|
| 810 |
+
font-size: 0.9rem;
|
| 811 |
+
display: none;
|
| 812 |
+
}
|
| 813 |
+
|
| 814 |
+
/* Status Messages */
|
| 815 |
+
.status-message {
|
| 816 |
+
background: rgba(124, 58, 237, 0.1);
|
| 817 |
+
border: 1px solid rgba(124, 58, 237, 0.2);
|
| 818 |
+
color: var(--primary);
|
| 819 |
+
padding: 12px 16px;
|
| 820 |
+
border-radius: 8px;
|
| 821 |
+
margin: 10px 0;
|
| 822 |
+
font-size: 0.9rem;
|
| 823 |
+
text-align: center;
|
| 824 |
+
font-weight: 600;
|
| 825 |
+
}
|
| 826 |
+
|
| 827 |
+
/* Footer */
|
| 828 |
+
.footer {
|
| 829 |
+
text-align: center;
|
| 830 |
+
padding: 20px;
|
| 831 |
+
background: rgba(124, 58, 237, 0.05);
|
| 832 |
+
border-top: 1px solid var(--border);
|
| 833 |
+
color: var(--text-secondary);
|
| 834 |
+
font-size: 0.9rem;
|
| 835 |
+
}
|
| 836 |
+
|
| 837 |
+
/* Responsive Design */
|
| 838 |
+
@media (max-width: 768px) {
|
| 839 |
+
body {
|
| 840 |
+
padding: 10px;
|
| 841 |
+
}
|
| 842 |
+
|
| 843 |
+
.landing-page {
|
| 844 |
+
padding: 20px;
|
| 845 |
+
}
|
| 846 |
+
|
| 847 |
+
.landing-header h1 {
|
| 848 |
+
font-size: 2.2rem;
|
| 849 |
+
}
|
| 850 |
+
|
| 851 |
+
.landing-form {
|
| 852 |
+
padding: 30px 20px;
|
| 853 |
+
}
|
| 854 |
+
|
| 855 |
+
.settings-bar {
|
| 856 |
+
padding: 12px 20px;
|
| 857 |
+
flex-direction: column;
|
| 858 |
+
align-items: stretch;
|
| 859 |
+
}
|
| 860 |
+
|
| 861 |
+
.language-info {
|
| 862 |
+
justify-content: center;
|
| 863 |
+
margin-bottom: 10px;
|
| 864 |
+
}
|
| 865 |
+
|
| 866 |
+
.api-key-section {
|
| 867 |
+
margin: 10px;
|
| 868 |
+
max-width: none;
|
| 869 |
+
}
|
| 870 |
+
|
| 871 |
+
.main-content {
|
| 872 |
+
padding: 15px 20px 20px;
|
| 873 |
+
}
|
| 874 |
+
|
| 875 |
+
.header h1 {
|
| 876 |
+
font-size: 2rem;
|
| 877 |
+
}
|
| 878 |
+
|
| 879 |
+
.form-section {
|
| 880 |
+
padding: 20px 15px;
|
| 881 |
+
}
|
| 882 |
+
|
| 883 |
+
.features-grid {
|
| 884 |
+
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
| 885 |
+
}
|
| 886 |
+
|
| 887 |
+
.form-grid {
|
| 888 |
+
grid-template-columns: 1fr;
|
| 889 |
+
}
|
| 890 |
+
|
| 891 |
+
.generate-btn {
|
| 892 |
+
width: 100%;
|
| 893 |
+
margin: 25px 0;
|
| 894 |
+
padding: 16px 32px;
|
| 895 |
+
font-size: 1.1rem;
|
| 896 |
+
}
|
| 897 |
+
|
| 898 |
+
.output-area {
|
| 899 |
+
padding: 20px;
|
| 900 |
+
}
|
| 901 |
+
}
|
| 902 |
+
|
| 903 |
+
@media (max-width: 480px) {
|
| 904 |
+
.landing-header h1 {
|
| 905 |
+
font-size: 1.8rem;
|
| 906 |
+
}
|
| 907 |
+
|
| 908 |
+
.header h1 {
|
| 909 |
+
font-size: 1.8rem;
|
| 910 |
+
}
|
| 911 |
+
|
| 912 |
+
.features-grid {
|
| 913 |
+
grid-template-columns: 1fr;
|
| 914 |
+
}
|
| 915 |
+
|
| 916 |
+
.feature-card {
|
| 917 |
+
padding: 12px;
|
| 918 |
+
}
|
| 919 |
+
}
|
| 920 |
+
|
| 921 |
+
/* Dark mode support */
|
| 922 |
+
@media (prefers-color-scheme: dark) {
|
| 923 |
+
:root {
|
| 924 |
+
--background: #0f172a;
|
| 925 |
+
--surface: #1e293b;
|
| 926 |
+
--text: #f1f5f9;
|
| 927 |
+
--text-secondary: #94a3b8;
|
| 928 |
+
--border: #334155;
|
| 929 |
+
}
|
| 930 |
+
|
| 931 |
+
body {
|
| 932 |
+
background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
|
| 933 |
+
}
|
| 934 |
+
}
|
| 935 |
+
|
| 936 |
+
/* Translation loading indicator */
|
| 937 |
+
.translation-loading {
|
| 938 |
+
opacity: 0.6;
|
| 939 |
+
pointer-events: none;
|
| 940 |
+
}
|
| 941 |
+
|
| 942 |
+
.translation-loading::after {
|
| 943 |
+
content: "🔄";
|
| 944 |
+
position: absolute;
|
| 945 |
+
top: 10px;
|
| 946 |
+
right: 10px;
|
| 947 |
+
animation: spin 1s linear infinite;
|
| 948 |
+
}
|
| 949 |
+
</style>
|
| 950 |
+
</head>
|
| 951 |
+
<body>
|
| 952 |
+
<!-- Landing Page -->
|
| 953 |
+
<div class="landing-page" id="landingPage">
|
| 954 |
+
<div class="landing-header">
|
| 955 |
+
<h1 data-translate="app_title">CodeTutor Pro</h1>
|
| 956 |
+
<p class="subtitle" data-translate="app_subtitle">Intelligent Code Explanation Platform</p>
|
| 957 |
+
<p class="description" data-translate="app_description">Transform complex code into clear, beginner-friendly explanations with AI-powered analysis</p>
|
| 958 |
+
</div>
|
| 959 |
+
|
| 960 |
+
<div class="landing-form">
|
| 961 |
+
<h2 data-translate="setup_title">Get Started</h2>
|
| 962 |
+
|
| 963 |
+
<div class="form-group">
|
| 964 |
+
<label for="languageSelect" data-translate="language_label">Select Language:</label>
|
| 965 |
+
<select id="languageSelect" required>
|
| 966 |
+
<option value="">Choose your language...</option>
|
| 967 |
+
<!-- Languages will be populated by JavaScript -->
|
| 968 |
+
</select>
|
| 969 |
+
</div>
|
| 970 |
+
|
| 971 |
+
<div class="form-group">
|
| 972 |
+
<label for="landingApiKey" data-translate="api_key_label">OpenAI API Key:</label>
|
| 973 |
+
<input type="password" id="landingApiKey" data-translate-placeholder="api_key_placeholder" placeholder="Enter your OpenAI API key" autocomplete="off" required>
|
| 974 |
+
</div>
|
| 975 |
+
|
| 976 |
+
<button class="start-btn" id="startBtn" data-translate="start_button">Start Using CodeTutor Pro</button>
|
| 977 |
+
</div>
|
| 978 |
+
</div>
|
| 979 |
+
|
| 980 |
+
<!-- Main Application -->
|
| 981 |
+
<div class="main-app" id="mainApp">
|
| 982 |
+
<!-- Settings Bar -->
|
| 983 |
+
<div class="settings-bar">
|
| 984 |
+
<div class="language-info">
|
| 985 |
+
<span data-translate="current_language">Language:</span>
|
| 986 |
+
<strong id="currentLanguageName">English</strong>
|
| 987 |
+
<button class="change-language-btn" id="changeLanguageBtn" data-translate="change_language">Change Language</button>
|
| 988 |
+
</div>
|
| 989 |
+
<div>
|
| 990 |
+
<button class="clear-cache-btn" id="clearCacheBtn" data-translate="clear_cache">Clear Translation Cache</button>
|
| 991 |
+
</div>
|
| 992 |
+
</div>
|
| 993 |
+
|
| 994 |
+
<div class="container">
|
| 995 |
+
<!-- API Key Section - Static Position Top Left -->
|
| 996 |
+
<div class="api-key-section">
|
| 997 |
+
<label for="apiKey" data-translate="api_key_short">🔑 API Key</label>
|
| 998 |
+
<input type="password" id="apiKey" data-translate-placeholder="api_key_placeholder" placeholder="Enter your OpenAI API key" autocomplete="off">
|
| 999 |
+
</div>
|
| 1000 |
+
|
| 1001 |
+
<div class="main-content">
|
| 1002 |
+
<!-- Header -->
|
| 1003 |
+
<div class="header">
|
| 1004 |
+
<h1 data-translate="app_title">CodeTutor Pro</h1>
|
| 1005 |
+
<p class="subtitle" data-translate="app_subtitle">Intelligent Code Explanation Platform</p>
|
| 1006 |
+
<p class="description" data-translate="app_description">Transform complex code into clear, beginner-friendly explanations with AI-powered analysis</p>
|
| 1007 |
+
</div>
|
| 1008 |
+
|
| 1009 |
+
<!-- Code Explanation Features Overview -->
|
| 1010 |
+
<div class="features-overview">
|
| 1011 |
+
<h3 data-translate="features_title">💡 Advanced Code Explanation Features</h3>
|
| 1012 |
+
<div class="features-grid">
|
| 1013 |
+
<div class="feature-card">
|
| 1014 |
+
<div class="icon">🎯</div>
|
| 1015 |
+
<h4 data-translate="feature_beginner_title">Beginner-Friendly</h4>
|
| 1016 |
+
<p data-translate="feature_beginner_desc">Plain language explanations without technical jargon</p>
|
| 1017 |
+
</div>
|
| 1018 |
+
<div class="feature-card">
|
| 1019 |
+
<div class="icon">🔍</div>
|
| 1020 |
+
<h4 data-translate="feature_analysis_title">Line-by-Line Analysis</h4>
|
| 1021 |
+
<p data-translate="feature_analysis_desc">Detailed breakdown of each code component</p>
|
| 1022 |
+
</div>
|
| 1023 |
+
<div class="feature-card">
|
| 1024 |
+
<div class="icon">📚</div>
|
| 1025 |
+
<h4 data-translate="feature_concept_title">Concept Explanation</h4>
|
| 1026 |
+
<p data-translate="feature_concept_desc">Clear examples and programming concepts</p>
|
| 1027 |
+
</div>
|
| 1028 |
+
<div class="feature-card">
|
| 1029 |
+
<div class="icon">✏️</div>
|
| 1030 |
+
<h4 data-translate="feature_editable_title">Editable Output</h4>
|
| 1031 |
+
<p data-translate="feature_editable_desc">Customize and refine explanations as needed</p>
|
| 1032 |
+
</div>
|
| 1033 |
+
<div class="feature-card">
|
| 1034 |
+
<div class="icon">🌐</div>
|
| 1035 |
+
<h4 data-translate="feature_multilang_title">Multi-Language Support</h4>
|
| 1036 |
+
<p data-translate="feature_multilang_desc">Works with all major programming languages</p>
|
| 1037 |
+
</div>
|
| 1038 |
+
</div>
|
| 1039 |
+
</div>
|
| 1040 |
+
|
| 1041 |
+
<!-- Progress Bar -->
|
| 1042 |
+
<div class="progress-container">
|
| 1043 |
+
<div class="progress-bar" id="progressBar"></div>
|
| 1044 |
+
</div>
|
| 1045 |
+
|
| 1046 |
+
<!-- Form Section -->
|
| 1047 |
+
<div class="form-section">
|
| 1048 |
+
<h3 data-translate="code_input_title">💻 Code Input & Analysis</h3>
|
| 1049 |
+
|
| 1050 |
+
<label for="codeInput" data-translate="code_input_label">Enter Your Code:</label>
|
| 1051 |
+
<textarea
|
| 1052 |
+
id="codeInput"
|
| 1053 |
+
data-translate-placeholder="code_input_placeholder"
|
| 1054 |
+
placeholder="Paste your code here... (supports all programming languages: Python, JavaScript, Java, C++, HTML, CSS, SQL, etc.)"
|
| 1055 |
+
maxlength="1000000"
|
| 1056 |
+
required
|
| 1057 |
+
></textarea>
|
| 1058 |
+
<div class="char-counter">
|
| 1059 |
+
<span id="charCount">0</span>/1000000 <span data-translate="characters">characters</span>
|
| 1060 |
+
</div>
|
| 1061 |
+
|
| 1062 |
+
<div class="form-grid">
|
| 1063 |
+
<div class="form-field">
|
| 1064 |
+
<label for="programmingLanguage" data-translate="programming_language_label">Programming Language (Optional):</label>
|
| 1065 |
+
<select id="programmingLanguage">
|
| 1066 |
+
<option value="" data-translate="auto_detect">Auto-detect language</option>
|
| 1067 |
+
<option value="Python">Python</option>
|
| 1068 |
+
<option value="JavaScript">JavaScript</option>
|
| 1069 |
+
<option value="Java">Java</option>
|
| 1070 |
+
<option value="C++">C++</option>
|
| 1071 |
+
<option value="C#">C#</option>
|
| 1072 |
+
<option value="HTML">HTML</option>
|
| 1073 |
+
<option value="CSS">CSS</option>
|
| 1074 |
+
<option value="SQL">SQL</option>
|
| 1075 |
+
<option value="PHP">PHP</option>
|
| 1076 |
+
<option value="Ruby">Ruby</option>
|
| 1077 |
+
<option value="Go">Go</option>
|
| 1078 |
+
<option value="Rust">Rust</option>
|
| 1079 |
+
<option value="Swift">Swift</option>
|
| 1080 |
+
<option value="Kotlin">Kotlin</option>
|
| 1081 |
+
<option value="TypeScript">TypeScript</option>
|
| 1082 |
+
<option value="R">R</option>
|
| 1083 |
+
<option value="MATLAB">MATLAB</option>
|
| 1084 |
+
<option value="Scala">Scala</option>
|
| 1085 |
+
<option value="Perl">Perl</option>
|
| 1086 |
+
<option value="Shell/Bash">Shell/Bash</option>
|
| 1087 |
+
</select>
|
| 1088 |
+
</div>
|
| 1089 |
+
|
| 1090 |
+
<div class="form-field">
|
| 1091 |
+
<label for="explanationLevel" data-translate="explanation_level_label">Explanation Level:</label>
|
| 1092 |
+
<select id="explanationLevel" required>
|
| 1093 |
+
<option value="" data-translate="select_explanation_level">Select explanation level</option>
|
| 1094 |
+
<option value="Complete Beginner" data-translate="level_complete_beginner">Complete Beginner (No programming experience)</option>
|
| 1095 |
+
<option value="Beginner" data-translate="level_beginner">Beginner (Basic programming knowledge)</option>
|
| 1096 |
+
<option value="Intermediate" data-translate="level_intermediate">Intermediate (Some programming experience)</option>
|
| 1097 |
+
<option value="Advanced" data-translate="level_advanced">Advanced (Experienced programmer)</option>
|
| 1098 |
+
</select>
|
| 1099 |
+
</div>
|
| 1100 |
+
</div>
|
| 1101 |
+
</div>
|
| 1102 |
+
|
| 1103 |
+
<!-- Error Message -->
|
| 1104 |
+
<div class="error-message" id="errorMessage"></div>
|
| 1105 |
+
|
| 1106 |
+
<!-- Status Message -->
|
| 1107 |
+
<div class="status-message" id="statusMessage" style="display: none;"></div>
|
| 1108 |
+
|
| 1109 |
+
<!-- Generate Button -->
|
| 1110 |
+
<button class="generate-btn" id="generateBtn">
|
| 1111 |
+
<span class="spinner" id="spinner"></span>
|
| 1112 |
+
<span id="buttonText" data-translate="generate_button">🧠 Generate Explanation</span>
|
| 1113 |
+
</button>
|
| 1114 |
+
|
| 1115 |
+
<!-- Output Section -->
|
| 1116 |
+
<div class="output-section">
|
| 1117 |
+
<h2 data-translate="output_title">📖 Code Explanation</h2>
|
| 1118 |
+
<div class="edit-notice" data-translate="edit_notice">
|
| 1119 |
+
✏️ This explanation is editable - click anywhere to customize and refine the content
|
| 1120 |
+
</div>
|
| 1121 |
+
<div class="output-area" id="explanationOutput" contenteditable="true"></div>
|
| 1122 |
+
</div>
|
| 1123 |
+
</div>
|
| 1124 |
+
|
| 1125 |
+
<!-- Footer -->
|
| 1126 |
+
<div class="footer" data-translate="footer">
|
| 1127 |
+
Created by Shift Mind AI Labs
|
| 1128 |
+
</div>
|
| 1129 |
+
</div>
|
| 1130 |
+
</div>
|
| 1131 |
+
|
| 1132 |
+
<script>
|
| 1133 |
+
// Global variables
|
| 1134 |
+
let currentLanguage = 'en';
|
| 1135 |
+
let translationCache = {};
|
| 1136 |
+
let isTranslating = false;
|
| 1137 |
+
|
| 1138 |
+
// 92 Languages with their codes and RTL information
|
| 1139 |
+
const languages = [
|
| 1140 |
+
{ code: 'en', name: 'English', nativeName: 'English', rtl: false },
|
| 1141 |
+
{ code: 'es', name: 'Spanish', nativeName: 'Español', rtl: false },
|
| 1142 |
+
{ code: 'fr', name: 'French', nativeName: 'Français', rtl: false },
|
| 1143 |
+
{ code: 'de', name: 'German', nativeName: 'Deutsch', rtl: false },
|
| 1144 |
+
{ code: 'it', name: 'Italian', nativeName: 'Italiano', rtl: false },
|
| 1145 |
+
{ code: 'pt', name: 'Portuguese', nativeName: 'Português', rtl: false },
|
| 1146 |
+
{ code: 'ru', name: 'Russian', nativeName: 'Русский', rtl: false },
|
| 1147 |
+
{ code: 'ja', name: 'Japanese', nativeName: '日本語', rtl: false },
|
| 1148 |
+
{ code: 'ko', name: 'Korean', nativeName: '한국어', rtl: false },
|
| 1149 |
+
{ code: 'zh', name: 'Chinese (Simplified)', nativeName: '中文 (简体)', rtl: false },
|
| 1150 |
+
{ code: 'zh-TW', name: 'Chinese (Traditional)', nativeName: '中文 (繁體)', rtl: false },
|
| 1151 |
+
{ code: 'ar', name: 'Arabic', nativeName: 'العربية', rtl: true },
|
| 1152 |
+
{ code: 'he', name: 'Hebrew', nativeName: 'עברית', rtl: true },
|
| 1153 |
+
{ code: 'hi', name: 'Hindi', nativeName: 'हिन्दी', rtl: false },
|
| 1154 |
+
{ code: 'th', name: 'Thai', nativeName: 'ไทย', rtl: false },
|
| 1155 |
+
{ code: 'vi', name: 'Vietnamese', nativeName: 'Tiếng Việt', rtl: false },
|
| 1156 |
+
{ code: 'tr', name: 'Turkish', nativeName: 'Türkçe', rtl: false },
|
| 1157 |
+
{ code: 'pl', name: 'Polish', nativeName: 'Polski', rtl: false },
|
| 1158 |
+
{ code: 'nl', name: 'Dutch', nativeName: 'Nederlands', rtl: false },
|
| 1159 |
+
{ code: 'sv', name: 'Swedish', nativeName: 'Svenska', rtl: false },
|
| 1160 |
+
{ code: 'da', name: 'Danish', nativeName: 'Dansk', rtl: false },
|
| 1161 |
+
{ code: 'no', name: 'Norwegian', nativeName: 'Norsk', rtl: false },
|
| 1162 |
+
{ code: 'fi', name: 'Finnish', nativeName: 'Suomi', rtl: false },
|
| 1163 |
+
{ code: 'cs', name: 'Czech', nativeName: 'Čeština', rtl: false },
|
| 1164 |
+
{ code: 'sk', name: 'Slovak', nativeName: 'Slovenčina', rtl: false },
|
| 1165 |
+
{ code: 'hu', name: 'Hungarian', nativeName: 'Magyar', rtl: false },
|
| 1166 |
+
{ code: 'ro', name: 'Romanian', nativeName: 'Română', rtl: false },
|
| 1167 |
+
{ code: 'bg', name: 'Bulgarian', nativeName: 'Български', rtl: false },
|
| 1168 |
+
{ code: 'hr', name: 'Croatian', nativeName: 'Hrvatski', rtl: false },
|
| 1169 |
+
{ code: 'sr', name: 'Serbian', nativeName: 'Српски', rtl: false },
|
| 1170 |
+
{ code: 'sl', name: 'Slovenian', nativeName: 'Slovenščina', rtl: false },
|
| 1171 |
+
{ code: 'et', name: 'Estonian', nativeName: 'Eesti', rtl: false },
|
| 1172 |
+
{ code: 'lv', name: 'Latvian', nativeName: 'Latviešu', rtl: false },
|
| 1173 |
+
{ code: 'lt', name: 'Lithuanian', nativeName: 'Lietuvių', rtl: false },
|
| 1174 |
+
{ code: 'uk', name: 'Ukrainian', nativeName: 'Українська', rtl: false },
|
| 1175 |
+
{ code: 'be', name: 'Belarusian', nativeName: 'Беларуская', rtl: false },
|
| 1176 |
+
{ code: 'mk', name: 'Macedonian', nativeName: 'Македонски', rtl: false },
|
| 1177 |
+
{ code: 'sq', name: 'Albanian', nativeName: 'Shqip', rtl: false },
|
| 1178 |
+
{ code: 'el', name: 'Greek', nativeName: 'Ελληνικά', rtl: false },
|
| 1179 |
+
{ code: 'mt', name: 'Maltese', nativeName: 'Malti', rtl: false },
|
| 1180 |
+
{ code: 'ga', name: 'Irish', nativeName: 'Gaeilge', rtl: false },
|
| 1181 |
+
{ code: 'cy', name: 'Welsh', nativeName: 'Cymraeg', rtl: false },
|
| 1182 |
+
{ code: 'is', name: 'Icelandic', nativeName: 'Íslenska', rtl: false },
|
| 1183 |
+
{ code: 'fo', name: 'Faroese', nativeName: 'Føroyskt', rtl: false },
|
| 1184 |
+
{ code: 'eu', name: 'Basque', nativeName: 'Euskera', rtl: false },
|
| 1185 |
+
{ code: 'ca', name: 'Catalan', nativeName: 'Català', rtl: false },
|
| 1186 |
+
{ code: 'gl', name: 'Galician', nativeName: 'Galego', rtl: false },
|
| 1187 |
+
{ code: 'oc', name: 'Occitan', nativeName: 'Occitan', rtl: false },
|
| 1188 |
+
{ code: 'br', name: 'Breton', nativeName: 'Brezhoneg', rtl: false },
|
| 1189 |
+
{ code: 'co', name: 'Corsican', nativeName: 'Corsu', rtl: false },
|
| 1190 |
+
{ code: 'sc', name: 'Sardinian', nativeName: 'Sardu', rtl: false },
|
| 1191 |
+
{ code: 'rm', name: 'Romansh', nativeName: 'Rumantsch', rtl: false },
|
| 1192 |
+
{ code: 'lb', name: 'Luxembourgish', nativeName: 'Lëtzebuergesch', rtl: false },
|
| 1193 |
+
{ code: 'fy', name: 'Frisian', nativeName: 'Frysk', rtl: false },
|
| 1194 |
+
{ code: 'af', name: 'Afrikaans', nativeName: 'Afrikaans', rtl: false },
|
| 1195 |
+
{ code: 'zu', name: 'Zulu', nativeName: 'isiZulu', rtl: false },
|
| 1196 |
+
{ code: 'xh', name: 'Xhosa', nativeName: 'isiXhosa', rtl: false },
|
| 1197 |
+
{ code: 'st', name: 'Sesotho', nativeName: 'Sesotho', rtl: false },
|
| 1198 |
+
{ code: 'tn', name: 'Setswana', nativeName: 'Setswana', rtl: false },
|
| 1199 |
+
{ code: 'ss', name: 'Swati', nativeName: 'siSwati', rtl: false },
|
| 1200 |
+
{ code: 've', name: 'Venda', nativeName: 'Tshivenḓa', rtl: false },
|
| 1201 |
+
{ code: 'ts', name: 'Tsonga', nativeName: 'Xitsonga', rtl: false },
|
| 1202 |
+
{ code: 'nr', name: 'Ndebele', nativeName: 'isiNdebele', rtl: false },
|
| 1203 |
+
{ code: 'sw', name: 'Swahili', nativeName: 'Kiswahili', rtl: false },
|
| 1204 |
+
{ code: 'am', name: 'Amharic', nativeName: 'አማርኛ', rtl: false },
|
| 1205 |
+
{ code: 'ti', name: 'Tigrinya', nativeName: 'ትግርኛ', rtl: false },
|
| 1206 |
+
{ code: 'om', name: 'Oromo', nativeName: 'Afaan Oromoo', rtl: false },
|
| 1207 |
+
{ code: 'so', name: 'Somali', nativeName: 'Soomaali', rtl: false },
|
| 1208 |
+
{ code: 'ha', name: 'Hausa', nativeName: 'Hausa', rtl: false },
|
| 1209 |
+
{ code: 'yo', name: 'Yoruba', nativeName: 'Yorùbá', rtl: false },
|
| 1210 |
+
{ code: 'ig', name: 'Igbo', nativeName: 'Igbo', rtl: false },
|
| 1211 |
+
{ code: 'ff', name: 'Fulah', nativeName: 'Fulfulde', rtl: false },
|
| 1212 |
+
{ code: 'wo', name: 'Wolof', nativeName: 'Wolof', rtl: false },
|
| 1213 |
+
{ code: 'bm', name: 'Bambara', nativeName: 'Bamanankan', rtl: false },
|
| 1214 |
+
{ code: 'rw', name: 'Kinyarwanda', nativeName: 'Ikinyarwanda', rtl: false },
|
| 1215 |
+
{ code: 'rn', name: 'Kirundi', nativeName: 'Ikirundi', rtl: false },
|
| 1216 |
+
{ code: 'ny', name: 'Chichewa', nativeName: 'Chichewa', rtl: false },
|
| 1217 |
+
{ code: 'sn', name: 'Shona', nativeName: 'chiShona', rtl: false },
|
| 1218 |
+
{ code: 'mg', name: 'Malagasy', nativeName: 'Malagasy', rtl: false },
|
| 1219 |
+
{ code: 'fa', name: 'Persian', nativeName: 'فارسی', rtl: true },
|
| 1220 |
+
{ code: 'ur', name: 'Urdu', nativeName: 'اردو', rtl: true },
|
| 1221 |
+
{ code: 'ps', name: 'Pashto', nativeName: 'پښتو', rtl: true },
|
| 1222 |
+
{ code: 'ku', name: 'Kurdish', nativeName: 'Kurdî', rtl: true },
|
| 1223 |
+
{ code: 'ckb', name: 'Sorani Kurdish', nativeName: 'کوردی', rtl: true },
|
| 1224 |
+
{ code: 'sd', name: 'Sindhi', nativeName: 'سنڌي', rtl: true },
|
| 1225 |
+
{ code: 'ug', name: 'Uyghur', nativeName: 'ئۇيغۇرچە', rtl: true },
|
| 1226 |
+
{ code: 'bn', name: 'Bengali', nativeName: 'বাংলা', rtl: false },
|
| 1227 |
+
{ code: 'gu', name: 'Gujarati', nativeName: 'ગુજરાતી', rtl: false },
|
| 1228 |
+
{ code: 'pa', name: 'Punjabi', nativeName: 'ਪੰਜਾਬੀ', rtl: false },
|
| 1229 |
+
{ code: 'ta', name: 'Tamil', nativeName: 'தமிழ்', rtl: false },
|
| 1230 |
+
{ code: 'te', name: 'Telugu', nativeName: 'తెలుగు', rtl: false },
|
| 1231 |
+
{ code: 'kn', name: 'Kannada', nativeName: 'ಕನ್ನಡ', rtl: false },
|
| 1232 |
+
{ code: 'ml', name: 'Malayalam', nativeName: 'മലയാളം', rtl: false },
|
| 1233 |
+
{ code: 'si', name: 'Sinhala', nativeName: 'සිංහල', rtl: false },
|
| 1234 |
+
{ code: 'my', name: 'Myanmar', nativeName: 'မြန်မာ', rtl: false },
|
| 1235 |
+
{ code: 'km', name: 'Khmer', nativeName: 'ខ្មែរ', rtl: false },
|
| 1236 |
+
{ code: 'lo', name: 'Lao', nativeName: 'ລາວ', rtl: false },
|
| 1237 |
+
{ code: 'ka', name: 'Georgian', nativeName: 'ქართული', rtl: false },
|
| 1238 |
+
{ code: 'hy', name: 'Armenian', nativeName: 'Հայերեն', rtl: false },
|
| 1239 |
+
{ code: 'az', name: 'Azerbaijani', nativeName: 'Azərbaycan', rtl: false },
|
| 1240 |
+
{ code: 'kk', name: 'Kazakh', nativeName: 'Қазақ', rtl: false },
|
| 1241 |
+
{ code: 'ky', name: 'Kyrgyz', nativeName: 'Кыргыз', rtl: false },
|
| 1242 |
+
{ code: 'uz', name: 'Uzbek', nativeName: 'Oʻzbek', rtl: false },
|
| 1243 |
+
{ code: 'tk', name: 'Turkmen', nativeName: 'Türkmen', rtl: false },
|
| 1244 |
+
{ code: 'tg', name: 'Tajik', nativeName: 'Тоҷикӣ', rtl: false },
|
| 1245 |
+
{ code: 'mn', name: 'Mongolian', nativeName: 'Монгол', rtl: false }
|
| 1246 |
+
];
|
| 1247 |
+
|
| 1248 |
+
// Default translations for English
|
| 1249 |
+
const defaultTranslations = {
|
| 1250 |
+
app_title: "CodeTutor Pro",
|
| 1251 |
+
app_subtitle: "Intelligent Code Explanation Platform",
|
| 1252 |
+
app_description: "Transform complex code into clear, beginner-friendly explanations with AI-powered analysis",
|
| 1253 |
+
setup_title: "Get Started",
|
| 1254 |
+
language_label: "Select Language:",
|
| 1255 |
+
api_key_label: "OpenAI API Key:",
|
| 1256 |
+
api_key_placeholder: "Enter your OpenAI API key",
|
| 1257 |
+
start_button: "Start Using CodeTutor Pro",
|
| 1258 |
+
current_language: "Language:",
|
| 1259 |
+
change_language: "Change Language",
|
| 1260 |
+
clear_cache: "Clear Translation Cache",
|
| 1261 |
+
api_key_short: "🔑 API Key",
|
| 1262 |
+
features_title: "💡 Advanced Code Explanation Features",
|
| 1263 |
+
feature_beginner_title: "Beginner-Friendly",
|
| 1264 |
+
feature_beginner_desc: "Plain language explanations without technical jargon",
|
| 1265 |
+
feature_analysis_title: "Line-by-Line Analysis",
|
| 1266 |
+
feature_analysis_desc: "Detailed breakdown of each code component",
|
| 1267 |
+
feature_concept_title: "Concept Explanation",
|
| 1268 |
+
feature_concept_desc: "Clear examples and programming concepts",
|
| 1269 |
+
feature_editable_title: "Editable Output",
|
| 1270 |
+
feature_editable_desc: "Customize and refine explanations as needed",
|
| 1271 |
+
feature_multilang_title: "Multi-Language Support",
|
| 1272 |
+
feature_multilang_desc: "Works with all major programming languages",
|
| 1273 |
+
code_input_title: "💻 Code Input & Analysis",
|
| 1274 |
+
code_input_label: "Enter Your Code:",
|
| 1275 |
+
code_input_placeholder: "Paste your code here... (supports all programming languages: Python, JavaScript, Java, C++, HTML, CSS, SQL, etc.)",
|
| 1276 |
+
characters: "characters",
|
| 1277 |
+
programming_language_label: "Programming Language (Optional):",
|
| 1278 |
+
auto_detect: "Auto-detect language",
|
| 1279 |
+
explanation_level_label: "Explanation Level:",
|
| 1280 |
+
select_explanation_level: "Select explanation level",
|
| 1281 |
+
level_complete_beginner: "Complete Beginner (No programming experience)",
|
| 1282 |
+
level_beginner: "Beginner (Basic programming knowledge)",
|
| 1283 |
+
level_intermediate: "Intermediate (Some programming experience)",
|
| 1284 |
+
level_advanced: "Advanced (Experienced programmer)",
|
| 1285 |
+
generate_button: "🧠 Generate Explanation",
|
| 1286 |
+
output_title: "📖 Code Explanation",
|
| 1287 |
+
edit_notice: "✏️ This explanation is editable - click anywhere to customize and refine the content",
|
| 1288 |
+
footer: "Created by Shift Mind AI Labs"
|
| 1289 |
+
};
|
| 1290 |
+
|
| 1291 |
+
// Load cached translations and settings with improved cache handling
|
| 1292 |
+
function loadSettings() {
|
| 1293 |
+
const savedLanguage = localStorage.getItem('codetutor_language');
|
| 1294 |
+
const savedCache = localStorage.getItem('codetutor_translation_cache');
|
| 1295 |
+
const savedApiKey = localStorage.getItem('codetutor_api_key');
|
| 1296 |
+
|
| 1297 |
+
if (savedLanguage) {
|
| 1298 |
+
currentLanguage = savedLanguage;
|
| 1299 |
+
}
|
| 1300 |
+
|
| 1301 |
+
if (savedCache) {
|
| 1302 |
+
try {
|
| 1303 |
+
const parsedCache = JSON.parse(savedCache);
|
| 1304 |
+
// Handle both old and new cache formats
|
| 1305 |
+
translationCache = {};
|
| 1306 |
+
Object.keys(parsedCache).forEach(key => {
|
| 1307 |
+
const value = parsedCache[key];
|
| 1308 |
+
if (typeof value === 'string') {
|
| 1309 |
+
// Old format - convert to new format
|
| 1310 |
+
translationCache[key] = {
|
| 1311 |
+
text: value,
|
| 1312 |
+
timestamp: Date.now() - (7 * 24 * 60 * 60 * 1000) // Mark as 7 days old
|
| 1313 |
+
};
|
| 1314 |
+
} else if (typeof value === 'object' && value.text) {
|
| 1315 |
+
// New format
|
| 1316 |
+
translationCache[key] = value;
|
| 1317 |
+
}
|
| 1318 |
+
});
|
| 1319 |
+
} catch (e) {
|
| 1320 |
+
console.error('Error loading translation cache:', e);
|
| 1321 |
+
translationCache = {};
|
| 1322 |
+
}
|
| 1323 |
+
}
|
| 1324 |
+
|
| 1325 |
+
if (savedApiKey) {
|
| 1326 |
+
document.getElementById('landingApiKey').value = savedApiKey;
|
| 1327 |
+
document.getElementById('apiKey').value = savedApiKey;
|
| 1328 |
+
}
|
| 1329 |
+
}
|
| 1330 |
+
|
| 1331 |
+
// Save settings with cache size management
|
| 1332 |
+
function saveSettings() {
|
| 1333 |
+
localStorage.setItem('codetutor_language', currentLanguage);
|
| 1334 |
+
|
| 1335 |
+
// Limit cache size to prevent localStorage overflow
|
| 1336 |
+
const cacheKeys = Object.keys(translationCache);
|
| 1337 |
+
if (cacheKeys.length > 1000) {
|
| 1338 |
+
// Keep only the 800 most recent entries
|
| 1339 |
+
const sortedEntries = cacheKeys
|
| 1340 |
+
.map(key => ({ key, timestamp: translationCache[key].timestamp || 0 }))
|
| 1341 |
+
.sort((a, b) => b.timestamp - a.timestamp)
|
| 1342 |
+
.slice(0, 800);
|
| 1343 |
+
|
| 1344 |
+
const newCache = {};
|
| 1345 |
+
sortedEntries.forEach(entry => {
|
| 1346 |
+
newCache[entry.key] = translationCache[entry.key];
|
| 1347 |
+
});
|
| 1348 |
+
translationCache = newCache;
|
| 1349 |
+
}
|
| 1350 |
+
|
| 1351 |
+
localStorage.setItem('codetutor_translation_cache', JSON.stringify(translationCache));
|
| 1352 |
+
}
|
| 1353 |
+
|
| 1354 |
+
// Populate language dropdown
|
| 1355 |
+
function populateLanguageDropdown() {
|
| 1356 |
+
const select = document.getElementById('languageSelect');
|
| 1357 |
+
select.innerHTML = '<option value="">Choose your language...</option>';
|
| 1358 |
+
|
| 1359 |
+
languages.forEach(lang => {
|
| 1360 |
+
const option = document.createElement('option');
|
| 1361 |
+
option.value = lang.code;
|
| 1362 |
+
option.textContent = `${lang.nativeName} (${lang.name})`;
|
| 1363 |
+
if (lang.code === currentLanguage) {
|
| 1364 |
+
option.selected = true;
|
| 1365 |
+
}
|
| 1366 |
+
select.appendChild(option);
|
| 1367 |
+
});
|
| 1368 |
+
}
|
| 1369 |
+
|
| 1370 |
+
// Set RTL/LTR direction
|
| 1371 |
+
function setTextDirection(langCode) {
|
| 1372 |
+
const language = languages.find(lang => lang.code === langCode);
|
| 1373 |
+
const body = document.body;
|
| 1374 |
+
|
| 1375 |
+
if (language && language.rtl) {
|
| 1376 |
+
body.classList.add('rtl');
|
| 1377 |
+
body.setAttribute('dir', 'rtl');
|
| 1378 |
+
} else {
|
| 1379 |
+
body.classList.remove('rtl');
|
| 1380 |
+
body.setAttribute('dir', 'ltr');
|
| 1381 |
+
}
|
| 1382 |
+
}
|
| 1383 |
+
|
| 1384 |
+
// Translation function using OpenAI API with improved caching and batch processing
|
| 1385 |
+
async function translateText(text, targetLanguage) {
|
| 1386 |
+
if (targetLanguage === 'en' || !text || text.trim() === '') {
|
| 1387 |
+
return text;
|
| 1388 |
+
}
|
| 1389 |
+
|
| 1390 |
+
const cacheKey = `${text.trim()}_${targetLanguage}`;
|
| 1391 |
+
if (translationCache[cacheKey]) {
|
| 1392 |
+
const cached = translationCache[cacheKey];
|
| 1393 |
+
return typeof cached === 'string' ? cached : cached.text;
|
| 1394 |
+
}
|
| 1395 |
+
|
| 1396 |
+
const apiKey = document.getElementById('landingApiKey').value || document.getElementById('apiKey').value;
|
| 1397 |
+
if (!apiKey) {
|
| 1398 |
+
console.warn('No API key available for translation');
|
| 1399 |
+
return text;
|
| 1400 |
+
}
|
| 1401 |
+
|
| 1402 |
+
try {
|
| 1403 |
+
const language = languages.find(lang => lang.code === targetLanguage);
|
| 1404 |
+
const languageName = language ? language.name : targetLanguage;
|
| 1405 |
+
|
| 1406 |
+
const prompt = `Translate the following text to ${languageName}. Maintain any HTML tags, emojis, and formatting. Only return the translated text, nothing else:\n\n${text}`;
|
| 1407 |
+
|
| 1408 |
+
const response = await fetch("https://api.openai.com/v1/chat/completions", {
|
| 1409 |
+
method: "POST",
|
| 1410 |
+
headers: {
|
| 1411 |
+
"Content-Type": "application/json",
|
| 1412 |
+
"Authorization": `Bearer ${apiKey}`
|
| 1413 |
+
},
|
| 1414 |
+
body: JSON.stringify({
|
| 1415 |
+
model: "gpt-4o-mini",
|
| 1416 |
+
messages: [{ role: "user", content: prompt }],
|
| 1417 |
+
max_tokens: 800,
|
| 1418 |
+
temperature: 0.2
|
| 1419 |
+
})
|
| 1420 |
+
});
|
| 1421 |
+
|
| 1422 |
+
if (!response.ok) {
|
| 1423 |
+
const errorData = await response.json();
|
| 1424 |
+
throw new Error(errorData.error?.message || 'Translation API request failed');
|
| 1425 |
+
}
|
| 1426 |
+
|
| 1427 |
+
const data = await response.json();
|
| 1428 |
+
const translatedText = data.choices[0].message.content.trim();
|
| 1429 |
+
|
| 1430 |
+
// Cache the translation with timestamp
|
| 1431 |
+
translationCache[cacheKey] = {
|
| 1432 |
+
text: translatedText,
|
| 1433 |
+
timestamp: Date.now()
|
| 1434 |
+
};
|
| 1435 |
+
saveSettings();
|
| 1436 |
+
|
| 1437 |
+
return translatedText;
|
| 1438 |
+
} catch (error) {
|
| 1439 |
+
console.error('Translation error:', error);
|
| 1440 |
+
// Try to find a similar cached translation as fallback
|
| 1441 |
+
const similarKey = Object.keys(translationCache).find(key =>
|
| 1442 |
+
key.includes(text.substring(0, 20)) && key.endsWith(`_${targetLanguage}`)
|
| 1443 |
+
);
|
| 1444 |
+
if (similarKey && translationCache[similarKey]) {
|
| 1445 |
+
return translationCache[similarKey].text || translationCache[similarKey];
|
| 1446 |
+
}
|
| 1447 |
+
return text; // Return original text if translation fails
|
| 1448 |
+
}
|
| 1449 |
+
}
|
| 1450 |
+
|
| 1451 |
+
// Batch translation for better performance
|
| 1452 |
+
async function translateBatch(textArray, targetLanguage) {
|
| 1453 |
+
if (targetLanguage === 'en') {
|
| 1454 |
+
return textArray;
|
| 1455 |
+
}
|
| 1456 |
+
|
| 1457 |
+
const results = [];
|
| 1458 |
+
const uncachedTexts = [];
|
| 1459 |
+
const uncachedIndices = [];
|
| 1460 |
+
|
| 1461 |
+
// Check cache first
|
| 1462 |
+
textArray.forEach((text, index) => {
|
| 1463 |
+
const cacheKey = `${text.trim()}_${targetLanguage}`;
|
| 1464 |
+
if (translationCache[cacheKey]) {
|
| 1465 |
+
const cached = translationCache[cacheKey];
|
| 1466 |
+
results[index] = typeof cached === 'string' ? cached : cached.text;
|
| 1467 |
+
} else {
|
| 1468 |
+
uncachedTexts.push(text);
|
| 1469 |
+
uncachedIndices.push(index);
|
| 1470 |
+
}
|
| 1471 |
+
});
|
| 1472 |
+
|
| 1473 |
+
// Translate uncached texts
|
| 1474 |
+
if (uncachedTexts.length > 0) {
|
| 1475 |
+
const apiKey = document.getElementById('landingApiKey').value || document.getElementById('apiKey').value;
|
| 1476 |
+
if (!apiKey) {
|
| 1477 |
+
// Fill remaining with original texts
|
| 1478 |
+
uncachedIndices.forEach((index, i) => {
|
| 1479 |
+
results[index] = uncachedTexts[i];
|
| 1480 |
+
});
|
| 1481 |
+
return results;
|
| 1482 |
+
}
|
| 1483 |
+
|
| 1484 |
+
try {
|
| 1485 |
+
const language = languages.find(lang => lang.code === targetLanguage);
|
| 1486 |
+
const languageName = language ? language.name : targetLanguage;
|
| 1487 |
+
|
| 1488 |
+
const batchText = uncachedTexts.map((text, i) => `${i + 1}. ${text}`).join('\n');
|
| 1489 |
+
const prompt = `Translate the following numbered list to ${languageName}. Maintain the numbering, HTML tags, emojis, and formatting. Return only the translated numbered list:\n\n${batchText}`;
|
| 1490 |
+
|
| 1491 |
+
const response = await fetch("https://api.openai.com/v1/chat/completions", {
|
| 1492 |
+
method: "POST",
|
| 1493 |
+
headers: {
|
| 1494 |
+
"Content-Type": "application/json",
|
| 1495 |
+
"Authorization": `Bearer ${apiKey}`
|
| 1496 |
+
},
|
| 1497 |
+
body: JSON.stringify({
|
| 1498 |
+
model: "gpt-4o-mini",
|
| 1499 |
+
messages: [{ role: "user", content: prompt }],
|
| 1500 |
+
max_tokens: 2000,
|
| 1501 |
+
temperature: 0.2
|
| 1502 |
+
})
|
| 1503 |
+
});
|
| 1504 |
+
|
| 1505 |
+
if (response.ok) {
|
| 1506 |
+
const data = await response.json();
|
| 1507 |
+
const translatedBatch = data.choices[0].message.content.trim();
|
| 1508 |
+
const translatedLines = translatedBatch.split('\n').filter(line => line.trim());
|
| 1509 |
+
|
| 1510 |
+
translatedLines.forEach((line, i) => {
|
| 1511 |
+
if (i < uncachedTexts.length) {
|
| 1512 |
+
const translatedText = line.replace(/^\d+\.\s*/, '').trim();
|
| 1513 |
+
const originalIndex = uncachedIndices[i];
|
| 1514 |
+
results[originalIndex] = translatedText;
|
| 1515 |
+
|
| 1516 |
+
// Cache the translation
|
| 1517 |
+
const cacheKey = `${uncachedTexts[i].trim()}_${targetLanguage}`;
|
| 1518 |
+
translationCache[cacheKey] = {
|
| 1519 |
+
text: translatedText,
|
| 1520 |
+
timestamp: Date.now()
|
| 1521 |
+
};
|
| 1522 |
+
}
|
| 1523 |
+
});
|
| 1524 |
+
|
| 1525 |
+
saveSettings();
|
| 1526 |
+
} else {
|
| 1527 |
+
// Fallback to individual translations
|
| 1528 |
+
for (let i = 0; i < uncachedTexts.length; i++) {
|
| 1529 |
+
const translatedText = await translateText(uncachedTexts[i], targetLanguage);
|
| 1530 |
+
results[uncachedIndices[i]] = translatedText;
|
| 1531 |
+
}
|
| 1532 |
+
}
|
| 1533 |
+
} catch (error) {
|
| 1534 |
+
console.error('Batch translation error:', error);
|
| 1535 |
+
// Fallback to original texts
|
| 1536 |
+
uncachedIndices.forEach((index, i) => {
|
| 1537 |
+
results[index] = uncachedTexts[i];
|
| 1538 |
+
});
|
| 1539 |
+
}
|
| 1540 |
+
}
|
| 1541 |
+
|
| 1542 |
+
return results;
|
| 1543 |
+
}
|
| 1544 |
+
|
| 1545 |
+
// Clean old cache entries (older than 30 days)
|
| 1546 |
+
function cleanOldCache() {
|
| 1547 |
+
const thirtyDaysAgo = Date.now() - (30 * 24 * 60 * 60 * 1000);
|
| 1548 |
+
let cleaned = false;
|
| 1549 |
+
|
| 1550 |
+
Object.keys(translationCache).forEach(key => {
|
| 1551 |
+
const cached = translationCache[key];
|
| 1552 |
+
if (typeof cached === 'object' && cached.timestamp && cached.timestamp < thirtyDaysAgo) {
|
| 1553 |
+
delete translationCache[key];
|
| 1554 |
+
cleaned = true;
|
| 1555 |
+
}
|
| 1556 |
+
});
|
| 1557 |
+
|
| 1558 |
+
if (cleaned) {
|
| 1559 |
+
saveSettings();
|
| 1560 |
+
}
|
| 1561 |
+
}
|
| 1562 |
+
|
| 1563 |
+
// Apply translations to the page with improved batch processing
|
| 1564 |
+
async function applyTranslations(langCode) {
|
| 1565 |
+
if (isTranslating) return;
|
| 1566 |
+
isTranslating = true;
|
| 1567 |
+
|
| 1568 |
+
const elements = document.querySelectorAll('[data-translate]');
|
| 1569 |
+
const placeholderElements = document.querySelectorAll('[data-translate-placeholder]');
|
| 1570 |
+
|
| 1571 |
+
// Add loading indicator
|
| 1572 |
+
document.body.classList.add('translation-loading');
|
| 1573 |
+
|
| 1574 |
+
// Show translation progress
|
| 1575 |
+
const progressElement = document.getElementById('progressBar');
|
| 1576 |
+
if (progressElement) {
|
| 1577 |
+
progressElement.style.width = '10%';
|
| 1578 |
+
}
|
| 1579 |
+
|
| 1580 |
+
try {
|
| 1581 |
+
// Clean old cache entries
|
| 1582 |
+
cleanOldCache();
|
| 1583 |
+
|
| 1584 |
+
if (langCode === 'en') {
|
| 1585 |
+
// Apply English (default) translations
|
| 1586 |
+
elements.forEach(element => {
|
| 1587 |
+
const key = element.getAttribute('data-translate');
|
| 1588 |
+
const originalText = defaultTranslations[key] || element.textContent;
|
| 1589 |
+
element.textContent = originalText;
|
| 1590 |
+
});
|
| 1591 |
+
|
| 1592 |
+
placeholderElements.forEach(element => {
|
| 1593 |
+
const key = element.getAttribute('data-translate-placeholder');
|
| 1594 |
+
if (key === 'api_key_placeholder') {
|
| 1595 |
+
element.setAttribute('placeholder', 'Enter your OpenAI API key');
|
| 1596 |
+
} else if (key === 'code_input_placeholder') {
|
| 1597 |
+
element.setAttribute('placeholder', 'Paste your code here... (supports all programming languages: Python, JavaScript, Java, C++, HTML, CSS, SQL, etc.)');
|
| 1598 |
+
}
|
| 1599 |
+
});
|
| 1600 |
+
} else {
|
| 1601 |
+
// Collect all texts to translate
|
| 1602 |
+
const textsToTranslate = [];
|
| 1603 |
+
const elementMap = [];
|
| 1604 |
+
|
| 1605 |
+
elements.forEach(element => {
|
| 1606 |
+
const key = element.getAttribute('data-translate');
|
| 1607 |
+
const originalText = defaultTranslations[key] || element.textContent;
|
| 1608 |
+
textsToTranslate.push(originalText);
|
| 1609 |
+
elementMap.push({ element, type: 'text' });
|
| 1610 |
+
});
|
| 1611 |
+
|
| 1612 |
+
placeholderElements.forEach(element => {
|
| 1613 |
+
const originalPlaceholder = element.getAttribute('placeholder');
|
| 1614 |
+
if (originalPlaceholder) {
|
| 1615 |
+
textsToTranslate.push(originalPlaceholder);
|
| 1616 |
+
elementMap.push({ element, type: 'placeholder' });
|
| 1617 |
+
}
|
| 1618 |
+
});
|
| 1619 |
+
|
| 1620 |
+
if (progressElement) {
|
| 1621 |
+
progressElement.style.width = '30%';
|
| 1622 |
+
}
|
| 1623 |
+
|
| 1624 |
+
// Batch translate all texts
|
| 1625 |
+
const translatedTexts = await translateBatch(textsToTranslate, langCode);
|
| 1626 |
+
|
| 1627 |
+
if (progressElement) {
|
| 1628 |
+
progressElement.style.width = '70%';
|
| 1629 |
+
}
|
| 1630 |
+
|
| 1631 |
+
// Apply translations
|
| 1632 |
+
translatedTexts.forEach((translatedText, index) => {
|
| 1633 |
+
const mapping = elementMap[index];
|
| 1634 |
+
if (mapping.type === 'text') {
|
| 1635 |
+
mapping.element.textContent = translatedText;
|
| 1636 |
+
} else if (mapping.type === 'placeholder') {
|
| 1637 |
+
mapping.element.setAttribute('placeholder', translatedText);
|
| 1638 |
+
}
|
| 1639 |
+
});
|
| 1640 |
+
}
|
| 1641 |
+
|
| 1642 |
+
if (progressElement) {
|
| 1643 |
+
progressElement.style.width = '90%';
|
| 1644 |
+
}
|
| 1645 |
+
|
| 1646 |
+
// Update current language display
|
| 1647 |
+
const language = languages.find(lang => lang.code === langCode);
|
| 1648 |
+
if (language) {
|
| 1649 |
+
const currentLangElement = document.getElementById('currentLanguageName');
|
| 1650 |
+
if (currentLangElement) {
|
| 1651 |
+
currentLangElement.textContent = language.nativeName;
|
| 1652 |
+
}
|
| 1653 |
+
}
|
| 1654 |
+
|
| 1655 |
+
if (progressElement) {
|
| 1656 |
+
progressElement.style.width = '100%';
|
| 1657 |
+
setTimeout(() => {
|
| 1658 |
+
progressElement.style.width = '0%';
|
| 1659 |
+
}, 1000);
|
| 1660 |
+
}
|
| 1661 |
+
|
| 1662 |
+
} catch (error) {
|
| 1663 |
+
console.error('Error applying translations:', error);
|
| 1664 |
+
// Show error message to user
|
| 1665 |
+
const errorDiv = document.getElementById('errorMessage');
|
| 1666 |
+
if (errorDiv) {
|
| 1667 |
+
errorDiv.textContent = `Translation error: ${error.message}`;
|
| 1668 |
+
errorDiv.style.display = 'block';
|
| 1669 |
+
setTimeout(() => {
|
| 1670 |
+
errorDiv.style.display = 'none';
|
| 1671 |
+
}, 5000);
|
| 1672 |
+
}
|
| 1673 |
+
} finally {
|
| 1674 |
+
document.body.classList.remove('translation-loading');
|
| 1675 |
+
isTranslating = false;
|
| 1676 |
+
}
|
| 1677 |
+
}
|
| 1678 |
+
|
| 1679 |
+
// Initialize the application with improved loading states
|
| 1680 |
+
function initializeApp() {
|
| 1681 |
+
loadSettings();
|
| 1682 |
+
populateLanguageDropdown();
|
| 1683 |
+
setTextDirection(currentLanguage);
|
| 1684 |
+
|
| 1685 |
+
// If language is already selected, show main app
|
| 1686 |
+
if (currentLanguage !== 'en' || localStorage.getItem('codetutor_language')) {
|
| 1687 |
+
showMainApp();
|
| 1688 |
+
|
| 1689 |
+
// Show loading state while translating
|
| 1690 |
+
const statusDiv = document.getElementById('statusMessage');
|
| 1691 |
+
if (statusDiv && currentLanguage !== 'en') {
|
| 1692 |
+
statusDiv.textContent = 'Loading translations...';
|
| 1693 |
+
statusDiv.style.display = 'block';
|
| 1694 |
+
}
|
| 1695 |
+
|
| 1696 |
+
applyTranslations(currentLanguage).then(() => {
|
| 1697 |
+
if (statusDiv) {
|
| 1698 |
+
statusDiv.style.display = 'none';
|
| 1699 |
+
}
|
| 1700 |
+
});
|
| 1701 |
+
}
|
| 1702 |
+
}
|
| 1703 |
+
|
| 1704 |
+
// Show main application with smooth transition
|
| 1705 |
+
function showMainApp() {
|
| 1706 |
+
const landingPage = document.getElementById('landingPage');
|
| 1707 |
+
const mainApp = document.getElementById('mainApp');
|
| 1708 |
+
|
| 1709 |
+
landingPage.classList.add('hidden');
|
| 1710 |
+
mainApp.classList.add('active');
|
| 1711 |
+
|
| 1712 |
+
// Copy API key from landing to main app
|
| 1713 |
+
const landingApiKey = document.getElementById('landingApiKey').value;
|
| 1714 |
+
if (landingApiKey) {
|
| 1715 |
+
document.getElementById('apiKey').value = landingApiKey;
|
| 1716 |
+
localStorage.setItem('codetutor_api_key', landingApiKey);
|
| 1717 |
+
}
|
| 1718 |
+
|
| 1719 |
+
// Focus on code input for better UX
|
| 1720 |
+
setTimeout(() => {
|
| 1721 |
+
const codeInput = document.getElementById('codeInput');
|
| 1722 |
+
if (codeInput) {
|
| 1723 |
+
codeInput.focus();
|
| 1724 |
+
}
|
| 1725 |
+
}, 500);
|
| 1726 |
+
}
|
| 1727 |
+
|
| 1728 |
+
// Show landing page with reset
|
| 1729 |
+
function showLandingPage() {
|
| 1730 |
+
const landingPage = document.getElementById('landingPage');
|
| 1731 |
+
const mainApp = document.getElementById('mainApp');
|
| 1732 |
+
|
| 1733 |
+
landingPage.classList.remove('hidden');
|
| 1734 |
+
mainApp.classList.remove('active');
|
| 1735 |
+
|
| 1736 |
+
// Reset language selection to current language
|
| 1737 |
+
const languageSelect = document.getElementById('languageSelect');
|
| 1738 |
+
if (languageSelect) {
|
| 1739 |
+
languageSelect.value = currentLanguage;
|
| 1740 |
+
}
|
| 1741 |
+
}
|
| 1742 |
+
|
| 1743 |
+
// Event Listeners
|
| 1744 |
+
document.getElementById('startBtn').addEventListener('click', async function() {
|
| 1745 |
+
const selectedLanguage = document.getElementById('languageSelect').value;
|
| 1746 |
+
const apiKey = document.getElementById('landingApiKey').value.trim();
|
| 1747 |
+
|
| 1748 |
+
if (!selectedLanguage) {
|
| 1749 |
+
alert('Please select a language');
|
| 1750 |
+
return;
|
| 1751 |
+
}
|
| 1752 |
+
|
| 1753 |
+
if (!apiKey) {
|
| 1754 |
+
alert('Please enter your OpenAI API key');
|
| 1755 |
+
return;
|
| 1756 |
+
}
|
| 1757 |
+
|
| 1758 |
+
// Save settings
|
| 1759 |
+
currentLanguage = selectedLanguage;
|
| 1760 |
+
localStorage.setItem('codetutor_api_key', apiKey);
|
| 1761 |
+
saveSettings();
|
| 1762 |
+
|
| 1763 |
+
// Set text direction
|
| 1764 |
+
setTextDirection(currentLanguage);
|
| 1765 |
+
|
| 1766 |
+
// Show main app
|
| 1767 |
+
showMainApp();
|
| 1768 |
+
|
| 1769 |
+
// Apply translations
|
| 1770 |
+
await applyTranslations(currentLanguage);
|
| 1771 |
+
});
|
| 1772 |
+
|
| 1773 |
+
document.getElementById('changeLanguageBtn').addEventListener('click', function() {
|
| 1774 |
+
showLandingPage();
|
| 1775 |
+
});
|
| 1776 |
+
|
| 1777 |
+
document.getElementById('clearCacheBtn').addEventListener('click', function() {
|
| 1778 |
+
const cacheSize = Object.keys(translationCache).length;
|
| 1779 |
+
const cacheMemory = JSON.stringify(translationCache).length;
|
| 1780 |
+
const cacheMemoryKB = Math.round(cacheMemory / 1024);
|
| 1781 |
+
|
| 1782 |
+
const confirmMessage = `Clear translation cache?\n\nCurrent cache contains:\n• ${cacheSize} translations\n• ~${cacheMemoryKB} KB of data\n\nThis will remove all cached translations and may require re-translating content.`;
|
| 1783 |
+
|
| 1784 |
+
if (confirm(confirmMessage)) {
|
| 1785 |
+
translationCache = {};
|
| 1786 |
+
localStorage.removeItem('codetutor_translation_cache');
|
| 1787 |
+
|
| 1788 |
+
// Show success message
|
| 1789 |
+
const statusDiv = document.getElementById('statusMessage');
|
| 1790 |
+
if (statusDiv) {
|
| 1791 |
+
statusDiv.textContent = `Translation cache cleared! Removed ${cacheSize} cached translations.`;
|
| 1792 |
+
statusDiv.style.display = 'block';
|
| 1793 |
+
setTimeout(() => {
|
| 1794 |
+
statusDiv.style.display = 'none';
|
| 1795 |
+
}, 3000);
|
| 1796 |
+
} else {
|
| 1797 |
+
alert(`Translation cache cleared successfully! Removed ${cacheSize} cached translations.`);
|
| 1798 |
+
}
|
| 1799 |
+
}
|
| 1800 |
+
});
|
| 1801 |
+
|
| 1802 |
+
// Store API key in localStorage
|
| 1803 |
+
const apiKeyInput = document.getElementById('apiKey');
|
| 1804 |
+
const landingApiKeyInput = document.getElementById('landingApiKey');
|
| 1805 |
+
|
| 1806 |
+
[apiKeyInput, landingApiKeyInput].forEach(input => {
|
| 1807 |
+
input.addEventListener('input', function() {
|
| 1808 |
+
localStorage.setItem('codetutor_api_key', this.value);
|
| 1809 |
+
// Sync both inputs
|
| 1810 |
+
if (this.id === 'apiKey') {
|
| 1811 |
+
landingApiKeyInput.value = this.value;
|
| 1812 |
+
} else {
|
| 1813 |
+
apiKeyInput.value = this.value;
|
| 1814 |
+
}
|
| 1815 |
+
});
|
| 1816 |
+
});
|
| 1817 |
+
|
| 1818 |
+
// Initialize when page loads
|
| 1819 |
+
document.addEventListener('DOMContentLoaded', initializeApp);
|
| 1820 |
+
|
| 1821 |
+
// Character counter
|
| 1822 |
+
const codeInputTextarea = document.getElementById('codeInput');
|
| 1823 |
+
const charCountSpan = document.getElementById('charCount');
|
| 1824 |
+
|
| 1825 |
+
codeInputTextarea.addEventListener('input', function() {
|
| 1826 |
+
const currentLength = this.value.length;
|
| 1827 |
+
charCountSpan.textContent = currentLength;
|
| 1828 |
+
|
| 1829 |
+
if (currentLength > 9000) {
|
| 1830 |
+
charCountSpan.style.color = 'var(--warning)';
|
| 1831 |
+
} else if (currentLength > 9500) {
|
| 1832 |
+
charCountSpan.style.color = 'var(--error)';
|
| 1833 |
+
} else {
|
| 1834 |
+
charCountSpan.style.color = 'var(--text-secondary)';
|
| 1835 |
+
}
|
| 1836 |
+
});
|
| 1837 |
+
|
| 1838 |
+
// Update progress bar
|
| 1839 |
+
function updateProgress(percent) {
|
| 1840 |
+
document.getElementById('progressBar').style.width = percent + '%';
|
| 1841 |
+
}
|
| 1842 |
+
|
| 1843 |
+
// Show status message
|
| 1844 |
+
function showStatus(message) {
|
| 1845 |
+
const statusDiv = document.getElementById('statusMessage');
|
| 1846 |
+
statusDiv.textContent = message;
|
| 1847 |
+
statusDiv.style.display = 'block';
|
| 1848 |
+
}
|
| 1849 |
+
|
| 1850 |
+
// Hide status message
|
| 1851 |
+
function hideStatus() {
|
| 1852 |
+
document.getElementById('statusMessage').style.display = 'none';
|
| 1853 |
+
}
|
| 1854 |
+
|
| 1855 |
+
// Error handling
|
| 1856 |
+
function showError(message) {
|
| 1857 |
+
const errorDiv = document.getElementById('errorMessage');
|
| 1858 |
+
errorDiv.textContent = message;
|
| 1859 |
+
errorDiv.style.display = 'block';
|
| 1860 |
+
setTimeout(() => {
|
| 1861 |
+
errorDiv.style.display = 'none';
|
| 1862 |
+
}, 5000);
|
| 1863 |
+
}
|
| 1864 |
+
|
| 1865 |
+
// Build the comprehensive code explanation prompt
|
| 1866 |
+
function buildCodeExplanationPrompt() {
|
| 1867 |
+
const codeInput = document.getElementById('codeInput').value.trim();
|
| 1868 |
+
const programmingLanguage = document.getElementById('programmingLanguage').value;
|
| 1869 |
+
const explanationLevel = document.getElementById('explanationLevel').value;
|
| 1870 |
+
|
| 1871 |
+
const languageContext = programmingLanguage ? `Programming Language: ${programmingLanguage}` : 'Programming Language: Auto-detect from code';
|
| 1872 |
+
|
| 1873 |
+
// Get the target language for the explanation
|
| 1874 |
+
const language = languages.find(lang => lang.code === currentLanguage);
|
| 1875 |
+
const languageName = language ? language.name : 'English';
|
| 1876 |
+
|
| 1877 |
+
return `You are CodeTutor Pro, an expert programming instructor and code explainer. Your mission is to make complex code understandable for learners at different levels. A user has provided code and wants a comprehensive explanation.
|
| 1878 |
+
|
| 1879 |
+
IMPORTANT: Provide the entire response in ${languageName}. All explanations, headings, and content should be in ${languageName}.
|
| 1880 |
+
|
| 1881 |
+
CRITICAL INSTRUCTION: DO NOT include any code snippets, code blocks, or actual code in your response. Provide ONLY descriptive explanations in natural language. Instead of showing code, describe what the code does in detail using words only.
|
| 1882 |
+
|
| 1883 |
+
USER DETAILS:
|
| 1884 |
+
${languageContext}
|
| 1885 |
+
Explanation Level: ${explanationLevel}
|
| 1886 |
+
Response Language: ${languageName}
|
| 1887 |
+
|
| 1888 |
+
CODE TO EXPLAIN:
|
| 1889 |
+
<<<BEGIN CODE>>>
|
| 1890 |
+
${codeInput}
|
| 1891 |
+
<<<END CODE>>>
|
| 1892 |
+
|
| 1893 |
+
Provide a comprehensive, well-structured explanation using section headers with underlines (not numbered lists). Format your response with clear section headers followed by detailed paragraphs. Use this structure:
|
| 1894 |
+
|
| 1895 |
+
**Section Header Format**: Use descriptive section titles that explain what will be discussed, followed by detailed paragraphs.
|
| 1896 |
+
|
| 1897 |
+
Structure your explanation with these types of sections:
|
| 1898 |
+
|
| 1899 |
+
**Code Overview Section**
|
| 1900 |
+
- What this code does in simple terms
|
| 1901 |
+
- The main purpose and functionality
|
| 1902 |
+
- What problem it solves or what task it accomplishes
|
| 1903 |
+
|
| 1904 |
+
**Detailed Analysis Section**
|
| 1905 |
+
- Describe each section and component in detail using natural language
|
| 1906 |
+
- Explain what each part does and why it's needed without showing the actual code
|
| 1907 |
+
- Describe how different parts work together
|
| 1908 |
+
|
| 1909 |
+
**Key Concepts Section**
|
| 1910 |
+
- Important programming concepts demonstrated in this code
|
| 1911 |
+
- Explain any algorithms, data structures, or design patterns used
|
| 1912 |
+
- Define technical terms in simple language
|
| 1913 |
+
|
| 1914 |
+
**Execution Flow Section**
|
| 1915 |
+
- Step-by-step execution flow described in words
|
| 1916 |
+
- What happens when the code runs
|
| 1917 |
+
- Input and output explanation
|
| 1918 |
+
|
| 1919 |
+
**Learning Insights Section**
|
| 1920 |
+
- What beginners can learn from this code
|
| 1921 |
+
- Best practices demonstrated
|
| 1922 |
+
- Common patterns or techniques shown
|
| 1923 |
+
|
| 1924 |
+
**Practical Applications Section**
|
| 1925 |
+
- Where this type of code might be used
|
| 1926 |
+
- Real-world scenarios and examples
|
| 1927 |
+
- How it could be modified or extended
|
| 1928 |
+
|
| 1929 |
+
FORMATTING INSTRUCTIONS:
|
| 1930 |
+
- Use descriptive section headers (not numbered lists like 1., 2., 3.)
|
| 1931 |
+
- Write each section as flowing paragraphs of text
|
| 1932 |
+
- Ensure proper text direction for RTL languages
|
| 1933 |
+
- Integrate English technical terms naturally within the text flow
|
| 1934 |
+
- Use clear, professional formatting with proper spacing
|
| 1935 |
+
|
| 1936 |
+
Tailor your explanation to the ${explanationLevel} level:
|
| 1937 |
+
- **Complete Beginner**: Use very simple language, explain basic concepts, avoid jargon
|
| 1938 |
+
- **Beginner**: Use clear language, explain intermediate concepts, minimal jargon with definitions
|
| 1939 |
+
- **Intermediate**: Use standard programming terminology, focus on logic and structure
|
| 1940 |
+
- **Advanced**: Use technical language, focus on optimization, patterns, and best practices
|
| 1941 |
+
|
| 1942 |
+
Make the explanation engaging, educational, and easy to follow. Use examples and analogies when helpful. Format with clear headings and structure for easy reading.
|
| 1943 |
+
|
| 1944 |
+
REMEMBER: Write everything in ${languageName}. DO NOT include any code snippets or code blocks - provide ONLY descriptive text explanations.`;
|
| 1945 |
+
}
|
| 1946 |
+
|
| 1947 |
+
// API call function
|
| 1948 |
+
async function callAPI(prompt) {
|
| 1949 |
+
const apiKey = document.getElementById('apiKey').value.trim();
|
| 1950 |
+
|
| 1951 |
+
if (!apiKey) {
|
| 1952 |
+
throw new Error('Please enter your OpenAI API key');
|
| 1953 |
+
}
|
| 1954 |
+
|
| 1955 |
+
const payload = {
|
| 1956 |
+
model: "gpt-4o-mini",
|
| 1957 |
+
messages: [{ role: "system", content: prompt }],
|
| 1958 |
+
max_tokens: 16000,
|
| 1959 |
+
temperature: 0.5
|
| 1960 |
+
};
|
| 1961 |
+
|
| 1962 |
+
const response = await fetch("https://api.openai.com/v1/chat/completions", {
|
| 1963 |
+
method: "POST",
|
| 1964 |
+
headers: {
|
| 1965 |
+
"Content-Type": "application/json",
|
| 1966 |
+
"Authorization": `Bearer ${apiKey}`
|
| 1967 |
+
},
|
| 1968 |
+
body: JSON.stringify(payload)
|
| 1969 |
+
});
|
| 1970 |
+
|
| 1971 |
+
if (!response.ok) {
|
| 1972 |
+
const errorData = await response.json();
|
| 1973 |
+
throw new Error(errorData.error?.message || "API request failed");
|
| 1974 |
+
}
|
| 1975 |
+
|
| 1976 |
+
const data = await response.json();
|
| 1977 |
+
|
| 1978 |
+
// Debug: Log the full response to check for truncation
|
| 1979 |
+
console.log('Full API response:', data);
|
| 1980 |
+
|
| 1981 |
+
// Check if the response was truncated
|
| 1982 |
+
if (data.choices[0].finish_reason === 'length') {
|
| 1983 |
+
console.warn('Response was truncated due to max_tokens limit');
|
| 1984 |
+
}
|
| 1985 |
+
|
| 1986 |
+
return data.choices[0].message.content;
|
| 1987 |
+
}
|
| 1988 |
+
|
| 1989 |
+
// Validation function
|
| 1990 |
+
function validateInputs() {
|
| 1991 |
+
const codeInput = document.getElementById('codeInput').value.trim();
|
| 1992 |
+
const explanationLevel = document.getElementById('explanationLevel').value;
|
| 1993 |
+
|
| 1994 |
+
if (!codeInput) {
|
| 1995 |
+
document.getElementById('codeInput').focus();
|
| 1996 |
+
throw new Error('Please enter the code you want explained');
|
| 1997 |
+
}
|
| 1998 |
+
|
| 1999 |
+
if (codeInput.length < 10) {
|
| 2000 |
+
document.getElementById('codeInput').focus();
|
| 2001 |
+
throw new Error('Please provide more code to analyze (at least 10 characters)');
|
| 2002 |
+
}
|
| 2003 |
+
|
| 2004 |
+
if (!explanationLevel) {
|
| 2005 |
+
document.getElementById('explanationLevel').focus();
|
| 2006 |
+
throw new Error('Please select your explanation level');
|
| 2007 |
+
}
|
| 2008 |
+
}
|
| 2009 |
+
|
| 2010 |
+
// Handle form submission
|
| 2011 |
+
document.getElementById('generateBtn').addEventListener('click', async function() {
|
| 2012 |
+
const button = this;
|
| 2013 |
+
const buttonText = document.getElementById('buttonText');
|
| 2014 |
+
const spinner = document.getElementById('spinner');
|
| 2015 |
+
const explanationOutput = document.getElementById('explanationOutput');
|
| 2016 |
+
|
| 2017 |
+
try {
|
| 2018 |
+
// Validate inputs
|
| 2019 |
+
validateInputs();
|
| 2020 |
+
|
| 2021 |
+
// Update button state
|
| 2022 |
+
button.disabled = true;
|
| 2023 |
+
spinner.style.display = 'inline-block';
|
| 2024 |
+
buttonText.textContent = 'Analyzing Code...';
|
| 2025 |
+
|
| 2026 |
+
// Clear previous output
|
| 2027 |
+
explanationOutput.innerHTML = '';
|
| 2028 |
+
hideStatus();
|
| 2029 |
+
|
| 2030 |
+
// Show progress and status
|
| 2031 |
+
updateProgress(20);
|
| 2032 |
+
showStatus("Analyzing code structure and syntax...");
|
| 2033 |
+
|
| 2034 |
+
// Build prompt and call API
|
| 2035 |
+
const prompt = buildCodeExplanationPrompt();
|
| 2036 |
+
|
| 2037 |
+
updateProgress(50);
|
| 2038 |
+
showStatus("Generating comprehensive explanation...");
|
| 2039 |
+
|
| 2040 |
+
const result = await callAPI(prompt);
|
| 2041 |
+
|
| 2042 |
+
updateProgress(100);
|
| 2043 |
+
hideStatus();
|
| 2044 |
+
|
| 2045 |
+
// Display result with section headers and underlines format
|
| 2046 |
+
let formattedResult = result;
|
| 2047 |
+
|
| 2048 |
+
// Debug: Log the raw result to see what we're getting
|
| 2049 |
+
console.log('Raw API result:', result);
|
| 2050 |
+
|
| 2051 |
+
// Remove any code block markers that might accidentally be included
|
| 2052 |
+
formattedResult = formattedResult.replace(/```[\s\S]*?```/g, '');
|
| 2053 |
+
formattedResult = formattedResult.replace(/`([^`\n]+)`/g, '$1');
|
| 2054 |
+
|
| 2055 |
+
// Handle section headers with underlines (convert markdown headers to section headers)
|
| 2056 |
+
formattedResult = formattedResult.replace(/^## (.*?)$/gm, '<div class="section-header">$1</div>');
|
| 2057 |
+
formattedResult = formattedResult.replace(/^### (.*?)$/gm, '<div class="section-header">$1</div>');
|
| 2058 |
+
formattedResult = formattedResult.replace(/^#### (.*?)$/gm, '<div class="section-header">$1</div>');
|
| 2059 |
+
|
| 2060 |
+
// Handle bold text
|
| 2061 |
+
formattedResult = formattedResult.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
|
| 2062 |
+
|
| 2063 |
+
// Convert line breaks to <br> tags BEFORE processing sections
|
| 2064 |
+
formattedResult = formattedResult.replace(/\n/g, "<br>");
|
| 2065 |
+
|
| 2066 |
+
// Group content after section headers into section-content divs
|
| 2067 |
+
formattedResult = formattedResult.replace(/(<div class="section-header">.*?<\/div>)<br>(.*?)(?=<div class="section-header">|$)/g,
|
| 2068 |
+
'$1<br><div class="section-content">$2</div>');
|
| 2069 |
+
|
| 2070 |
+
// Clean up extra <br> tags around section headers
|
| 2071 |
+
formattedResult = formattedResult.replace(/<br><div class="section-header">/g, '<div class="section-header">');
|
| 2072 |
+
formattedResult = formattedResult.replace(/<\/div><br><div class="section-content">/g, '</div><div class="section-content">');
|
| 2073 |
+
|
| 2074 |
+
// Handle any remaining content that's not in a section (like intro text)
|
| 2075 |
+
if (!formattedResult.includes('<div class="section-header">')) {
|
| 2076 |
+
// If no section headers, wrap everything in section-content
|
| 2077 |
+
formattedResult = `<div class="section-content">${formattedResult}</div>`;
|
| 2078 |
+
} else {
|
| 2079 |
+
// Handle content before the first section header
|
| 2080 |
+
formattedResult = formattedResult.replace(/^(.*?)(<div class="section-header">)/s,
|
| 2081 |
+
'<div class="section-content">$1</div>$2');
|
| 2082 |
+
}
|
| 2083 |
+
|
| 2084 |
+
explanationOutput.innerHTML = formattedResult;
|
| 2085 |
+
|
| 2086 |
+
} catch (error) {
|
| 2087 |
+
console.error('Error:', error);
|
| 2088 |
+
showError(error.message);
|
| 2089 |
+
explanationOutput.innerHTML = '';
|
| 2090 |
+
hideStatus();
|
| 2091 |
+
updateProgress(0);
|
| 2092 |
+
} finally {
|
| 2093 |
+
// Reset button state
|
| 2094 |
+
button.disabled = false;
|
| 2095 |
+
spinner.style.display = 'none';
|
| 2096 |
+
buttonText.textContent = '🧠 Generate Explanation';
|
| 2097 |
+
}
|
| 2098 |
+
});
|
| 2099 |
+
|
| 2100 |
+
// Handle input changes
|
| 2101 |
+
document.getElementById('codeInput').addEventListener('input', function() {
|
| 2102 |
+
updateProgress(0);
|
| 2103 |
+
hideStatus();
|
| 2104 |
+
});
|
| 2105 |
+
|
| 2106 |
+
document.getElementById('programmingLanguage').addEventListener('change', function() {
|
| 2107 |
+
updateProgress(0);
|
| 2108 |
+
hideStatus();
|
| 2109 |
+
});
|
| 2110 |
+
|
| 2111 |
+
document.getElementById('explanationLevel').addEventListener('change', function() {
|
| 2112 |
+
updateProgress(0);
|
| 2113 |
+
hideStatus();
|
| 2114 |
+
});
|
| 2115 |
+
|
| 2116 |
+
// Keyboard shortcut for generation
|
| 2117 |
+
document.addEventListener('keydown', function(e) {
|
| 2118 |
+
if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
|
| 2119 |
+
e.preventDefault();
|
| 2120 |
+
if (document.getElementById('mainApp').classList.contains('active')) {
|
| 2121 |
+
document.getElementById('generateBtn').click();
|
| 2122 |
+
}
|
| 2123 |
+
}
|
| 2124 |
+
});
|
| 2125 |
+
|
| 2126 |
+
// Handle contenteditable placeholder
|
| 2127 |
+
const outputArea = document.getElementById('explanationOutput');
|
| 2128 |
+
outputArea.addEventListener('focus', function() {
|
| 2129 |
+
if (this.innerHTML === '') {
|
| 2130 |
+
this.innerHTML = '';
|
| 2131 |
+
}
|
| 2132 |
+
});
|
| 2133 |
+
|
| 2134 |
+
outputArea.addEventListener('blur', function() {
|
| 2135 |
+
if (this.innerHTML.trim() === '') {
|
| 2136 |
+
this.innerHTML = '';
|
| 2137 |
+
}
|
| 2138 |
+
});
|
| 2139 |
+
</script>
|
| 2140 |
+
</body>
|
| 2141 |
+
</html>
|
| 2142 |
+
|
📘 Educator & Student Guide CodeTut.txt
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
📘 Educator & Student Guide: CodeTutor Pro
|
| 2 |
+
1. Purpose & Audience
|
| 3 |
+
CodeTutor Pro enables anyone—from total beginners to advanced programmers—to receive natural-language, stepwise code explanations in their preferred language and depth. It’s ideal for schools, self-learners, and multilingual classes.
|
| 4 |
+
|
| 5 |
+
2. Getting Started
|
| 6 |
+
Access: Open the HTML file or visit the Hugging Face Space.
|
| 7 |
+
|
| 8 |
+
Select Language: Choose from 90+ languages (including Arabic, Chinese, Spanish, and more). UI and outputs are instantly translated.
|
| 9 |
+
|
| 10 |
+
Enter OpenAI API Key: This enables AI-powered code analysis and translation. The key is never shared externally.
|
| 11 |
+
|
| 12 |
+
3. Using the Tool
|
| 13 |
+
A. Input Your Code
|
| 14 |
+
|
| 15 |
+
Paste code (any language or style) into the main textbox.
|
| 16 |
+
|
| 17 |
+
Select the language and explanation level for tailored feedback.
|
| 18 |
+
|
| 19 |
+
B. Generate Explanation
|
| 20 |
+
|
| 21 |
+
Click “🧠 Generate Explanation”.
|
| 22 |
+
|
| 23 |
+
The tool analyzes code and produces sectioned, beginner-friendly output with no code snippets—just clear, structured text.
|
| 24 |
+
|
| 25 |
+
C. Review & Edit
|
| 26 |
+
|
| 27 |
+
Output is editable. Click anywhere to add notes, highlight key points, or personalize the explanation.
|
| 28 |
+
|
| 29 |
+
D. Switch Languages or Depth
|
| 30 |
+
|
| 31 |
+
Change UI/output language or explanation depth at any time for differentiated learning.
|
| 32 |
+
|
| 33 |
+
4. Advanced Tips
|
| 34 |
+
Classroom Use:
|
| 35 |
+
|
| 36 |
+
Assign code samples and have students explain, compare, or critique AI outputs.
|
| 37 |
+
|
| 38 |
+
Great for flipped learning, remote/hybrid classrooms, or international groups.
|
| 39 |
+
|
| 40 |
+
Professional/PD Use:
|
| 41 |
+
|
| 42 |
+
Use for onboarding staff, cross-team code sharing, or technical documentation.
|
| 43 |
+
|
| 44 |
+
Support Multilingual Learners:
|
| 45 |
+
|
| 46 |
+
Instantly switch explanation language for ELLs or bilingual programs.
|
| 47 |
+
|
| 48 |
+
Portfolio Building:
|
| 49 |
+
|
| 50 |
+
Students can save, edit, and showcase their understanding of code for projects or interviews.
|
| 51 |
+
|
| 52 |
+
5. Data Privacy & Security
|
| 53 |
+
All operations are fully local; nothing leaves your browser.
|
| 54 |
+
|
| 55 |
+
No login, registration, or data collection.
|
| 56 |
+
|
| 57 |
+
API keys and code remain on your device only.
|
| 58 |
+
|
| 59 |
+
6. Troubleshooting & Support
|
| 60 |
+
API Key Errors:
|
| 61 |
+
|
| 62 |
+
Make sure your OpenAI key is valid and has sufficient quota.
|
| 63 |
+
|
| 64 |
+
Translation Issues:
|
| 65 |
+
|
| 66 |
+
Try clearing the translation cache or reloading the app.
|
| 67 |
+
|
| 68 |
+
Output Issues:
|
| 69 |
+
|
| 70 |
+
For very large code or long outputs, break code into sections for better results.
|
| 71 |
+
|
| 72 |
+
Contact:
|
| 73 |
+
|
| 74 |
+
Email info@shiftmind.io or visit www.shiftmind.io.
|
| 75 |
+
|
| 76 |
+
CodeTutor Pro brings high-quality, safe, multilingual code explanations to every learner—everywhere.
|