From 83551d40410315eb71e07ee8db25d69e7b4b9fe1 Mon Sep 17 00:00:00 2001 From: HFerrahoglu Date: Sun, 20 Jul 2025 01:40:06 +0300 Subject: [PATCH] Initial commit: Chrome extension with enhanced data sets and full-screen settings modal --- .eslintrc.json | 11 + .github/ISSUE_TEMPLATE/bug_report.md | 40 ++ .github/ISSUE_TEMPLATE/custom.md | 7 + .github/ISSUE_TEMPLATE/feature_request.md | 19 + .github/PULL_REQUEST_TEMPLATE.md | 33 ++ .github/self_review.md | 15 + .gitignore | 171 ++++++ .prettierrc | 7 + README.md | 113 ++++ assets/icon128.png | Bin 0 -> 10320 bytes assets/icon16.png | Bin 0 -> 508 bytes assets/icon32.png | Bin 0 -> 1490 bytes assets/icon48.png | Bin 0 -> 4075 bytes background.js | 151 +++++ data/address.json | 70 +++ data/email.json | 319 +++++++++++ data/enAddress.json | 42 ++ data/enFemaleFirstName.json | 229 ++++++++ data/enMaleFirstName.json | 171 ++++++ data/enSurname.json | 532 +++++++++++++++++ data/femaleFirstName.json | 209 +++++++ data/maleFirstName.json | 212 +++++++ data/password.json | 165 ++++++ data/surname.json | 180 ++++++ manifest.json | 33 ++ package.json | 24 + popup.html | 200 +++++++ privacy-policy.txt | 27 + src/css/popup.css | 666 ++++++++++++++++++++++ src/js/copy.js | 42 ++ src/js/func.js | 35 ++ src/js/i18n.js | 227 ++++++++ src/js/misc.js | 430 ++++++++++++++ src/js/popup.js | 419 ++++++++++++++ src/js/settings.js | 229 ++++++++ 35 files changed, 5028 insertions(+) create mode 100644 .eslintrc.json create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/custom.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/self_review.md create mode 100644 .gitignore create mode 100644 .prettierrc create mode 100644 README.md create mode 100644 assets/icon128.png create mode 100644 assets/icon16.png create mode 100644 assets/icon32.png create mode 100644 assets/icon48.png create mode 100644 background.js create mode 100644 data/address.json create mode 100644 data/email.json create mode 100644 data/enAddress.json create mode 100644 data/enFemaleFirstName.json create mode 100644 data/enMaleFirstName.json create mode 100644 data/enSurname.json create mode 100644 data/femaleFirstName.json create mode 100644 data/maleFirstName.json create mode 100644 data/password.json create mode 100644 data/surname.json create mode 100644 manifest.json create mode 100644 package.json create mode 100644 popup.html create mode 100644 privacy-policy.txt create mode 100644 src/css/popup.css create mode 100644 src/js/copy.js create mode 100644 src/js/func.js create mode 100644 src/js/i18n.js create mode 100644 src/js/misc.js create mode 100644 src/js/popup.js create mode 100644 src/js/settings.js diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..4a9616d --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,11 @@ +{ + "env": { + "browser": true, + "es2021": true + }, + "extends": "eslint:recommended", + "parserOptions": { + "ecmaVersion": 12 + }, + "rules": {} +} diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..b5c68e5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,40 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: + +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + +- OS: [e.g. iOS] +- Browser [e.g. chrome, safari] +- Version [e.g. 22] + +**Smartphone (please complete the following information):** + +- Device: [e.g. iPhone6] +- OS: [e.g. iOS8.1] +- Browser [e.g. stock browser, safari] +- Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/custom.md b/.github/ISSUE_TEMPLATE/custom.md new file mode 100644 index 0000000..96a4735 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/custom.md @@ -0,0 +1,7 @@ +--- +name: Custom issue template +about: Describe this issue template's purpose here. +title: '' +labels: '' +assignees: '' +--- diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..2f28cea --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,19 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..8734870 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,33 @@ + + +**This PR Closes:** + + + +A clear and concise description of which issue this PR closes. (You can tag issues by writing `#issuenum`) [REPLACE ME] + +**What's being changed in this PR (if available, include any code snippets, screenshots, or gifs)** + + + +A clear and concise description of what's being changed. [REPLACE ME] + +--- + +### Checklist + +Before submitting the PR make sure the following are checked: + + + +- [ ] I've created new branch in my fork for this PR. +- [ ] For content changes, I have completed the [self-review checklist](self_review.md). diff --git a/.github/self_review.md b/.github/self_review.md new file mode 100644 index 0000000..1c13810 --- /dev/null +++ b/.github/self_review.md @@ -0,0 +1,15 @@ +## Self review + +You should always review your own PR first. + +For changes, make sure that you: + + + +- [ ] Please be sure you've created a new branch in your fork for this PR. +- [ ] Pull Request should be related to one change. Changes that are unrelated should be opened in separate PRs. +- [ ] Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable. +- [ ] Confirm that the changes meet the user experience and goals outlined in the content design plan (if there is one). +- [ ] Review the content for technical accuracy. +- [ ] Copy-edit the changes for grammar, spelling, and syntax errors. +- [ ] If there are any failing checks in your PR, troubleshoot them until they're all passing. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b83a362 --- /dev/null +++ b/.gitignore @@ -0,0 +1,171 @@ +# Ignore node_modules directory +node_modules/ + +# Ignore build artifacts +dist/ +build/ + +# Ignore IDE and editor files +.vscode/ +.idea/ +*.sublime-project +*.sublime-workspace + +# Ignore logs and temporary files +*.log +*.tmp + +# Ignore environment-specific files +.env +.env.local +.env.*.local +.env.*.production + +# Ignore sensitive or personal information +config.js +secrets.json + +# Ignore package-lock.json +package-lock.json + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +# Ignore any other files or directories specific to your project +.DS_Store + +test-string-generator.zip +storedescriptions + +# Development and documentation files (keep locally, don't track in git) +.cursorrules +CODE_STYLE.md +PROGRESS.md diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..ad5b5e1 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,7 @@ +{ + "singleQuote": true, + "trailingComma": "es5", + "tabWidth": 2, + "semi": true, + "printWidth": 100 +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..3fb57a1 --- /dev/null +++ b/README.md @@ -0,0 +1,113 @@ +# Text String Generator Chrome Extension + +## 🛒 Install from Chrome Web Store + +The extension is now available on the Chrome Web Store! [**Install it directly from here**]() + +[![Chrome Web Store](https://img.shields.io/chrome-web-store/v/dncchfcbdengdgodhbjmakoaiildjigl?style=for-the-badge&logo=google-chrome)]() + +> **Recommended:** For the easiest and most up-to-date experience, install via the Chrome Web Store link above. + +## 🚀 Stable Release + +For the most stable and fully tested version, [**download the latest release here**](https://github.com/sevilayerkan/test-string-extention/releases/tag/v0.2.0-alpha). + +> **Note:** The `main` branch is pre-production and may include features under development. For production use, always prefer the latest release above. + +## Project Details + +Text String Generator is a powerful and versatile Chrome browser extension designed to assist developers and testers by generating customizable test text data. Whether you need specific-length strings, Lorem Ipsum text, or randomized data, this tool is designed with simplicity and efficiency in mind. + +With the latest update, the extension includes a modernized, tabbed interface for seamless navigation, Dark Mode support, and a **Miscellaneous** section for generating Turkish names, addresses, and passwords. Optimized for security and memory usage, this extension ensures smooth performance without compromising functionality. + +Once installed, the extension works completely offline, allowing users to continue using all features without an active internet connection. + +> For quick demo please click here + + +## Installation + +### Preferred: Install from Chrome Web Store + +1. Go to the [Chrome Web Store listing](). +2. Click "Add to Chrome" and follow the prompts. +3. The extension icon will appear in your Chrome toolbar after installation. + +### Manual Installation (for development or advanced users): + +1- Download the Extension Files: + +- Download the HTML, CSS, JS, and manifest.json files from this repository. +- If you want to use fully stable version please download files from release - add link https://github.com/sevilayerkan/test-string-extention/releases/tag/v0.2.0-alpha + +2- Set Up the Extension: + +- Create a new folder on your computer to store the extension files. +- Place the downloaded HTML, CSS, JS, and manifest.json files into the folder. + +3- Load the Extension in Chrome: + +- Open Google Chrome and navigate to chrome://extensions/. +- Enable "Developer mode" in the top right corner of the page. + +4- Load Unpacked Extension: + +- Click on the "Load unpacked" button. +- Select the folder where you saved the extension files. +- Test the Extension: + +5- After loading the extension, you should see the extension icon in your Chrome toolbar. + +## Usage + +1. Click on the extension icon to open the popup. +2. Enter the desired text length for generation. +3. Use the following options to customize the text: + - **Remove Punctuation**: Exclude punctuation marks from the generated text. + - **Remove Spaces**: Remove spaces between words. +4. Use the **Character Counter** to see the real-time length of the given text. +5. Navigate to the **Miscellaneous** tab for additional tools: + - Generate **Turkish Names** for use in test scenarios. + - Generate **Email Adresses** for use in test scenarios. + - Create **Turkish Addresses** for testing localization. + - Generate secure **Passwords** for test accounts or other needs. +6. Click "Generate" to create the customized text. +7. Copy the generated text to the clipboard using the "Copy to Clipboard" button. + +## Honorable Mentions + +Special thanks to my friend’s repository for its inspiration and usage: + +- [Custom Turkish Data Generator](https://github.com/tw4/responserun-mock) + +## Features + +- **Modernized UI**: Redesigned with a sleek, scalable, and responsive interface. +- **Tabbed Navigation**: Added a tabbed layout for better organization of features. +- **Miscellaneous Tools Section**: Room for future expansions and added utilities. For now it supports Turkish name, address, email, and password generation. +- **Dark Mode Support** (Upcoming): Switch between light and dark modes for a better user experience. +- **Character Counter**: Real-time character counter to track text length dynamically. +- **Random Text Generation**: Generate customizable random strings with options for uppercase letters, numbers, and symbols. +- **Offline Functionality**: Full functionality without requiring an internet or AI connection. + +## Support + +If you like this project and want to support its development, you can **[Buy Me a Coffee](https://buymeacoffee.com/notdepressedeveloper)**. Your support helps keep this project going and motivates me to build more awesome tools! + +[![Buy Me a Coffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-Support-yellow?style=for-the-badge&logo=buy-me-a-coffee)](https://buymeacoffee.com/notdepressedeveloper) + +## 🧪 Tested Platforms + +- **Google Chrome:** Version 138.0.7204.101 (arm64) +- **Opera One:** Version 120.0.5543.61 (arm64) + - Chromium version: 135.0.7049.115 + +## Contributing and Contact + +Contributions are welcome! If you encounter any issues or have suggestions for improvements, please feel free to: + +- Open an issue or pull request in this repository. +- Reach out to me via the contact information provided in my profile. +- Contact me directly on Discord: **notdepressedeveloper**. + +Thank you for your support and feedback! diff --git a/assets/icon128.png b/assets/icon128.png new file mode 100644 index 0000000000000000000000000000000000000000..abd647c5a2d0f79999f13bb810488941741774e2 GIT binary patch literal 10320 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 literal 0 HcmV?d00001 diff --git a/assets/icon48.png b/assets/icon48.png new file mode 100644 index 0000000000000000000000000000000000000000..0ab85816e7833c87554e48bf789bcba88376cb55 GIT binary patch literal 4075 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 O#~tllY|E?zWB&#J6Y_ol literal 0 HcmV?d00001 diff --git a/background.js b/background.js new file mode 100644 index 0000000..e32ba1a --- /dev/null +++ b/background.js @@ -0,0 +1,151 @@ +// Background Service Worker for Test String Generator Extension + +// Handle extension installation and updates +if (typeof chrome !== 'undefined' && chrome.runtime) { + chrome.runtime.onInstalled.addListener((details) => { + if (details.reason === 'install') { + console.log('Test String Generator extension installed'); + + // Set default settings + chrome.storage.sync.set({ + theme: 'light', + language: 'en' + }).catch(err => { + console.warn('Failed to set default settings:', err); + }); + } else if (details.reason === 'update') { + console.log('Test String Generator extension updated'); + + // Handle version migration if needed + handleVersionUpdate(details.previousVersion); + + // Show update notification + showUpdateNotification(); + } + }); +} + +// Handle extension startup +if (typeof chrome !== 'undefined' && chrome.runtime) { + chrome.runtime.onStartup.addListener(() => { + console.log('Test String Generator extension started'); + }); + + // Handle messages from content scripts or popup + chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + // Handle any background tasks if needed in the future + console.log('Background received message:', request); + + // Always respond to keep the message channel open + sendResponse({ status: 'received' }); + + return true; // Keep message channel open for async operations + }); + + // Handle external connections + chrome.runtime.onConnect.addListener((port) => { + if (port.name === 'popup') { + console.log('Popup connected'); + + port.onDisconnect.addListener(() => { + console.log('Popup disconnected'); + }); + } + }); +} + +// Handle context menu creation (if needed in future) +// chrome.contextMenus.create({ +// id: 'generate-test-string', +// title: 'Generate Test String', +// contexts: ['editable'] +// }); + +// Keep service worker alive by periodically performing tasks +if (typeof chrome !== 'undefined' && chrome.storage) { + const keepAlive = () => { + // Perform a lightweight operation + chrome.storage.local.set({ lastHeartbeat: Date.now() }); + }; + + // Set up heartbeat every 20 seconds + setInterval(keepAlive, 20000); +} + +// Update handling functions +function handleVersionUpdate(previousVersion) { + const currentVersion = chrome.runtime.getManifest().version; + console.log(`Updated from ${previousVersion} to ${currentVersion}`); + + // Handle data migration between versions if needed + if (previousVersion && chrome.storage) { + migrateDataIfNeeded(previousVersion, currentVersion); + } +} + +function showUpdateNotification() { + // Create a notification for the update + if (chrome.notifications) { + chrome.notifications.create('update-notification', { + type: 'basic', + iconUrl: 'assets/icon48.png', + title: 'Test String Generator Updated!', + message: 'New features and improvements are now available.' + }); + } +} + +function migrateDataIfNeeded(previousVersion, currentVersion) { + // Example: Migrate old settings format to new format + chrome.storage.sync.get(null).then(data => { + let needsMigration = false; + + // Add migration logic here based on version comparisons + if (compareVersions(previousVersion, '1.1.0') < 0) { + // Migrate to v1.1.0 format if needed + console.log('Migrating to v1.1.0 format...'); + needsMigration = true; + } + + if (needsMigration) { + chrome.storage.sync.set(data).then(() => { + console.log('Data migration completed'); +}); + } + }).catch(err => { + console.warn('Migration failed:', err); + }); +} + +function compareVersions(version1, version2) { + const v1parts = version1.split('.').map(Number); + const v2parts = version2.split('.').map(Number); + + for (let i = 0; i < Math.max(v1parts.length, v2parts.length); i++) { + const v1part = v1parts[i] || 0; + const v2part = v2parts[i] || 0; + + if (v1part < v2part) return -1; + if (v1part > v2part) return 1; + } + + return 0; +} + +// Check for updates periodically (optional) +function checkForUpdates() { + if (chrome.runtime.requestUpdateCheck) { + chrome.runtime.requestUpdateCheck((status, details) => { + if (status === 'update_available') { + console.log('Update available:', details); + // Optionally restart to apply update immediately + // chrome.runtime.reload(); + } + }); + } +} + +// Set up periodic update checks (every 24 hours) +setInterval(checkForUpdates, 24 * 60 * 60 * 1000); + +console.log('Test String Generator background script loaded'); diff --git a/data/address.json b/data/address.json new file mode 100644 index 0000000..e6b5240 --- /dev/null +++ b/data/address.json @@ -0,0 +1,70 @@ +[ + "İstiklal Caddesi No: 123, Beyoğlu, İstanbul", + "Atatürk Bulvarı No: 45, Çankaya, Ankara", + "Kordonboyu Mahallesi, Deniz Sokak No: 67, Alsancak, İzmir", + "Bahçelievler Mahallesi, Gül Sokak No: 89, Bornova, İzmir", + "Güneşli Caddesi No: 34, Bağcılar, İstanbul", + "Sakarya Caddesi No: 78, Osmangazi, Bursa", + "Yeni Mahalle, Meşe Sokak No: 12, Keçiören, Ankara", + "Fatih Bulvarı No: 45, Nilüfer, Bursa", + "Çamlık Mahallesi, Orman Sokak No: 56, Karşıyaka, İzmir", + "Atatürk Caddesi No: 67, Seyhan, Adana", + "Gazi Bulvarı No: 34, Çukurova, Adana", + "Kocatepe Caddesi No: 56, Bayraklı, İzmir", + "Samsun Caddesi No: 23, Konyaaltı, Antalya", + "Talatpaşa Bulvarı No: 78, Muratpaşa, Antalya", + "Dumlupınar Mahallesi, İncir Sokak No: 12, Samsun", + "Çarşı Mahallesi, Pazar Sokak No: 45, Denizli", + "Adnan Menderes Bulvarı No: 56, Eskişehir", + "Karaağaç Mahallesi, Zeytin Sokak No: 23, Trabzon", + "Gaziosmanpaşa Caddesi No: 89, Maltepe, İstanbul", + "Menderes Mahallesi, Atatürk Sokak No: 67, Edirne", + "Cumhuriyet Mahallesi, Çiçek Sokak No: 15, Konya", + "Zafer Bulvarı No: 91, Merkez, Kayseri", + "Doğanbey Mahallesi, Lale Sokak No: 24, Erzurum", + "Fevzi Çakmak Caddesi No: 36, Sivas", + "Hürriyet Mahallesi, Papatya Sokak No: 77, Gaziantep", + "Milli Egemenlik Bulvarı No: 42, Şanlıurfa", + "Barış Mahallesi, Kardelen Sokak No: 18, Van", + "Kültür Caddesi No: 63, Diyarbakır", + "Yeşiltepe Mahallesi, Nergis Sokak No: 29, Malatya", + "Güven Bulvarı No: 85, Elazığ", + "Çınarlı Mahallesi, Menekşe Sokak No: 41, Kocaeli", + "Özgürlük Caddesi No: 52, Sakarya", + "Tekkeköy Mahallesi, Karanfil Sokak No: 73, Samsun", + "Altınova Bulvarı No: 19, Ordu", + "Sahil Mahallesi, Martı Sokak No: 66, Sinop", + "Çay Caddesi No: 28, Rize", + "Değirmen Mahallesi, Fulya Sokak No: 94, Artvin", + "Akşemsettin Bulvarı No: 37, Kastamonu", + "Toprak Mahallesi, Begonva Sokak No: 59, Çorum", + "Yıldırım Caddesi No: 81, Amasya", + "Çilek Mahallesi, Lavanta Sokak No: 13, Tokat", + "Doğu Bulvarı No: 48, Yozgat", + "Kızılırmak Caddesi No: 76, Kırıkkale", + "Şehit Mahallesi, Gül Sokak No: 22, Nevşehir", + "Kapadokya Bulvarı No: 65, Kırşehir", + "Bagdat Caddesi No: 147, Üsküdar, İstanbul", + "Nişantaşı Mahallesi, Teşvikiye Sokak No: 88, Şişli, İstanbul", + "Levent Caddesi No: 201, Beşiktaş, İstanbul", + "Etiler Mahallesi, Akmerkez Sokak No: 35, Beşiktaş, İstanbul", + "Bebek Yolu No: 99, Bebek, İstanbul", + "Ortaköy Meydanı No: 17, Beşiktaş, İstanbul", + "Galata Kulesi Caddesi No: 44, Galata, İstanbul", + "Sultanahmet Meydanı No: 8, Fatih, İstanbul", + "Karaköy Mahallesi, Banker Sokak No: 52, Beyoğlu, İstanbul", + "Cihangir Mahallesi, Susam Sokak No: 71, Beyoğlu, İstanbul", + "Kızılay Meydanı No: 25, Çankaya, Ankara", + "Bahçelievler Mahallesi, Adalet Sokak No: 33, Çankaya, Ankara", + "Çayyolu Bulvarı No: 156, Çankaya, Ankara", + "Bilkent Üniversitesi Caddesi No: 1, Çankaya, Ankara", + "Tunalı Hilmi Caddesi No: 67, Çankaya, Ankara", + "Güvenpark Mahallesi, Atatürk Bulvarı No: 123, Altındağ, Ankara", + "Konak Meydanı No: 5, Konak, İzmir", + "Alsancak Limanı Caddesi No: 78, Konak, İzmir", + "Foça Sahil Yolu No: 34, Foça, İzmir", + "Çeşme Marina Bulvarı No: 92, Çeşme, İzmir", + "Alaçatı Mahallesi, Rüzgar Sokak No: 16, Çeşme, İzmir", + "Sığacık Limanı Caddesi No: 41, Seferihisar, İzmir" + ] + \ No newline at end of file diff --git a/data/email.json b/data/email.json new file mode 100644 index 0000000..413f17e --- /dev/null +++ b/data/email.json @@ -0,0 +1,319 @@ +[ + "ali.yilmaz@example.com", + "veli.kaya@example.com", + "ahmet.demir@example.com", + "mehmet.celik@example.com", + "ayse.arslan@example.com", + "fatma.koc@example.com", + "mustafa.gunes@example.com", + "elif.aydin@example.com", + "cem.turk@example.com", + "serkan.kurt@example.com", + "aydin.aksoy@example.com", + "deniz.karadeniz@example.com", + "emre.basaran@example.com", + "sevim.tektas@example.com", + "gizem.kurtulus@example.com", + "gokhan.yilmaz@example.com", + "hakan.kaya@example.com", + "irem.demir@example.com", + "jale.celik@example.com", + "kemal.arslan@example.com", + "ayse.kurt@example.com", + "onur.yildiz@example.com", + "elif.turan@example.com", + "ali.gur@example.com", + "merve.erdem@example.com", + "volkan.kaplan@example.com", + "nihan.guzel@example.com", + "deniz.yalin@example.com", + "emre.kilic@example.com", + "asli.kurtulus@example.com", + "selim.bulut@example.com", + "zeynep.aykan@example.com", + "murat.karaman@example.com", + "seda.yavuz@example.com", + "tayyar.turan@example.com", + "tugba.can@example.com", + "yasin.buyukkaya@example.com", + "esra.bilir@example.com", + "halit.taskin@example.com", + "nur.tosun@example.com", + "burak.unlu@example.com", + "yusuf.avci@example.com", + "nuray.gungor@example.com", + "enes.karagoz@example.com", + "serife.arican@example.com", + "gul.karatay@example.com", + "ahmet.toprak@example.com", + "irem.yildirim@example.com", + "berk.ozmen@example.com", + "mert.ozdemir@example.com", + "busra.yildiz@example.com", + "seda.kocyigit@example.com", + "yasin.koyuncu@example.com", + "zeynep.karaaslan@example.com", + "ilayda.tosun@example.com", + "fatih.gonul@example.com", + "sedef.kara@example.com", + "ozan.yilmaz@example.com", + "emine.akinci@example.com", + "ugur.tasdemir@example.com", + "hasan.ozkan@example.com", + "elif.pamir@example.com", + "yusuf.pelin@example.com", + "sevgi.polat@example.com", + "yunus.bulut@example.com", + "aysegul.erdem@example.com", + "ilknur.karakaya@example.com", + "bahar.karaoglu@example.com", + "ali.akyuz@example.com", + "emine.yurtsever@example.com", + "aslihan.yilmazer@example.com", + "eda.gorgulu@example.com", + "ahmet.karakas@example.com", + "ece.akgun@example.com", + "okan.kayaci@example.com", + "tugba.topcu@example.com", + "sule.karaoglan@example.com", + "yusuf.gur@example.com", + "eda.kuru@example.com", + "mustafa.ergin@example.com", + "elif.uzun@example.com", + "serdar.toprak@example.com", + "huseyin.yildiz@example.com", + "ayse.unal@example.com", + "oguzhan.koc@example.com", + "esra.yaman@example.com", + "serkan.cetin@example.com", + "sema.toprak@example.com", + "yasin.gurkan@example.com", + "fatih.erdem@example.com", + "sevda.senol@example.com", + "cagla.bayram@example.com", + "hakan.bulut@example.com", + "enes.saglam@example.com", + "seda.yildirim@example.com", + "ilayda.arslan@example.com", + "furkan.karahan@example.com", + "irem.atalay@example.com", + "mustafa.yazici@example.com", + "buse.gumus@example.com", + "serhat.demirci@example.com", + "selma.karaca@example.com", + "merve.kocak@example.com", + "cengiz.akinci@example.com", + "ayse.senol@example.com", + "umut.demir@example.com", + "enes.karadeniz@example.com", + "merve.yilmaz@example.com", + "gokhan.karaoglu@example.com", + "beyza.ates@example.com", + "tolga.kocak@example.com", + "dilara.ozdemir@example.com", + "emine.kara@example.com", + "alp.kurt@example.com", + "sibel.aksu@example.com", + "dogan.demir@example.com", + "serife.yildiz@example.com", + "yunus.ozturk@example.com", + "derya.ozkan@example.com", + "tunc.erol@example.com", + "fatma.turan@example.com", + "berkay.ozkan@example.com", + "zeynep.ozturk@example.com", + "serap.kaya@example.com", + "onur.atalay@example.com", + "esra.ates@example.com", + "ali.cicek@example.com", + "ipek.yilmaz@example.com", + "cansu.karahan@example.com", + "berk.kurt@example.com", + "esra.akinci@example.com", + "mehmet.karaman@example.com", + "melike.ozdemir@example.com", + "emel.yilmaz@example.com", + "taner.bas@example.com", + "ahmet.koc@example.com", + "zeynep.yilmaz@example.com", + "berfin.yildiz@example.com", + "veysel.celik@example.com", + "sevda.yildiz@example.com", + "emre.yilmaz@example.com", + "huseyin.yavuz@example.com", + "ayse.bayram@example.com", + "deniz.yavuz@example.com", + "tayyar.turkmen@example.com", + "kubra.ates@example.com", + "okan.bayram@example.com", + "enes.kaplan@example.com", + "serap.ozturk@example.com", + "ayse.turan@example.com", + "test@test.com", + "admin@admin.com", + "user@user.com", + "guest@guest.com", + "support@support.com", + "info@info.com", + "contact@contact.com", + "help@help.com", + "sales@sales.com", + "marketing@marketing.com", + "hr@hr.com", + "finance@finance.com", + "it@it.com", + "security@security.com", + "legal@legal.com", + "customer@customer.com", + "support@support.com", + "billing@billing.com", + "privacy@privacy.com", + "terms@terms.com", + "privacy@privacy.com", + "terms@terms.com", + "privacy@privacy.com", + "terms@terms.com", + "privacy@privacy.com", + "terms@terms.com", + "noreply@noreply.com", + "no-reply@no-reply.com", + "no-response@no-response.com", + "no-reply@no-reply.com", + "no-response@no-response.com", + "no-reply@no-reply.com", + "no-response@no-response.com", + "noreply@test.com", + "admin@test.com", + "user@test.com", + "guest@test.com", + "support@test.com", + "info@test.com", + "contact@test.com", + "help@test.com", + "sales@test.com", + "marketing@test.com", + "hr@test.com", + "finance@test.com", + "it@test.com", + "security@test.com", + "admin@example.com", + "user@example.com", + "guest@example.com", + "support@example.com", + "info@example.com", + "contact@example.com", + "help@example.com", + "sales@example.com", + "marketing@example.com", + "hr@example.com", + "finance@example.com", + "it@example.com", + "security@example.com", + "info@teknoloji.com", + "destek@yazilim.net", + "iletisim@proje.org", + "admin@sistem.gov.tr", + "user@domain.edu.tr", + "test@sample.co.uk", + "demo@example.io", + "contact@business.biz", + "help@support.tech", + "mail@webmail.online", + "inbox@messaging.app", + "notification@alerts.system", + "newsletter@updates.news", + "marketing@campaigns.digital", + "sales@ecommerce.shop", + "service@customer.care", + "feedback@review.platform", + "team@collaboration.workspace", + "dev@development.studio", + "api@integration.cloud", + "data@analytics.insights", + "security@protection.shield", + "backup@storage.vault", + "monitoring@performance.metrics", + "logging@tracking.events", + "report@business.intelligence", + "dashboard@visualization.charts", + "mobile@responsive.design", + "frontend@ui.experience", + "backend@server.infrastructure", + "database@sql.management", + "cache@redis.memory", + "queue@messaging.async", + "worker@background.process", + "scheduler@cron.automation", + "webhook@callback.integration", + "oauth@authentication.secure", + "jwt@token.authorization", + "session@state.management", + "cookie@browser.storage", + "localstorage@client.persistence", + "websocket@realtime.communication", + "sse@server.events", + "graphql@query.language", + "rest@api.endpoints", + "soap@legacy.protocol", + "xml@structured.data", + "json@lightweight.format", + "yaml@configuration.files", + "toml@simple.config", + "ini@settings.format", + "env@environment.variables", + "docker@container.platform", + "kubernetes@orchestration.system", + "aws@cloud.services", + "azure@microsoft.cloud", + "gcp@google.platform", + "heroku@deployment.service", + "netlify@static.hosting", + "vercel@frontend.deployment", + "firebase@google.backend", + "supabase@open.alternative", + "mongodb@document.database", + "postgresql@relational.sql", + "mysql@popular.database", + "sqlite@embedded.database", + "redis@inmemory.store", + "elasticsearch@search.engine", + "kafka@streaming.platform", + "rabbitmq@message.broker", + "nginx@web.server", + "apache@http.server", + "nodejs@javascript.runtime", + "python@programming.language", + "java@enterprise.platform", + "csharp@dotnet.framework", + "php@web.development", + "ruby@elegant.language", + "go@google.language", + "rust@systems.programming", + "swift@apple.development", + "kotlin@android.modern", + "typescript@javascript.typed", + "dart@flutter.language", + "scala@jvm.functional", + "clojure@lisp.dialect", + "haskell@pure.functional", + "erlang@concurrent.language", + "elixir@actor.model", + "react@facebook.library", + "vue@progressive.framework", + "angular@google.framework", + "svelte@compile.framework", + "nextjs@react.framework", + "nuxtjs@vue.framework", + "gatsby@static.generator", + "jekyll@ruby.generator", + "hugo@go.generator", + "eleventy@simple.generator", + "wordpress@content.management", + "drupal@flexible.cms", + "joomla@open.cms", + "magento@ecommerce.platform", + "shopify@hosted.ecommerce", + "woocommerce@wordpress.shop", + "prestashop@open.commerce" +] + \ No newline at end of file diff --git a/data/enAddress.json b/data/enAddress.json new file mode 100644 index 0000000..1202f61 --- /dev/null +++ b/data/enAddress.json @@ -0,0 +1,42 @@ +[ + "123 Main Street, New York, NY 10001", + "456 Oak Avenue, Los Angeles, CA 90210", + "789 Pine Road, Chicago, IL 60601", + "321 Elm Street, Houston, TX 77001", + "654 Maple Drive, Phoenix, AZ 85001", + "987 Cedar Lane, Philadelphia, PA 19101", + "147 Birch Way, San Antonio, TX 78201", + "258 Spruce Court, San Diego, CA 92101", + "369 Willow Street, Dallas, TX 75201", + "741 Ash Boulevard, San Jose, CA 95101", + "852 Poplar Avenue, Austin, TX 73301", + "963 Cherry Street, Jacksonville, FL 32099", + "159 Walnut Drive, Fort Worth, TX 76101", + "357 Hickory Lane, Columbus, OH 43085", + "486 Sycamore Road, Charlotte, NC 28201", + "792 Magnolia Court, San Francisco, CA 94102", + "138 Dogwood Street, Indianapolis, IN 46201", + "246 Redwood Avenue, Seattle, WA 98101", + "468 Sequoia Drive, Denver, CO 80201", + "579 Cypress Lane, Washington, DC 20001", + "681 Juniper Way, Boston, MA 02101", + "793 Aspen Street, El Paso, TX 79901", + "135 Beech Court, Detroit, MI 48201", + "247 Fir Boulevard, Nashville, TN 37201", + "359 Hemlock Avenue, Portland, OR 97201", + "471 Larch Drive, Oklahoma City, OK 73101", + "583 Palm Street, Las Vegas, NV 89101", + "695 Yew Lane, Louisville, KY 40201", + "807 Alder Road, Baltimore, MD 21201", + "919 Basswood Court, Milwaukee, WI 53201", + "246 Buckeye Street, Albuquerque, NM 87101", + "357 Catalpa Avenue, Tucson, AZ 85701", + "468 Chestnut Drive, Fresno, CA 93701", + "579 Cottonwood Lane, Sacramento, CA 94203", + "681 Hackberry Way, Long Beach, CA 90801", + "793 Hawthorn Street, Kansas City, MO 64101", + "135 Ironwood Court, Mesa, AZ 85201", + "247 Locust Boulevard, Virginia Beach, VA 23451", + "359 Mesquite Avenue, Atlanta, GA 30301", + "471 Mulberry Drive, Colorado Springs, CO 80901" +] \ No newline at end of file diff --git a/data/enFemaleFirstName.json b/data/enFemaleFirstName.json new file mode 100644 index 0000000..47fa25e --- /dev/null +++ b/data/enFemaleFirstName.json @@ -0,0 +1,229 @@ +[ + "Mary", + "Patricia", + "Jennifer", + "Linda", + "Elizabeth", + "Barbara", + "Susan", + "Jessica", + "Sarah", + "Karen", + "Nancy", + "Lisa", + "Betty", + "Helen", + "Sandra", + "Donna", + "Carol", + "Ruth", + "Sharon", + "Michelle", + "Laura", + "Sarah", + "Kimberly", + "Deborah", + "Dorothy", + "Lisa", + "Nancy", + "Karen", + "Betty", + "Helen", + "Sandra", + "Donna", + "Carol", + "Ruth", + "Sharon", + "Michelle", + "Laura", + "Sarah", + "Kimberly", + "Deborah", + "Dorothy", + "Amy", + "Angela", + "Ashley", + "Brenda", + "Emma", + "Olivia", + "Cynthia", + "Marie", + "Janet", + "Catherine", + "Frances", + "Christine", + "Samantha", + "Debra", + "Rachel", + "Carolyn", + "Janet", + "Virginia", + "Maria", + "Heather", + "Diane", + "Julie", + "Joyce", + "Victoria", + "Kelly", + "Christina", + "Joan", + "Evelyn", + "Lauren", + "Judith", + "Megan", + "Cheryl", + "Andrea", + "Hannah", + "Jacqueline", + "Martha", + "Gloria", + "Teresa", + "Sara", + "Janice", + "Marie", + "Julia", + "Heather", + "Diane", + "Ruth", + "Julie", + "Joyce", + "Virginia", + "Victoria", + "Kelly", + "Christina", + "Joan", + "Evelyn", + "Lauren", + "Judith", + "Megan", + "Anna", + "Jacqueline", + "Cheryl", + "Grace", + "Sophia", + "Isabella", + "Ava", + "Mia", + "Charlotte", + "Amelia", + "Olivia", + "Sophia", + "Harper", + "Evelyn", + "Abigail", + "Emily", + "Elizabeth", + "Mila", + "Ella", + "Avery", + "Sofia", + "Camila", + "Aria", + "Scarlett", + "Victoria", + "Madison", + "Luna", + "Grace", + "Chloe", + "Penelope", + "Layla", + "Riley", + "Zoey", + "Nora", + "Lily", + "Eleanor", + "Hannah", + "Lillian", + "Addison", + "Aubrey", + "Ellie", + "Stella", + "Natalie", + "Zoe", + "Leah", + "Hazel", + "Violet", + "Aurora", + "Savannah", + "Audrey", + "Brooklyn", + "Bella", + "Claire", + "Skylar", + "Lucy", + "Paisley", + "Everly", + "Anna", + "Caroline", + "Nova", + "Genesis", + "Emilia", + "Kennedy", + "Samantha", + "Maya", + "Willow", + "Kinsley", + "Naomi", + "Aaliyah", + "Elena", + "Sarah", + "Ariana", + "Allison", + "Gabriella", + "Alice", + "Madelyn", + "Cora", + "Ruby", + "Eva", + "Serenity", + "Autumn", + "Adeline", + "Hailey", + "Gianna", + "Valentina", + "Isla", + "Eliana", + "Quinn", + "Nevaeh", + "Ivy", + "Sadie", + "Piper", + "Lydia", + "Alexa", + "Josephine", + "Emery", + "Julia", + "Delilah", + "Arianna", + "Vivian", + "Kaylee", + "Sophie", + "Brielle", + "Madeline", + "Peyton", + "Rylee", + "Clara", + "Hadley", + "Melanie", + "Mackenzie", + "Reagan", + "Adalynn", + "Liliana", + "Aubree", + "Jade", + "Katherine", + "Isabelle", + "Natalia", + "Raelynn", + "Maria", + "Athena", + "Ximena", + "Arya", + "Leilani", + "Taylor", + "Alyssa", + "Eden", + "Khloe", + "Remi", + "Remington" +] \ No newline at end of file diff --git a/data/enMaleFirstName.json b/data/enMaleFirstName.json new file mode 100644 index 0000000..2da225d --- /dev/null +++ b/data/enMaleFirstName.json @@ -0,0 +1,171 @@ +[ + "James", + "Robert", + "John", + "Michael", + "William", + "David", + "Richard", + "Joseph", + "Thomas", + "Christopher", + "Charles", + "Daniel", + "Matthew", + "Anthony", + "Mark", + "Donald", + "Steven", + "Paul", + "Andrew", + "Kenneth", + "Joshua", + "Kevin", + "Brian", + "George", + "Timothy", + "Ronald", + "Jason", + "Edward", + "Jeffrey", + "Ryan", + "Jacob", + "Gary", + "Nicholas", + "Eric", + "Jonathan", + "Stephen", + "Larry", + "Justin", + "Scott", + "Brandon", + "Benjamin", + "Samuel", + "Gregory", + "Alexander", + "Patrick", + "Frank", + "Raymond", + "Jack", + "Dennis", + "Jerry", + "Tyler", + "Aaron", + "Jose", + "Henry", + "Adam", + "Douglas", + "Nathan", + "Peter", + "Zachary", + "Kyle", + "Noah", + "Alan", + "Ethan", + "Jeremy", + "Lionel", + "Angel", + "Wayne", + "Arthur", + "Sean", + "Carl", + "Harold", + "Bruce", + "Logan", + "Billy", + "Joe", + "Ralph", + "Roy", + "Eugene", + "Louis", + "Philip", + "Bobby", + "Mason", + "Albert", + "Wayne", + "Willie", + "Juan", + "Lawrence", + "Victor", + "Louis", + "Jesse", + "Wayne", + "Ralph", + "Roy", + "Eugene", + "Arthur", + "Carl", + "Harold", + "Bruce", + "Logan", + "Billy", + "Austin", + "Miles", + "Cole", + "Mason", + "Luke", + "Alexander", + "William", + "Benjamin", + "Lucas", + "Henry", + "Theodore", + "Jack", + "Levi", + "Oliver", + "Jackson", + "Mateo", + "Daniel", + "Michael", + "Mason", + "Sebastian", + "Ethan", + "Logan", + "Owen", + "Samuel", + "Jacob", + "Asher", + "Aiden", + "John", + "Joseph", + "Wyatt", + "David", + "Leo", + "Luke", + "Julian", + "Hudson", + "Grayson", + "Matthew", + "Ezra", + "Gabriel", + "Carter", + "Isaac", + "Jayden", + "Luca", + "Anthony", + "Dylan", + "Lincoln", + "Thomas", + "Maverick", + "Elijah", + "Cooper", + "Josiah", + "Hunter", + "Jordan", + "Adrian", + "Nicholas", + "Mason", + "Parker", + "Ian", + "Nolan", + "Jameson", + "Christopher", + "Jaxon", + "Leonardo", + "Axel", + "Everett", + "Kayden", + "Miles", + "Sawyer", + "Jason" +] \ No newline at end of file diff --git a/data/enSurname.json b/data/enSurname.json new file mode 100644 index 0000000..8a6fa30 --- /dev/null +++ b/data/enSurname.json @@ -0,0 +1,532 @@ +[ + "Smith", + "Johnson", + "Williams", + "Brown", + "Jones", + "Garcia", + "Miller", + "Davis", + "Rodriguez", + "Martinez", + "Hernandez", + "Lopez", + "Gonzalez", + "Wilson", + "Anderson", + "Thomas", + "Taylor", + "Moore", + "Jackson", + "Martin", + "Lee", + "Perez", + "Thompson", + "White", + "Harris", + "Sanchez", + "Clark", + "Ramirez", + "Lewis", + "Robinson", + "Walker", + "Young", + "Allen", + "King", + "Wright", + "Scott", + "Torres", + "Nguyen", + "Hill", + "Flores", + "Green", + "Adams", + "Nelson", + "Baker", + "Hall", + "Rivera", + "Campbell", + "Mitchell", + "Carter", + "Roberts", + "Gomez", + "Phillips", + "Evans", + "Turner", + "Diaz", + "Parker", + "Cruz", + "Edwards", + "Collins", + "Reyes", + "Stewart", + "Morris", + "Morales", + "Murphy", + "Cook", + "Rogers", + "Gutierrez", + "Ortiz", + "Morgan", + "Cooper", + "Peterson", + "Bailey", + "Reed", + "Kelly", + "Howard", + "Ramos", + "Kim", + "Cox", + "Ward", + "Richardson", + "Watson", + "Brooks", + "Chavez", + "Wood", + "James", + "Bennett", + "Gray", + "Mendoza", + "Ruiz", + "Hughes", + "Price", + "Alvarez", + "Castillo", + "Sanders", + "Patel", + "Myers", + "Long", + "Ross", + "Foster", + "Jimenez", + "Powell", + "Jenkins", + "Perry", + "Russell", + "Sullivan", + "Bell", + "Coleman", + "Butler", + "Henderson", + "Barnes", + "Gonzales", + "Fisher", + "Vasquez", + "Simmons", + "Romero", + "Jordan", + "Patterson", + "Alexander", + "Hamilton", + "Graham", + "Reynolds", + "Griffin", + "Wallace", + "Moreno", + "West", + "Cole", + "Hayes", + "Bryant", + "Herrera", + "Gibson", + "Ellis", + "Tran", + "Medina", + "Aguilar", + "Stevens", + "Murray", + "Ford", + "Castro", + "Marshall", + "Owens", + "Harrison", + "Fernandez", + "Mcdonald", + "Woods", + "Washington", + "Kennedy", + "Wells", + "Vargas", + "Henry", + "Chen", + "Freeman", + "Webb", + "Tucker", + "Guzman", + "Burns", + "Crawford", + "Olson", + "Simpson", + "Porter", + "Hunter", + "Gordon", + "Mendez", + "Silva", + "Shaw", + "Snyder", + "Mason", + "Dixon", + "Munoz", + "Hunt", + "Hicks", + "Holmes", + "Palmer", + "Wagner", + "Black", + "Robertson", + "Boyd", + "Rose", + "Stone", + "Salazar", + "Fox", + "Warren", + "Mills", + "Meyer", + "Rice", + "Schmidt", + "Garza", + "Daniels", + "Ferguson", + "Nichols", + "Stephens", + "Soto", + "Weaver", + "Ryan", + "Gardner", + "Payne", + "Grant", + "Dunn", + "Kelley", + "Spencer", + "Hawkins", + "Arnold", + "Pierce", + "Vazquez", + "Hansen", + "Peters", + "Santos", + "Hart", + "Bradley", + "Knight", + "Elliott", + "Cunningham", + "Duncan", + "Armstrong", + "Hudson", + "Carroll", + "Lane", + "Riley", + "Andrews", + "Alvarado", + "Ray", + "Delgado", + "Berry", + "Perkins", + "Hoffman", + "Johnston", + "Matthews", + "Pena", + "Richards", + "Contreras", + "Willis", + "Carpenter", + "Lawrence", + "Sandoval", + "Guerrero", + "George", + "Chapman", + "Rios", + "Estrada", + "Ortega", + "Watkins", + "Greene", + "Nunez", + "Wheeler", + "Valdez", + "Harper", + "Burke", + "Larson", + "Santiago", + "Maldonado", + "Morrison", + "Franklin", + "Carlson", + "Austin", + "Dominguez", + "Carr", + "Lawson", + "Jacobs", + "Obrien", + "Lynch", + "Singh", + "Vega", + "Bishop", + "Montgomery", + "Oliver", + "Jensen", + "Harvey", + "Williamson", + "Gilbert", + "Dean", + "Sims", + "Espinoza", + "Howell", + "Li", + "Wong", + "Reid", + "Hanson", + "Le", + "Mccoy", + "Garrett", + "Burton", + "Fuller", + "Wang", + "Weber", + "Welch", + "Rojas", + "Lucas", + "Marquez", + "Fields", + "Park", + "Yang", + "Little", + "Banks", + "Padilla", + "Day", + "Walsh", + "Bowman", + "Schultz", + "Luna", + "Fowler", + "Mejia", + "Davidson", + "Acosta", + "Brewer", + "May", + "Holland", + "Juarez", + "Newman", + "Pearson", + "Curtis", + "Cortez", + "Douglas", + "Schneider", + "Joseph", + "Barrett", + "Navarro", + "Figueroa", + "Keller", + "Avila", + "Wade", + "Molina", + "Stanley", + "Hopkins", + "Campos", + "Barnett", + "Bates", + "Chambers", + "Caldwell", + "Beck", + "Lambert", + "Miranda", + "Byrd", + "Craig", + "Ayala", + "Lowe", + "Frazier", + "Powers", + "Neal", + "Leonard", + "Gregory", + "Carrillo", + "Sutton", + "Fleming", + "Rhodes", + "Shelton", + "Schwartz", + "Norris", + "Jennings", + "Watts", + "Duran", + "Walters", + "Cohen", + "Mcdaniel", + "Moran", + "Parks", + "Steele", + "Vaughn", + "Becker", + "Holt", + "Deleon", + "Barker", + "Terry", + "Hale", + "Leon", + "Hail", + "Benson", + "Haynes", + "Horton", + "Miles", + "Lyons", + "Pham", + "Graves", + "Bush", + "Thornton", + "Wolfe", + "Warner", + "Cabrera", + "Mckinney", + "Mann", + "Zimmerman", + "Dawson", + "Lara", + "Fletcher", + "Page", + "Mccarthy", + "Love", + "Robles", + "Cervantes", + "Solis", + "Erickson", + "Reeves", + "Chang", + "Klein", + "Salinas", + "Fuentes", + "Baldwin", + "Daniel", + "Simon", + "Velazquez", + "Hardy", + "Higgins", + "Aguirre", + "Lin", + "Cummings", + "Chandler", + "Sharp", + "Barber", + "Bowen", + "Ochoa", + "Dennis", + "Robbins", + "Liu", + "Ramsey", + "Francis", + "Griffith", + "Paul", + "Blair", + "Oconnor", + "Cardenas", + "Pacheco", + "Cross", + "Calderon", + "Quinn", + "Moss", + "Swanson", + "Chan", + "Rivas", + "Khan", + "Rodgers", + "Serrano", + "Fitzgerald", + "Rosales", + "Stevenson", + "Christensen", + "Manning", + "Gill", + "Curry", + "Mclaughlin", + "Harmon", + "Mcgee", + "Gross", + "Doyle", + "Garner", + "Newton", + "Burgess", + "Reese", + "Walton", + "Blake", + "Trujillo", + "Adkins", + "Brady", + "Goodman", + "Roman", + "Webster", + "Goodwin", + "Fischer", + "Huang", + "Potter", + "Delacruz", + "Montoya", + "Todd", + "Wu", + "Hines", + "Mullins", + "Castaneda", + "Malone", + "Cannon", + "Tate", + "Mack", + "Sherman", + "Hubbard", + "Hodges", + "Zhang", + "Guerra", + "Wolf", + "Valencia", + "Franco", + "Saunders", + "Rowe", + "Gallagher", + "Farmer", + "Hammond", + "Hampton", + "Townsend", + "Ingram", + "Wise", + "Gallegos", + "Clarke", + "Bautista", + "Colon", + "Mahoney", + "Hurst", + "Hendricks", + "Mcconnell", + "Sanford", + "Mcmahon", + "Waters", + "Kramer", + "Mccormick", + "Vazquez", + "Abbott", + "Price", + "Pearson", + "Mckenzie", + "Frank", + "Monroe", + "Christensen", + "Keller", + "Klein", + "Lowe", + "Lynch", + "Oconnor", + "Garner", + "Fischer", + "Powell", + "Mcgee", + "Weber", + "Lynch", + "Robertson", + "Alvarez", + "Reese", + "Andrews", + "Hubbard", + "Webb", + "Silva", + "Mendez", + "Guerra", + "Burke", + "Jimenez", + "Sanchez", + "Smith" +] \ No newline at end of file diff --git a/data/femaleFirstName.json b/data/femaleFirstName.json new file mode 100644 index 0000000..00d47b3 --- /dev/null +++ b/data/femaleFirstName.json @@ -0,0 +1,209 @@ +[ + "Ayşe", + "Aslı", + "Asuman", + "Arzu", + "Ayla", + "Azra", + "Aynur", + "Adalet", + "Acelya", + "Alev", + "Bahar", + "Banu", + "Berrin", + "Binnur", + "Burcu", + "Belgin", + "Berna", + "Beril", + "Beyza", + "Buse", + "Cemile", + "Ceyda", + "Cansu", + "Canan", + "Ceren", + "Çiğdem", + "Çisem", + "Çağla", + "Derya", + "Deniz", + "Duygu", + "Dilek", + "Duru", + "Dilara", + "Defne", + "Damla", + "Dilan", + "Elif", + "Emine", + "Esra", + "Ebru", + "Ece", + "Ela", + "Emel", + "Esin", + "Evrim", + "Eda", + "Fadime", + "Feride", + "Figen", + "Fatma", + "Fulya", + "Funda", + "Filiz", + "Fahriye", + "Ferda", + "Gül", + "Gonca", + "Gülden", + "Gülay", + "Gamze", + "Gizem", + "Gülşen", + "Gönül", + "Güler", + "Hacer", + "Hale", + "Hande", + "Hilal", + "Hülya", + "Hatice", + "Hava", + "Havva", + "Hayriye", + "Irmak", + "İlkay", + "İpek", + "İnci", + "İrem", + "İdil", + "İlknur", + "Jale", + "Jülide", + "Kader", + "Kamile", + "Kumru", + "Kardelen", + "Kıymet", + "Kübra", + "Kezban", + "Leyla", + "Lale", + "Leman", + "Lütfiye", + "Leyla", + "Merve", + "Melek", + "Müjde", + "Meryem", + "Mine", + "Meral", + "Müberra", + "Miray", + "Meltem", + "Nesrin", + "Nuray", + "Nihan", + "Nermin", + "Nurten", + "Neslihan", + "Nilüfer", + "Nazlı", + "Oya", + "Özlem", + "Özge", + "Özgür", + "Pelin", + "Perihan", + "Pınar", + "Papatya", + "Pembe", + "Rabia", + "Reyhan", + "Rüya", + "Rengin", + "Rojda", + "Seda", + "Sevil", + "Sibel", + "Serap", + "Selen", + "Şeyma", + "Şule", + "Şebnem", + "Şenay", + "Şermin", + "Şirin", + "Tuğba", + "Tuba", + "Tülay", + "Tansu", + "Tülin", + "Tülün", + "Ülkü", + "Ümmü", + "Ülker", + "Ülkem", + "Ünzile", + "Vildan", + "Vahide", + "Vuslat", + "Yasemin", + "Yeliz", + "Yüksel", + "Yasmin", + "Yelda", + "Zeynep", + "Züleyha", + "Zehra", + "Zeliha", + "Zerrin", + "Zara", + "Arıf", + "Berkan", + "Cihan", + "Doğa", + "Ecrin", + "Feyza", + "Gaye", + "Handan", + "İlay", + "Jülide", + "Kısmet", + "Lara", + "Mahira", + "Nilgün", + "Olgun", + "Pırıl", + "Rüveyda", + "Sıla", + "Şeyda", + "Tanya", + "Ülkü", + "Vefa", + "Yıldız", + "Zümrüt", + "Asya", + "Büşra", + "Çetin", + "Derin", + "Ezgi", + "Feryal", + "Gürkan", + "Hava", + "İpek", + "Jelal", + "Kadriye", + "Lara", + "Mina", + "Naz", + "Oğul", + "Pırıl", + "Renda", + "Sıla", + "Şevval", + "Tara" +] + \ No newline at end of file diff --git a/data/maleFirstName.json b/data/maleFirstName.json new file mode 100644 index 0000000..e29f4b3 --- /dev/null +++ b/data/maleFirstName.json @@ -0,0 +1,212 @@ +[ + "Ahmet", + "Ali", + "Ayhan", + "Arif", + "Adem", + "Abdullah", + "Abdurrahman", + "Adnan", + "Akif", + "Alparslan", + "Barış", + "Burak", + "Berk", + "Bilal", + "Bora", + "Bayram", + "Berkay", + "Batuhan", + "Bülent", + "Bahadır", + "Cem", + "Can", + "Cihan", + "Celal", + "Cihat", + "Cengiz", + "Ceyhun", + "Caner", + "Cemil", + "Cafer", + "Çağrı", + "Çetin", + "Çınar", + "Çağlar", + "Çetinkaya", + "Çağdaş", + "Çağatay", + "Doğan", + "Deniz", + "Derviş", + "Devrim", + "Doruk", + "Dursun", + "Davut", + "Duran", + "Erdal", + "Eren", + "Emre", + "Enes", + "Erkan", + "Ercan", + "Erol", + "Emir", + "Erdem", + "Ergin", + "Erhan", + "Fatih", + "Ferit", + "Fikret", + "Furkan", + "Fırat", + "Ferhat", + "Faruk", + "Fazıl", + "Fuat", + "Gökhan", + "Gürcan", + "Gürkan", + "Güven", + "Güney", + "Gökmen", + "Gürsel", + "Galip", + "Hakan", + "Halit", + "Hasan", + "Hüseyin", + "Hüsnü", + "Halil", + "Hamit", + "Haydar", + "Hilmi", + "İbrahim", + "İlker", + "İlkay", + "İnan", + "İlyas", + "İsmail", + "İdris", + "İhsan", + "İrfan", + "Kemal", + "Kaan", + "Kerem", + "Kaya", + "Kürşat", + "Kadir", + "Kamil", + "Kazım", + "Levent", + "Lütfü", + "Lezgin", + "Lokman", + "Mustafa", + "Mert", + "Murat", + "Mehmet", + "Mazlum", + "Mahmut", + "Metin", + "Muharrem", + "Musa", + "Nail", + "Necmi", + "Nihat", + "Nuh", + "Nuri", + "Necdet", + "Nazım", + "Oğuz", + "Onur", + "Osman", + "Oktay", + "Orhan", + "Ömer", + "Özgür", + "Özkan", + "Özhan", + "Özdemir", + "Pamir", + "Polat", + "Poyraz", + "Ramazan", + "Raşit", + "Recep", + "Rüzgar", + "Rıza", + "Rıfat", + "Rifat", + "Sercan", + "Selim", + "Sinan", + "Sadi", + "Savaş", + "Salih", + "Semih", + "Sedat", + "Serdar", + "Seyit", + "Şükrü", + "Şeref", + "Şahin", + "Şafak", + "Şevket", + "Şaban", + "Tolga", + "Tarkan", + "Tayyar", + "Tansu", + "Talat", + "Tuncay", + "Tuğrul", + "Ufuk", + "Umut", + "Utku", + "Uğur", + "Uysal", + "Ümit", + "Ünal", + "Volkan", + "Veysel", + "Vedat", + "Veli", + "Vural", + "Yasin", + "Yalın", + "Yavuz", + "Yunus", + "Yiğit", + "Yusuf", + "Yakup", + "Zafer", + "Zeki", + "Zülfikar", + "Ziya", + "Zeynel", + "Adil", + "Akın", + "Atilla", + "Aziz", + "Bekir", + "Cahit", + "Cemal", + "Engin", + "Ertuğrul", + "Fahrettin", + "Haluk", + "İzzet", + "Kahraman", + "Latif", + "Mesut", + "Nihat", + "Orhan", + "Rıdvan", + "Süleyman", + "Tahsin", + "Vecdi", + "Yılmaz", + "Ziyad" + ] + \ No newline at end of file diff --git a/data/password.json b/data/password.json new file mode 100644 index 0000000..efdd0d6 --- /dev/null +++ b/data/password.json @@ -0,0 +1,165 @@ +[ + "G3l1ş1m5h", + "K0dL@r1m", + "Pr0j3Y0n3t1m", + "Güv3nL!k2o2", + "T3kNoloj1F0rum", + "P@r0l@G1zle", + "Y4z1l1mDuny4s1", + "S1fr3s1zl1k", + "Y@z1l!m@Ş3h!r", + "B!lg!Güv3nL!ği", + "K0dY@z1l!m", + "S1b3rGüv3nL!k", + "Ş1fr3l3n3nDuny4", + "G3l1ş1m3", + "Y@zılımD3st3k", + "Pr0j3Y0n3t1m2", + "Güv3nL!k123", + "B!lg!Güv3nL!ğ1", + "Ş1fr3l3", + "S1fr3L0g", + "Y@z1l!mT3kn0l0j!s1", + "B!lg!Yönt3m", + "Pr0j3Y0n3t1m3", + "Güv3nL!k456", + "S1f3rS1fr3", + "Ş1fr3K0d", + "G3l1ş1m4", + "Y@z1l!mY@z1l!m", + "Pr0j3Y0n3t1m4", + "Güv3nL!k789", + "B!lg!Y@zılım", + "Ş1fr3l3nm1ş", + "S1f3rT3kn0l0j1", + "G3l1ş1m5", + "Y@z1l!mB3lg!s1", + "Pr0j3Y0n3t1m5", + "Güv3nL!kABC", + "B!lg!Y@zılım2", + "Ş1fr3Kod1", + "S1f3rGüv3nL!k", + "G3l1ş1m6", + "Y@z1l!mY3nt3m", + "Pr0j3Y0n3t1m6", + "Güv3nL!kDEF", + "B!lg!Y@zılım3", + "Ş1fr3Kod2", + "S1f3rGüv3nL!k1", + "G3l1ş1m7", + "Y@z1l!mY0nt3m", + "Pr0j3Y0n3t1m7", + "Güv3nL!kGHI", + "B!lg!Y@zılım4", + "Ş1fr3Kod3", + "S1f3rGüv3nL!k2", + "G3l1ş1m8", + "Y@z1l!mY@zılım", + "Pr0j3Y0n3t1m8", + "Güv3nL!kJKL", + "B!lg!Y@zılım5", + "Ş1fr3Kod4", + "S1f3rGüv3nL!k3", + "G3l1ş1m9", + "Y@z1l!mB3lg!l3r1", + "Pr0j3Y0n3t1m9", + "Güv3nL!kMNO", + "B!lg!Y@zılım6", + "Ş1fr3Kod5", + "S1f3rGüv3nL!k4", + "G3l1ş1m10", + "Y@z1l!mB3lg!l3r2", + "Pr0j3Y0n3t1m10", + "Güv3nL!kPQR", + "B!lg!Y@zılım7", + "Ş1fr3Kod6", + "S1f3rGüv3nL!k5", + "V3r1T4b4n1!", + "M0d3rn@P4ssw0rd", + "S4f3&S3cur3!", + "K0mpl3ks$1fr3", + "Güçlü#Ş1fr3", + "D1j1t4l&Düny4", + "T3kn0@G3l3c3k", + "Y3n1Ç4ğ#2024", + "S1b3r@Sp4c3", + "K0d&G3l1şt1r", + "B1lg1$4y4r", + "Pr0t3k$1y0n", + "V3r1#Güv3nl1k", + "S1st3m@Yön3t1c1", + "D4t4B4s3&Mgmt", + "W3b#D3v3l0pm3nt", + "M0b1l3$4pp", + "Cl0ud&C0mput1ng", + "A1&M4ch1n3L3rn", + "Bl0ckCh41n#T3ch", + "I0T&Sm4rtD3v1c3", + "C1b3r$3cur1ty", + "D1g1t4l@Tr4nsf0rm", + "1nn0v4t10n#L4b", + "T3ch$St4rtup", + "C0d1ng&Pr0gr4m", + "S0ftw4r3#Eng1n33r", + "D3v0ps&4ut0m4t10n", + "4g1l3@M3th0d0l0gy", + "Sc4l4bl3$Syst3m", + "M1cr0s3rv1c3#4rch", + "4P1&1nt3gr4t10n", + "D4t4$V1su4l1z4t10n", + "M4ch1n3@L34rn1ng", + "D33p&N3ur4lN3tw0rk", + "4rt1f1c14l#1nt3ll", + "Q4ntum$C0mput1ng", + "V1rtu4l@R34l1ty", + "4ugm3nt3d#R34l1ty", + "1mm3rs1v3$T3ch", + "G4m3@D3v3l0pm3nt", + "3$p0rts&G4m1ng", + "Str34m1ng#T3ch", + "S0c14l@M3d14", + "D1g1t4l$M4rk3t1ng", + "3C0mm3rc3#Pl4tf0rm", + "F1nT3ch&1nn0v4t10n", + "Cr1pt0@Curr3ncy", + "NFT&D1g1t4lA4rt", + "M3t4v3rs3#3xp3r13nc3", + "W3b3&D3c3ntr4l1z3d", + "Sm4rt$C0ntr4ct", + "D40&Bl0ckCh41n", + "C0ns3nsus@M3ch4n1sm", + "D1str1but3d#L3dg3r", + "P33r2P33r$N3tw0rk", + "D3c3ntr4l1z3d@F1n4nc3", + "Y13ld&F4rm1ng", + "L1qu1d1ty$P00l", + "St4k1ng@R3w4rds", + "G0v3rn4nc3#T0k3n", + "D40&V0t1ng", + "C0mmun1ty@Dr1v3n", + "0p3nS0urc3#Pr0j3ct", + "C0ll4b0r4t1v3$D3v", + "R3m0t3@W0rk", + "D1g1t4l#N0m4d", + "W0rk&L1f3B4l4nc3", + "M1ndfuln3ss$T3ch", + "W3llb31ng@4pp", + "H34lth#M0n1t0r1ng", + "F1tn3ss$Tr4ck3r", + "Nutr1t10n@4n4lys1s", + "Sl33p&0pt1m1z4t10n", + "M3nt4l#H34lthT3ch", + "Th3r4py$4pp", + "M3d1t4t10n@Gu1d3", + "Y0g4&M1ndfuln3ss", + "Str3ss$M4n4g3m3nt", + "password123", + "123456789", + "123456", + "12345678", + "1234567890", + "12345678901", + "123456789012", + "1234567890123" + ] + \ No newline at end of file diff --git a/data/surname.json b/data/surname.json new file mode 100644 index 0000000..8808246 --- /dev/null +++ b/data/surname.json @@ -0,0 +1,180 @@ +[ + "Yılmaz", + "Kaya", + "Demir", + "Çelik", + "Arslan", + "Koç", + "Güneş", + "Aydın", + "Türk", + "Kurt", + "Erbay", + "Aksoy", + "Karadeniz", + "Uçar", + "Başaran", + "Yalçın", + "Tekin", + "Öztürk", + "Can", + "Büyükkaya", + "Bilgin", + "Ceylan", + "Dağdelen", + "Durmaz", + "Özkan", + "Erdoğan", + "Göktürk", + "Şahin", + "Sezer", + "Sönmez", + "Şen", + "Yıldız", + "Tuncer", + "Bilir", + "Taşkın", + "Ünlü", + "Avcı", + "Gür", + "Erdem", + "Kaplan", + "Güzel", + "Yalın", + "Kılıç", + "Kurtuluş", + "Şeker", + "Bulut", + "Aykan", + "Karaman", + "Yavuz", + "Koçak", + "Turan", + "Çetin", + "Alkan", + "Aslan", + "Dinçer", + "Gündoğdu", + "Yücel", + "Demirtaş", + "Özdemir", + "Türkoğlu", + "Eren", + "Cengiz", + "Demirci", + "Çetinkaya", + "Balcı", + "Kasap", + "Karagöz", + "Güngör", + "Arıcan", + "Uzun", + "Toprak", + "Yıldırım", + "Özmen", + "Karakaş", + "Tosun", + "Akgün", + "Kırıcı", + "Oğuz", + "Yüksel", + "Erdal", + "Ateş", + "Aktaş", + "Akyüz", + "Yurtsever", + "Yılmazer", + "Görgülü", + "Karakaya", + "Karataş", + "Yaman", + "Bayrak", + "Bozkurt", + "Çakır", + "Duman", + "Erkin", + "Fidan", + "Gökçe", + "Hazar", + "İşler", + "Kartal", + "Levent", + "Meral", + "Nazlı", + "Oral", + "Polat", + "Rençber", + "Sarı", + "Turgut", + "Uysal", + "Vural", + "Yener", + "Zorlu", + "Akay", + "Başar", + "Candan", + "Dost", + "Elmas", + "Fırat", + "Gençer", + "Hakim", + "İnce", + "Karadağ", + "Liman", + "Mutlu", + "Nalçacı", + "Okur", + "Peker", + "Rüzgar", + "Sever", + "Tanrıverdi", + "Uluç", + "Varol", + "Yakar", + "Zengin", + "Adıgüzel", + "Baş", + "Çakmak", + "Deniz", + "Evren", + "Fındık", + "Gazi", + "Hazer", + "İçli", + "Kaynak", + "Leylek", + "Mavioğlu", + "Nas", + "Okan", + "Pamuk", + "Reşit", + "Solmaz", + "Teker", + "Uğurlu", + "Verimli", + "Yaşar", + "Zenginer", + "Altın", + "Berber", + "Çiftçi", + "Diker", + "Erol", + "Fırın", + "Gider", + "Hacı", + "İmar", + "Kader", + "Lider", + "Maden", + "Nalbur", + "Ocak", + "Pala", + "Reis", + "Sağlam", + "Tuna", + "Usta", + "Vatan", + "Yazgı", + "Zaman" +] + \ No newline at end of file diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..386b2b2 --- /dev/null +++ b/manifest.json @@ -0,0 +1,33 @@ +{ + "manifest_version": 3, + "name": "Test String Generator", + "version": "1.1.0", + "description": "A lightweight Chrome extension designed for test data generation and multi-language localization.", + "update_url": "https://clients2.google.com/service/update2/crx", + "icons": { + "16": "assets/icon16.png", + "32": "assets/icon32.png", + "48": "assets/icon48.png", + "128": "assets/icon128.png" + }, + "action": { + "default_icon": { + "128": "assets/icon128.png" + }, + "default_popup": "popup.html" + }, + "permissions": [ + "activeTab", + "clipboardRead", + "clipboardWrite", + "storage", + "notifications" + ], + "web_accessible_resources": [{ + "resources": ["data/*.json"], + "matches": [""] + }], + "background": { + "service_worker": "background.js" + } +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..051996f --- /dev/null +++ b/package.json @@ -0,0 +1,24 @@ +{ + "name": "test-string-generator", + "version": "1.0.0", + "description": "Chrome extension to generate test strings", + "main": "popup.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "echo \"No build step required\" && exit 0", + "lint": "eslint *.js", + "format": "prettier --write *.{js,html,css,json}" + }, + "keywords": [ + "chrome-extension", + "test-string", + "lorem-ipsum" + ], + "author": "sevilayerkan", + "license": "MIT", + "devDependencies": { + "eslint": "^8.42.0", + "open": "^10.1.0", + "prettier": "2.8.8" + } +} diff --git a/popup.html b/popup.html new file mode 100644 index 0000000..9820886 --- /dev/null +++ b/popup.html @@ -0,0 +1,200 @@ + + + + + + + Test String Generator + + +
+ +
+

