Fix: Unified hover icons overlay and dynamic font loading with previews
This commit is contained in:
parent
13c513b314
commit
40e565645a
@ -683,14 +683,20 @@ h3 {
|
||||
padding-top: 2px; /* Align with icons */
|
||||
}
|
||||
|
||||
/* Task Actions Visibility */
|
||||
.weekly-task-item .task-actions {
|
||||
/* Task Actions Visibility - Unified for Weekly and Time Grid */
|
||||
.weekly-task-item .task-actions,
|
||||
.time-slot-task .task-actions {
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease;
|
||||
pointer-events: none;
|
||||
transition: opacity 0.2s ease, visibility 0.2s;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.weekly-task-item:hover .task-actions {
|
||||
.weekly-task-item:hover .task-actions,
|
||||
.time-slot-task:hover .task-actions {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.weekly-task-text.completed {
|
||||
@ -784,6 +790,13 @@ h3 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
z-index: 10;
|
||||
padding-left: 8px;
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
.task-action-btn {
|
||||
@ -791,19 +804,24 @@ h3 {
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
padding: 2px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
color: var(--weekly-text-light);
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.15s;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.task-action-btn:hover {
|
||||
background-color: rgba(0,0,0,0.05);
|
||||
color: var(--weekly-text);
|
||||
background: rgba(0,0,0,0.08);
|
||||
}
|
||||
|
||||
.dark .task-action-btn:hover {
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* Specific button styles */
|
||||
@ -2061,29 +2079,7 @@ h3 {
|
||||
animation: slideInFromLeft 0.5s ease-out forwards;
|
||||
}
|
||||
|
||||
/* Fix 2: Task Hover Actions */
|
||||
.weekly-task-item,
|
||||
.time-slot-task {
|
||||
/* Ensure positioning context for absolute actions if needed, though flex is used */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.weekly-task-item .task-actions,
|
||||
.time-slot-task .task-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease;
|
||||
margin-left: auto;
|
||||
/* Push to far right */
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
.weekly-task-item:hover .task-actions,
|
||||
.time-slot-task:hover .task-actions {
|
||||
opacity: 1;
|
||||
}
|
||||
/* Consolidate Task Hover Actions - Removed redundant entries */
|
||||
|
||||
.task-action-btn {
|
||||
background: none;
|
||||
|
||||
@ -85,6 +85,8 @@ const AVAILABLE_FONTS = [
|
||||
{ name: 'Playfair Display', value: 'Playfair Display' },
|
||||
{ name: 'Merriweather', value: 'Merriweather' },
|
||||
{ name: 'Nunito', value: 'Nunito' },
|
||||
{ name: 'Dancing Script', value: 'Dancing Script' },
|
||||
{ name: 'Pacifico', value: 'Pacifico' },
|
||||
];
|
||||
|
||||
const FONT_WEIGHTS = [
|
||||
@ -94,6 +96,29 @@ const FONT_WEIGHTS = [
|
||||
{ name: 'Bold', value: '700' },
|
||||
];
|
||||
|
||||
// Helper to load Google Fonts
|
||||
const useGoogleFonts = (fonts: string[]) => {
|
||||
useEffect(() => {
|
||||
if (typeof window === 'undefined') return;
|
||||
const fontsToLoad = fonts.filter(f => f && f !== 'Inter');
|
||||
if (fontsToLoad.length === 0) return;
|
||||
|
||||
const linkId = 'google-fonts-link';
|
||||
let link = document.getElementById(linkId) as HTMLLinkElement;
|
||||
|
||||
const fontQuery = fontsToLoad.map(f => f.replace(' ', '+')).join('|');
|
||||
const href = `https://fonts.googleapis.com/css2?family=${fontsToLoad.map(f => `${f.replace(' ', '+')}:wght@300;400;500;700`).join('&family=')}&display=swap`;
|
||||
|
||||
if (!link) {
|
||||
link = document.createElement('link');
|
||||
link.id = linkId;
|
||||
link.rel = 'stylesheet';
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
link.href = href;
|
||||
}, [fonts]);
|
||||
};
|
||||
|
||||
// Translations
|
||||
const translations: Record<string, any> = {
|
||||
en: {
|
||||
@ -323,7 +348,8 @@ export default function WeeklyView() {
|
||||
const [somedayLists, setSomedayLists] = useState<SomedayList[]>([]);
|
||||
const [editingTaskId, setEditingTaskId] = useState<string | null>(null);
|
||||
const [showSettings, setShowSettings] = useState(false);
|
||||
const [showDatePicker, setShowDatePicker] = useState(false);
|
||||
const [showSummary, setShowSummary] = useState(false);
|
||||
|
||||
const [isAddingSomedayList, setIsAddingSomedayList] = useState(false);
|
||||
const [newSomedayListName, setNewSomedayListName] = useState('');
|
||||
const [language, setLanguage] = useState('de');
|
||||
@ -365,30 +391,10 @@ export default function WeeklyView() {
|
||||
const [bodyFont, setBodyFont] = useState('Inter');
|
||||
const [fontWeight, setFontWeight] = useState('400');
|
||||
|
||||
// Load Google Fonts
|
||||
useEffect(() => {
|
||||
const fontsToLoad = new Set([headlineFont, bodyFont]);
|
||||
fontsToLoad.delete('Inter'); // Inter is likely already loaded or default
|
||||
// Load fonts
|
||||
useGoogleFonts([headlineFont, bodyFont, 'Dancing Script', 'Pacifico']);
|
||||
|
||||
if (fontsToLoad.size === 0) return;
|
||||
|
||||
const linkId = 'google-fonts-dynamic';
|
||||
let link = document.getElementById(linkId) as HTMLLinkElement;
|
||||
|
||||
if (!link) {
|
||||
link = document.createElement('link');
|
||||
link.id = linkId;
|
||||
link.rel = 'stylesheet';
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
|
||||
// Simplification: Load all needed weights for selected fonts
|
||||
const families = Array.from(fontsToLoad).map(font =>
|
||||
`${font.replace(/\s+/g, '+')}:wght@300;400;500;700`
|
||||
).join('&');
|
||||
|
||||
link.href = `https://fonts.googleapis.com/css2?family=${families}&display=swap`;
|
||||
}, [headlineFont, bodyFont]);
|
||||
// Dynamic font loading is handled by useGoogleFonts hook call above
|
||||
|
||||
// Calendar Event Modal State
|
||||
const [calendarEventModal, setCalendarEventModal] = useState<{
|
||||
@ -3021,7 +3027,7 @@ function TaskItem({ task, isEditing, onToggle, onEdit, onUpdate, onDelete, onNot
|
||||
{task.title}
|
||||
</span>
|
||||
|
||||
<div className="task-actions absolute right-0 top-0 bottom-0 flex items-center bg-white/95 dark:bg-gray-800/95 pl-2 pr-1 shadow-[-8px_0_8px_-4px_rgba(255,255,255,0.95)] dark:shadow-[-8px_0_8px_-4px_rgba(31,41,55,0.95)]">
|
||||
<div className="task-actions absolute right-0 top-0 bottom-0 flex items-center bg-white/95 dark:bg-gray-800/95 pl-2 pr-1 shadow-[-12px_0_12px_-4px_rgba(255,255,255,0.95)] dark:shadow-[-12px_0_12px_-4px_rgba(31,41,55,0.95)] z-20">
|
||||
{/* Edit */}
|
||||
<button className="task-action-btn" onClick={(e) => { e.stopPropagation(); onEdit(); }} title="Edit">
|
||||
<svg viewBox="0 0 24 24" width="12" height="12" stroke="currentColor" strokeWidth="2.5" fill="none" strokeLinecap="round" strokeLinejoin="round"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path></svg>
|
||||
@ -3349,6 +3355,9 @@ function SettingsSidebar({
|
||||
|
||||
const t = translations[profile.language || 'en'] || translations['en'];
|
||||
|
||||
// Load fonts for preview
|
||||
useGoogleFonts([profile.headlineFont || '', profile.bodyFont || '']);
|
||||
|
||||
useEffect(() => {
|
||||
fetchProfile();
|
||||
// Trigger slide-in after mount
|
||||
@ -3846,10 +3855,10 @@ function SettingsSidebar({
|
||||
value={profile.headlineFont || 'Inter'}
|
||||
onChange={(e) => setProfile({ ...profile, headlineFont: e.target.value })}
|
||||
className="weekly-input"
|
||||
style={{ width: '100%', padding: '8px', border: '1px solid #ddd', borderRadius: '4px' }}
|
||||
style={{ width: '100%', padding: '8px', border: '1px solid #ddd', borderRadius: '4px', fontFamily: profile.headlineFont || 'Inter' }}
|
||||
>
|
||||
{AVAILABLE_FONTS.map(font => (
|
||||
<option key={font.value} value={font.value}>{font.name}</option>
|
||||
<option key={font.value} value={font.value} style={{ fontFamily: font.value }}>{font.name}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
@ -3861,10 +3870,10 @@ function SettingsSidebar({
|
||||
value={profile.bodyFont || 'Inter'}
|
||||
onChange={(e) => setProfile({ ...profile, bodyFont: e.target.value })}
|
||||
className="weekly-input"
|
||||
style={{ width: '100%', padding: '8px', border: '1px solid #ddd', borderRadius: '4px' }}
|
||||
style={{ width: '100%', padding: '8px', border: '1px solid #ddd', borderRadius: '4px', fontFamily: profile.bodyFont || 'Inter' }}
|
||||
>
|
||||
{AVAILABLE_FONTS.map(font => (
|
||||
<option key={font.value} value={font.value}>{font.name}</option>
|
||||
<option key={font.value} value={font.value} style={{ fontFamily: font.value }}>{font.name}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user