@glatam/calendar-ui 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/components/calendar-modal.d.ts +24 -0
  2. package/dist/components/calendar-modal.d.ts.map +1 -0
  3. package/dist/glatam-calendar-mini.d.ts +38 -0
  4. package/dist/glatam-calendar-mini.d.ts.map +1 -0
  5. package/dist/glatam-calendar.cjs +836 -0
  6. package/dist/glatam-calendar.d.ts +58 -0
  7. package/dist/glatam-calendar.d.ts.map +1 -0
  8. package/dist/glatam-calendar.js +1541 -0
  9. package/{src/index.ts → dist/index.d.ts} +1 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/styles/calendar-modal.css.d.ts +2 -0
  12. package/dist/styles/calendar-modal.css.d.ts.map +1 -0
  13. package/dist/styles/calendar.css.d.ts +2 -0
  14. package/dist/styles/calendar.css.d.ts.map +1 -0
  15. package/dist/styles/variables.css.d.ts +2 -0
  16. package/dist/styles/variables.css.d.ts.map +1 -0
  17. package/dist/utils/timezone-utils.d.ts +16 -0
  18. package/dist/utils/timezone-utils.d.ts.map +1 -0
  19. package/dist/views/day-view.d.ts +27 -0
  20. package/dist/views/day-view.d.ts.map +1 -0
  21. package/dist/views/month-view.d.ts +23 -0
  22. package/dist/views/month-view.d.ts.map +1 -0
  23. package/dist/views/week-view.d.ts +28 -0
  24. package/dist/views/week-view.d.ts.map +1 -0
  25. package/package.json +6 -2
  26. package/src/components/calendar-modal.ts +0 -163
  27. package/src/glatam-calendar-mini.ts +0 -147
  28. package/src/glatam-calendar.ts +0 -194
  29. package/src/styles/calendar-modal.css.ts +0 -158
  30. package/src/styles/calendar.css.ts +0 -259
  31. package/src/styles/variables.css.ts +0 -91
  32. package/src/utils/timezone-utils.ts +0 -87
  33. package/src/views/day-view.ts +0 -130
  34. package/src/views/month-view.ts +0 -117
  35. package/src/views/week-view.ts +0 -158
  36. package/tsconfig.json +0 -8
  37. package/vite.config.ts +0 -35
