-
-
Notifications
You must be signed in to change notification settings - Fork 588
[6.x] Collection Calendar mode #12597
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
jackmcdade
wants to merge
51
commits into
master
Choose a base branch
from
collection-calendar
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
51 commits
Select commit
Hold shift + click to select a range
f5a3a57
wip
jackmcdade 30dcc5d
Wire up CreateEntryButton
jackmcdade c0001c7
Make sure we don't get a row full of days outside the currently displ…
jackmcdade d4fc72d
Fix line clamp
jackmcdade 50be588
fix more indicator
jackmcdade e31f51b
Remove redundant API Call on Component Mount
jackmcdade da67395
Better dark mode bg
jackmcdade 2b1404e
Add keyboard navigation
jackmcdade 8413714
Remove incorrect entry count badge
jackmcdade e93f78d
Initial mobile layout
jackmcdade efef0c1
Mobile indicators of entries on any given day.
jackmcdade cf909e3
Adjust math so less entries = narrower bar indicator
jackmcdade 20ad04b
Remove keyboard binding in favor of just standard tab controls which …
jackmcdade d68cd74
Show entries on a given selected date on small screens
jackmcdade e9dcc15
Adds Week View
jackmcdade b9ec79e
Better "today" cell state
jackmcdade 3bda9bd
wip drag & drop entries
jackmcdade 879ce0b
wip hourly drop state
jackmcdade 0708c1a
Refactor and restyle a bit
jackmcdade e34133c
Prevent entries flashing back to their original position on save.
jackmcdade 741e7da
Refactor into smaller components for readability/maintainability
jackmcdade 8c59b71
Bring back 8am day state position
jackmcdade f0fa6d1
Improve dark mode
jackmcdade 9214f42
Calendar suggestions / objective - correct day spacing and text contrast
JayGeorge c7ddfb5
Calendar suggestions / subjective suggestions
JayGeorge 03d625b
Calendar suggestions / add a dot for current day
JayGeorge 7e13588
Calendar suggestions / make colors ui-accent instead
JayGeorge 9ae4fec
Calendar suggestions / compress rows without events
JayGeorge 912a19b
Calendar / fix multiple entries on the week view by adding an overflo…
JayGeorge 8342943
Calendar / week / suggestion to make rows smaller
JayGeorge 30eef3e
Calendar / month / show all entries with overflow scroll, same as wee…
JayGeorge 5fddc71
move css to inline tw + data attr
jackmcdade d61938e
Switch this to a max-height media query
jackmcdade 05196ff
Click the CalendarHeader to change the month and year
jackmcdade 65d5769
Merge branch 'master' into collection-calendar
jasonvarga 6ed9a73
add dated prop to controller
jasonvarga 096be70
Fix field conditions not applying in filters
jasonvarga 54335d4
Adjust field filter logic
jasonvarga e22675c
Merge branch 'date-filter' into collection-calendar
jasonvarga e078281
only get entries for that period
jasonvarga 30e775d
The date range for getting entries should include those few days of t…
jasonvarga 7fb5709
move in preparation to becoming util
jasonvarga f0b34ec
make it a utility file. there was nothing composable about it
jasonvarga 71317f2
Merge branch 'master' into collection-calendar
jasonvarga f595117
remove unused stuff
jasonvarga bddbec9
un-wangjangle existing props
jasonvarga ba7d75a
dont need customTrigger. if you dont pass a slot, it'll use what you …
jasonvarga c390ac6
unwrap template - just put v-if on the slot
jasonvarga 5330ea3
Merge branch 'master' into collection-calendar
jasonvarga 1ad7bd2
use inertia link/redirect
jasonvarga da39244
Create entry button sends the utc datetime to the form
jasonvarga File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
<template> | ||
<Link | ||
:href="entry.edit_url" | ||
:key="entry.id" | ||
class="text-2xs @3xl:text-xs px-2 border-s-2 rounded-e-sm cursor-pointer flex flex-col" | ||
:class="entryClasses" | ||
draggable="true" | ||
@dragstart="handleDragStart" | ||
> | ||
<span class="line-clamp-2"> | ||
{{ entry.title }} | ||
</span> | ||
<span class="hidden @4xl:block text-2xs text-gray-400 dark:text-gray-400"> | ||
{{ formatTime(entry.date?.date || entry.date) }} | ||
</span> | ||
</Link> | ||
</template> | ||
|
||
<script setup> | ||
import { computed } from 'vue'; | ||
import { formatTime } from '@/util/calendar.js'; | ||
import { Link } from '@inertiajs/vue3'; | ||
|
||
const props = defineProps({ | ||
entry: { type: Object, required: true } | ||
}); | ||
|
||
const emit = defineEmits(['dragstart']); | ||
|
||
const entryClasses = computed(() => ({ | ||
'border-green-500 hover:bg-green-50': props.entry.status === 'published', | ||
'border-gray-300 hover:bg-gray-50': props.entry.status === 'draft', | ||
'border-purple-500 hover:bg-purple-50': props.entry.status === 'scheduled' | ||
})); | ||
|
||
const handleDragStart = (event) => { | ||
emit('dragstart', event, props.entry); | ||
}; | ||
</script> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
<script setup> | ||
import { CalendarCell, CalendarCellTrigger, CalendarGrid, CalendarGridBody, CalendarGridHead, CalendarGridRow, CalendarHeadCell } from 'reka-ui'; | ||
import CalendarEntry from './CalendarEntry.vue'; | ||
import CreateEntryButton from './CreateEntryButton.vue'; | ||
import { formatDateString, isToday, getCreateUrlDateParam } from '@/util/calendar.js'; | ||
|
||
const props = defineProps({ | ||
weekDays: { type: Array, required: true }, | ||
grid: { type: Array, required: true }, | ||
entries: { type: Array, required: true }, | ||
pendingDateChanges: { type: Map, required: true }, | ||
selectedDate: { type: Object, default: null }, | ||
dragOverTarget: { type: Object, default: null }, | ||
createUrl: { type: String, required: true }, | ||
blueprints: { type: Array, default: () => [] } | ||
}); | ||
|
||
const emit = defineEmits(['select-date', 'entry-dragstart', 'drag-over', 'drag-enter', 'drag-leave', 'drop']); | ||
|
||
const isCurrentDay = (dayIndex) => { | ||
const today = new Date(); | ||
const currentDayName = today.toLocaleDateString('en-US', {weekday: 'long'}); | ||
|
||
// Find the index of today's day name in the weekDays array | ||
const todayIndex = props.weekDays.findIndex(day => | ||
day.toLowerCase() === currentDayName.toLowerCase() | ||
); | ||
|
||
return dayIndex === todayIndex; | ||
}; | ||
|
||
const getEntriesForDate = (date) => { | ||
const dateStr = formatDateString(date); | ||
return props.entries.filter(entry => { | ||
// Check if this entry has a pending date change | ||
if (props.pendingDateChanges.has(entry.id)) { | ||
const newDate = props.pendingDateChanges.get(entry.id); | ||
return newDate.toISOString().split('T')[0] === dateStr; | ||
} | ||
|
||
const entryDate = new Date(entry.date?.date || entry.date); | ||
return entryDate.toISOString().split('T')[0] === dateStr; | ||
}); | ||
}; | ||
|
||
const weekHasEntries = (weekDates) => { | ||
return weekDates.some(date => getEntriesForDate(date).length > 0); | ||
}; | ||
|
||
const cellClasses = (weekDate, monthValue) => ({ | ||
'bg-gray-100 dark:bg-gray-800 ring-1 ring-gray-200 dark:ring-gray-700': weekDate.month !== monthValue.month, | ||
'bg-white dark:bg-gray-900': weekDate.month === monthValue.month, | ||
'bg-ui-accent/10! border border-ui-accent!': isToday(weekDate), | ||
'border-2 border-blue-400 bg-blue-50 dark:bg-blue-900/20': isDragOverDate(weekDate) | ||
}); | ||
|
||
const dateNumberClasses = (weekDate, selected, today, outsideView) => ({ | ||
'text-gray-400 dark:text-gray-600': outsideView, | ||
'text-gray-900 dark:text-white': !outsideView, | ||
'text-white bg-blue-600': props.selectedDate && props.selectedDate.toString() === weekDate.toString(), | ||
'text-ui-accent': today | ||
}); | ||
|
||
const entryStatusClasses = (status) => ({ | ||
'bg-green-500': status === 'published', | ||
'bg-gray-300': status === 'draft', | ||
'bg-purple-500': status === 'scheduled' | ||
}); | ||
|
||
const isDragOverDate = (date) => { | ||
return props.dragOverTarget && props.dragOverTarget.toString() === date.toString(); | ||
}; | ||
|
||
const selectDate = (date) => { | ||
emit('select-date', date); | ||
}; | ||
|
||
const handleEntryDragStart = (event, entry) => { | ||
emit('entry-dragstart', event, entry); | ||
}; | ||
|
||
const handleDragOver = (event) => { | ||
emit('drag-over', event); | ||
}; | ||
|
||
const handleDragEnter = (event, target) => { | ||
emit('drag-enter', event, target); | ||
}; | ||
|
||
const handleDragLeave = (event) => { | ||
emit('drag-leave', event); | ||
}; | ||
|
||
const handleDrop = (event, targetDate) => { | ||
emit('drop', event, targetDate); | ||
}; | ||
</script> | ||
|
||
<template> | ||
<CalendarGrid class="w-full border-collapse"> | ||
<CalendarGridHead> | ||
<CalendarGridRow class="grid grid-cols-7 gap-3 mb-2"> | ||
<CalendarHeadCell | ||
v-for="(day, index) in weekDays" | ||
:key="day" | ||
class="p-2 text-center font-medium text-sm text-gray-700 dark:text-gray-400 bg-gray-200/75 dark:bg-gray-900/75 rounded-lg" | ||
> | ||
<div class="flex items-center justify-center gap-1"> | ||
<div | ||
v-if="isCurrentDay(index)" | ||
class="w-1.5 h-1.5 mr-1 bg-ui-accent rounded-full" | ||
></div> | ||
<span class="@4xl:hidden">{{ day.slice(0, 2) }}</span> | ||
<span class="hidden @4xl:block">{{ day }}</span> | ||
</div> | ||
</CalendarHeadCell> | ||
</CalendarGridRow> | ||
</CalendarGridHead> | ||
|
||
<CalendarGridBody class="space-y-3 calendar-grid"> | ||
<template v-for="month in grid" :key="month.value.toString()"> | ||
<CalendarGridRow | ||
v-for="(weekDates, weekIndex) in month.rows.filter(weekDates => | ||
weekDates.some(date => date.month === month.value.month) | ||
)" | ||
:key="`weekDate-${weekIndex}`" | ||
:data-week-has-entries="weekHasEntries(weekDates)" | ||
class="grid grid-cols-7 gap-3" | ||
> | ||
<CalendarCell | ||
v-for="weekDate in weekDates" | ||
:key="weekDate.toString()" | ||
:date="weekDate" | ||
class="aspect-square p-2 rounded-xl ring ring-gray-200 dark:ring-gray-700 shadow-ui-sm group relative" | ||
:class="cellClasses(weekDate, month.value)" | ||
@dragover="handleDragOver" | ||
@dragenter="handleDragEnter($event, weekDate)" | ||
@dragleave="handleDragLeave" | ||
@drop="handleDrop($event, weekDate)" | ||
> | ||
<CalendarCellTrigger | ||
:day="weekDate" | ||
:month="month.value" | ||
class="w-full h-full flex flex-col items-center justify-center @3xl:items-start @3xl:justify-start" | ||
v-slot="{ dayValue, selected, today, outsideView }" | ||
@click="selectDate(weekDate)" | ||
> | ||
<!-- Date number --> | ||
<div | ||
class="text-sm mb-1 rounded-full size-6 flex items-center justify-center" | ||
v-text="dayValue" | ||
:class="dateNumberClasses(weekDate, selected, today, outsideView)" | ||
/> | ||
|
||
<!-- Mobile entry indicators --> | ||
<div class="@3xl:hidden w-full" v-if="getEntriesForDate(weekDate).length > 0"> | ||
<div class="flex h-1 rounded-full overflow-hidden items-center justify-center"> | ||
<div | ||
v-for="(entry, index) in getEntriesForDate(weekDate).slice(0, 4)" | ||
:key="entry.id" | ||
class="h-full first:rounded-s-full last:rounded-e-full" | ||
:class="entryStatusClasses(entry.status)" | ||
style="width: 25%" | ||
/> | ||
</div> | ||
</div> | ||
|
||
<!-- Desktop entries --> | ||
<div class="space-y-1.5 flex-1 overflow-scroll h-full w-full hidden @3xl:block"> | ||
<CalendarEntry | ||
v-for="entry in getEntriesForDate(weekDate)" | ||
:key="entry.id" | ||
:entry="entry" | ||
@dragstart="handleEntryDragStart" | ||
/> | ||
</div> | ||
</CalendarCellTrigger> | ||
|
||
<!-- Create entry button (shows on hover) --> | ||
<div class="absolute top-1 right-1 opacity-0 group-hover:opacity-100 transition-opacity hidden @3xl:block"> | ||
<CreateEntryButton | ||
:params="{ values: { date: getCreateUrlDateParam(weekDate) } }" | ||
:blueprints="blueprints" | ||
variant="subtle" | ||
size="sm" | ||
> | ||
<template #trigger="{ create }"> | ||
<ui-button icon="plus" size="sm" variant="subtle" @click="create" /> | ||
</template> | ||
</CreateEntryButton> | ||
</div> | ||
</CalendarCell> | ||
</CalendarGridRow> | ||
</template> | ||
</CalendarGridBody> | ||
</CalendarGrid> | ||
</template> | ||
|
||
<style scoped> | ||
@media (max-height: 999px) { | ||
.calendar-grid { | ||
tr:not([data-week-has-entries="true"]) td { | ||
aspect-ratio: 2 / 1; | ||
} | ||
} | ||
} | ||
</style> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<template> | ||
<a | ||
:href="entry.edit_url" | ||
:key="entry.id" | ||
class="block text-xs p-1 rounded-r border-l-2 mb-1 cursor-pointer hover:shadow-sm" | ||
:class="entryClasses" | ||
draggable="true" | ||
@dragstart="handleDragStart" | ||
> | ||
<div class="font-medium line-clamp-2">{{ entry.title }}</div> | ||
</a> | ||
</template> | ||
|
||
<script setup> | ||
import { computed } from 'vue'; | ||
|
||
const props = defineProps({ | ||
entry: { type: Object, required: true } | ||
}); | ||
|
||
const emit = defineEmits(['dragstart']); | ||
|
||
const entryClasses = computed(() => ({ | ||
'border-green-500 bg-green-50 dark:bg-green-900/20': props.entry.status === 'published', | ||
'border-gray-300 bg-gray-50 dark:bg-gray-800': props.entry.status === 'draft', | ||
'border-purple-500 bg-purple-50 dark:bg-purple-900/20': props.entry.status === 'scheduled' | ||
})); | ||
|
||
const handleDragStart = (event) => { | ||
emit('dragstart', event, props.entry); | ||
}; | ||
</script> |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.