Test String Generator

+ +
+ +
+ + + +
+ +
+
+
+ +
+ +
+
+ +
+ + + +
+
+ + + + +
+ +
+ +
+
+ + Characters + 0 + + + Words + 0 + +
+
+ + Lines + 0 + + + Sentences + 0 + + + Paragraphs + 0 + +
+
+
+ +
+ + +
+ + +
+ +
+ + +
+ +
+
+ + +
+ +
+ + +
+
+ + + + +
+
+ + + + + + + + + + + + + + + diff --git a/privacy-policy.txt b/privacy-policy.txt new file mode 100644 index 0000000..1dfcb75 --- /dev/null +++ b/privacy-policy.txt @@ -0,0 +1,27 @@ +# Privacy Policy for Test String Generator + +## Data Collection +This extension does NOT collect, store, or transmit any personal data or user information. + +## What We Don't Do +- We don't collect any personal information +- We don't track your browsing history +- We don't store any data on our servers +- We don't use cookies or tracking technologies +- We don't share any information with third parties + +## How It Works +- All data generation happens locally in your browser +- No internet connection is required +- All data is stored locally in the extension +- No external API calls are made + +## Permissions +The extension requests minimal permissions: +- activeTab: To interact with the current tab +- clipboardRead/clipboardWrite: To copy generated text + +## Contact +If you have any questions about privacy, contact: notdepressedeveloper (Discord) + +Last updated: 16 July 2025 \ No newline at end of file diff --git a/src/css/popup.css b/src/css/popup.css new file mode 100644 index 0000000..82c5368 --- /dev/null +++ b/src/css/popup.css @@ -0,0 +1,666 @@ +:root { + --primary-color: #2196F3; + --secondary-color: #90CAF9; + --background-color: #FFFFFF; + --surface-color: #F8F9FA; + --text-color: #333333; + --text-secondary: #666666; + --border-color: #E0E0E0; + --shadow-color: rgba(0, 0, 0, 0.1); + --radius: 8px; + --radius-large: 12px; + --spacing: 16px; + --header-bg: linear-gradient(135deg, var(--primary-color), #1976D2); + --transition: all 0.2s ease; +} + +[data-theme="dark"] { + --primary-color: #2196F3; + --secondary-color: #1565C0; + --background-color: #1E1E1E; + --surface-color: #2D2D2D; + --text-color: #FFFFFF; + --text-secondary: #B0B0B0; + --border-color: #404040; + --shadow-color: rgba(0, 0, 0, 0.3); + --header-bg: linear-gradient(135deg, #1976D2, #0D47A1); +} + +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +body { + width: 350px; + margin: 0; + padding: 0; + font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', sans-serif; + background-color: var(--background-color); + color: var(--text-color); + font-size: 14px; + line-height: 1.5; + transition: var(--transition); + overflow-x: hidden; +} + +.app-container { + display: flex; + flex-direction: column; +} + +/* Header Styles */ +.app-header { + background: var(--header-bg); + color: white; + padding: 12px; + display: flex; + justify-content: space-between; + align-items: center; + box-shadow: 0 2px 8px var(--shadow-color); + position: relative; +} + +.app-header h1 { + font-size: 18px; + font-weight: 600; + margin: 0; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); +} + +.settings-button { + background: rgba(255, 255, 255, 0.2); + border: none; + border-radius: 50%; + width: 36px; + height: 36px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: var(--transition); + color: white; +} + +.settings-button:hover { + background: rgba(255, 255, 255, 0.3); + transform: rotate(90deg); +} + +.settings-button svg { + width: 20px; + height: 20px; +} + +/* Main Content */ +.tabs { + display: flex; + gap: 4px; + padding: 12px; + padding-bottom: 0; + background: var(--background-color); +} + +.tab-button { + flex: 1; + padding: 12px 8px; + border: none; + background: var(--surface-color); + color: var(--text-secondary); + border-radius: var(--radius); + cursor: pointer; + font-weight: 500; + font-size: 13px; + transition: var(--transition); + border: 1px solid var(--border-color); +} + +.tab-button:hover { + background: var(--secondary-color); + color: white; +} + +.tab-button.active { + background: var(--primary-color); + color: white; + box-shadow: 0 2px 4px rgba(33, 150, 243, 0.3); +} + +.tab-content { + display: none; + flex-direction: column; + gap: var(--spacing); + padding: 12px; +} + +.tab-content.active { + display: flex; +} + +/* Form Elements */ +.input-group { + display: flex; + flex-direction: column; + gap: 12px; +} + +.length-input-container { + display: flex; + gap: 8px; + align-items: stretch; +} + +.length-input-container input { + flex: 1; +} + +.unit-toggle { + display: flex; +} + +.unit-toggle-btn { + padding: 8px 12px; + border: 1px solid var(--border-color); + background: var(--surface-color); + color: var(--text-color); + border-radius: var(--radius); + cursor: pointer; + transition: var(--transition); + display: flex; + align-items: center; + gap: 6px; + font-size: 12px; + font-weight: 500; + min-width: 90px; + justify-content: space-between; +} + +.unit-toggle-btn:hover { + background: var(--secondary-color); + color: white; +} + +.unit-toggle-btn[data-unit="words"] { + background: var(--primary-color); + color: white; + border-color: var(--primary-color); +} + +.toggle-icon { + width: 16px; + height: 16px; + transition: transform 0.2s ease; +} + +.unit-toggle-btn[data-unit="words"] .toggle-icon { + transform: rotate(180deg); +} + +.checkbox-row { + display: flex; + gap: 16px; + flex-wrap: wrap; +} + +/* Bulk Generation Options */ +.bulk-options { + background: var(--surface-color); + border: 1px solid var(--border-color); + border-radius: var(--radius); + padding: 12px; + margin: 8px 0; +} + +.bulk-row { + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 8px; +} + +.bulk-row:last-child { + margin-bottom: 0; +} + +.bulk-label { + font-size: 13px; + font-weight: 500; + color: var(--text-color); + min-width: 60px; +} + +.bulk-input { + flex: 1; + padding: 6px 7px !important; + border: 1px solid var(--border-color); + border-radius: var(--radius); + background: var(--background-color); + color: var(--text-color); + font-size: 13px; +} + +.bulk-select { + flex: 1; + padding: 6px 8px; + border: 1px solid var(--border-color); + border-radius: var(--radius); + background: var(--background-color); + color: var(--text-color); + font-size: 13px; +} + +input[type="number"], +input[type="text"], +select, +textarea { + width: 100%; + padding: 12px; + border: 1px solid var(--border-color); + border-radius: var(--radius); + background: var(--surface-color); + color: var(--text-color); + font-size: 14px; + font-family: inherit; + transition: var(--transition); +} + +input:focus, +select:focus, +textarea:focus { + outline: none; + border-color: var(--primary-color); + box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1); +} + +textarea { + min-height: 80px; + max-height: 160px; + resize: vertical; +} + +/* Checkboxes and Radio Buttons */ +.checkbox-wrapper, +.radio-wrapper { + display: flex; + align-items: center; + gap: 8px; + cursor: pointer; + padding: 8px 0; +} + +.checkbox-wrapper input, +.radio-wrapper input { + width: auto; + margin: 0; +} + +/* Buttons */ +.primary-button, +.secondary-button { + width: 100%; + padding: 12px; + border: none; + border-radius: var(--radius); + font-weight: 500; + font-size: 14px; + cursor: pointer; + transition: var(--transition); + display: flex; + align-items: center; + justify-content: center; + gap: 8px; +} + +.primary-button { + background: var(--primary-color); + color: white; +} + +.primary-button:hover { + background: #1976D2; + transform: translateY(-1px); + box-shadow: 0 4px 8px rgba(33, 150, 243, 0.3); +} + +.secondary-button { + background: var(--surface-color); + color: var(--text-color); + border: 1px solid var(--border-color); +} + +.secondary-button:hover { + background: var(--border-color); +} + +/* Counter Stats */ +.counter-stats { + font-size: 13px; + color: var(--text-secondary); + padding: 12px; + background: var(--surface-color); + border-radius: var(--radius); + border: 1px solid var(--border-color); +} + +.stats-row { + display: flex; + justify-content: space-around; + margin-bottom: 8px; +} + +.stats-row:last-child { + margin-bottom: 0; +} + +.stat-item { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + min-width: 60px; +} + +.stat-label { + font-size: 11px; + color: var(--text-secondary); + margin-bottom: 2px; +} + +.stat-value { + font-size: 16px; + font-weight: 600; + color: var(--text-color); +} + +/* Option Groups */ +.option-group { + display: none; + gap: 12px; + padding: 12px; + background: var(--surface-color); + border-radius: var(--radius); + border: 1px solid var(--border-color); +} + +.option-group.active { + display: flex; +} + +/* Modal Styles */ +.modal { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: var(--background-color); + display: flex; + flex-direction: column; + z-index: 1000; + opacity: 0; + visibility: hidden; + transition: var(--transition); +} + +.modal[style*="display: none"] { + display: none !important; +} + +.modal.active { + opacity: 1; + visibility: visible; +} + +.modal-content { + background: var(--background-color); + width: 100%; + height: 100%; + overflow-y: auto; + display: flex; + flex-direction: column; + transition: var(--transition); +} + +.modal.active .modal-content { + transform: none; +} + +.modal-header { + padding: 16px; + border-bottom: 1px solid var(--border-color); + display: flex; + justify-content: space-between; + align-items: center; + background: var(--surface-color); + min-height: 60px; +} + +.modal-header h2 { + font-size: 18px; + font-weight: 600; + color: var(--text-color); +} + +.close-button { + background: none; + border: none; + font-size: 24px; + color: var(--text-secondary); + cursor: pointer; + padding: 0; + width: 36px; + height: 36px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + transition: var(--transition); +} + +.close-button:hover { + background: var(--border-color); + color: var(--text-color); +} + +.close-button:active { + background: var(--secondary-color); + color: white; +} + +.modal-body { + padding: 20px; + flex: 1; + overflow-y: auto; +} + +.setting-group { + margin-bottom: 24px; +} + +.setting-group:last-child { + margin-bottom: 0; +} + +.setting-label { + display: block; + font-weight: 500; + margin-bottom: 8px; + color: var(--text-color); +} + +/* Theme Selector */ +.theme-selector { + display: flex; + gap: 8px; +} + +.theme-button { + flex: 1; + padding: 10px; + border: 1px solid var(--border-color); + background: var(--surface-color); + color: var(--text-color); + border-radius: var(--radius); + cursor: pointer; + transition: var(--transition); + font-size: 13px; + font-weight: 500; +} + +.theme-button:hover { + background: var(--secondary-color); + color: white; +} + +.theme-button.active { + background: var(--primary-color); + color: white; + border-color: var(--primary-color); +} + +/* Support Links */ +.support-links { + display: flex; + flex-direction: column; + gap: 12px; +} + +.support-link { + display: flex; + align-items: center; + gap: 12px; + padding: 12px; + background: var(--surface-color); + color: var(--text-color); + text-decoration: none; + border-radius: var(--radius); + border: 1px solid var(--border-color); + transition: var(--transition); + font-size: 14px; +} + +.support-link:hover { + background: var(--primary-color); + color: white; + transform: translateY(-1px); + box-shadow: 0 4px 8px rgba(33, 150, 243, 0.2); +} + +.support-icon { + width: 20px; + height: 20px; + flex-shrink: 0; +} + +/* Loading Overlay */ +.loading-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.7); + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + z-index: 2000; + color: white; + font-size: 16px; + font-weight: 500; +} + +.loading-spinner { + width: 40px; + height: 40px; + border: 3px solid rgba(255, 255, 255, 0.3); + border-top: 3px solid white; + border-radius: 50%; + animation: spin 1s linear infinite; + margin-bottom: 16px; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +/* Feedback Messages */ +.feedback { + position: fixed; + bottom: 20px; + left: 50%; + transform: translateX(-50%); + padding: 12px 24px; + border-radius: var(--radius); + color: white; + font-weight: 500; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + z-index: 1500; + animation: slideUp 0.3s ease; + max-width: 90%; + text-align: center; +} + +.feedback.success { + background: #4CAF50; +} + +.feedback.error { + background: #F44336; +} + +@keyframes slideUp { + from { + transform: translate(-50%, 20px); + opacity: 0; + } + to { + transform: translate(-50%, 0); + opacity: 1; + } +} + +/* Extension Fixed Width - No Responsive */ + +/* Focus Styles for Accessibility */ +button:focus-visible, +input:focus-visible, +select:focus-visible, +textarea:focus-visible { + outline: 2px solid var(--primary-color); + outline-offset: 2px; +} + +/* Print Styles */ +@media print { + .app-header, + .settings-button, + .modal, + .loading-overlay { + display: none !important; + } +} + +/* High Contrast Mode */ +@media (prefers-contrast: high) { + :root { + --border-color: #000000; + --text-color: #000000; + } + + [data-theme="dark"] { + --border-color: #FFFFFF; + --text-color: #FFFFFF; + } +} + +/* Reduced Motion */ +@media (prefers-reduced-motion: reduce) { + * { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } +} \ No newline at end of file diff --git a/src/js/copy.js b/src/js/copy.js new file mode 100644 index 0000000..6b47f26 --- /dev/null +++ b/src/js/copy.js @@ -0,0 +1,42 @@ +// Text manipulation functions + +function capitalizeFirstLetter(string) { + return string.charAt(0).toUpperCase() + string.slice(1); +} + +function toUpperCase(string) { + return string.toUpperCase(); +} + +function toLowerCase(string) { + return string.toLowerCase(); +} + +function removeExtraSpaces(string) { + return string.replace(/\s+/g, ' ').trim(); +} + +function reverseString(string) { + return string.split('').reverse().join(''); +} + +// Clipboard functions + +function copyToClipboard(text) { + return navigator.clipboard.writeText(text); +} + +function readFromClipboard() { + return navigator.clipboard.readText(); +} + +// Expose functions to be used in other files +window.textUtils = { + capitalizeFirstLetter, + toUpperCase, + toLowerCase, + removeExtraSpaces, + reverseString, + copyToClipboard, + readFromClipboard, +}; diff --git a/src/js/func.js b/src/js/func.js new file mode 100644 index 0000000..636780d --- /dev/null +++ b/src/js/func.js @@ -0,0 +1,35 @@ +// Constants +const LOREM_IPSUM_TEXT = + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam euismod, nisl eget ultricies ultricies, nunc nisl aliquam nunc, vitae aliquam'; +const PUNCTUATION_REGEX = /[.,\/#!$%\^&\*;:{}=\-_`~()]/g; +const WHITESPACE_REGEX = /\s+/g; + +// Core functionality +function generateLoremIpsum(length, removeSpace, removePunct) { + // Performance optimization: pre-calculate processed text + let baseText = LOREM_IPSUM_TEXT; + if (removePunct) { + baseText = baseText.replace(PUNCTUATION_REGEX, ''); + } + if (removeSpace) { + baseText = baseText.replace(WHITESPACE_REGEX, ''); + } + + // Calculate how many times we need to repeat the base text + const repeatCount = Math.ceil(length / baseText.length); + let result = baseText.repeat(repeatCount); + + // Trim to exact length + result = result.slice(0, length); + + // If we still need more characters, pad with appropriate character + if (result.length < length) { + const paddingChar = removeSpace ? 'a' : ' '; + result += paddingChar.repeat(length - result.length); + } + + return result; +} + +// Expose function to be used in other files +window.generateLoremIpsum = generateLoremIpsum; diff --git a/src/js/i18n.js b/src/js/i18n.js new file mode 100644 index 0000000..1454d01 --- /dev/null +++ b/src/js/i18n.js @@ -0,0 +1,227 @@ +// Internationalization (i18n) System +class I18n { + constructor() { + this.currentLanguage = 'en'; + this.translations = { + en: { + // App + 'app-title': 'Test String Generator', + 'loading': 'Loading...', + + // Tabs + 'tab-generator': 'Generator', + 'tab-counter': 'Counter', + 'tab-misc': 'Misc', + + // Generator + 'placeholder-length': 'Text Length', + 'unit-characters': 'Characters', + 'unit-words': 'Words', + 'label-remove-punct': 'Remove Punctuation', + 'label-remove-space': 'Remove Spaces', + 'btn-generate': 'Generate Text', + 'placeholder-result': 'Generated text will appear here...', + 'btn-copy': 'Copy to Clipboard', + + // Counter + 'placeholder-counter': 'Enter or paste your text here...', + 'stats-chars': 'Characters', + 'stats-words': 'Words', + 'stats-lines': 'Lines', + 'stats-sentences': 'Sentences', + 'stats-paragraphs': 'Paragraphs', + + // Misc + 'select-data-type': 'Select Data Type', + 'option-name': 'Full Name', + 'option-email': 'Email', + 'option-address': 'Address', + 'option-password': 'Password', + 'gender-male': 'Male', + 'gender-female': 'Female', + 'domain-random': 'Random Domain', + 'domain-custom': 'Custom Domain', + 'placeholder-custom-domain': 'Enter custom domain', + 'bulk-count': 'Count', + 'bulk-format': 'Format', + 'format-plain': 'Plain Text', + 'format-json': 'JSON', + 'format-json-id': 'JSON with ID', + + // Settings + 'settings-title': 'Settings', + 'setting-theme': 'Theme', + 'theme-light': 'Light', + 'theme-dark': 'Dark', + 'setting-language': 'Language', + 'setting-support': 'Support', + 'support-coffee': 'Buy Me a Coffee', + 'support-github': 'GitHub', + + // Messages + 'msg-copied': 'Copied to clipboard!', + 'msg-copy-failed': 'Failed to copy to clipboard', + 'msg-no-text': 'No text to copy', + 'msg-invalid-length': 'Please enter a valid positive number for length', + 'msg-max-length': 'Maximum length is 999,999 characters', + 'msg-select-type': 'Please select a data type', + 'msg-loading-error': 'Error loading data' + }, + + tr: { + // App + 'app-title': 'Test Metin Üreteci', + 'loading': 'Yükleniyor...', + + // Tabs + 'tab-generator': 'Üretici', + 'tab-counter': 'Sayaç', + 'tab-misc': 'Diğer', + + // Generator + 'placeholder-length': 'Metin Uzunluğu', + 'unit-characters': 'Karakter', + 'unit-words': 'Kelime', + 'label-remove-punct': 'Noktalama İşaretlerini Kaldır', + 'label-remove-space': 'Boşlukları Kaldır', + 'btn-generate': 'Metin Üret', + 'placeholder-result': 'Üretilen metin burada görünecek...', + 'btn-copy': 'Panoya Kopyala', + + // Counter + 'placeholder-counter': 'Metninizi buraya girin veya yapıştırın...', + 'stats-chars': 'Karakter', + 'stats-words': 'Kelime', + 'stats-lines': 'Satır', + 'stats-sentences': 'Cümle', + 'stats-paragraphs': 'Paragraf', + + // Misc + 'select-data-type': 'Veri Türü Seçin', + 'option-name': 'Tam İsim', + 'option-email': 'E-posta', + 'option-address': 'Adres', + 'option-password': 'Şifre', + 'gender-male': 'Erkek', + 'gender-female': 'Kadın', + 'domain-random': 'Rastgele Domain', + 'domain-custom': 'Özel Domain', + 'placeholder-custom-domain': 'Özel domain girin', + 'bulk-count': 'Adet', + 'bulk-format': 'Format', + 'format-plain': 'Düz Metin', + 'format-json': 'JSON', + 'format-json-id': 'ID\'li JSON', + + // Settings + 'settings-title': 'Ayarlar', + 'setting-theme': 'Tema', + 'theme-light': 'Açık', + 'theme-dark': 'Koyu', + 'setting-language': 'Dil', + 'setting-support': 'Destek', + 'support-coffee': 'Bana Kahve Ismarla', + 'support-github': 'GitHub', + + // Messages + 'msg-copied': 'Panoya kopyalandı!', + 'msg-copy-failed': 'Panoya kopyalama başarısız', + 'msg-no-text': 'Kopyalanacak metin yok', + 'msg-invalid-length': 'Lütfen uzunluk için geçerli pozitif bir sayı girin', + 'msg-max-length': 'Maksimum uzunluk 999.999 karakterdir', + 'msg-select-type': 'Lütfen bir veri türü seçin', + 'msg-loading-error': 'Veri yükleme hatası' + } + }; + + this.initialize(); + } + + async initialize() { + // Load saved language from storage + try { + if (typeof chrome !== 'undefined' && chrome.storage) { + const result = await chrome.storage.sync.get(['language']); + if (result.language) { + this.currentLanguage = result.language; + } + } else { + // Fallback to localStorage for development + const savedLanguage = localStorage.getItem('language'); + if (savedLanguage) { + this.currentLanguage = savedLanguage; + } + } + } catch (error) { + console.warn('Failed to load language preference:', error); + } + + this.updateUI(); + } + + translate(key, fallback = '') { + const translation = this.translations[this.currentLanguage]?.[key] || + this.translations['en']?.[key] || + fallback || + key; + return translation; + } + + async setLanguage(lang) { + if (this.translations[lang]) { + this.currentLanguage = lang; + + // Save to storage + try { + if (typeof chrome !== 'undefined' && chrome.storage) { + await chrome.storage.sync.set({ language: lang }); + } else { + // Fallback to localStorage for development + localStorage.setItem('language', lang); + } + } catch (error) { + console.warn('Failed to save language preference:', error); + } + + this.updateUI(); + + // Dispatch event for other components + window.dispatchEvent(new CustomEvent('languageChanged', { + detail: { language: lang } + })); + } + } + + updateUI() { + // Update all elements with data-i18n attribute + document.querySelectorAll('[data-i18n]').forEach(element => { + const key = element.getAttribute('data-i18n'); + element.textContent = this.translate(key); + }); + + // Update placeholders + document.querySelectorAll('[data-i18n-placeholder]').forEach(element => { + const key = element.getAttribute('data-i18n-placeholder'); + element.placeholder = this.translate(key); + }); + + // Update HTML lang attribute + document.documentElement.lang = this.currentLanguage; + } + + getCurrentLanguage() { + return this.currentLanguage; + } + + getSupportedLanguages() { + return Object.keys(this.translations); + } +} + +// Create global instance +window.i18n = new I18n(); + +// Export for other modules +if (typeof module !== 'undefined' && module.exports) { + module.exports = I18n; +} \ No newline at end of file diff --git a/src/js/misc.js b/src/js/misc.js new file mode 100644 index 0000000..6beadcd --- /dev/null +++ b/src/js/misc.js @@ -0,0 +1,430 @@ +// Enhanced Miscellaneous Data Generator with Multi-language Support +class MiscDataGenerator { + constructor() { + this.DATA = { + tr: { + maleNames: [], + femaleNames: [], + surnames: [], + emails: [], + addresses: [], + passwords: [] + }, + en: { + maleNames: [], + femaleNames: [], + surnames: [], + emails: [], + addresses: [], + passwords: [] + } + }; + + this.isLoading = false; + this.loadPromise = null; + this.currentLanguage = 'en'; + + this.initialize(); + } + + async initialize() { + // Listen for language changes + window.addEventListener('languageChanged', (e) => { + this.currentLanguage = e.detail.language; + }); + + // Get current language from i18n + if (window.i18n) { + this.currentLanguage = window.i18n.getCurrentLanguage(); + } + + await this.loadAllData(); + this.initializeUI(); + } + + async loadAllData() { + if (this.isLoading) { + return this.loadPromise; + } + + this.isLoading = true; + this.showLoading(true); + + this.loadPromise = this.performDataLoad(); + + try { + await this.loadPromise; + } catch (error) { + console.error('Failed to load data:', error); + this.showFeedback(window.i18n?.translate('msg-loading-error') || 'Error loading data', 'error'); + } finally { + this.isLoading = false; + this.showLoading(false); + } + + return this.loadPromise; + } + + async performDataLoad() { + const dataFiles = { + tr: { + maleNames: 'data/maleFirstName.json', + femaleNames: 'data/femaleFirstName.json', + surnames: 'data/surname.json', + emails: 'data/email.json', + addresses: 'data/address.json', + passwords: 'data/password.json' + }, + en: { + maleNames: 'data/enMaleFirstName.json', + femaleNames: 'data/enFemaleFirstName.json', + surnames: 'data/enSurname.json', + emails: 'data/email.json', // Shared + addresses: 'data/enAddress.json', + passwords: 'data/password.json' // Shared + } + }; + + const loadLanguageData = async (lang) => { + const files = dataFiles[lang]; + const results = await Promise.allSettled([ + this.loadJSONFile(files.maleNames), + this.loadJSONFile(files.femaleNames), + this.loadJSONFile(files.surnames), + this.loadJSONFile(files.emails), + this.loadJSONFile(files.addresses), + this.loadJSONFile(files.passwords) + ]); + + return { + maleNames: results[0].status === 'fulfilled' ? results[0].value : [], + femaleNames: results[1].status === 'fulfilled' ? results[1].value : [], + surnames: results[2].status === 'fulfilled' ? results[2].value : [], + emails: results[3].status === 'fulfilled' ? results[3].value : [], + addresses: results[4].status === 'fulfilled' ? results[4].value : [], + passwords: results[5].status === 'fulfilled' ? results[5].value : [] + }; + }; + + // Load both languages in parallel + const [trData, enData] = await Promise.all([ + loadLanguageData('tr'), + loadLanguageData('en') + ]); + + this.DATA.tr = trData; + this.DATA.en = enData; + } + + async loadJSONFile(path) { + try { + let url; + + // Use chrome.runtime.getURL for extension compatibility + if (typeof chrome !== 'undefined' && chrome.runtime) { + url = chrome.runtime.getURL(path); + } else { + // Fallback for development - relative path + url = path; + } + + const response = await fetch(url); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const data = await response.json(); + return Array.isArray(data) ? data : []; + } catch (error) { + console.warn(`Failed to load ${path}:`, error); + return []; + } + } + + getCurrentData() { + return this.DATA[this.currentLanguage] || this.DATA.en; + } + + getRandomItem(array) { + if (!Array.isArray(array) || array.length === 0) { + return ''; + } + return array[Math.floor(Math.random() * array.length)]; + } + + generateFullName(gender) { + const data = this.getCurrentData(); + const nameArray = gender === 'male' ? data.maleNames : data.femaleNames; + const firstName = this.getRandomItem(nameArray); + const surname = this.getRandomItem(data.surnames); + return `${firstName} ${surname}`; + } + + sanitizeEmailLocalPart(str) { + return str + .toLowerCase() + .normalize('NFD') + .replace(/[\u0300-\u036f]/g, '') // Remove diacritics + .replace(/[çğıöşü]/g, match => { + const map = { 'ç': 'c', 'ğ': 'g', 'ı': 'i', 'ö': 'o', 'ş': 's', 'ü': 'u' }; + return map[match] || match; + }) + .replace(/[^a-z0-9.]/g, '') + .replace(/\.+/g, '.') + .replace(/^\.+|\.+$/g, ''); + } + + generateEmail(domainType, customDomain) { + const data = this.getCurrentData(); + + if (domainType === 'random') { + return this.getRandomItem(data.emails); + } + + // Generate a structured email + const gender = Math.random() > 0.5 ? 'male' : 'female'; + const fullName = this.generateFullName(gender); + let localPart = fullName.toLowerCase().replace(/\s+/g, '.'); + localPart = this.sanitizeEmailLocalPart(localPart); + + // Fallback if sanitization results in empty string + if (!localPart) { + localPart = 'user' + Math.floor(Math.random() * 1000); + } + + let domain; + if (domainType === 'custom') { + domain = customDomain?.trim(); + if (!domain || !this.isValidDomain(domain)) { + domain = 'example.com'; + } + } else { + domain = domainType; + } + + return `${localPart}@${domain}`; + } + + isValidDomain(domain) { + const domainRegex = /^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*$/; + return domainRegex.test(domain) && domain.length <= 253; + } + + generateAddress() { + const data = this.getCurrentData(); + return this.getRandomItem(data.addresses); + } + + generatePassword() { + const data = this.getCurrentData(); + return this.getRandomItem(data.passwords); + } + + initializeUI() { + const dataType = document.getElementById('dataType'); + const nameOptions = document.getElementById('nameOptions'); + const emailOptions = document.getElementById('emailOptions'); + const emailDomain = document.getElementById('emailDomain'); + const customDomain = document.getElementById('customDomain'); + const generateButton = document.getElementById('generateMiscButton'); + const copyButton = document.getElementById('copyMiscButton'); + const resultText = document.getElementById('miscResultText'); + + if (!dataType) return; + + // Data type change handler + dataType.addEventListener('change', () => { + this.updateOptionGroups(); + }); + + // Email domain change handler + emailDomain?.addEventListener('change', () => { + const isCustom = emailDomain.value === 'custom'; + if (customDomain) { + customDomain.style.display = isCustom ? 'block' : 'none'; + customDomain.required = isCustom; + } + }); + + // Generate button handler + generateButton?.addEventListener('click', () => { + this.handleGenerate(); + }); + + // Copy button handler + copyButton?.addEventListener('click', () => { + this.handleCopy(); + }); + + // Initialize option groups visibility + this.updateOptionGroups(); + } + + updateOptionGroups() { + const dataType = document.getElementById('dataType'); + const nameOptions = document.getElementById('nameOptions'); + const emailOptions = document.getElementById('emailOptions'); + + if (!dataType) return; + + const selectedType = dataType.value; + + if (nameOptions) { + nameOptions.style.display = selectedType === 'name' ? 'flex' : 'none'; + } + + if (emailOptions) { + emailOptions.style.display = selectedType === 'email' ? 'flex' : 'none'; + } + } + + async handleGenerate() { + // Ensure data is loaded + if (this.isLoading) { + await this.loadAllData(); + } + + const dataType = document.getElementById('dataType'); + const resultText = document.getElementById('miscResultText'); + const bulkCount = document.getElementById('bulkCount'); + const outputFormat = document.getElementById('outputFormat'); + + if (!dataType || !resultText) return; + + const count = parseInt(bulkCount?.value) || 1; + const format = outputFormat?.value || 'plain'; + + if (count > 1000) { + this.showFeedback('Maximum count is 1000', 'error'); + return; + } + + try { + const results = []; + + for (let i = 0; i < count; i++) { + let singleResult = ''; + + switch (dataType.value) { + case 'name': + const genderElement = document.querySelector('input[name="gender"]:checked'); + const gender = genderElement ? genderElement.value : 'male'; + singleResult = this.generateFullName(gender); + break; + + case 'email': + const emailDomain = document.getElementById('emailDomain'); + const customDomain = document.getElementById('customDomain'); + const domainValue = emailDomain ? emailDomain.value : 'random'; + const customValue = customDomain ? customDomain.value : ''; + singleResult = this.generateEmail(domainValue, customValue); + break; + + case 'address': + singleResult = this.generateAddress(); + break; + + case 'password': + singleResult = this.generatePassword(); + break; + + default: + this.showFeedback(window.i18n?.translate('msg-select-type') || 'Please select a data type', 'error'); + return; + } + + if (!singleResult) { + this.showFeedback(window.i18n?.translate('msg-loading-error') || 'Error generating data', 'error'); + return; + } + + results.push(singleResult); + } + + // Format output + let finalResult = ''; + + switch (format) { + case 'plain': + finalResult = results.join('\n'); + break; + + case 'json': + finalResult = JSON.stringify(results, null, 2); + break; + + case 'json-with-id': + const dataWithIds = results.map((item, index) => ({ + id: index + 1, + value: item + })); + finalResult = JSON.stringify(dataWithIds, null, 2); + break; + + default: + finalResult = results.join('\n'); + } + + resultText.value = finalResult; + + } catch (error) { + console.error('Generation error:', error); + this.showFeedback(window.i18n?.translate('msg-loading-error') || 'Error generating data', 'error'); + } + } + + handleCopy() { + const resultText = document.getElementById('miscResultText'); + + if (!resultText || !resultText.value.trim()) { + this.showFeedback(window.i18n?.translate('msg-no-text') || 'No text to copy', 'error'); + return; + } + + navigator.clipboard.writeText(resultText.value) + .then(() => { + this.showFeedback(window.i18n?.translate('msg-copied') || 'Copied to clipboard!', 'success'); + }) + .catch((error) => { + console.error('Copy failed:', error); + this.showFeedback(window.i18n?.translate('msg-copy-failed') || 'Failed to copy to clipboard', 'error'); + }); + } + + showLoading(show) { + const loadingOverlay = document.getElementById('loadingOverlay'); + if (loadingOverlay) { + loadingOverlay.style.display = show ? 'flex' : 'none'; + } + } + + showFeedback(message, type) { + // Remove existing feedback + const existingFeedback = document.querySelector('.feedback'); + if (existingFeedback) { + existingFeedback.remove(); + } + + const feedbackElement = document.createElement('div'); + feedbackElement.textContent = message; + feedbackElement.className = `feedback ${type}`; + document.body.appendChild(feedbackElement); + + setTimeout(() => { + feedbackElement.remove(); + }, 3000); + } +} + +// Initialize when DOM is loaded +document.addEventListener('DOMContentLoaded', () => { + window.miscDataGenerator = new MiscDataGenerator(); +}); + +// Legacy function for backward compatibility +function initializeMiscTab() { + if (window.miscDataGenerator) { + window.miscDataGenerator.initializeUI(); + } +} diff --git a/src/js/popup.js b/src/js/popup.js new file mode 100644 index 0000000..84868c3 --- /dev/null +++ b/src/js/popup.js @@ -0,0 +1,419 @@ +// Enhanced Popup Management System +class PopupManager { + constructor() { + this.elements = {}; + this.isInitialized = false; + this.initialize(); + } + + async initialize() { + if (this.isInitialized) return; + + // Wait for i18n to be ready + await this.waitForI18n(); + + this.cacheElements(); + this.clearTextarea(); + this.initializeTabs(); + this.initializeCharacterCounter(); + this.bindEvents(); + this.updateUnitToggleText(); + + this.isInitialized = true; + } + + async waitForI18n() { + let retries = 0; + const maxRetries = 50; // 5 seconds max + + while (!window.i18n && retries < maxRetries) { + await new Promise(resolve => setTimeout(resolve, 100)); + retries++; + } + } + + cacheElements() { + this.elements = { + generateButton: document.getElementById('generateButton'), + copyButton: document.getElementById('copyButton'), + lengthInput: document.getElementById('lengthInput'), + unitToggle: document.getElementById('unitToggle'), + removePunct: document.getElementById('removePunct'), + removeSpace: document.getElementById('removeSpace'), + resultText: document.getElementById('resultText'), + counterText: document.getElementById('counterText'), + characterCount: document.getElementById('characterCount'), + tabButtons: document.querySelectorAll('.tab-button'), + tabContents: document.querySelectorAll('.tab-content') + }; + } + + bindEvents() { + // Generator events + this.elements.generateButton?.addEventListener('click', () => { + this.handleGenerate(); + }); + + this.elements.copyButton?.addEventListener('click', () => { + this.handleCopy(); + }); + + // Input validation + this.elements.lengthInput?.addEventListener('input', (e) => { + this.validateLengthInput(e.target); + }); + + // Enter key support for generation + this.elements.lengthInput?.addEventListener('keydown', (e) => { + if (e.key === 'Enter') { + this.handleGenerate(); + } + }); + + // Unit toggle functionality + this.elements.unitToggle?.addEventListener('click', () => { + this.toggleUnit(); + }); + + // Listen for language changes + window.addEventListener('languageChanged', () => { + this.updateCharacterCount(); + this.updateUnitToggleText(); + }); + } + + handleGenerate() { + const length = parseInt(this.elements.lengthInput?.value); + const removePunct = this.elements.removePunct?.checked || false; + const removeSpace = this.elements.removeSpace?.checked || false; + const unit = this.elements.unitToggle?.getAttribute('data-unit') || 'characters'; + + // Validation + if (!this.validateLength(length)) { + return; + } + + try { + // Show loading state + this.setGenerateButtonState(true); + + let generatedText; + + if (unit === 'words') { + // Generate by word count + generatedText = this.generateByWords(length, removeSpace, removePunct); + } else { + // Generate by character count (default) + generatedText = window.generateLoremIpsum(length, removeSpace, removePunct); + } + + if (this.elements.resultText) { + this.elements.resultText.value = generatedText; + } + + } catch (error) { + console.error('Generation error:', error); + this.showFeedback( + window.i18n?.translate('msg-loading-error') || 'Error generating text', + 'error' + ); + } finally { + this.setGenerateButtonState(false); + } + } + + validateLength(length) { + if (isNaN(length) || length <= 0) { + this.showFeedback( + window.i18n?.translate('msg-invalid-length') || 'Please enter a valid positive number for length', + 'error' + ); + this.clearTextarea(); + return false; + } + + if (length > 999999) { + this.showFeedback( + window.i18n?.translate('msg-max-length') || 'Maximum length is 999,999 characters', + 'error' + ); + this.clearTextarea(); + return false; + } + + return true; + } + + validateLengthInput(input) { + const value = parseInt(input.value); + + // Visual feedback for invalid input + if (input.value && (isNaN(value) || value <= 0)) { + input.style.borderColor = '#f44336'; + } else if (input.value && value > 999999) { + input.style.borderColor = '#ff9800'; + } else { + input.style.borderColor = ''; + } + } + + setGenerateButtonState(loading) { + if (!this.elements.generateButton) return; + + if (loading) { + this.elements.generateButton.disabled = true; + this.elements.generateButton.textContent = window.i18n?.translate('loading') || 'Loading...'; + } else { + this.elements.generateButton.disabled = false; + this.elements.generateButton.textContent = window.i18n?.translate('btn-generate') || 'Generate Text'; + } + } + + handleCopy() { + const resultText = this.elements.resultText?.value; + + if (!resultText || !resultText.trim()) { + this.showFeedback( + window.i18n?.translate('msg-no-text') || 'No text to copy', + 'error' + ); + return; + } + + navigator.clipboard.writeText(resultText) + .then(() => { + this.showFeedback( + window.i18n?.translate('msg-copied') || 'Copied to clipboard!', + 'success' + ); + }) + .catch((err) => { + console.error('Failed to copy:', err); + this.showFeedback( + window.i18n?.translate('msg-copy-failed') || 'Failed to copy to clipboard', + 'error' + ); + }); + } + + initializeTabs() { + this.elements.tabButtons.forEach(button => { + button.addEventListener('click', () => { + this.switchTab(button); + }); + }); + } + + switchTab(activeButton) { + // Remove active class from all buttons and contents + this.elements.tabButtons.forEach(btn => btn.classList.remove('active')); + this.elements.tabContents.forEach(content => content.classList.remove('active')); + + // Add active class to clicked button and corresponding content + activeButton.classList.add('active'); + const tabId = activeButton.getAttribute('data-tab'); + const targetContent = document.getElementById(tabId); + + if (targetContent) { + targetContent.classList.add('active'); + } + + // Focus management for accessibility + const firstFocusableElement = targetContent?.querySelector( + 'input, button, select, textarea, [tabindex]:not([tabindex="-1"])' + ); + if (firstFocusableElement) { + firstFocusableElement.focus(); + } + } + + initializeCharacterCounter() { + if (!this.elements.counterText || !this.elements.characterCount) return; + + const updateCount = () => { + this.updateCharacterCount(); + }; + + this.elements.counterText.addEventListener('input', updateCount); + this.elements.counterText.addEventListener('paste', () => { + // Update count after paste + setTimeout(updateCount, 10); + }); + + // Initialize with empty state + updateCount(); + } + + updateCharacterCount() { + if (!this.elements.counterText || !this.elements.characterCount) return; + + const text = this.elements.counterText.value; + const chars = text.length; + const words = text.trim() === '' ? 0 : text.trim().split(/\s+/).length; + const lines = text.trim() === '' ? 0 : text.split('\n').length; + + // Count sentences (split by ., !, ?) + const sentences = text.trim() === '' ? 0 : + text.split(/[.!?]+/).filter(s => s.trim().length > 0).length; + + // Count paragraphs (split by double newlines or more) + const paragraphs = text.trim() === '' ? 0 : + text.split(/\n\s*\n/).filter(p => p.trim().length > 0).length; + + // Update individual stat values + const charCount = document.getElementById('charCount'); + const wordCount = document.getElementById('wordCount'); + const lineCount = document.getElementById('lineCount'); + const sentenceCount = document.getElementById('sentenceCount'); + const paragraphCount = document.getElementById('paragraphCount'); + + if (charCount) charCount.textContent = chars.toLocaleString(); + if (wordCount) wordCount.textContent = words.toLocaleString(); + if (lineCount) lineCount.textContent = lines.toLocaleString(); + if (sentenceCount) sentenceCount.textContent = sentences.toLocaleString(); + if (paragraphCount) paragraphCount.textContent = paragraphs.toLocaleString(); + } + + toggleUnit() { + if (!this.elements.unitToggle) return; + + const currentUnit = this.elements.unitToggle.getAttribute('data-unit'); + const newUnit = currentUnit === 'characters' ? 'words' : 'characters'; + + this.elements.unitToggle.setAttribute('data-unit', newUnit); + this.updateUnitToggleText(); + } + + updateUnitToggleText() { + if (!this.elements.unitToggle) return; + + const unit = this.elements.unitToggle.getAttribute('data-unit'); + const unitLabel = this.elements.unitToggle.querySelector('.unit-label'); + + if (unitLabel) { + const key = unit === 'words' ? 'unit-words' : 'unit-characters'; + unitLabel.textContent = window.i18n?.translate(key) || (unit === 'words' ? 'Words' : 'Characters'); + } + } + + generateByWords(wordCount, removeSpace, removePunct) { + const LOREM_WORDS = [ + 'lorem', 'ipsum', 'dolor', 'sit', 'amet', 'consectetur', 'adipiscing', 'elit', + 'sed', 'do', 'eiusmod', 'tempor', 'incididunt', 'ut', 'labore', 'et', 'dolore', + 'magna', 'aliqua', 'enim', 'ad', 'minim', 'veniam', 'quis', 'nostrud', + 'exercitation', 'ullamco', 'laboris', 'nisi', 'aliquip', 'ex', 'ea', 'commodo', + 'consequat', 'duis', 'aute', 'irure', 'in', 'reprehenderit', 'voluptate', + 'velit', 'esse', 'cillum', 'fugiat', 'nulla', 'pariatur', 'excepteur', 'sint', + 'occaecat', 'cupidatat', 'non', 'proident', 'sunt', 'culpa', 'qui', 'officia', + 'deserunt', 'mollit', 'anim', 'id', 'est', 'laborum' + ]; + + let words = []; + for (let i = 0; i < wordCount; i++) { + words.push(LOREM_WORDS[i % LOREM_WORDS.length]); + } + + let result = words.join(' '); + + // Apply transformations + if (removePunct) { + result = result.replace(/[.,\/#!$%\^&\*;:{}=\-_`~()]/g, ''); + } + + if (removeSpace) { + result = result.replace(/\s+/g, ''); + } + + return result; + } + + clearTextarea() { + if (this.elements.resultText) { + this.elements.resultText.value = ''; + } + } + + showFeedback(message, type) { + // Remove existing feedback + const existingFeedback = document.querySelector('.feedback'); + if (existingFeedback) { + existingFeedback.remove(); + } + + const feedbackElement = document.createElement('div'); + feedbackElement.textContent = message; + feedbackElement.className = `feedback ${type}`; + feedbackElement.setAttribute('role', 'alert'); + feedbackElement.setAttribute('aria-live', 'polite'); + + document.body.appendChild(feedbackElement); + + // Auto-remove after 3 seconds + setTimeout(() => { + feedbackElement.remove(); + }, 3000); + + // Remove on click + feedbackElement.addEventListener('click', () => { + feedbackElement.remove(); + }); + } +} + +// Legacy compatibility functions +function clearTextarea() { + if (window.popupManager) { + window.popupManager.clearTextarea(); + } +} + +function showFeedback(message, type) { + if (window.popupManager) { + window.popupManager.showFeedback(message, type); + } +} + +function copyToClipboard() { + if (window.popupManager) { + window.popupManager.handleCopy(); + } +} + +function initializeTabs() { + // Handled by PopupManager +} + +function initializeCharacterCounter() { + // Handled by PopupManager +} + +function initializeMiscTab() { + // Handled by MiscDataGenerator +} + +// Initialize when DOM is loaded +document.addEventListener('DOMContentLoaded', async () => { + window.popupManager = new PopupManager(); + + // Handle runtime connection for popup clearing + try { + if (typeof chrome !== 'undefined' && chrome.runtime) { + const port = chrome.runtime.connect({ name: 'popup' }); + port.onDisconnect.addListener(() => { + // Clean up when popup closes + if (window.popupManager) { + window.popupManager.clearTextarea(); + } + }); + } + } catch (error) { + console.warn('Could not establish runtime connection:', error); + } +}); + +// Handle popup being reopened +document.addEventListener('visibilitychange', () => { + if (document.visibilityState === 'visible' && window.popupManager) { + window.popupManager.clearTextarea(); + } +}); diff --git a/src/js/settings.js b/src/js/settings.js new file mode 100644 index 0000000..6cb54e6 --- /dev/null +++ b/src/js/settings.js @@ -0,0 +1,229 @@ +// Settings Management System +class SettingsManager { + constructor() { + this.settings = { + theme: 'light', + language: 'en' + }; + + this.initialize(); + } + + async initialize() { + await this.loadSettings(); + this.bindEvents(); + this.applyTheme(); + } + + async loadSettings() { + try { + if (typeof chrome !== 'undefined' && chrome.storage) { + const result = await chrome.storage.sync.get(['theme', 'language']); + this.settings = { + theme: result.theme || 'light', + language: result.language || 'en' + }; + } else { + // Fallback to localStorage for development + this.settings = { + theme: localStorage.getItem('theme') || 'light', + language: localStorage.getItem('language') || 'en' + }; + } + } catch (error) { + console.warn('Failed to load settings:', error); + } + } + + async saveSettings() { + try { + if (typeof chrome !== 'undefined' && chrome.storage) { + await chrome.storage.sync.set(this.settings); + } else { + // Fallback to localStorage for development + localStorage.setItem('theme', this.settings.theme); + localStorage.setItem('language', this.settings.language); + } + } catch (error) { + console.warn('Failed to save settings:', error); + } + } + + bindEvents() { + // Settings button + const settingsButton = document.getElementById('settingsButton'); + const settingsModal = document.getElementById('settingsModal'); + const closeSettings = document.getElementById('closeSettings'); + + if (settingsButton) { + settingsButton.addEventListener('click', (e) => { + e.preventDefault(); + e.stopPropagation(); + this.openModal(); + }); + } + + // Close modal events + closeSettings?.addEventListener('click', () => { + this.closeModal(); + }); + + // Remove click-outside-to-close since it's now fullscreen + // settingsModal?.addEventListener('click', (e) => { + // if (e.target === settingsModal) { + // this.closeModal(); + // } + // }); + + // Escape key to close modal + document.addEventListener('keydown', (e) => { + if (e.key === 'Escape' && settingsModal?.classList.contains('active')) { + this.closeModal(); + } + }); + + // Theme buttons + const lightTheme = document.getElementById('lightTheme'); + const darkTheme = document.getElementById('darkTheme'); + + lightTheme?.addEventListener('click', () => { + this.setTheme('light'); + }); + + darkTheme?.addEventListener('click', () => { + this.setTheme('dark'); + }); + + // Language select + const languageSelect = document.getElementById('languageSelect'); + languageSelect?.addEventListener('change', (e) => { + this.setLanguage(e.target.value); + }); + + // Update UI with current settings + this.updateSettingsUI(); + } + + openModal() { + const modal = document.getElementById('settingsModal'); + + if (modal) { + modal.classList.add('active'); + modal.style.display = 'flex'; + + // Focus trap + const focusableElements = modal.querySelectorAll( + 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])' + ); + if (focusableElements?.length > 0) { + focusableElements[0].focus(); + } + } + } + + closeModal() { + const modal = document.getElementById('settingsModal'); + + if (modal) { + modal.classList.remove('active'); + modal.style.display = 'none'; + } + + // Return focus to settings button + document.getElementById('settingsButton')?.focus(); + } + + async setTheme(theme) { + if (theme !== this.settings.theme) { + this.settings.theme = theme; + await this.saveSettings(); + this.applyTheme(); + this.updateThemeButtons(); + } + } + + applyTheme() { + document.body.setAttribute('data-theme', this.settings.theme); + + // Update meta theme-color + let themeColorMeta = document.querySelector('meta[name="theme-color"]'); + if (!themeColorMeta) { + themeColorMeta = document.createElement('meta'); + themeColorMeta.name = 'theme-color'; + document.head.appendChild(themeColorMeta); + } + + const themeColor = this.settings.theme === 'dark' ? '#1E1E1E' : '#FFFFFF'; + themeColorMeta.content = themeColor; + } + + async setLanguage(language) { + if (language !== this.settings.language && window.i18n) { + this.settings.language = language; + await this.saveSettings(); + await window.i18n.setLanguage(language); + this.updateLanguageSelect(); + } + } + + updateSettingsUI() { + this.updateThemeButtons(); + this.updateLanguageSelect(); + } + + updateThemeButtons() { + const lightTheme = document.getElementById('lightTheme'); + const darkTheme = document.getElementById('darkTheme'); + + lightTheme?.classList.toggle('active', this.settings.theme === 'light'); + darkTheme?.classList.toggle('active', this.settings.theme === 'dark'); + } + + updateLanguageSelect() { + const languageSelect = document.getElementById('languageSelect'); + if (languageSelect) { + languageSelect.value = this.settings.language; + } + } + + getSettings() { + return { ...this.settings }; + } +} + +// Initialize when DOM is loaded +document.addEventListener('DOMContentLoaded', () => { + window.settingsManager = new SettingsManager(); +}); + +// Handle system theme changes +if (window.matchMedia) { + const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); + + const handleSystemThemeChange = (e) => { + // Only auto-switch if user hasn't manually set a preference + if (typeof chrome !== 'undefined' && chrome.storage) { + chrome.storage.sync.get(['theme']).then(result => { + if (!result.theme && window.settingsManager) { + const systemTheme = e.matches ? 'dark' : 'light'; + window.settingsManager.setTheme(systemTheme); + } + }).catch(() => { + console.warn('Could not check theme preference'); + }); + } else { + // Fallback for development + if (!localStorage.getItem('theme') && window.settingsManager) { + const systemTheme = e.matches ? 'dark' : 'light'; + window.settingsManager.setTheme(systemTheme); + } + } + }; + + mediaQuery.addEventListener('change', handleSystemThemeChange); + + // Check initial system preference + document.addEventListener('DOMContentLoaded', () => { + handleSystemThemeChange(mediaQuery); + }); +} \ No newline at end of file