@@ -1,194 +0,0 @@
1
- import { LitElement, html } from 'lit';
2
- import { customElement, property, state } from 'lit/decorators.js';
3
- import { generateMonthDays, generateWeekDays, formatISODate, isTimeBlocked, BlockingRule, TimeSlot } from '@glatam/calendar-core';
4
- import { variablesStyles } from './styles/variables.css.js';
5
- import { calendarStyles } from './styles/calendar.css.js';
6
- import { getTimezoneOffsetDiff, shiftSlot } from './utils/timezone-utils.js';
7
-
8
- import './views/month-view.js';
9
- import './views/week-view.js';
10
- import './views/day-view.js';
11
- import './components/calendar-modal.js';
12
-
13
- const DEFAULT_SLOTS: TimeSlot[] = [
14
- { start: '09:00', end: '10:00' }, { start: '10:00', end: '11:00' },
15
- { start: '11:00', end: '12:00' }, { start: '12:00', end: '13:00' },
16
- { start: '13:00', end: '14:00' }, { start: '14:00', end: '15:00' },
17
- { start: '15:00', end: '16:00' }, { start: '16:00', end: '17:00' },
18
- { start: '17:00', end: '18:00' },
19
- ];
20
-
21
- @customElement('glatam-calendar')
22
- export class GlatamCalendar extends LitElement {
23
- static styles = [variablesStyles, calendarStyles];
24
-
25
- @property({ type: String }) role = 'provider'; @property({ type: String, reflect: true }) size = 'medium';
26
- @property({ type: String }) view: 'month' | 'week' | 'day' = 'month'; @property({ type: String }) locale = 'es';
27
- @property({ type: Number }) startOfWeekDay = 0; @property({ type: Array }) rules: BlockingRule[] = [];
28
- @property({ type: Array }) selectedDates: string[] = []; @property({ type: Object }) selectedRange: { dateString: string; start: string; end: string } | null = null;
29
- @property({ type: String }) hostTimezone = 'America/Bogota'; @property({ type: String }) activeTimezone = 'local';
30
- @property({ type: Array }) slots: TimeSlot[] = DEFAULT_SLOTS; @property({ type: String }) minDate = ''; @property({ type: String }) maxDate = '';
31
- @property({ type: Boolean }) showNeighboringMonth = true; @property({ attribute: false }) tileClassName: ((data: { date: Date; dateString: string }) => string) | null = null;
32
-
33
- @state() private activeDate = new Date(); @state() private localRules: BlockingRule[] = [];
34
- @state() private darkMode = false; @state() private modalOpen = false;
35
- @state() private modalDateString = ''; @state() private modalStartTime = ''; @state() private modalEndTime = '';
36
- @state() private modalIsRange = false; @state() private modalExistingRule: BlockingRule | null = null;
37
-
38
- firstUpdated() { this.darkMode = window.matchMedia('(prefers-color-scheme: dark)').matches; this.localRules = [...this.rules]; }
39
- willUpdate(changedProps: Map<string, any>) { if (changedProps.has('rules') && this.rules.length > 0 && this.localRules.length === 0) this.localRules = [...this.rules]; }
40
- updated(changedProps: Map<string, any>) { if (changedProps.has('darkMode')) this.classList.toggle('dark-mode', this.darkMode); }
41
-
42
- private handlePrev() {
43
- const d = new Date(this.activeDate);
44
- this.view === 'month' ? d.setMonth(d.getMonth() - 1) : this.view === 'week' ? d.setDate(d.getDate() - 7) : d.setDate(d.getDate() - 1);
45
- this.activeDate = d;
46
- }
47
-
48
- private handleNext() {
49
- const d = new Date(this.activeDate);
50
- this.view === 'month' ? d.setMonth(d.getMonth() + 1) : this.view === 'week' ? d.setDate(d.getDate() + 7) : d.setDate(d.getDate() + 1);
51
- this.activeDate = d;
52
- }
53
-
54
- private getHeaderTitle(): string {
55
- const opt: Intl.DateTimeFormatOptions = this.view === 'month' ? { month: 'long', year: 'numeric' } : this.view === 'week' ? { month: 'short', year: 'numeric' } : { day: 'numeric', month: 'long', year: 'numeric' };
56
- return new Intl.DateTimeFormat(this.locale, opt).format(this.activeDate);
57
- }
58
-
59
- private handleDaySelect(e: CustomEvent<{ dateString: string; isBlocked: boolean }>) {
60
- const { dateString, isBlocked } = e.detail;
61
- if (this.role === 'buyer' && isBlocked) return;
62
- this.activeDate = new Date(dateString + 'T00:00:00');
63
- this.view = 'day';
64
- this.dispatchEvent(new CustomEvent('date-selected', { detail: { dateString }, bubbles: true, composed: true }));
65
- }
66
-
67
- private handleRangeSelect(e: CustomEvent<{ dateString: string; start: string; end: string }>) {
68
- const { dateString, start, end } = e.detail, offset = this.activeTimezone === 'local' ? getTimezoneOffsetDiff(this.activeDate, this.hostTimezone, 'local') : 0;
69
- const todayStr = new Date().toISOString().split('T')[0];
70
- const limitMinDate = this.minDate || (this.role === 'buyer' ? todayStr : '');
71
- if (this.role === 'buyer' && limitMinDate && dateString < limitMinDate) return;
72
-
73
- const displaySlots = this.getDisplaySlots(offset), startIdx = displaySlots.findIndex(s => s.start === start), endIdx = displaySlots.findIndex(s => s.end === end);
74
- const hostStart = this.slots[startIdx]?.start || start, hostEnd = this.slots[endIdx]?.end || end;
75
- if (this.role === 'buyer') {
76
- this.selectedRange = { dateString, start, end };
77
- this.dispatchEvent(new CustomEvent('booking-selected', { detail: { dateString, start, end, hostStart, hostEnd }, bubbles: true, composed: true }));
78
- return;
79
- }
80
- this.openModal(dateString, hostStart, hostEnd, true, null);
81
- }
82
-
83
- private handleSlotClick(e: CustomEvent<{ dateString: string; slot: TimeSlot & { isBlocked?: boolean } }>) {
84
- const { dateString, slot } = e.detail, date = new Date(dateString + 'T00:00:00'), offset = this.activeTimezone === 'local' ? getTimezoneOffsetDiff(this.activeDate, this.hostTimezone, 'local') : 0;
85
- const todayStr = new Date().toISOString().split('T')[0];
86
- const limitMinDate = this.minDate || (this.role === 'buyer' ? todayStr : '');
87
- if (this.role === 'buyer' && (slot.isBlocked || (limitMinDate && dateString < limitMinDate))) return;
88
-
89
- const displaySlots = this.getDisplaySlots(offset), idx = displaySlots.findIndex(s => s.start === slot.start), hostSlot = this.slots[idx] || slot;
90
- if (this.role === 'buyer') {
91
- this.selectedRange = { dateString, start: slot.start, end: slot.end };
92
- this.dispatchEvent(new CustomEvent('booking-selected', { detail: { dateString, start: slot.start, end: slot.end, hostStart: hostSlot.start, hostEnd: hostSlot.end }, bubbles: true, composed: true }));
93
- return;
94
- }
95
- const rule = this.localRules.find(r => isTimeBlocked(date, hostSlot, [r]));
96
- this.openModal(dateString, hostSlot.start, hostSlot.end, true, rule || null);
97
- }
98
-
99
- private handleBlockDayAction() {
100
- const dateStr = formatISODate(this.activeDate), rule = this.localRules.find(r => isTimeBlocked(this.activeDate, undefined, [r]));
101
- this.openModal(dateStr, '', '', false, rule || null);
102
- }
103
-
104
- private openModal(date: string, start: string, end: string, isRange: boolean, rule: BlockingRule | null) {
105
- this.modalDateString = date; this.modalStartTime = start; this.modalEndTime = end; this.modalIsRange = isRange; this.modalExistingRule = rule; this.modalOpen = true;
106
- }
107
-
108
- private handleSaveRule(e: CustomEvent) {
109
- const data = e.detail, ruleId = this.modalExistingRule ? this.modalExistingRule.id : `rule-${Date.now()}`;
110
- const newRule: BlockingRule = {
111
- id: ruleId, type: data.isRecurring ? 'weekly' : 'date-range',
112
- slots: data.blockAllDay ? undefined : [{ start: data.startTime, end: data.endTime }],
113
- daysOfWeek: data.isRecurring ? data.selectedDays : undefined,
114
- startDate: data.isRecurring ? undefined : data.dateString,
115
- endDate: data.isRecurring ? undefined : data.dateString,
116
- description: data.title
117
- };
118
- this.localRules = this.modalExistingRule ? this.localRules.map(r => r.id === ruleId ? newRule : r) : [...this.localRules, newRule];
119
- this.modalOpen = false;
120
- this.dispatchEvent(new CustomEvent('rules-changed', { detail: { rules: this.localRules }, bubbles: true, composed: true }));
121
- }
122
-
123
- private handleDeleteRule(e: CustomEvent<{ id: string }>) {
124
- this.localRules = this.localRules.filter(r => r.id !== e.detail.id);
125
- this.modalOpen = false;
126
- this.dispatchEvent(new CustomEvent('rules-changed', { detail: { rules: this.localRules }, bubbles: true, composed: true }));
127
- }
128
-
129
- private getDisplaySlots(offset: number): TimeSlot[] {
130
- if (offset === 0) return this.slots;
131
- return this.slots.map(s => {
132
- const shifted = shiftSlot(s, offset);
133
- const suffix = shifted.dayShift > 0 ? ' (+1d)' : shifted.dayShift < 0 ? ' (-1d)' : '';
134
- return { start: shifted.start + suffix, end: shifted.end + suffix };
135
- });
136
- }
137
-
138
- render() {
139
- const y = this.activeDate.getFullYear(), m = this.activeDate.getMonth(), isCurrentDayBlocked = isTimeBlocked(this.activeDate, undefined, this.localRules);
140
- const offset = this.activeTimezone === 'local' ? getTimezoneOffsetDiff(this.activeDate, this.hostTimezone, 'local') : 0, displaySlots = this.getDisplaySlots(offset);
141
- const mapDays = (days: any[]) => days.map(d => ({ ...d, slots: d.slots.map((s: any, idx: number) => ({ ...s, start: displaySlots[idx]?.start || s.start, end: displaySlots[idx]?.end || s.end })) }));
142
- const tzCity = this.hostTimezone.split('/').pop()?.replace('_', ' ') || 'Anfitrión';
143
-
144
- return html`
145
- <div class="calendar-header">
146
- <div class="nav-group">
147
- <button class="btn" @click=${() => this.activeDate = new Date()}>Hoy</button>
148
- <button class="btn" @click=${this.handlePrev}>&lt;</button>
149
- <button class="btn" @click=${this.handleNext}>&gt;</button>
150
- <span class="nav-title" style="text-transform: capitalize;">${this.getHeaderTitle()}</span>
151
- </div>
152
-
153
- <div class="view-group">
154
- ${this.role === 'provider' ? html`
155
- <div class="timezone-badge">
156
- 🌐 Zona:
157
- <select class="timezone-select" @change=${(e: any) => this.activeTimezone = e.target.value}>
158
- <option value="local" ?selected=${this.activeTimezone === 'local'}>Mi Hora</option>
159
- <option value="host" ?selected=${this.activeTimezone === 'host'}>Hora ${tzCity}</option>
160
- </select>
161
- </div>
162
- ` : ''}
163
- ${this.role === 'provider' && this.view === 'day'
164
- ? html`<button class="btn btn-primary" @click=${this.handleBlockDayAction} style="margin-right: 8px;">${isCurrentDayBlocked ? 'Liberar Día' : 'Bloquear Día'}</button>`
165
- : ''}
166
- <button class="btn" @click=${() => this.darkMode = !this.darkMode} style="margin-right: 8px;">${this.darkMode ? '☀️' : '🌙'}</button>
167
- <div class="btn-group">
168
- <button class="btn ${this.view === 'month' ? 'active' : ''}" @click=${() => this.view = 'month'}>Mes</button>
169
- <button class="btn ${this.view === 'week' ? 'active' : ''}" @click=${() => this.view = 'week'}>Semana</button>
170
- <button class="btn ${this.view === 'day' ? 'active' : ''}" @click=${() => this.view = 'day'}>Día</button>
171
- </div>
172
- </div>
173
- </div>
174
-
175
- <div class="calendar-body">
176
- ${this.view === 'month'
177
- ? html`<glatam-calendar-month-view .days=${generateMonthDays(y, m, this.localRules, this.slots, this.startOfWeekDay)} .locale=${this.locale} .startOfWeekDay=${this.startOfWeekDay} .role=${this.role} .size=${this.size} .minDate=${this.minDate || (this.role === 'buyer' ? new Date().toISOString().split('T')[0] : '')} .maxDate=${this.maxDate} .showNeighboringMonth=${this.showNeighboringMonth} .tileClassName=${this.tileClassName} @day-select=${this.handleDaySelect}></glatam-calendar-month-view>`
178
- : this.view === 'week'
179
- ? html`<glatam-calendar-week-view .days=${mapDays(generateWeekDays(this.activeDate, this.localRules, this.slots, this.startOfWeekDay))} .slots=${displaySlots} .locale=${this.locale} .selectedRange=${this.selectedRange} .role=${this.role} @range-select=${this.handleRangeSelect} @slot-click=${this.handleSlotClick}></glatam-calendar-week-view>`
180
- : html`<glatam-calendar-day-view .day=${mapDays(generateWeekDays(this.activeDate, this.localRules, this.slots, this.startOfWeekDay)).find(d => d.dateString === formatISODate(this.activeDate)) || null} .slots=${displaySlots} .locale=${this.locale} .selectedRange=${this.selectedRange} .role=${this.role} @range-select=${this.handleRangeSelect} @slot-click=${this.handleSlotClick}></glatam-calendar-day-view>`}
181
- </div>
182
-
183
- <glatam-calendar-modal
184
- .open=${this.modalOpen} .dateString=${this.modalDateString} .startTime=${this.modalStartTime} .endTime=${this.modalEndTime}
185
- .isRange=${this.modalIsRange} .existingRule=${this.modalExistingRule} @save-rule=${this.handleSaveRule}
186
- @delete-rule=${this.handleDeleteRule} @close=${() => this.modalOpen = false}
187
- ></glatam-calendar-modal>
188
- `;
189
- }
190
- }
191
-
192
- declare global {
193
- interface HTMLElementTagNameMap { 'glatam-calendar': GlatamCalendar; }
194
- }
@@ -1,158 +0,0 @@
1
- import { css } from 'lit';
2
-
3
- export const modalStyles = css`
4
- dialog {
5
- background: transparent;
6
- border: none;
7
- padding: 0;
8
- overflow: visible;
9
- outline: none;
10
- max-width: 100vw;
11
- max-height: 100vh;
12
- }
13
- dialog::backdrop {
14
- background: rgba(0, 0, 0, 0.35);
15
- backdrop-filter: blur(10px);
16
- -webkit-backdrop-filter: blur(10px);
17
- }
18
- .modal-content {
19
- background: var(--glatam-bg);
20
- color: var(--glatam-text);
21
- border-radius: 24px;
22
- padding: 28px;
23
- width: 90vw;
24
- max-width: 400px;
25
- box-shadow: 0 20px 50px rgba(0, 0, 0, 0.12);
26
- border: 1px solid var(--glatam-border);
27
- display: flex;
28
- flex-direction: column;
29
- gap: 18px;
30
- box-sizing: border-box;
31
- animation: zoomIn 0.3s cubic-bezier(0.16, 1, 0.3, 1) forwards;
32
- }
33
- @keyframes zoomIn {
34
- from {
35
- transform: scale(0.92) translateY(10px);
36
- opacity: 0;
37
- }
38
- to {
39
- transform: scale(1) translateY(0);
40
- opacity: 1;
41
- }
42
- }
43
- h3 { margin: 0; font-size: 1.3rem; font-weight: 700; letter-spacing: -0.02em; }
44
- .form-group { display: flex; flex-direction: column; gap: 6px; }
45
- label { font-size: 0.8rem; color: var(--glatam-text-secondary); font-weight: 600; }
46
- input[type="text"] {
47
- background: var(--glatam-surface);
48
- border: 1px solid var(--glatam-border);
49
- border-radius: 10px;
50
- padding: 10px 14px;
51
- color: var(--glatam-text);
52
- font-family: inherit;
53
- font-size: 0.9rem;
54
- outline: none;
55
- transition: border-color var(--glatam-transition-fast);
56
- }
57
- input[type="text"]:focus {
58
- border-color: var(--glatam-primary);
59
- }
60
- .switch-row {
61
- display: flex;
62
- justify-content: space-between;
63
- align-items: center;
64
- padding: 4px 0;
65
- }
66
-
67
- /* Apple Switch Style */
68
- .switch {
69
- position: relative;
70
- display: inline-block;
71
- width: 46px;
72
- height: 26px;
73
- }
74
- .switch input { opacity: 0; width: 0; height: 0; }
75
- .slider {
76
- position: absolute;
77
- cursor: pointer;
78
- top: 0; left: 0; right: 0; bottom: 0;
79
- background-color: var(--glatam-border);
80
- transition: .25s cubic-bezier(0.16, 1, 0.3, 1);
81
- border-radius: 26px;
82
- }
83
- .slider:before {
84
- position: absolute;
85
- content: "";
86
- height: 20px;
87
- width: 20px;
88
- left: 3px;
89
- bottom: 3px;
90
- background-color: white;
91
- transition: .25s cubic-bezier(0.16, 1, 0.3, 1);
92
- border-radius: 50%;
93
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
94
- }
95
- input:checked + .slider {
96
- background-color: var(--glatam-primary);
97
- }
98
- input:checked + .slider:before {
99
- transform: translateX(20px);
100
- }
101
-
102
- .days-grid {
103
- display: grid;
104
- grid-template-columns: repeat(7, 1fr);
105
- gap: 6px;
106
- margin-top: 4px;
107
- }
108
- .day-btn {
109
- width: 36px;
110
- height: 36px;
111
- margin: 0 auto;
112
- border-radius: 50%;
113
- border: 1px solid var(--glatam-border);
114
- background: var(--glatam-bg);
115
- color: var(--glatam-text);
116
- font-size: 0.8rem;
117
- font-weight: 600;
118
- cursor: pointer;
119
- display: flex;
120
- align-items: center;
121
- justify-content: center;
122
- transition: background-color var(--glatam-transition-fast), color var(--glatam-transition-fast), border-color var(--glatam-transition-fast);
123
- }
124
- .day-btn:hover {
125
- background-color: var(--glatam-surface);
126
- }
127
- .day-btn.selected {
128
- background: var(--glatam-primary);
129
- color: var(--glatam-text-light);
130
- border-color: var(--glatam-primary);
131
- }
132
- .btn-actions { display: flex; gap: 10px; margin-top: 10px; justify-content: flex-end; }
133
- .btn {
134
- padding: 10px 18px;
135
- border-radius: 20px;
136
- font-size: 0.875rem;
137
- font-weight: 600;
138
- cursor: pointer;
139
- border: none;
140
- transition: opacity var(--glatam-transition-fast), transform var(--glatam-transition-fast);
141
- display: inline-flex;
142
- align-items: center;
143
- justify-content: center;
144
- }
145
- .btn:active { transform: scale(0.97); }
146
- .btn-cancel { background: transparent; color: var(--glatam-text); border: 1px solid var(--glatam-border); }
147
- .btn-cancel:hover { background-color: var(--glatam-surface); }
148
- .btn-save { background: var(--glatam-primary); color: var(--glatam-text-light); }
149
- .btn-save:hover { opacity: 0.95; }
150
- .btn-danger {
151
- background: rgba(255, 69, 58, 0.12);
152
- color: #ff453a;
153
- margin-right: auto;
154
- }
155
- .btn-danger:hover {
156
- background: rgba(255, 69, 58, 0.18);
157
- }
158
- `;
@@ -1,259 +0,0 @@
1
- import { css } from 'lit';
2
-
3
- export const calendarStyles = css`
4
- :host {
5
- display: grid;
6
- min-width: 0;
7
- font-family: var(--glatam-font-family);
8
- color: var(--glatam-text);
9
- background-color: var(--glatam-bg);
10
- border-radius: var(--glatam-border-radius);
11
- padding: var(--glatam-padding);
12
- box-shadow: 0 4px 25px rgba(0, 0, 0, 0.05);
13
- border: 1px solid var(--glatam-border);
14
- box-sizing: border-box;
15
- width: 100%;
16
- max-width: 100%;
17
- overflow: hidden;
18
- transition: background-color var(--glatam-transition-normal), border-color var(--glatam-transition-normal);
19
- }
20
-
21
- *, *::before, *::after {
22
- box-sizing: border-box;
23
- }
24
-
25
- .calendar-header {
26
- display: flex;
27
- justify-content: space-between;
28
- align-items: center;
29
- margin-bottom: var(--glatam-padding);
30
- flex-wrap: wrap;
31
- gap: 12px;
32
- }
33
-
34
- .nav-group, .view-group {
35
- display: flex;
36
- align-items: center;
37
- gap: 8px;
38
- }
39
-
40
- .nav-title {
41
- font-size: 1.25rem;
42
- font-weight: 600;
43
- min-width: 140px;
44
- text-align: center;
45
- letter-spacing: -0.01em;
46
- }
47
-
48
- .btn {
49
- font-family: inherit;
50
- font-size: 0.875rem;
51
- font-weight: 500;
52
- padding: 8px 12px;
53
- border-radius: 8px;
54
- border: 1px solid var(--glatam-border);
55
- background-color: var(--glatam-bg);
56
- color: var(--glatam-text);
57
- cursor: pointer;
58
- transition: background-color var(--glatam-transition-fast), border-color var(--glatam-transition-fast), transform var(--glatam-transition-fast);
59
- display: inline-flex;
60
- align-items: center;
61
- justify-content: center;
62
- min-width: 36px;
63
- height: 36px;
64
- }
65
-
66
- .btn:hover:not(:disabled) {
67
- background-color: var(--glatam-surface);
68
- border-color: var(--glatam-text-secondary);
69
- }
70
-
71
- .btn:active:not(:disabled) {
72
- transform: scale(0.97);
73
- }
74
-
75
- .btn:disabled {
76
- opacity: 0.5;
77
- cursor: not-allowed;
78
- }
79
-
80
- .btn-primary {
81
- background-color: var(--glatam-primary);
82
- color: var(--glatam-text-light);
83
- border: none;
84
- }
85
-
86
- .btn-primary:hover:not(:disabled) {
87
- background-color: var(--glatam-primary-hover);
88
- }
89
-
90
- .btn-group {
91
- display: flex;
92
- border-radius: 8px;
93
- overflow: hidden;
94
- border: 1px solid var(--glatam-border);
95
- }
96
-
97
- .btn-group .btn {
98
- border-radius: 0;
99
- border: none;
100
- border-right: 1px solid var(--glatam-border);
101
- }
102
-
103
- .btn-group .btn:last-child {
104
- border-right: none;
105
- }
106
-
107
- .btn-group .btn.active {
108
- background-color: var(--glatam-primary-light);
109
- color: var(--glatam-primary);
110
- font-weight: 600;
111
- }
112
-
113
- /* Timezone Selector Styles */
114
- .timezone-badge {
115
- font-size: 0.75rem;
116
- padding: 4px 8px;
117
- background: var(--glatam-surface);
118
- border: 1px solid var(--glatam-border);
119
- border-radius: 20px;
120
- display: inline-flex;
121
- align-items: center;
122
- gap: 4px;
123
- color: var(--glatam-text-secondary);
124
- }
125
-
126
- .timezone-select {
127
- background: transparent;
128
- border: none;
129
- color: var(--glatam-text);
130
- font-family: inherit;
131
- font-size: 0.75rem;
132
- font-weight: 600;
133
- cursor: pointer;
134
- outline: none;
135
- padding-right: 4px;
136
- }
137
-
138
- /* Mini Popover Variant Styles */
139
- .dropdown-container {
140
- position: relative;
141
- display: inline-block;
142
- width: 100%;
143
- }
144
-
145
- .dropdown-toggle {
146
- width: 100%;
147
- justify-content: space-between;
148
- padding: 12px 16px;
149
- border-radius: 12px;
150
- font-weight: 600;
151
- height: 48px;
152
- }
153
-
154
- .dropdown-card {
155
- position: absolute;
156
- top: calc(100% + 8px);
157
- left: 0;
158
- width: 320px;
159
- background: var(--glatam-bg);
160
- border-radius: 16px;
161
- border: 1px solid var(--glatam-border);
162
- box-shadow: 0 12px 40px rgba(0, 0, 0, 0.1);
163
- z-index: 100;
164
- padding: 16px;
165
- display: flex;
166
- flex-direction: column;
167
- gap: 12px;
168
- animation: fadeInUp 0.3s cubic-bezier(0.16, 1, 0.3, 1) forwards;
169
- }
170
-
171
- .slot-list {
172
- display: flex;
173
- flex-direction: column;
174
- gap: 8px;
175
- max-height: 220px;
176
- overflow-y: auto;
177
- padding-right: 4px;
178
- }
179
-
180
- .slot-btn {
181
- width: 100%;
182
- padding: 10px;
183
- border-radius: 8px;
184
- border: 1px solid var(--glatam-border);
185
- background: var(--glatam-bg);
186
- color: var(--glatam-text);
187
- cursor: pointer;
188
- font-family: inherit;
189
- font-size: 0.85rem;
190
- font-weight: 500;
191
- text-align: center;
192
- transition: background-color var(--glatam-transition-fast);
193
- }
194
-
195
- .slot-btn:hover:not(.blocked) {
196
- background-color: var(--glatam-surface);
197
- border-color: var(--glatam-text-secondary);
198
- }
199
-
200
- .slot-btn.blocked {
201
- background-color: var(--glatam-surface);
202
- color: var(--glatam-blocked-text);
203
- text-decoration: line-through;
204
- cursor: not-allowed;
205
- border-color: var(--glatam-border);
206
- opacity: 0.6;
207
- }
208
-
209
- /* Smooth Apple Animation */
210
- .calendar-body {
211
- position: relative;
212
- width: 100%;
213
- overflow-x: auto;
214
- animation: fadeInUp 0.4s cubic-bezier(0.16, 1, 0.3, 1) forwards;
215
- }
216
-
217
- @keyframes fadeInUp {
218
- from {
219
- opacity: 0;
220
- transform: translateY(8px) scale(0.995);
221
- }
222
- to {
223
- opacity: 1;
224
- transform: translateY(0) scale(1);
225
- }
226
- }
227
-
228
- @media (max-width: 600px) {
229
- :host {
230
- padding: 8px;
231
- }
232
- .calendar-header {
233
- flex-direction: column;
234
- align-items: stretch;
235
- gap: 10px;
236
- }
237
- .nav-group, .view-group {
238
- width: 100%;
239
- justify-content: space-between;
240
- flex-wrap: wrap;
241
- gap: 6px;
242
- }
243
- .nav-title {
244
- flex: 1;
245
- font-size: 1.1rem;
246
- min-width: unset;
247
- text-align: right;
248
- white-space: nowrap;
249
- overflow: hidden;
250
- text-overflow: ellipsis;
251
- }
252
- .btn {
253
- font-size: 0.8rem;
254
- padding: 6px 10px;
255
- height: 32px;
256
- min-width: 32px;
257
- }
258
- }
259
- `;
@@ -1,91 +0,0 @@
1
- import { css } from 'lit';
2
-
3
- export const variablesStyles = css`
4
- :host {
5
- /* Fonts */
6
- --glatam-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
7
-
8
- /* Colors - Premium Apple Light Theme */
9
- --glatam-primary: #5856d6;
10
- --glatam-primary-hover: #4745b4;
11
- --glatam-primary-light: rgba(88, 86, 214, 0.1);
12
- --glatam-primary-light-hover: rgba(88, 86, 214, 0.25);
13
-
14
- --glatam-bg: #ffffff;
15
- --glatam-surface: #f5f5f7;
16
- --glatam-border: #e5e5ea;
17
- --glatam-text: #1d1d1f;
18
- --glatam-text-secondary: #86868b;
19
- --glatam-text-light: #ffffff;
20
-
21
- /* Blocked/Unavailable states */
22
- --glatam-blocked-bg: #fcfcfd;
23
- --glatam-blocked-stripe: #f2f2f7;
24
- --glatam-blocked-text: #aeaeae;
25
- --glatam-blocked-border: #e5e5ea;
26
-
27
- /* Selection Colors */
28
- --glatam-selection-bg: rgba(88, 86, 214, 0.15);
29
- --glatam-selection-border: #5856d6;
30
-
31
- /* Today highlighting */
32
- --glatam-today-text: #5856d6;
33
- --glatam-today-bg: rgba(88, 86, 214, 0.08);
34
-
35
- /* Dimensions & Layout */
36
- --glatam-border-radius: 12px;
37
- --glatam-padding: 16px;
38
- --glatam-grid-border-radius: 8px;
39
- --glatam-day-min-height: 72px;
40
- --glatam-time-col-width: 60px;
41
- --glatam-slot-height: 48px;
42
-
43
- /* Animation duration */
44
- --glatam-transition-fast: 0.15s ease;
45
- --glatam-transition-normal: 0.25s ease;
46
- }
47
-
48
- :host(.dark-mode) {
49
- /* Colors - Premium Apple Dark Theme */
50
- --glatam-primary: #5e5ce6;
51
- --glatam-primary-hover: #7d7aff;
52
- --glatam-primary-light: rgba(94, 92, 230, 0.15);
53
- --glatam-primary-light-hover: rgba(94, 92, 230, 0.3);
54
-
55
- --glatam-bg: #1c1c1e;
56
- --glatam-surface: #2c2c2e;
57
- --glatam-border: #38383a;
58
- --glatam-text: #f5f5f7;
59
- --glatam-text-secondary: #8e8e93;
60
-
61
- /* Blocked/Unavailable states */
62
- --glatam-blocked-bg: #242426;
63
- --glatam-blocked-stripe: #2c2c2e;
64
- --glatam-blocked-text: #707074;
65
- --glatam-blocked-border: #38383a;
66
-
67
- /* Selection Colors */
68
- --glatam-selection-bg: rgba(94, 92, 230, 0.25);
69
- --glatam-selection-border: #5e5ce6;
70
-
71
- /* Today highlighting */
72
- --glatam-today-text: #7d7aff;
73
- --glatam-today-bg: rgba(94, 92, 230, 0.12);
74
- }
75
-
76
- :host([size="small"]) {
77
- --glatam-day-min-height: 48px;
78
- --glatam-slot-height: 36px;
79
- --glatam-time-col-width: 48px;
80
- --glatam-padding: 10px;
81
- font-size: 0.8rem;
82
- }
83
-
84
- :host([size="large"]) {
85
- --glatam-day-min-height: 96px;
86
- --glatam-slot-height: 60px;
87
- --glatam-time-col-width: 72px;
88
- --glatam-padding: 24px;
89
- font-size: 1.1rem;
90
- }
91
- `;