spring updates, timeslots
This commit is contained in:
parent
725547faa8
commit
4d40559205
|
|
@ -1,5 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
$MY_TITLE = "Events, Training, & Workshops";
|
$MY_TITLE = "Schedule & Sessions";
|
||||||
$MY_CRUMB = "Activities";
|
$MY_CRUMB = "Schedule & Sessions";
|
||||||
$CONTENT = '<activitylist :static="0" :itineraryview="false" zoom_on="0" survey_on="0"></activitylist>';
|
$CONTENT = '<activitylist :itineraryview="1" :show_all_sessions="true"></activitylist>';
|
||||||
include 'layout.php';
|
include 'layout.php';
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
$MY_TITLE = "Itinerary";
|
$MY_TITLE = "Schedule & Sessions";
|
||||||
$MY_CRUMB = "My Schedule";
|
$MY_CRUMB = "My Schedule";
|
||||||
$CONTENT = "<activitylist :itineraryview='1'></activitylist>";
|
$CONTENT = '<activitylist :itineraryview="1" :show_all_sessions="true"></activitylist>';
|
||||||
include 'layout.php';
|
include 'layout.php';
|
||||||
|
|
|
||||||
275
js/dir_app.js
275
js/dir_app.js
|
|
@ -856,11 +856,11 @@ const ActivityEditor = Vue.component('activityedit', {
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
const ActivityList = Vue.component('activitylist', {
|
const ActivityList = Vue.component('activitylist', {
|
||||||
props: [ 'itineraryview','static' ],
|
props: [ 'itineraryview','static','show_all_sessions' ],
|
||||||
data: function () {
|
data: function () {
|
||||||
return { activities:[], mysessions:[], search:'', sortby:'starttime', reversed:false, my_ses_ids:[], my_host_ids:[],
|
return { activities:[], mysessions:[], search:'', sortby:'starttime', reversed:false, my_ses_ids:[], my_host_ids:[],
|
||||||
show_filters: 'all', expanded: 1, editing: -1, active:-1, hosts:{},
|
show_filters: 'all', expanded: 1, editing: -1, active:-1, hosts:{}, selectedSlotKey: null,
|
||||||
hosts_by_sesid: {}, options:{}, conference:{}, ay:{}, conf:-1, survey_on:0, zoom_on:1, } },
|
hosts_by_sesid: {}, options:{}, conference:{}, ay:{}, conf:-1, survey_on:0, zoom_on:1, cancelingIds:[], } },
|
||||||
mounted: function() {
|
mounted: function() {
|
||||||
this.fetch_myevents()
|
this.fetch_myevents()
|
||||||
},
|
},
|
||||||
|
|
@ -890,6 +890,21 @@ const ActivityList = Vue.component('activitylist', {
|
||||||
para.classList.toggle('line-clamp-2');
|
para.classList.toggle('line-clamp-2');
|
||||||
btn.textContent = para.classList.contains('line-clamp-2') ? 'Show More' : 'Show Less';
|
btn.textContent = para.classList.contains('line-clamp-2') ? 'Show More' : 'Show Less';
|
||||||
},
|
},
|
||||||
|
slotKeyFromStart: function(starttime) {
|
||||||
|
if (!starttime) { return null; }
|
||||||
|
return this.$root.$dj(starttime).format('YYYY-MM-DDTHH:mm');
|
||||||
|
},
|
||||||
|
slotSelection: function(slot) {
|
||||||
|
var self = this;
|
||||||
|
var list = this.filtered(this.mysessions, { applySearch: false, applySlot: false });
|
||||||
|
return _.filter(list, function(s) { return self.slotKeyFromStart(s.starttime) === slot.key; });
|
||||||
|
},
|
||||||
|
selectSlot: function(slot) {
|
||||||
|
if (this.selectedSlotKey === slot.key) { this.selectedSlotKey = null; return; }
|
||||||
|
this.selectedSlotKey = slot.key;
|
||||||
|
this.search = '';
|
||||||
|
},
|
||||||
|
clearSlot: function() { this.selectedSlotKey = null; },
|
||||||
addTime: function(time, x) {
|
addTime: function(time, x) {
|
||||||
x = parseInt(x)
|
x = parseInt(x)
|
||||||
let [y, m, d, h, i, s] = time.split(/[- :]/); // split time into parts
|
let [y, m, d, h, i, s] = time.split(/[- :]/); // split time into parts
|
||||||
|
|
@ -949,16 +964,38 @@ const ActivityList = Vue.component('activitylist', {
|
||||||
},
|
},
|
||||||
dumpme: function(id) {
|
dumpme: function(id) {
|
||||||
var self = this
|
var self = this
|
||||||
|
if (!self.cancelingIds.includes(id)) { self.cancelingIds.push(id) }
|
||||||
basic_get('dir_api.php?a=signdown/' + id,
|
basic_get('dir_api.php?a=signdown/' + id,
|
||||||
function(r2) {
|
function(r2) {
|
||||||
|
setTimeout(function() {
|
||||||
self.mysessions = _.without( self.mysessions, _.findWhere(self.activities, {'id':id}))
|
self.mysessions = _.without( self.mysessions, _.findWhere(self.activities, {'id':id}))
|
||||||
self.my_ses_ids = _.without( self.my_ses_ids, id)
|
self.my_ses_ids = _.without( self.my_ses_ids, id)
|
||||||
|
self.cancelingIds = _.without(self.cancelingIds, id)
|
||||||
self.$forceUpdate()
|
self.$forceUpdate()
|
||||||
alert_message("Removed activity") })
|
alert_message("Removed activity")
|
||||||
|
}, 250)
|
||||||
|
})
|
||||||
},
|
},
|
||||||
filtered: function(ff) {
|
sessionsForSlot: function(slot) {
|
||||||
|
var self=this;
|
||||||
|
return _.chain(this.activities_for_slots)
|
||||||
|
.filter(function(item) { return self.slotKeyFromStart(item.starttime) === slot.key; })
|
||||||
|
.sortBy('starttime')
|
||||||
|
.value();
|
||||||
|
},
|
||||||
|
chooseSession: function(activity) {
|
||||||
|
var self=this;
|
||||||
|
if (!self.my_ses_ids.includes(activity.id)) {
|
||||||
|
self.joinme(activity.id);
|
||||||
|
}
|
||||||
|
self.clearSlot();
|
||||||
|
},
|
||||||
|
isCanceling: function(id) { return this.cancelingIds.includes(id) },
|
||||||
|
filtered: function(ff, opts = { applySearch: true, applySlot: false }) {
|
||||||
var self = this
|
var self = this
|
||||||
if (this.search) {
|
var applySearch = (opts.applySearch !== false)
|
||||||
|
var applySlot = (opts.applySlot !== false)
|
||||||
|
if (applySearch && this.search) {
|
||||||
var ss = self.search.toLowerCase()
|
var ss = self.search.toLowerCase()
|
||||||
ff = ff.filter(function(x) { return ('searchable' in x ? x.searchable.includes(ss) : 0) })
|
ff = ff.filter(function(x) { return ('searchable' in x ? x.searchable.includes(ss) : 0) })
|
||||||
}
|
}
|
||||||
|
|
@ -971,6 +1008,9 @@ const ActivityList = Vue.component('activitylist', {
|
||||||
ff = ff.filter( function(item,index) {
|
ff = ff.filter( function(item,index) {
|
||||||
this_time = dayjs(item.starttime)
|
this_time = dayjs(item.starttime)
|
||||||
return this_time.isBefore(end) && start.isBefore(this_time) } )
|
return this_time.isBefore(end) && start.isBefore(this_time) } )
|
||||||
|
if (this.selectedSlotKey && applySlot) {
|
||||||
|
ff = ff.filter(function(item) { return self.slotKeyFromStart(item.starttime) === self.selectedSlotKey })
|
||||||
|
}
|
||||||
ff = _.sortBy(ff, function(x) {
|
ff = _.sortBy(ff, function(x) {
|
||||||
if (x[self.sortby]) { var s = x[self.sortby]; return s.trim().toLowerCase() }
|
if (x[self.sortby]) { var s = x[self.sortby]; return s.trim().toLowerCase() }
|
||||||
return '' })
|
return '' })
|
||||||
|
|
@ -984,7 +1024,33 @@ const ActivityList = Vue.component('activitylist', {
|
||||||
current_time: function() { return dayjs().format('MMM D, h:mma') },
|
current_time: function() { return dayjs().format('MMM D, h:mma') },
|
||||||
activities_filtered: function() { var a = this.filtered(this.activities); return a; },
|
activities_filtered: function() { var a = this.filtered(this.activities); return a; },
|
||||||
mysessions_filtered: function() { return this.filtered(this.mysessions) },
|
mysessions_filtered: function() { return this.filtered(this.mysessions) },
|
||||||
|
activities_for_slots: function() { return this.filtered(this.activities, { applySearch: false, applySlot: false }) },
|
||||||
|
timeSlotsByDay: function() {
|
||||||
|
if (this.active < 1) { return {}; }
|
||||||
|
var self=this;
|
||||||
|
var grouped = _.groupBy(this.activities_for_slots, function(x) { return self.month_year(x.starttime) });
|
||||||
|
return _.mapObject(grouped, function(list) {
|
||||||
|
return _.chain(list)
|
||||||
|
.sortBy('starttime')
|
||||||
|
.map(function(item) {
|
||||||
|
var start = self.$root.$dj(item.starttime);
|
||||||
|
return {
|
||||||
|
key: self.slotKeyFromStart(item.starttime),
|
||||||
|
startLabel: start.format('h:mma'),
|
||||||
|
endLabel: self.addTime(item.starttime, item.length),
|
||||||
|
dayLabel: self.month_year(item.starttime)
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.uniq(false, function(slot) { return slot.key; })
|
||||||
|
.value();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
selectedSlotLabel: function() {
|
||||||
|
if (!this.selectedSlotKey) { return '' }
|
||||||
|
var m = dayjs(this.selectedSlotKey);
|
||||||
|
if (!m.isValid()) { return '' }
|
||||||
|
return m.format('MMM D, h:mma');
|
||||||
|
},
|
||||||
activities_g_filtered: function() { if (this.active<1) { return {} }
|
activities_g_filtered: function() { if (this.active<1) { return {} }
|
||||||
var self=this;
|
var self=this;
|
||||||
return _.groupBy(self.activities_filtered, function(x) { return self.month_year(x.starttime) } ); },
|
return _.groupBy(self.activities_filtered, function(x) { return self.month_year(x.starttime) } ); },
|
||||||
|
|
@ -1003,6 +1069,83 @@ const ActivityList = Vue.component('activitylist', {
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Time slots view -->
|
||||||
|
<div v-if="itineraryview && active > 0" class="mb-8">
|
||||||
|
<div v-if="Object.keys(timeSlotsByDay).length === 0" class="bg-white border rounded p-4 text-sm text-gray-700">
|
||||||
|
No session times are available yet.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-for="(slots, mmyy) in timeSlotsByDay" :key="mmyy" class="mb-6">
|
||||||
|
<h4 class="text-lg font-semibold text-gray-700 mb-2">{{ mmyy }} {{ get_day_title(mmyy) }}</h4>
|
||||||
|
<div class="space-y-3">
|
||||||
|
<div v-for="slot in slots" :key="slot.key" :class="['border rounded-lg p-4 bg-white shadow-sm flex items-start gap-4', selectedSlotKey === slot.key ? 'ring-2 ring-blue-400' : '']">
|
||||||
|
<div class="w-32 text-right">
|
||||||
|
<div class="text-2xl font-extrabold text-blue-800 leading-tight">{{ slot.startLabel }}</div>
|
||||||
|
<div class="text-sm text-gray-500">to {{ slot.endLabel }}</div>
|
||||||
|
<span class="block text-xs text-gray-500 mt-1" v-if="selectedSlotKey === slot.key">Selected</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-1">
|
||||||
|
<div v-if="slotSelection(slot).length" class="space-y-2">
|
||||||
|
<div v-for="sel in slotSelection(slot)" :key="sel.id" :class="['border-b last:border-none pb-2 last:pb-0 transition-opacity duration-300', isCanceling(sel.id) ? 'opacity-40' : '']">
|
||||||
|
<div class="font-semibold text-gray-900">{{ sel.title }}</div>
|
||||||
|
<div class="text-sm text-gray-600">
|
||||||
|
{{ $root.$dj(sel.starttime).format('h:mma') }} · {{ mode_string(sel) }}
|
||||||
|
</div>
|
||||||
|
<button v-if="!my_host_ids.includes(sel.id)"
|
||||||
|
class="mt-2 text-sm text-red-600 hover:underline"
|
||||||
|
@click.prevent="dumpme(sel.id)">Cancel</button>
|
||||||
|
</div>
|
||||||
|
<button class="mt-1 text-sm text-blue-600 hover:underline" @click="selectSlot(slot)">Change selection</button>
|
||||||
|
</div>
|
||||||
|
<div v-else class="mt-1">
|
||||||
|
<button class="w-full border-2 border-dashed border-blue-300 text-blue-700 font-semibold rounded-md py-3 hover:bg-blue-50 text-left px-4" @click="selectSlot(slot)">
|
||||||
|
Pick a session
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<transition name="slotpanel">
|
||||||
|
<div v-if="selectedSlotKey === slot.key" class="mt-4 border rounded-lg bg-blue-50 border-blue-200 p-4 shadow-inner">
|
||||||
|
<div class="flex items-start justify-between gap-3 mb-3">
|
||||||
|
<div>
|
||||||
|
<div class="text-sm text-gray-600">Pick for {{ slot.startLabel }} - {{ slot.endLabel }}</div>
|
||||||
|
<div class="text-base font-semibold text-gray-800">Available sessions</div>
|
||||||
|
</div>
|
||||||
|
<button class="text-sm text-gray-600 hover:text-gray-800" @click="clearSlot">X</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="sessionsForSlot(slot).length" class="space-y-3 max-h-72 overflow-y-auto pr-1">
|
||||||
|
<div v-for="a in sessionsForSlot(slot)" :key="a.id" class="bg-white rounded border border-gray-200 p-3 shadow-sm">
|
||||||
|
<div class="flex items-start justify-between gap-3">
|
||||||
|
<div class="flex-1">
|
||||||
|
<div class="font-semibold text-gray-900">{{ a.title }}</div>
|
||||||
|
<div class="text-xs uppercase text-gray-500">{{ mode_string(a) }}</div>
|
||||||
|
<div class="text-sm text-gray-600 mt-1">
|
||||||
|
<span v-if="a.mode === 'hybrid'">In person at {{ a.location_irl }} or online</span>
|
||||||
|
<span v-if="a.mode === 'inperson'">In person at {{ a.location_irl }}</span>
|
||||||
|
<span v-if="a.mode === 'online'">Online</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<button v-if="!my_ses_ids.includes(a.id)"
|
||||||
|
class="px-3 py-1 text-sm font-medium text-white bg-blue-600 rounded hover:bg-blue-700"
|
||||||
|
@click.prevent="chooseSession(a)">
|
||||||
|
Sign Up
|
||||||
|
</button>
|
||||||
|
<span v-else class="text-sm text-green-700 font-semibold">In itinerary</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else class="text-sm text-gray-700">No sessions are available in this time slot.</div>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- No sessions signed up -->
|
<!-- No sessions signed up -->
|
||||||
<div v-if="itineraryview && mysessions_filtered.length === 0" class="mb-6">
|
<div v-if="itineraryview && mysessions_filtered.length === 0" class="mb-6">
|
||||||
<p class="font-semibold text-gray-800">It looks like you haven't signed up for any sessions yet!</p>
|
<p class="font-semibold text-gray-800">It looks like you haven't signed up for any sessions yet!</p>
|
||||||
|
|
@ -1011,128 +1154,10 @@ const ActivityList = Vue.component('activitylist', {
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Grouped sessions by date -->
|
|
||||||
<div v-if="itineraryview && active > 0" v-for="(items, mmyy) in mysessions_g_filtered" :key="mmyy" class="mb-8">
|
|
||||||
<h3 class="text-xl font-bold text-gray-800 mb-2">{{ mmyy }} {{ get_day_title(mmyy) }}</h3>
|
|
||||||
|
|
||||||
<div v-for="a in items" :key="a.id" class="bg-white rounded-lg shadow p-4 mb-6 border-l-4 border-blue-200">
|
|
||||||
<div class="flex flex-col md:flex-row md:justify-between md:items-start gap-4">
|
|
||||||
|
|
||||||
<!-- Left side controls -->
|
|
||||||
<div class="flex flex-wrap gap-2 md:flex-col md:min-w-[100px]">
|
|
||||||
<a v-if="my_host_ids.includes(a.id)"
|
|
||||||
:href="'ed_act.php?w=' + a.id"
|
|
||||||
class="text-sm text-blue-600 hover:underline">Edit</a>
|
|
||||||
|
|
||||||
<a v-if="my_host_ids.includes(a.id)"
|
|
||||||
:href="'report.php?s=' + a.id"
|
|
||||||
class="text-sm text-blue-600 hover:underline">Info</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Session info -->
|
|
||||||
<div class="flex-grow relative">
|
|
||||||
<h2 class="text-base font-semibold text-gray-800">{{ a.title }}</h2>
|
|
||||||
<p class="text-sm text-gray-600">
|
|
||||||
{{ $root.$dj(a.starttime).format('h:mma') }} - {{ addTime(a.starttime, a.length) }} <!--· {{ mode_string(a) }} -->
|
|
||||||
<span v-if="a.mode === 'hybrid'"> · In person at {{ a.location_irl }} or
|
|
||||||
<a v-if="zoom_on && a.location" :href="a.location" class="underline text-blue-600">online</a>
|
|
||||||
<span v-else>online</span>
|
|
||||||
</span>
|
|
||||||
<span v-if="a.mode === 'inperson'"> · In person at {{ a.location_irl }}</span>
|
|
||||||
<span v-if="zoom_on && a.mode === 'online'"> · <a :href="a.location" class="underline text-blue-600">Online</a></span>
|
|
||||||
<span v-if="!zoom_on && a.mode === 'online'"> · Online</span>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<!-- Bottom action buttons -->
|
|
||||||
<div class="mt-4 flex gap-3 flex-wrap">
|
|
||||||
<a v-if="zoom_on && a.location"
|
|
||||||
:href="a.location"
|
|
||||||
class="px-3 py-1 text-sm font-medium text-white bg-blue-600 rounded hover:bg-blue-700">
|
|
||||||
Join Zoom
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a v-if="survey_on"
|
|
||||||
:href="'survey.php?s=' + a.id"
|
|
||||||
class="px-3 py-1 text-sm font-medium text-white bg-purple-600 rounded hover:bg-purple-700">
|
|
||||||
Survey
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div v-if="!itineraryview && active > 0" v-for="(items, mmyy) in activities_g_filtered" :key="mmyy" class="mb-6">
|
|
||||||
<div
|
|
||||||
class="flex justify-between items-baseline text-xl font-semibold text-gray-800 border-b pb-1 mb-2 clickme"
|
|
||||||
@click="toggleDay(get_day_index(mmyy))">
|
|
||||||
{{ mmyy }} {{ get_day_title(mmyy) }}
|
|
||||||
<button
|
|
||||||
:id="get_day_index(mmyy) + '-toggle'"
|
|
||||||
class="text-sm text-blue-600 hover:underline font-normal"
|
|
||||||
>
|
|
||||||
Collapse Day
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- all sessions in a day -->
|
|
||||||
<div :id="get_day_index(mmyy)">
|
|
||||||
<div v-for="a in items" :key="a.id" class="relative bg-white rounded-lg shadow p-4 mb-4">
|
|
||||||
<div class="flex flex-col md:flex-row md:justify-between md:items-start gap-4">
|
|
||||||
<!-- Action buttons (left on desktop) -->
|
|
||||||
<div v-if="!static" class="flex-shrink-0 flex gap-2">
|
|
||||||
<a v-if="my_ses_ids.includes(a.id) && !my_host_ids.includes(a.id)"
|
|
||||||
@click.prevent="dumpme(a.id)"
|
|
||||||
href="#"
|
|
||||||
class="px-3 py-1 text-sm font-medium rounded text-sm text-white bg-red-600 hover:underline">Cancel</a>
|
|
||||||
|
|
||||||
<a v-if="!special_signup(a.id) && !my_ses_ids.includes(a.id) && !my_host_ids.includes(a.id)"
|
|
||||||
@click.prevent="joinme(a.id)"
|
|
||||||
href="#"
|
|
||||||
class="px-3 py-1 text-sm font-medium text-white bg-purple-600 rounded hover:bg-purple-700">Sign Up</a>
|
|
||||||
|
|
||||||
<!--<a v-if="special_signup(a.id)"
|
|
||||||
target="_blank"
|
|
||||||
href="https://forms.office.com/r/GGz56DdSEG"
|
|
||||||
class="px-3 py-1 text-sm font-medium text-white bg-amber-500 rounded hover:bg-amber-700">Sign Up</a>
|
|
||||||
-->
|
|
||||||
<span v-if="special_signup(a.id)"
|
|
||||||
class="px-3 py-1 text-sm font-medium text-white">
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<a v-if="my_host_ids.includes(a.id)"
|
|
||||||
:href="'ed_act.php?w=' + a.id"
|
|
||||||
class="px-3 py-1 text-sm font-medium text-white bg-purple-600 rounded hover:bg-purple-700">Edit</a>
|
|
||||||
<b v-if="my_host_ids.includes(a.id)">You are Host.</b>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Main session info -->
|
|
||||||
<div class="flex-grow">
|
|
||||||
<h2 class="text-lg font-semibold text-gray-900">{{ a.title }}</h2>
|
|
||||||
<ModePill :mode="a.mode" class="absolute top-2 right-2" />
|
|
||||||
<p class="text-sm text-gray-700">
|
|
||||||
{{ $root.$dj(a.starttime).format('h:mma') }} - {{ addTime(a.starttime, a.length) }} ·
|
|
||||||
{{ mode_string(a) }}
|
|
||||||
<span v-if="a.mode == 'hybrid' || a.mode == 'inperson'"> · {{ a.location_irl }}</span>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p v-if="hoststr(a.id)" class="text-sm text-gray-600">Presented by: {{ hoststr(a.id) }}</p>
|
|
||||||
<p v-if="static && a.location_irl" class="text-sm text-gray-600">Location: {{ a.location_irl }}</p>
|
|
||||||
<p v-if="static && a.location" class="text-sm text-blue-600">
|
|
||||||
Zoom Link:
|
|
||||||
<a :href="a.location" class="underline hover:text-blue-800">{{ a.location }}</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div v-if="expanded" class="mt-2 text-sm text-gray-700" v-html="a.desc"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>` })
|
</div>` })
|
||||||
|
|
||||||
|
|
|
||||||
16
style.css
16
style.css
|
|
@ -48,3 +48,19 @@ ol {
|
||||||
overflow-wrap: anywhere;
|
overflow-wrap: anywhere;
|
||||||
word-break: break-all; /* only affects long unbroken tokens like URLs */
|
word-break: break-all; /* only affects long unbroken tokens like URLs */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Slot picker slide/fade */
|
||||||
|
.slotpanel-enter-active,
|
||||||
|
.slotpanel-leave-active {
|
||||||
|
transition: all 0.25s ease;
|
||||||
|
}
|
||||||
|
.slotpanel-enter,
|
||||||
|
.slotpanel-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-6px);
|
||||||
|
max-height: 0;
|
||||||
|
}
|
||||||
|
.slotpanel-enter-to,
|
||||||
|
.slotpanel-leave {
|
||||||
|
max-height: 600px;
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue