Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 271780f48a | |||
| 264441f83b | |||
| c218162edf | |||
| 886a2f7372 | |||
| 68e11c57e1 |
262
README.md
262
README.md
@@ -4,79 +4,35 @@ A powerful task management and focus timer plugin for [Obsidian](https://obsidia
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
## 🎯 Overview
|
||||
|
||||
Immerse brings the power of time-boxed task management directly into your Obsidian vault. Plan your day, track time with the Pomodoro technique, and crush your tasks with satisfying checkoffs - all without leaving your notes.
|
||||
Task management and focus timer for Obsidian. Plan your day, track time with Pomodoro technique, and manage tasks without leaving your vault.
|
||||
|
||||
### Why Immerse?
|
||||
## ✨ Key Features
|
||||
|
||||
- **Stay in Flow**: No need to switch between apps - manage tasks where you take notes
|
||||
- **Time Awareness**: Know exactly how long tasks take vs. your estimates
|
||||
- **Pomodoro Built-in**: Work in focused sprints with automatic break reminders
|
||||
- **Satisfying Feedback**: Celebratory messages and sounds when you complete tasks
|
||||
- **Visual Progress**: See your daily progress with stats and streaks
|
||||
**📋 Task Management**
|
||||
- Create tasks with time estimates and organize into customizable lists
|
||||
- Filter by list, status, or date
|
||||
- Schedule tasks with reminders (5/10/15/30/60 min before due)
|
||||
- Daily note integration with automatic task logging
|
||||
|
||||
## ✨ Features
|
||||
**⏱️ Dual Timer Modes**
|
||||
- **Pomodoro**: Configurable work sessions with automatic breaks
|
||||
- **Stopwatch**: Free-form time tracking with estimate alerts
|
||||
|
||||
### 📋 Task Management
|
||||
- Create tasks with time estimates
|
||||
- Organize tasks into customizable lists (Work, Personal, Learning, etc.)
|
||||
- Add notes and details to tasks
|
||||
- Filter tasks by list, today's tasks, or completed items
|
||||
- Drag-and-drop task reordering
|
||||
**📊 Analytics & Reports**
|
||||
- View productivity metrics (tasks/day, hours/day, streaks)
|
||||
- Pie charts and bar graphs showing activity breakdown
|
||||
- Time tracking by list category
|
||||
- Insights on most productive hours, days, and months
|
||||
|
||||
### ⏱️ Dual Timer Modes
|
||||
|
||||
#### Pomodoro Timer
|
||||
- Configurable work sessions (default: 25 minutes)
|
||||
- Short breaks (default: 5 minutes)
|
||||
- Long breaks after a set number of pomodoros (default: 15 minutes every 4 pomodoros)
|
||||
- Auto-start break option
|
||||
- Visual countdown with progress bar
|
||||
|
||||
#### Stopwatch Mode
|
||||
- Free-form time tracking
|
||||
- Alerts when you exceed your estimate
|
||||
- Track actual time vs. estimated time
|
||||
|
||||
### 📊 Progress Tracking
|
||||
- **Daily Stats**: See tasks completed, focus time, and more
|
||||
- **Streak Counter**: Build momentum with consecutive productive days
|
||||
- **Time Comparison**: Compare estimated vs. actual time to improve planning
|
||||
- **Pomodoro Count**: Track total pomodoros completed
|
||||
- **Daily Note Logging**: Automatically log completed tasks to your daily notes with timestamps and performance metrics
|
||||
|
||||
### 📈 Reporting & Analytics (New in v1.1.0!)
|
||||
- **Comprehensive Reports**: View detailed productivity reports with date range filtering
|
||||
- **Key Metrics Dashboard**: Track tasks done, tasks per day, hours per day, minutes per task, and day streaks
|
||||
- **Visual Analytics**: Pie charts showing task distribution and time allocation
|
||||
- **Time by List**: See how much time you spend on different task categories
|
||||
- **Productivity Insights**: Discover your most productive hour, day, and month
|
||||
- **Daily Breakdown**: Visual bar charts showing last 10 days of activity
|
||||
- **Quick Filters**: Today, Last 7/30/90 days for easy report generation
|
||||
|
||||
### 🗓️ Task Scheduling & Reminders (New in v1.1.0!)
|
||||
- **Schedule Tasks**: Set specific date and time for tasks
|
||||
- **Smart Reminders**: Get notifications before task is due (5/10/15/30/60 minute options)
|
||||
- **Overdue Detection**: Visual indicators (⚠️ red badge) for past-due tasks
|
||||
- **Startup Checks**: Alerts when opening Obsidian if tasks are overdue
|
||||
- **Background Monitoring**: Automatic 30-second checks for due tasks
|
||||
- **Sound Alerts**: Optional audio notifications for reminders
|
||||
|
||||
### 📱 Mobile Optimized (New in v1.1.0!)
|
||||
- **Responsive Design**: Fully optimized for mobile screens (tablets and phones)
|
||||
- **Touch-Friendly**: Larger buttons and tap targets (44px minimum)
|
||||
- **Adaptive Layouts**: Charts and visualizations scale appropriately
|
||||
- **Mobile Testing**: Works great on Obsidian mobile app
|
||||
|
||||
### 🎨 User Experience
|
||||
- **Status Bar Timer**: Timer that stays visible while you work
|
||||
- **Celebration Messages**: Fun, randomized messages when you complete tasks
|
||||
- **Sound Notifications**: Audio alerts for timer completion and task completion
|
||||
- **Keyboard Shortcuts**: Quick access to common actions
|
||||
- **Responsive Design**: Works great in any panel size
|
||||
**🎨 Polish**
|
||||
- Status bar timer, celebration messages, sound alerts
|
||||
- Keyboard shortcuts, dark mode support
|
||||
- Overdue task detection with visual indicators
|
||||
- Works on desktop and mobile
|
||||
|
||||
## 🚀 Installation
|
||||
|
||||
@@ -111,183 +67,45 @@ npm run build
|
||||
cp main.js manifest.json styles.css /path/to/your/vault/.obsidian/plugins/immerse/
|
||||
```
|
||||
|
||||
## 📖 Usage
|
||||
## 📖 Quick Start
|
||||
|
||||
### Getting Started
|
||||
1. Click ⚡ icon in ribbon or use command palette (`Ctrl/Cmd + P` → "Open Immerse Panel")
|
||||
2. Add a task with "+ Add Task" (description, time estimate, list)
|
||||
3. Start timer: ▶ for Pomodoro or ⏱ for stopwatch
|
||||
4. Complete and enjoy the celebration!
|
||||
|
||||
1. **Open Immerse**: Click the ⚡ icon in the ribbon or use the command palette (`Ctrl/Cmd + P` → "Open Immerse Panel")
|
||||
## ⚙️ Configuration
|
||||
|
||||
2. **Add a Task**: Click "+ Add Task" and fill in:
|
||||
- Task description
|
||||
- Time estimate
|
||||
- List category
|
||||
All settings available in Settings → Immerse:
|
||||
- Pomodoro durations (work: 25min, short break: 5min, long break: 15min)
|
||||
- Default time estimates, sounds, celebrations
|
||||
- Daily note integration (auto-log completed tasks)
|
||||
- Custom lists with names, emojis, and colors
|
||||
|
||||
3. **Start Focusing**: Click ▶ on any task to start a Pomodoro session, or ⏱ for stopwatch mode
|
||||
## 🙏 Credits
|
||||
|
||||
4. **Complete Tasks**: Check off tasks when done and enjoy the celebration!
|
||||
|
||||
### Keyboard Shortcuts
|
||||
|
||||
| Action | Command |
|
||||
|--------|---------|
|
||||
| Open Panel | `Ctrl/Cmd + P` → "Open Immerse Panel" |
|
||||
| Quick Add Task | `Ctrl/Cmd + P` → "Quick Add Task" |
|
||||
| Toggle Timer | `Ctrl/Cmd + P` → "Toggle Timer" |
|
||||
| Complete Task | `Ctrl/Cmd + P` → "Complete Current Task" |
|
||||
| Start Focus | `Ctrl/Cmd + P` → "Start Focus Mode on Next Task" |
|
||||
|
||||
### Timer Modes Explained
|
||||
|
||||
#### 🍅 Pomodoro Mode (▶ button)
|
||||
Best for: Maintaining focus on challenging tasks
|
||||
|
||||
1. Timer counts down from your configured work duration
|
||||
2. When time's up, you'll get a notification
|
||||
3. Take a break (short or long, based on your settings)
|
||||
4. Repeat until the task is complete
|
||||
|
||||
#### ⏱️ Stopwatch Mode (⏱ button)
|
||||
Best for: Tracking time on open-ended tasks
|
||||
|
||||
1. Timer counts up from zero
|
||||
2. Get alerted when you exceed your estimate
|
||||
3. Stop whenever the task is complete
|
||||
4. See exactly how long the task took
|
||||
|
||||
## ⚙️ Settings
|
||||
|
||||
### Pomodoro Timer
|
||||
| Setting | Description | Default |
|
||||
|---------|-------------|---------|
|
||||
| Work Duration | Length of each work session | 25 min |
|
||||
| Short Break | Length of short breaks | 5 min |
|
||||
| Long Break | Length of long breaks | 15 min |
|
||||
| Long Break Interval | Pomodoros before a long break | 4 |
|
||||
| Auto-start Breaks | Automatically start break timer | On |
|
||||
|
||||
### General
|
||||
| Setting | Description | Default |
|
||||
|---------|-------------|---------|
|
||||
| Default Time Estimate | Default estimate for new tasks | 30 min |
|
||||
| Enable Sounds | Play completion/alert sounds | On |
|
||||
| Enable Celebrations | Show celebration messages | On |
|
||||
| Show Floating Timer | Display draggable timer widget | On |
|
||||
|
||||
### Daily Note Integration
|
||||
|
||||
| Setting | Description | Default |
|
||||
|---------|-------------|---------|
|
||||
| Log to Daily Note | Automatically log completed tasks to your daily note | Off |
|
||||
|
||||
When enabled, completed tasks are automatically appended to your daily note with:
|
||||
|
||||
- Task name and list category
|
||||
- Time spent vs. estimated time
|
||||
- Completion timestamp
|
||||
- Performance indicator (under/over/on target)
|
||||
|
||||
**Example entry:**
|
||||
|
||||
```
|
||||
- [x] Write project proposal | 💼 Work | ⏱️ 45min / 30min (15min over estimate) | ✅ 14:30
|
||||
```
|
||||
|
||||
**Requirements:** The core "Daily Notes" plugin must be enabled in Obsidian settings. Immerse respects your Daily Notes configuration (folder, date format, and template).
|
||||
|
||||
### Lists
|
||||
Customize your task lists with:
|
||||
- Custom names
|
||||
- Emoji icons
|
||||
- Color coding
|
||||
|
||||
Default lists: Work 💼, Personal 🏠, Learning 📚
|
||||
|
||||
## 🎨 Customization
|
||||
|
||||
### Adding Custom Lists
|
||||
1. Go to Settings → Immerse → Lists
|
||||
2. Click "+ Add List"
|
||||
3. Set the name, emoji, and color
|
||||
4. Click Save
|
||||
|
||||
### Theming
|
||||
Immerse respects your Obsidian theme and adapts to both light and dark modes automatically.
|
||||
|
||||
## 📁 Project Structure
|
||||
|
||||
```
|
||||
immerse/
|
||||
├── src/
|
||||
│ ├── main.ts # Main plugin class
|
||||
│ ├── types.ts # TypeScript interfaces
|
||||
│ ├── view.ts # Main UI view
|
||||
│ └── modals.ts # Task modals
|
||||
├── styles.css # Plugin styles
|
||||
├── manifest.json # Obsidian plugin manifest
|
||||
├── package.json # npm configuration
|
||||
├── tsconfig.json # TypeScript config
|
||||
├── esbuild.config.mjs # Build configuration
|
||||
└── README.md # This file
|
||||
```
|
||||
|
||||
## 🙏 Inspiration & Credits
|
||||
|
||||
This plugin is **heavily inspired by [Blitzit](https://www.blitzit.app/)**, a fantastic standalone productivity app that combines task management with focused time tracking.
|
||||
|
||||
Blitzit's approach to productivity resonated with me:
|
||||
- Simple, focused interface
|
||||
- Time estimation and tracking
|
||||
- Pomodoro technique integration
|
||||
- Satisfying task completion experience
|
||||
- Progress insights
|
||||
|
||||
I wanted to bring this experience directly into Obsidian, where I already manage my notes and knowledge. Immerse is my attempt to capture the essence of what makes Blitzit great while leveraging Obsidian's powerful ecosystem.
|
||||
|
||||
**If you're looking for a dedicated productivity app, I highly recommend checking out [Blitzit](https://www.blitzit.app/)!**
|
||||
Heavily inspired by [Blitzit](https://www.blitzit.app/) - a fantastic productivity app. Immerse brings that experience into Obsidian.
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
Contributions are welcome! Feel free to:
|
||||
|
||||
1. Fork the repository
|
||||
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
||||
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
||||
4. Push to the branch (`git push origin feature/amazing-feature`)
|
||||
5. Open a Pull Request
|
||||
|
||||
### Development Setup
|
||||
Contributions welcome! Fork, create a feature branch, and open a PR.
|
||||
|
||||
**Dev Setup:**
|
||||
```bash
|
||||
# Clone the repo
|
||||
git clone https://git.cribdev.com/crib/immerse.git
|
||||
cd immerse
|
||||
|
||||
# Install dependencies
|
||||
npm install
|
||||
|
||||
# Start development build (watches for changes)
|
||||
npm run dev
|
||||
|
||||
# Create symlink to your test vault
|
||||
ln -s $(pwd) /path/to/vault/.obsidian/plugins/immerse
|
||||
```
|
||||
|
||||
## 📜 License
|
||||
|
||||
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
||||
|
||||
## 🔗 Links
|
||||
|
||||
- **Repository**: [https://git.cribdev.com/crib/immerse](https://git.cribdev.com/crib/immerse)
|
||||
- **Issues**: [https://git.cribdev.com/crib/immerse/issues](https://git.cribdev.com/crib/immerse/issues)
|
||||
- **Inspiration**: [Blitzit App](https://www.blitzit.app/)
|
||||
MIT License - see [LICENSE](LICENSE) file.
|
||||
|
||||
---
|
||||
|
||||
**Links:** [Repository](https://git.cribdev.com/crib/immerse) • [Issues](https://git.cribdev.com/crib/immerse/issues) • [Blitzit](https://www.blitzit.app/)
|
||||
|
||||
<p align="center">
|
||||
Made with ❤️ for the Obsidian community
|
||||
<br>
|
||||
Inspired by <a href="https://www.blitzit.app/">Blitzit</a> ⚡
|
||||
<br><br>
|
||||
<em>✨ Vibe coded with assistance from <a href="https://claude.ai">Claude.ai</a></em>
|
||||
<em>Made with ❤️ for the Obsidian community • Inspired by Blitzit ⚡</em>
|
||||
</p>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"id": "immerse",
|
||||
"name": "Immerse",
|
||||
"version": "1.1.1",
|
||||
"minAppVersion": "0.15.0",
|
||||
"description": "A Blitzit-inspired task management and focus timer plugin. Plan your day, track time with Pomodoro technique, and crush your tasks with satisfying checkoffs.",
|
||||
"author": "Crib",
|
||||
"authorUrl": "https://git.cribdev.com/crib",
|
||||
"fundingUrl": "",
|
||||
"isDesktopOnly": false
|
||||
}
|
||||
"id": "immerse",
|
||||
"name": "Immerse",
|
||||
"version": "1.1.3",
|
||||
"minAppVersion": "0.15.0",
|
||||
"description": "A Blitzit-inspired task management and focus timer plugin. Plan your day, track time with Pomodoro technique, and crush your tasks with satisfying checkoffs.",
|
||||
"author": "Crib",
|
||||
"authorUrl": "https://git.cribdev.com/crib",
|
||||
"fundingUrl": "",
|
||||
"isDesktopOnly": false
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "immerse",
|
||||
"version": "1.1.1",
|
||||
"version": "1.1.3",
|
||||
"description": "A Blitzit-inspired task management and focus timer plugin for Obsidian",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
||||
22
src/main.ts
22
src/main.ts
@@ -22,7 +22,7 @@ import {
|
||||
|
||||
import { ImmerseView } from './view';
|
||||
import { ReportView, VIEW_TYPE_REPORT } from './reportView';
|
||||
import { QuickAddTaskModal } from './modals';
|
||||
import { QuickAddTaskModal, EmojiPickerModal } from './modals';
|
||||
|
||||
// ============ Main Plugin Class ============
|
||||
|
||||
@@ -1385,12 +1385,20 @@ class ImmerseSettingTab extends PluginSettingTab {
|
||||
this.plugin.settings.lists[index].name = value;
|
||||
await this.plugin.saveAllData();
|
||||
}))
|
||||
.addText(text => text
|
||||
.setValue(list.icon)
|
||||
.setPlaceholder('Emoji')
|
||||
.onChange(async value => {
|
||||
this.plugin.settings.lists[index].icon = value;
|
||||
await this.plugin.saveAllData();
|
||||
.addButton(btn => btn
|
||||
.setButtonText(list.icon || '📁')
|
||||
.setTooltip('Choose emoji')
|
||||
.onClick(() => {
|
||||
const modal = new EmojiPickerModal(
|
||||
this.app,
|
||||
list.icon,
|
||||
async (emoji) => {
|
||||
this.plugin.settings.lists[index].icon = emoji;
|
||||
await this.plugin.saveAllData();
|
||||
this.display();
|
||||
}
|
||||
);
|
||||
modal.open();
|
||||
}))
|
||||
.addColorPicker(picker => picker
|
||||
.setValue(list.color)
|
||||
|
||||
400
src/modals.ts
400
src/modals.ts
@@ -8,6 +8,293 @@ import {
|
||||
import { ImmerseTask } from './types';
|
||||
import ImmersePlugin from './main';
|
||||
|
||||
// Emoji search keywords mapping
|
||||
const EMOJI_KEYWORDS: { [key: string]: string } = {
|
||||
'💼': 'briefcase work business office job',
|
||||
'🏠': 'home house',
|
||||
'📚': 'books study read library',
|
||||
'🎯': 'target goal aim dart',
|
||||
'✅': 'check mark done complete checkbox tick',
|
||||
'📝': 'memo note write pencil',
|
||||
'💡': 'light bulb idea',
|
||||
'🔥': 'fire hot flame',
|
||||
'⚡': 'lightning bolt electric zap',
|
||||
'🎨': 'art paint palette',
|
||||
'🏆': 'trophy award win',
|
||||
'💪': 'muscle strong flex',
|
||||
'🚀': 'rocket ship launch',
|
||||
'📊': 'chart graph data',
|
||||
'⏰': 'clock time alarm',
|
||||
'💰': 'money bag cash dollar',
|
||||
'😀': 'smile happy face grin',
|
||||
'😃': 'smile happy grin',
|
||||
'😄': 'smile happy laugh',
|
||||
'😁': 'grin smile happy',
|
||||
'😆': 'laugh smile happy',
|
||||
'😅': 'sweat smile nervous',
|
||||
'🤣': 'laugh rolling floor',
|
||||
'😂': 'tears joy laugh cry',
|
||||
'🙂': 'smile happy slight',
|
||||
'🙃': 'upside down smile',
|
||||
'😉': 'wink smile flirt',
|
||||
'😊': 'blush smile happy',
|
||||
'😇': 'angel halo smile',
|
||||
'🥰': 'love hearts smile',
|
||||
'😍': 'love heart eyes smile',
|
||||
'🤩': 'star eyes excited',
|
||||
'😘': 'kiss love heart',
|
||||
'😗': 'kiss love',
|
||||
'😚': 'kiss love',
|
||||
'😙': 'kiss love smile',
|
||||
'🥲': 'smile tear cry happy',
|
||||
'😋': 'yum delicious smile',
|
||||
'😛': 'tongue playful',
|
||||
'😜': 'wink tongue playful',
|
||||
'🤪': 'crazy wild eyes',
|
||||
'😝': 'tongue eyes squint',
|
||||
'🤑': 'money dollar rich',
|
||||
'🤗': 'hug smile',
|
||||
'🤭': 'hand over mouth giggle',
|
||||
'🤫': 'shush quiet secret',
|
||||
'🤔': 'think hmm wonder',
|
||||
'🤐': 'zipper mouth secret',
|
||||
'🤨': 'eyebrow raised skeptical',
|
||||
'😐': 'neutral meh',
|
||||
'😑': 'expressionless blank',
|
||||
'😶': 'no mouth silent',
|
||||
'😏': 'smirk confident',
|
||||
'😒': 'unamused annoyed',
|
||||
'🙄': 'eye roll annoyed',
|
||||
'😬': 'grimace awkward',
|
||||
'🤥': 'liar lying pinocchio',
|
||||
'😌': 'relieved content',
|
||||
'😔': 'sad pensive',
|
||||
'😪': 'sleepy tired',
|
||||
'🤤': 'drool sleep',
|
||||
'😴': 'sleep zzz',
|
||||
'😷': 'mask sick medical',
|
||||
'🤒': 'sick thermometer',
|
||||
'🤕': 'injured bandage',
|
||||
'🤢': 'nausea sick',
|
||||
'🤮': 'vomit sick',
|
||||
'🤧': 'sneeze sick tissue',
|
||||
'🥵': 'hot sweat',
|
||||
'🥶': 'cold freeze',
|
||||
'😎': 'cool sunglasses',
|
||||
'🤓': 'nerd glasses',
|
||||
'🧐': 'monocle fancy',
|
||||
'😕': 'confused uncertain',
|
||||
'😟': 'worried concerned',
|
||||
'🙁': 'frown sad',
|
||||
'☹️': 'frown sad',
|
||||
'😮': 'wow surprised',
|
||||
'😯': 'surprised shocked',
|
||||
'😲': 'shocked astonished',
|
||||
'😳': 'flushed embarrassed',
|
||||
'🥺': 'pleading puppy eyes',
|
||||
'😦': 'frown worried',
|
||||
'😧': 'anguished worried',
|
||||
'😨': 'fearful scared',
|
||||
'😰': 'anxious sweat',
|
||||
'😥': 'sad sweat',
|
||||
'😢': 'cry tear sad',
|
||||
'😭': 'cry tears sob',
|
||||
'😱': 'scream fear',
|
||||
'😖': 'confounded',
|
||||
'😣': 'persevere struggle',
|
||||
'😞': 'disappointed sad',
|
||||
'😓': 'downcast sweat',
|
||||
'😩': 'weary tired',
|
||||
'😫': 'tired exhausted',
|
||||
'🥱': 'yawn tired',
|
||||
'😤': 'triumph proud',
|
||||
'😡': 'angry mad rage',
|
||||
'😠': 'angry mad',
|
||||
'🤬': 'cursing swearing angry',
|
||||
'😈': 'devil smiling evil',
|
||||
'👿': 'devil angry evil',
|
||||
'💀': 'skull death',
|
||||
'☠️': 'skull crossbones death',
|
||||
'💩': 'poop poo',
|
||||
'🤡': 'clown funny',
|
||||
'👹': 'ogre monster',
|
||||
'👺': 'goblin monster',
|
||||
'👻': 'ghost boo',
|
||||
'👽': 'alien extraterrestrial',
|
||||
'👾': 'alien monster game',
|
||||
'🤖': 'robot bot',
|
||||
'❤️': 'red heart love',
|
||||
'🧡': 'orange heart love',
|
||||
'💛': 'yellow heart love',
|
||||
'💚': 'green heart love',
|
||||
'💙': 'blue heart love',
|
||||
'💜': 'purple heart love',
|
||||
'🤎': 'brown heart love',
|
||||
'🖤': 'black heart love',
|
||||
'🤍': 'white heart love',
|
||||
'💔': 'broken heart sad',
|
||||
'❣️': 'heart exclamation love',
|
||||
'💕': 'two hearts love',
|
||||
'💞': 'revolving hearts love',
|
||||
'💓': 'beating heart love',
|
||||
'💗': 'growing heart love',
|
||||
'💖': 'sparkling heart love',
|
||||
'💘': 'arrow heart love cupid',
|
||||
'💝': 'heart box gift love',
|
||||
'💟': 'heart decoration love',
|
||||
'❤️🔥': 'heart fire love passion',
|
||||
'❤️🩹': 'heart bandage healing',
|
||||
'💌': 'love letter heart',
|
||||
'💋': 'kiss lips',
|
||||
'💑': 'couple love kiss',
|
||||
'💏': 'kiss couple love',
|
||||
'👋': 'wave hand hello goodbye',
|
||||
'🤚': 'raised hand back',
|
||||
'🖐️': 'hand fingers spread',
|
||||
'✋': 'raised hand stop',
|
||||
'🖖': 'vulcan salute spock',
|
||||
'👌': 'ok okay hand',
|
||||
'🤌': 'pinched fingers italian',
|
||||
'🤏': 'pinching hand small',
|
||||
'✌️': 'peace victory hand',
|
||||
'🤞': 'crossed fingers luck',
|
||||
'🤟': 'love you hand',
|
||||
'🤘': 'rock on horns',
|
||||
'🤙': 'call me hang loose',
|
||||
'👈': 'left point finger',
|
||||
'👉': 'right point finger',
|
||||
'👆': 'up point finger',
|
||||
'🖕': 'middle finger rude',
|
||||
'👇': 'down point finger',
|
||||
'☝️': 'up point finger',
|
||||
'👍': 'thumbs up yes good',
|
||||
'👎': 'thumbs down no bad',
|
||||
'✊': 'fist hand',
|
||||
'👊': 'fist bump punch',
|
||||
'🤛': 'left fist bump',
|
||||
'🤜': 'right fist bump',
|
||||
'👏': 'clap applause',
|
||||
'🙌': 'raising hands celebration',
|
||||
'👐': 'open hands',
|
||||
'🤲': 'palms together pray',
|
||||
'🤝': 'handshake deal',
|
||||
'🙏': 'pray please thank',
|
||||
'✍️': 'writing hand',
|
||||
'💅': 'nail polish manicure',
|
||||
'🤳': 'selfie camera phone',
|
||||
'🐶': 'dog puppy pet',
|
||||
'🐱': 'cat kitty pet',
|
||||
'🐭': 'mouse rat',
|
||||
'🐹': 'hamster pet',
|
||||
'🐰': 'rabbit bunny',
|
||||
'🦊': 'fox',
|
||||
'🐻': 'bear',
|
||||
'🐼': 'panda bear',
|
||||
'🐨': 'koala bear',
|
||||
'🐯': 'tiger face',
|
||||
'🦁': 'lion face',
|
||||
'🐮': 'cow face',
|
||||
'🐷': 'pig face',
|
||||
'🐸': 'frog face',
|
||||
'🐵': 'monkey face',
|
||||
'🍎': 'apple red fruit',
|
||||
'🍊': 'orange fruit',
|
||||
'🍋': 'lemon fruit',
|
||||
'🍌': 'banana fruit',
|
||||
'🍉': 'watermelon fruit',
|
||||
'🍇': 'grapes fruit',
|
||||
'🍓': 'strawberry fruit',
|
||||
'🍒': 'cherry fruit',
|
||||
'🍑': 'peach fruit',
|
||||
'🥭': 'mango fruit',
|
||||
'🍍': 'pineapple fruit',
|
||||
'🥥': 'coconut fruit',
|
||||
'🥝': 'kiwi fruit',
|
||||
'🍅': 'tomato vegetable',
|
||||
'🥑': 'avocado fruit',
|
||||
'🍞': 'bread food',
|
||||
'⚽': 'soccer ball football',
|
||||
'🏀': 'basketball ball',
|
||||
'🏈': 'american football',
|
||||
'⚾': 'baseball ball',
|
||||
'🎾': 'tennis ball',
|
||||
'🏐': 'volleyball ball',
|
||||
'🚗': 'car auto vehicle',
|
||||
'🚕': 'taxi car',
|
||||
'🚙': 'suv car vehicle',
|
||||
'🚌': 'bus vehicle',
|
||||
'🚎': 'trolleybus bus',
|
||||
'🏎️': 'racing car fast',
|
||||
'🚓': 'police car cop',
|
||||
'🚑': 'ambulance emergency',
|
||||
'🚒': 'fire truck engine',
|
||||
'🚲': 'bicycle bike',
|
||||
'✈️': 'airplane plane flight',
|
||||
'💻': 'laptop computer',
|
||||
'⌨️': 'keyboard computer',
|
||||
'🖱️': 'mouse computer',
|
||||
'🖥️': 'desktop computer',
|
||||
'🖨️': 'printer',
|
||||
'📱': 'phone mobile iphone',
|
||||
'📞': 'phone telephone',
|
||||
'☎️': 'telephone phone',
|
||||
'📺': 'tv television',
|
||||
'📻': 'radio',
|
||||
'📁': 'folder file',
|
||||
'📂': 'open folder file',
|
||||
'📅': 'calendar date',
|
||||
'📆': 'calendar date',
|
||||
'📈': 'chart up graph',
|
||||
'📉': 'chart down graph',
|
||||
'📌': 'pushpin pin',
|
||||
'📍': 'pin location map',
|
||||
'📎': 'paperclip clip',
|
||||
'🎵': 'music note',
|
||||
'🎶': 'music notes',
|
||||
'🎼': 'musical score',
|
||||
'🎹': 'piano keyboard music',
|
||||
'🎸': 'guitar music',
|
||||
'🎺': 'trumpet music',
|
||||
'🎷': 'saxophone music',
|
||||
'🥁': 'drum music',
|
||||
'🎤': 'microphone mic sing',
|
||||
'🎧': 'headphones music',
|
||||
'🔊': 'speaker loud volume',
|
||||
'❌': 'cross x no cancel',
|
||||
'⚠️': 'warning caution alert',
|
||||
'🔴': 'red circle',
|
||||
'🟢': 'green circle',
|
||||
'🔵': 'blue circle',
|
||||
'🟡': 'yellow circle',
|
||||
'🟣': 'purple circle',
|
||||
'⚫': 'black circle',
|
||||
'⚪': 'white circle',
|
||||
'🟤': 'brown circle',
|
||||
'🔺': 'triangle red up',
|
||||
'🔻': 'triangle red down',
|
||||
'🔸': 'diamond orange small',
|
||||
'🔹': 'diamond blue small',
|
||||
'🔶': 'diamond orange large',
|
||||
'🔷': 'diamond blue large',
|
||||
};
|
||||
|
||||
// Emoji categories for picker
|
||||
const EMOJI_CATEGORIES = {
|
||||
'⭐ Frequently Used': ['💼', '🏠', '📚', '🎯', '✅', '📝', '💡', '🔥', '⚡', '🎨', '🏆', '💪', '🚀', '📊', '⏰', '💰'],
|
||||
'😀 Smileys & Emotion': ['😀', '😃', '😄', '😁', '😆', '😅', '🤣', '😂', '🙂', '🙃', '😉', '😊', '😇', '🥰', '😍', '🤩', '😘', '😗', '😚', '😙', '🥲', '😋', '😛', '😜', '🤪', '😝', '🤑', '🤗', '🤭', '🤫', '🤔', '🤐', '🤨', '😐', '😑', '😶', '😏', '😒', '🙄', '😬', '🤥', '😌', '😔', '😪', '🤤', '😴', '😷', '🤒', '🤕', '🤢', '🤮', '🤧', '🥵', '🥶', '😎', '🤓', '🧐', '😕', '😟', '🙁', '☹️', '😮', '😯', '😲', '😳', '🥺', '😦', '😧', '😨', '😰', '😥', '😢', '😭', '😱', '😖', '😣', '😞', '😓', '😩', '😫', '🥱', '😤', '😡', '😠', '🤬', '😈', '👿', '💀', '☠️', '💩', '🤡', '👹', '👺', '👻', '👽', '👾', '🤖'],
|
||||
'❤️ Hearts & Love': ['❤️', '🧡', '💛', '💚', '💙', '💜', '🤎', '🖤', '🤍', '💔', '❣️', '💕', '💞', '💓', '💗', '💖', '💘', '💝', '💟', '❤️🔥', '❤️🩹', '💌', '💋', '💑', '💏', '👩❤️👨', '👨❤️👨', '👩❤️👩'],
|
||||
'👤 People & Body': ['👋', '🤚', '🖐️', '✋', '🖖', '👌', '🤌', '🤏', '✌️', '🤞', '🤟', '🤘', '🤙', '👈', '👉', '👆', '🖕', '👇', '☝️', '👍', '👎', '✊', '👊', '🤛', '🤜', '👏', '🙌', '👐', '🤲', '🤝', '🙏', '✍️', '💅', '🤳', '💪', '🦾', '🦿', '🦵', '🦶', '👂', '🦻', '👃', '🧠', '🫀', '🫁', '🦷', '🦴', '👀', '👁️', '👅', '👄', '👶', '🧒', '👦', '👧', '🧑', '👨', '👩', '🧔', '🧑🦰', '👨🦰', '👩🦰', '🧑🦱', '👨🦱', '👩🦱', '🧑🦳', '👨🦳', '👩🦳', '🧑🦲', '👨🦲', '👩🦲', '👱', '👱♂️', '👱♀️', '🧓', '👴', '👵', '🙍', '🙍♂️', '🙍♀️', '🙎', '🙎♂️', '🙎♀️', '🙅', '🙅♂️', '🙅♀️', '🙆', '🙆♂️', '🙆♀️', '💁', '💁♂️', '💁♀️', '🙋', '🙋♂️', '🙋♀️', '🧏', '🧏♂️', '🧏♀️', '🙇', '🙇♂️', '🙇♀️', '🤦', '🤦♂️', '🤦♀️', '🤷', '🤷♂️', '🤷♀️'],
|
||||
'🐶 Animals & Nature': ['🐶', '🐱', '🐭', '🐹', '🐰', '🦊', '🐻', '🐼', '🐨', '🐯', '🦁', '🐮', '🐷', '🐽', '🐸', '🐵', '🙈', '🙉', '🙊', '🐒', '🐔', '🐧', '🐦', '🐤', '🐣', '🐥', '🦆', '🦅', '🦉', '🦇', '🐺', '🐗', '🐴', '🦄', '🐝', '🐛', '🦋', '🐌', '🐞', '🐜', '🦟', '🦗', '🕷️', '🕸️', '🦂', '🐢', '🐍', '🦎', '🦖', '🦕', '🐙', '🦑', '🦐', '🦞', '🦀', '🐡', '🐠', '🐟', '🐬', '🐳', '🐋', '🦈', '🐊', '🐅', '🐆', '🦓', '🦍', '🦧', '🐘', '🦛', '🦏', '🐪', '🐫', '🦒', '🦘', '🐃', '🐂', '🐄', '🐎', '🐖', '🐏', '🐑', '🦙', '🐐', '🦌', '🐕', '🐩', '🦮', '🐕🦺', '🐈', '🐈⬛', '🐓', '🦃', '🦚', '🦜', '🦢', '🦩', '🕊️', '🐇', '🦝', '🦨', '🦡', '🦦', '🦥', '🐁', '🐀', '🐿️', '🦔', '🌲', '🌳', '🌴', '🌱', '🌿', '☘️', '🍀', '🎍', '🎋', '🍃', '🍂', '🍁', '🍄', '🌾', '💐', '🌷', '🌹', '🥀', '🌺', '🌸', '🌼', '🌻', '🌞', '🌝', '🌛', '🌜', '🌚', '🌕', '🌖', '🌗', '🌘', '🌑', '🌒', '🌓', '🌔', '🌙', '🌎', '🌍', '🌏', '🪐', '💫', '⭐', '🌟', '✨', '⚡', '☄️', '💥', '🔥', '🌪️', '🌈', '☀️', '🌤️', '⛅', '🌥️', '☁️', '🌦️', '🌧️', '⛈️', '🌩️', '🌨️', '❄️', '☃️', '⛄', '🌬️', '💨', '💧', '💦', '☔', '☂️', '🌊', '🌫️'],
|
||||
'🍎 Food & Drink': ['🍇', '🍈', '🍉', '🍊', '🍋', '🍌', '🍍', '🥭', '🍎', '🍏', '🍐', '🍑', '🍒', '🍓', '🫐', '🥝', '🍅', '🫒', '🥥', '🥑', '🍆', '🥔', '🥕', '🌽', '🌶️', '🫑', '🥒', '🥬', '🥦', '🧄', '🧅', '🍄', '🥜', '🌰', '🍞', '🥐', '🥖', '🫓', '🥨', '🥯', '🥞', '🧇', '🧀', '🍖', '🍗', '🥩', '🥓', '🍔', '🍟', '🍕', '🌭', '🥪', '🌮', '🌯', '🫔', '🥙', '🧆', '🥚', '🍳', '🥘', '🍲', '🫕', '🥣', '🥗', '🍿', '🧈', '🧂', '🥫', '🍱', '🍘', '🍙', '🍚', '🍛', '🍜', '🍝', '🍠', '🍢', '🍣', '🍤', '🍥', '🥮', '🍡', '🥟', '🥠', '🥡', '🦀', '🦞', '🦐', '🦑', '🦪', '🍦', '🍧', '🍨', '🍩', '🍪', '🎂', '🍰', '🧁', '🥧', '🍫', '🍬', '🍭', '🍮', '🍯', '🍼', '🥛', '☕', '🫖', '🍵', '🍶', '🍾', '🍷', '🍸', '🍹', '🍺', '🍻', '🥂', '🥃', '🥤', '🧋', '🧃', '🧉', '🧊'],
|
||||
'⚽ Activities & Sports': ['⚽', '🏀', '🏈', '⚾', '🥎', '🎾', '🏐', '🏉', '🥏', '🎱', '🪀', '🏓', '🏸', '🏒', '🏑', '🥍', '🏏', '🪃', '🥅', '⛳', '🪁', '🏹', '🎣', '🤿', '🥊', '🥋', '🎽', '🛹', '🛼', '🛷', '⛸️', '🥌', '🎿', '⛷️', '🏂', '🪂', '🏋️', '🏋️♂️', '🏋️♀️', '🤼', '🤼♂️', '🤼♀️', '🤸', '🤸♂️', '🤸♀️', '⛹️', '⛹️♂️', '⛹️♀️', '🤺', '🤾', '🤾♂️', '🤾♀️', '🏌️', '🏌️♂️', '🏌️♀️', '🏇', '🧘', '🧘♂️', '🧘♀️', '🏄', '🏄♂️', '🏄♀️', '🏊', '🏊♂️', '🏊♀️', '🤽', '🤽♂️', '🤽♀️', '🚣', '🚣♂️', '🚣♀️', '🧗', '🧗♂️', '🧗♀️', '🚵', '🚵♂️', '🚵♀️', '🚴', '🚴♂️', '🚴♀️', '🏆', '🥇', '🥈', '🥉', '🏅', '🎖️', '🏵️', '🎗️', '🎫', '🎟️', '🎪', '🤹', '🤹♂️', '🤹♀️', '🎭', '🩰', '🎨', '🎬', '🎤', '🎧', '🎼', '🎹', '🥁', '🪘', '🎷', '🎺', '🪗', '🎸', '🪕', '🎻', '🎲', '♟️', '🎯', '🎳', '🎮', '🎰', '🧩'],
|
||||
'🚗 Travel & Places': ['🚗', '🚕', '🚙', '🚌', '🚎', '🏎️', '🚓', '🚑', '🚒', '🚐', '🛻', '🚚', '🚛', '🚜', '🦯', '🦽', '🦼', '🛴', '🚲', '🛵', '🏍️', '🛺', '🚨', '🚔', '🚍', '🚘', '🚖', '🚡', '🚠', '🚟', '🚃', '🚋', '🚞', '🚝', '🚄', '🚅', '🚈', '🚂', '🚆', '🚇', '🚊', '🚉', '✈️', '🛫', '🛬', '🛩️', '💺', '🛰️', '🚀', '🛸', '🚁', '🛶', '⛵', '🚤', '🛥️', '🛳️', '⛴️', '🚢', '⚓', '⛽', '🚧', '🚦', '🚥', '🚏', '🗺️', '🗿', '🗽', '🗼', '🏰', '🏯', '🏟️', '🎡', '🎢', '🎠', '⛲', '⛱️', '🏖️', '🏝️', '🏜️', '🌋', '⛰️', '🏔️', '🗻', '🏕️', '⛺', '🛖', '🏠', '🏡', '🏘️', '🏚️', '🏗️', '🏭', '🏢', '🏬', '🏣', '🏤', '🏥', '🏦', '🏨', '🏪', '🏫', '🏩', '💒', '🏛️', '⛪', '🕌', '🕍', '🛕', '🕋', '⛩️', '🛤️', '🛣️', '🗾', '🎑', '🏞️', '🌅', '🌄', '🌠', '🎇', '🎆', '🌇', '🌆', '🏙️', '🌃', '🌌', '🌉', '🌁'],
|
||||
'💻 Objects & Technology': ['⌚', '📱', '📲', '💻', '⌨️', '🖥️', '🖨️', '🖱️', '🖲️', '🕹️', '🗜️', '💾', '💿', '📀', '📼', '📷', '📸', '📹', '🎥', '📽️', '🎞️', '📞', '☎️', '📟', '📠', '📺', '📻', '🎙️', '🎚️', '🎛️', '🧭', '⏱️', '⏲️', '⏰', '🕰️', '⌛', '⏳', '📡', '🔋', '🔌', '💡', '🔦', '🕯️', '🪔', '🧯', '🛢️', '💸', '💵', '💴', '💶', '💷', '🪙', '💰', '💳', '💎', '⚖️', '🪜', '🧰', '🪛', '🔧', '🔨', '⚒️', '🛠️', '⛏️', '🪚', '🔩', '⚙️', '🪤', '🧱', '⛓️', '🧲', '🔫', '💣', '🧨', '🪓', '🔪', '🗡️', '⚔️', '🛡️', '🚬', '⚰️', '🪦', '⚱️', '🏺', '🔮', '📿', '🧿', '💈', '⚗️', '🔭', '🔬', '🕳️', '🩹', '🩺', '💊', '💉', '🩸', '🧬', '🦷', '🧪', '🌡️', '🧹', '🪠', '🧺', '🧻', '🚽', '🚰', '🚿', '🛁', '🛀', '🧼', '🪥', '🪒', '🧽', '🪣', '🧴', '🛎️', '🔑', '🗝️', '🚪', '🪑', '🛋️', '🛏️', '🛌', '🧸', '🪆', '🖼️', '🪞', '🪟', '🛍️', '🛒', '🎁', '🎈', '🎏', '🎀', '🪄', '🪅', '🎊', '🎉', '🎎', '🏮', '🎐', '🧧'],
|
||||
'📋 Office & Writing': ['✉️', '📧', '📨', '📩', '📤', '📥', '📦', '📫', '📪', '📬', '📭', '📮', '🗳️', '✏️', '✒️', '🖋️', '🖊️', '🖌️', '🖍️', '📝', '💼', '📁', '📂', '🗂️', '📅', '📆', '🗒️', '🗓️', '📇', '📈', '📉', '📊', '📋', '📌', '📍', '📎', '🖇️', '📏', '📐', '✂️', '🗃️', '🗄️', '🗑️', '🔒', '🔓', '🔏', '🔐', '🔑', '🗝️', '🔨', '🪓', '⛏️', '⚒️', '🛠️', '🗡️', '⚔️', '💣', '🪃', '🏹', '🛡️', '🪚', '🔧', '🪛', '🔩', '⚙️', '🗜️', '⚖️'],
|
||||
'🎵 Music & Sound': ['🎵', '🎶', '🎼', '🎹', '🎸', '🎺', '🎷', '🥁', '🪘', '🎤', '🎧', '📻', '🎙️', '🔊', '🔉', '🔈', '🔇', '📢', '📣', '📯', '🔔', '🔕', '🎚️', '🎛️', '🎖️', '🏆', '🥇', '🥈', '🥉', '⚡', '🔥', '💥'],
|
||||
'⚡ Symbols & Signs': ['❤️', '🧡', '💛', '💚', '💙', '💜', '🖤', '🤍', '🤎', '💔', '❣️', '💕', '💞', '💓', '💗', '💖', '💘', '💝', '💟', '☮️', '✝️', '☪️', '🕉️', '☸️', '✡️', '🔯', '🕎', '☯️', '☦️', '🛐', '⛎', '♈', '♉', '♊', '♋', '♌', '♍', '♎', '♏', '♐', '♑', '♒', '♓', '🆔', '⚛️', '🉑', '☢️', '☣️', '📴', '📳', '🈶', '🈚', '🈸', '🈺', '🈷️', '✴️', '🆚', '💮', '🉐', '㊙️', '㊗️', '🈴', '🈵', '🈹', '🈲', '🅰️', '🅱️', '🆎', '🆑', '🅾️', '🆘', '❌', '⭕', '🛑', '⛔', '📛', '🚫', '💯', '💢', '♨️', '🚷', '🚯', '🚳', '🚱', '🔞', '📵', '🚭', '❗', '❕', '❓', '❔', '‼️', '⁉️', '🔅', '🔆', '〽️', '⚠️', '🚸', '🔱', '⚜️', '🔰', '♻️', '✅', '🈯', '💹', '❇️', '✳️', '❎', '🌐', '💠', 'Ⓜ️', '🌀', '💤', '🏧', '🚾', '♿', '🅿️', '🛗', '🈳', '🈂️', '🛂', '🛃', '🛄', '🛅', '🚹', '🚺', '🚼', '⚧️', '🚻', '🚮', '🎦', '📶', '🈁', '🔣', 'ℹ️', '🔤', '🔡', '🔠', '🆖', '🆗', '🆙', '🆒', '🆕', '🆓', '0️⃣', '1️⃣', '2️⃣', '3️⃣', '4️⃣', '5️⃣', '6️⃣', '7️⃣', '8️⃣', '9️⃣', '🔟', '🔢', '#️⃣', '*️⃣', '⏏️', '▶️', '⏸️', '⏯️', '⏹️', '⏺️', '⏭️', '⏮️', '⏩', '⏪', '⏫', '⏬', '◀️', '🔼', '🔽', '➡️', '⬅️', '⬆️', '⬇️', '↗️', '↘️', '↙️', '↖️', '↕️', '↔️', '↪️', '↩️', '⤴️', '⤵️', '🔀', '🔁', '🔂', '🔄', '🔃', '🎵', '🎶', '➕', '➖', '➗', '✖️', '♾️', '💲', '💱', '™️', '©️', '®️', '〰️', '➰', '➿', '🔚', '🔙', '🔛', '🔝', '🔜', '✔️', '☑️', '🔘', '🔴', '🟠', '🟡', '🟢', '🔵', '🟣', '⚫', '⚪', '🟤', '🔺', '🔻', '🔸', '🔹', '🔶', '🔷', '🔳', '🔲', '▪️', '▫️', '◾', '◽', '◼️', '◻️', '🟥', '🟧', '🟨', '🟩', '🟦', '🟪', '⬛', '⬜', '🟫', '🔈', '🔇', '🔉', '🔊', '🔔', '🔕', '📣', '📢', '💬', '💭', '🗯️', '♠️', '♣️', '♥️', '♦️', '🃏', '🎴', '🀄', '🕐', '🕑', '🕒', '🕓', '🕔', '🕕', '🕖', '🕗', '🕘', '🕙', '🕚', '🕛', '🕜', '🕝', '🕞', '🕟', '🕠', '🕡', '🕢', '🕣', '🕤', '🕥', '🕦', '🕧'],
|
||||
'🏁 Flags': ['🏁', '🚩', '🎌', '🏴', '🏳️', '🏳️🌈', '🏳️⚧️', '🏴☠️', '🇦🇨', '🇦🇩', '🇦🇪', '🇦🇫', '🇦🇬', '🇦🇮', '🇦🇱', '🇦🇲', '🇦🇴', '🇦🇶', '🇦🇷', '🇦🇸', '🇦🇹', '🇦🇺', '🇦🇼', '🇦🇽', '🇦🇿', '🇧🇦', '🇧🇧', '🇧🇩', '🇧🇪', '🇧🇫', '🇧🇬', '🇧🇭', '🇧🇮', '🇧🇯', '🇧🇱', '🇧🇲', '🇧🇳', '🇧🇴', '🇧🇶', '🇧🇷', '🇧🇸', '🇧🇹', '🇧🇻', '🇧🇼', '🇧🇾', '🇧🇿', '🇨🇦', '🇨🇨', '🇨🇩', '🇨🇫', '🇨🇬', '🇨🇭', '🇨🇮', '🇨🇰', '🇨🇱', '🇨🇲', '🇨🇳', '🇨🇴', '🇨🇵', '🇨🇷', '🇨🇺', '🇨🇻', '🇨🇼', '🇨🇽', '🇨🇾', '🇨🇿', '🇩🇪', '🇩🇬', '🇩🇯', '🇩🇰', '🇩🇲', '🇩🇴', '🇩🇿', '🇪🇦', '🇪🇨', '🇪🇪', '🇪🇬', '🇪🇭', '🇪🇷', '🇪🇸', '🇪🇹', '🇪🇺', '🇫🇮', '🇫🇯', '🇫🇰', '🇫🇲', '🇫🇴', '🇫🇷', '🇬🇦', '🇬🇧', '🇬🇩', '🇬🇪', '🇬🇫', '🇬🇬', '🇬🇭', '🇬🇮', '🇬🇱', '🇬🇲', '🇬🇳', '🇬🇵', '🇬🇶', '🇬🇷', '🇬🇸', '🇬🇹', '🇬🇺', '🇬🇼', '🇬🇾', '🇭🇰', '🇭🇲', '🇭🇳', '🇭🇷', '🇭🇹', '🇭🇺', '🇮🇨', '🇮🇩', '🇮🇪', '🇮🇱', '🇮🇲', '🇮🇳', '🇮🇴', '🇮🇶', '🇮🇷', '🇮🇸', '🇮🇹', '🇯🇪', '🇯🇲', '🇯🇴', '🇯🇵', '🇰🇪', '🇰🇬', '🇰🇭', '🇰🇮', '🇰🇲', '🇰🇳', '🇰🇵', '🇰🇷', '🇰🇼', '🇰🇾', '🇰🇿', '🇱🇦', '🇱🇧', '🇱🇨', '🇱🇮', '🇱🇰', '🇱🇷', '🇱🇸', '🇱🇹', '🇱🇺', '🇱🇻', '🇱🇾', '🇲🇦', '🇲🇨', '🇲🇩', '🇲🇪', '🇲🇫', '🇲🇬', '🇲🇭', '🇲🇰', '🇲🇱', '🇲🇲', '🇲🇳', '🇲🇴', '🇲🇵', '🇲🇶', '🇲🇷', '🇲🇸', '🇲🇹', '🇲🇺', '🇲🇻', '🇲🇼', '🇲🇽', '🇲🇾', '🇲🇿', '🇳🇦', '🇳🇨', '🇳🇪', '🇳🇫', '🇳🇬', '🇳🇮', '🇳🇱', '🇳🇴', '🇳🇵', '🇳🇷', '🇳🇺', '🇳🇿', '🇴🇲', '🇵🇦', '🇵🇪', '🇵🇫', '🇵🇬', '🇵🇭', '🇵🇰', '🇵🇱', '🇵🇲', '🇵🇳', '🇵🇷', '🇵🇸', '🇵🇹', '🇵🇼', '🇵🇾', '🇶🇦', '🇷🇪', '🇷🇴', '🇷🇸', '🇷🇺', '🇷🇼', '🇸🇦', '🇸🇧', '🇸🇨', '🇸🇩', '🇸🇪', '🇸🇬', '🇸🇭', '🇸🇮', '🇸🇯', '🇸🇰', '🇸🇱', '🇸🇲', '🇸🇳', '🇸🇴', '🇸🇷', '🇸🇸', '🇸🇹', '🇸🇻', '🇸🇽', '🇸🇾', '🇸🇿', '🇹🇦', '🇹🇨', '🇹🇩', '🇹🇫', '🇹🇬', '🇹🇭', '🇹🇯', '🇹🇰', '🇹🇱', '🇹🇲', '🇹🇳', '🇹🇴', '🇹🇷', '🇹🇹', '🇹🇻', '🇹🇼', '🇹🇿', '🇺🇦', '🇺🇬', '🇺🇲', '🇺🇳', '🇺🇸', '🇺🇾', '🇺🇿', '🇻🇦', '🇻🇨', '🇻🇪', '🇻🇬', '🇻🇮', '🇻🇳', '🇻🇺', '🇼🇫', '🇼🇸', '🇽🇰', '🇾🇪', '🇾🇹', '🇿🇦', '🇿🇲', '🇿🇼', '🏴', '🏴', '🏴'],
|
||||
};
|
||||
|
||||
// ============ Quick Add Task Modal ============
|
||||
|
||||
export class QuickAddTaskModal extends Modal {
|
||||
@@ -547,4 +834,115 @@ export class ReportModal extends Modal {
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============ Emoji Picker Modal ============
|
||||
|
||||
export class EmojiPickerModal extends Modal {
|
||||
onSelect: (emoji: string) => void;
|
||||
currentEmoji: string;
|
||||
|
||||
constructor(app: App, currentEmoji: string, onSelect: (emoji: string) => void) {
|
||||
super(app);
|
||||
this.currentEmoji = currentEmoji;
|
||||
this.onSelect = onSelect;
|
||||
}
|
||||
|
||||
onOpen() {
|
||||
const { contentEl } = this;
|
||||
contentEl.addClass('immerse-emoji-picker');
|
||||
|
||||
contentEl.createEl('h2', { text: 'Select Emoji' });
|
||||
|
||||
// Current selection
|
||||
if (this.currentEmoji) {
|
||||
const currentDiv = contentEl.createDiv({ cls: 'immerse-emoji-current' });
|
||||
currentDiv.createEl('span', { text: 'Current: ' });
|
||||
currentDiv.createEl('span', { text: this.currentEmoji, cls: 'immerse-emoji-current-icon' });
|
||||
}
|
||||
|
||||
// Search box
|
||||
const searchContainer = contentEl.createDiv({ cls: 'immerse-emoji-search' });
|
||||
const searchInput = searchContainer.createEl('input', {
|
||||
type: 'text',
|
||||
placeholder: 'Search emojis...',
|
||||
cls: 'immerse-emoji-search-input'
|
||||
});
|
||||
|
||||
// Emoji grid container
|
||||
const gridContainer = contentEl.createDiv({ cls: 'immerse-emoji-categories' });
|
||||
|
||||
// Render all categories
|
||||
const renderCategories = (filter: string = '') => {
|
||||
gridContainer.empty();
|
||||
|
||||
Object.entries(EMOJI_CATEGORIES).forEach(([category, emojis]) => {
|
||||
const filteredEmojis = filter
|
||||
? emojis.filter(emoji => {
|
||||
const keywords = EMOJI_KEYWORDS[emoji] || '';
|
||||
return keywords.toLowerCase().includes(filter) || emoji.includes(filter);
|
||||
})
|
||||
: emojis;
|
||||
|
||||
if (filteredEmojis.length === 0) return;
|
||||
|
||||
const categoryDiv = gridContainer.createDiv({ cls: 'immerse-emoji-category' });
|
||||
categoryDiv.createEl('h3', { text: category, cls: 'immerse-emoji-category-title' });
|
||||
|
||||
const grid = categoryDiv.createDiv({ cls: 'immerse-emoji-grid' });
|
||||
|
||||
filteredEmojis.forEach(emoji => {
|
||||
const button = grid.createEl('button', {
|
||||
text: emoji,
|
||||
cls: 'immerse-emoji-button'
|
||||
});
|
||||
|
||||
if (emoji === this.currentEmoji) {
|
||||
button.addClass('immerse-emoji-selected');
|
||||
}
|
||||
|
||||
button.addEventListener('click', () => {
|
||||
this.onSelect(emoji);
|
||||
this.close();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Initial render
|
||||
renderCategories();
|
||||
|
||||
// Search functionality
|
||||
searchInput.addEventListener('input', (e) => {
|
||||
const filter = (e.target as HTMLInputElement).value.toLowerCase();
|
||||
renderCategories(filter);
|
||||
});
|
||||
|
||||
// Custom emoji input
|
||||
const customDiv = contentEl.createDiv({ cls: 'immerse-emoji-custom' });
|
||||
customDiv.createEl('span', { text: 'Or enter custom emoji: ' });
|
||||
const customInput = customDiv.createEl('input', {
|
||||
type: 'text',
|
||||
placeholder: 'Paste emoji',
|
||||
cls: 'immerse-emoji-custom-input',
|
||||
});
|
||||
|
||||
const customBtn = customDiv.createEl('button', {
|
||||
text: 'Use Custom',
|
||||
cls: 'immerse-btn immerse-btn-primary'
|
||||
});
|
||||
|
||||
customBtn.addEventListener('click', () => {
|
||||
const customEmoji = customInput.value.trim();
|
||||
if (customEmoji) {
|
||||
this.onSelect(customEmoji);
|
||||
this.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onClose() {
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
}
|
||||
}
|
||||
|
||||
136
styles.css
136
styles.css
@@ -288,11 +288,16 @@
|
||||
}
|
||||
|
||||
.immerse-active-controls .immerse-btn {
|
||||
flex: 1;
|
||||
min-width: 80px;
|
||||
flex: 1 1 auto;
|
||||
min-width: 100px;
|
||||
max-width: 100%;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
color: white;
|
||||
border: none;
|
||||
white-space: normal;
|
||||
word-wrap: break-word;
|
||||
line-height: 1.3;
|
||||
padding: 8px 12px;
|
||||
}
|
||||
|
||||
.immerse-active-controls .immerse-btn:hover {
|
||||
@@ -1442,4 +1447,129 @@
|
||||
.immerse-report-section-title {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ============ Emoji Picker ============ */
|
||||
.immerse-emoji-picker {
|
||||
width: 85vw;
|
||||
max-width: 400px;
|
||||
max-height: 80vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.immerse-emoji-picker .modal-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.immerse-emoji-current {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
padding: 10px;
|
||||
background: var(--ft-bg-secondary);
|
||||
border-radius: var(--ft-radius-sm);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.immerse-emoji-current-icon {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.immerse-emoji-search {
|
||||
margin-bottom: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.immerse-emoji-search-input {
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
border-radius: var(--ft-radius-sm);
|
||||
border: 1px solid var(--ft-border);
|
||||
background: var(--ft-bg);
|
||||
color: var(--ft-text);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.immerse-emoji-categories {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
margin-bottom: 12px;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.immerse-emoji-category {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.immerse-emoji-category-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--ft-text-muted);
|
||||
margin-bottom: 8px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.immerse-emoji-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(32px, 1fr));
|
||||
gap: 4px;
|
||||
max-width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.immerse-emoji-button {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border: 1px solid var(--ft-border);
|
||||
background: var(--ft-bg);
|
||||
border-radius: 6px;
|
||||
font-size: 18px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.immerse-emoji-button:hover {
|
||||
background: var(--ft-bg-tertiary);
|
||||
transform: scale(1.1);
|
||||
border-color: var(--ft-primary);
|
||||
}
|
||||
|
||||
.immerse-emoji-button.immerse-emoji-selected {
|
||||
background: var(--ft-primary);
|
||||
border-color: var(--ft-primary);
|
||||
box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.3);
|
||||
}
|
||||
|
||||
.immerse-emoji-custom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding-top: 12px;
|
||||
border-top: 1px solid var(--ft-border);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.immerse-emoji-custom-input {
|
||||
flex: 1;
|
||||
padding: 8px 12px;
|
||||
border-radius: var(--ft-radius-sm);
|
||||
border: 1px solid var(--ft-border);
|
||||
background: var(--ft-bg);
|
||||
color: var(--ft-text);
|
||||
font-size: 18px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
{
|
||||
"1.0.4": "0.15.0",
|
||||
"1.0.5": "0.15.0",
|
||||
"1.0.6": "0.15.0",
|
||||
"1.0.7": "0.15.0",
|
||||
"1.0.8": "0.15.0",
|
||||
"1.0.9": "0.15.0"
|
||||
}
|
||||
"1.0.4": "0.15.0",
|
||||
"1.0.5": "0.15.0",
|
||||
"1.0.6": "0.15.0",
|
||||
"1.0.7": "0.15.0",
|
||||
"1.0.8": "0.15.0",
|
||||
"1.0.9": "0.15.0",
|
||||
"1.1.3": "0.15.0"
|
||||
}
|
||||
Reference in New Issue
Block a user