Browse Source

Scheduler UI improvements

development
Godwin 7 years ago
parent
commit
f36d9468df
  1. 292
      app/assets/stylesheets/_admin.scss
  2. 69
      app/assets/stylesheets/_application.scss
  3. 8
      app/assets/stylesheets/_settings.scss
  4. 6
      app/controllers/application_controller.rb
  5. 19
      app/helpers/widgets_helper.rb
  6. 44
      app/views/conference_administration/_schedule.html.haml
  7. 4
      config/locales/en.yml
  8. 3
      config/locales/fr.yml

292
app/assets/stylesheets/_admin.scss

@ -41,7 +41,7 @@ table, .table {
white-space: nowrap;
@include after {
content: '';
content: $down-icon;
position: absolute;
bottom: -1em;
left: 50%;
@ -67,18 +67,18 @@ table, .table {
&:hover {
@include after {
content: '';
content: $up-icon;
}
}
}
[data-dir="up"] {
@include after {
content: '';
content: $up-icon;
}
&:hover {
@include after {
content: '';
content: $down-icon;
}
}
}
@ -98,26 +98,6 @@ table, .table {
background-color: transparent;
border: 0;
}
&.state {
background-size: 1.333em;
background-repeat: no-repeat;
background-position: center;
width: 1.75em;
&.happy {
@include after {
content: '\1F601';
opacity: 0.5;
}
}
&.unhappy {
@include after {
content: '\1F621';
}
}
}
}
td, .table-td {
@ -809,6 +789,103 @@ nav.sub-menu {
}
}
.admin-notes {
position: relative;
float: left;
margin-top: -0.2em;
margin-right: 0.25em;
cursor: pointer;
@include after {
content: $note-icon;
width: 2em;
height: 2em;
}
.notes {
@include hover-info;
top: auto;
bottom: 100%;
right: auto;
min-width: 25em;
p {
font-size: 1.125em;
&:first-child {
margin-top: 0;
}
&:last-child {
margin-bottom: 0;
}
}
}
&:hover, &:focus {
.notes {
display: block;
}
}
}
#main article .admin-status.state {
background-size: 1.333em;
background-repeat: no-repeat;
background-position: center;
width: 1.75em;
position: relative;
font-family: inherit;
padding: 0;
position: relative;
width: 2em;
height: 2em;
@include after {
position: absolute;
bottom: 0;
left: 0;
font-size: 1.5em;
}
&.happy {
@include after {
content: $happy-icon;
opacity: 0.5;
}
}
&.unhappy {
cursor: pointer;
@include after {
content: $angry-icon;
@include _(transform-origin, bottom);
@include _(animation, unhappy ease-in-out 1s infinite alternate both);
}
}
ul {
@include hover-info;
}
li {
white-space: nowrap;
margin: 0 0 0 1em;
&:first-child:last-child {
list-style: none;
margin: 0;
}
}
&:hover, &:focus {
ul {
display: block;
}
}
}
#admin-housing, #admin-schedule {
.guests-housed {
margin-bottom: 1em;
@ -831,13 +908,13 @@ nav.sub-menu {
&.happy {
@include after {
content: '\1F60D';
content: $love-icon;
}
}
&.unhappy {
@include after {
content: '\1F61E';
content: $unhappy-icon;
}
}
}
@ -886,45 +963,6 @@ nav.sub-menu {
overflow: auto;
}
.guest-notes {
position: relative;
float: left;
margin-top: -0.2em;
margin-right: 0.25em;
cursor: pointer;
@include after {
content: '\1F4C4';
width: 2em;
height: 2em;
}
.notes {
@include hover-info;
top: auto;
bottom: 100%;
right: auto;
min-width: 25em;
p {
font-size: 1.125em;
&:first-child {
margin-top: 0;
}
&:last-child {
margin-bottom: 0;
}
}
}
&:hover {
.notes {
display: block;
}
}
}
.address {
margin-top: 1em;
text-align: right;
@ -964,51 +1002,6 @@ nav.sub-menu {
td {
vertical-align: middle;
}
.state {
position: relative;
font-family: inherit;
padding: 0;
position: relative;
width: 2em;
height: 2em;
@include after {
position: absolute;
bottom: 0;
left: 0;
font-size: 1.5em;
}
&.unhappy {
cursor: pointer;
@include after {
@include _(transform-origin, bottom);
@include _(animation, unhappy ease-in-out 1s infinite alternate both);
}
}
ul {
@include hover-info;
}
li {
white-space: nowrap;
margin: 0 0 0 1em;
&:first-child:last-child {
list-style: none;
margin: 0;
}
}
&:hover {
ul {
display: block;
}
}
}
}
#workshop-selector {
@ -1364,6 +1357,85 @@ nav.sub-menu {
#admin-schedule {
#schedule-preview {
overflow: visible
}
table.schedule {
td.workshop {
vertical-align: top;
text-align: left;
position: relative;
.event-detail-link {
width: auto;
font-size: 1.25em;
}
}
.status {
display: inline-block;
text-align: left;
float: right;
font-size: 0.9em;
margin-top: 0.5em;
}
.conflict-score {
text-align: right;
.title {
@include font-family(secondary);
}
}
.admin-status {
position: absolute;
top: 0;
right: 0.25em;
ul {
width: 15em;
}
+ .event-detail-link {
padding-right: 1em;
}
}
.admin-notes {
@include after {
font-size: 1.25em;
}
}
.workshop-container {
padding-bottom: 4em;
}
.deschedule-workshop {
position: absolute;
right: 0.5em;
bottom: 0.5em;
left: 0.5em;
}
form {
margin-top: 0;
button {
margin-top: 0.5em;
float: left;
z-index: 1;
opacity: 0.5;
&:hover, &:focus {
opacity: 1;
}
}
}
}
.workshops-to-schedule {
@include _-(display, flex);
@include _(flex-wrap, wrap);

69
app/assets/stylesheets/_application.scss

@ -2136,70 +2136,6 @@ table.schedule {
align-items: center;
@include not-link-like;
.details {
flex: 1;
}
}
.status {
display: inline-block;
text-align: left;
float: right;
font-size: 0.9em;
margin-top: 0.5em;
}
.conflict-score {
text-align: right;
.title {
@include font-family(secondary);
}
}
.errors {
position: relative;
border-top: 0.1rem solid $dark-gray;
margin-top: 0.5em;
padding-top: 0.25em;
@include before {
content: '!';
display: inline-block;
position: absolute;
z-index: 1;
top: 0;
left: -1.2em;
width: 1em;
color: $white;
@include font-family(secondary);
}
@include after {
content: '';
position: absolute;
top: 0.1em;
left: -1.333em;
width: 0;
height: 0;
font-size: 1.25em;
border: 0.5em solid;
border-left-color: transparent;
border-right-color: transparent;
border-width: 0 0.5em 0.75em;
color: darken($colour-2, 25%);
}
}
#main .columns & form {
margin-top: 0;
button {
margin-top: 0.5em;
float: left;
z-index: 1;
}
}
}
}
@ -3510,9 +3446,10 @@ body.policy .policy-agreement ul {
}
.nav {
display: block;
@include _-(display, flex);
position: static;
font-size: 1.75em;
display: block;
text-align: center;
background-color: transparent;
@include _(box-shadow, none);
@ -3520,6 +3457,8 @@ body.policy .policy-agreement ul {
.nav a {
&[class] {
@include _(flex, 1);
white-space: nowrap;
width: auto;
float: none;
overflow: visible;

8
app/assets/stylesheets/_settings.scss

@ -39,6 +39,14 @@ $link-colour: darken($colour-1, 13%);
$selected-colour: rgba($blue, 0.5);
$note-icon: '\1F4C4';
$down-icon: '';
$up-icon: '';
$happy-icon: '\1F601';
$unhappy-icon: '\1F61E';
$love-icon: '\1F60D';
$angry-icon: '\1F621';
@mixin default-box-shadow($direction: top, $distance: 1, $inset: false, $additional-shadow: false) {
@if capable_of(box-shadow) {
$offset: 0.2em;

6
app/controllers/application_controller.rb

@ -491,7 +491,9 @@ class ApplicationController < BaseController
@schedule.each do |day, data|
@schedule[day][:times] = data[:times].sort.to_h
@schedule[day][:locations] ||= {}
# sort the locations by name
@schedule[day][:locations] = @schedule[day][:locations].sort_by { |event_id, event| event.present? ? event.title.downcase : '' }.to_h
# add an empty block if no workshops are scheduled on this day yet
@schedule[day][:locations][0] = :add if do_analyze || @schedule[day][:locations].empty?
@ -537,7 +539,7 @@ class ApplicationController < BaseController
location: location,
workshop: workshop_i,
i18nVars: {
need: need.to_s,
need: I18n.t("workshop.options.amenity.#{need}"),
location: location.title,
workshop_title: workshop_i.title
}

19
app/helpers/widgets_helper.rb

@ -138,17 +138,14 @@ module WidgetsHelper
other = (guest[:guest].housing_data || {})['other']
other.strip! if other.present?
if other.present?
name_html += content_tag :div, (content_tag :div, paragraph(other), class: 'notes').html_safe, class: 'guest-notes'
end
name_html += admin_notes(other) if other.present?
guest_rows += content_tag :tr, id: "hosted-guest-#{guest_id}" do
(content_tag :td, name_html.html_safe) +
(content_tag :td do
(guest[:guest].from +
(content_tag :a, (_'actions.workshops.Remove'), href: '#', class: 'remove-guest', data: { guest: guest_id })).html_safe
end) +
(content_tag :td, status_html.html_safe, class: [:state, status_html.present? ? :unhappy : :happy])
end) + admin_status(status_html, :td)
end
end
@ -163,7 +160,7 @@ module WidgetsHelper
status_html = ''
if @housing_data[id][:warnings].present? && @housing_data[id][:warnings][:space].present? && @housing_data[id][:warnings][:space][area].present?
@housing_data[id][:warnings][:space][area].each do |w|
status_html += content_tag(:li, _("warnings.messages.housing.space.#{w.to_s}"))
status_html += content_tag(:li, _("warnings.messages.housing.space.#{w.to_s}", ))
end
end
if status_html.present?
@ -178,7 +175,7 @@ module WidgetsHelper
html += content_tag :tr do
(content_tag :th, (_"forms.labels.generic.#{area}"), colspan: 2) +
(content_tag :th, status_html.html_safe, class: [:state, status_html.present? ? :unhappy : :happy])
admin_status(status_html, :th)
end
html += guest_rows
html += content_tag :tr, class: 'place-guest' do
@ -193,6 +190,14 @@ module WidgetsHelper
content_tag :table, html.html_safe, class: 'host-table'
end
def admin_notes(notes)
content_tag :div, (content_tag :div, paragraph(notes), class: 'notes').html_safe, class: 'admin-notes', tabindex: -1
end
def admin_status(status_html, tag = :div)
content_tag tag, status_html.html_safe, class: "admin-status state #{status_html.present? ? 'un' : ''}happy", tabindex: -1
end
def host_guests_widget(registration)
html = ''

44
app/views/conference_administration/_schedule.html.haml

@ -29,27 +29,29 @@
- workshop = status = nil
%td{class: [time_data[:type], workshop.present? ? :filled : :open], rowspan: rowspan, data: workshop.present? ? nil : { block: time_data[:item][:block], day: day, location: id }}
- if workshop.present? && workshop.event_location.present?
= link_to view_workshop_path(@conference.slug, workshop.id), class: 'event-detail-link' do
.details
.title=_!workshop.title
%template.event-details{data: { href: view_workshop_path(@conference.slug, workshop.id) }}
%h1.title=_!workshop.title
%p.address
= _!("#{workshop.event_location.title}:")
= location_link workshop.event_location
.workshop-description= richtext workshop.info, 1
- if @can_edit
= form_tag administration_update_path(conference.slug, @admin_step), class: 'deschedule-workshop' do
.status
.conflict-score
%span.title Conflicts:
%span.value="#{status[:conflict_score]} / #{workshop.interested.size}"
- if status[:errors].present?
.errors
- status[:errors].each do |error|
.error=_"errors.messages.schedule.#{error[:name].to_s}", vars: error[:i18nVars]
= hidden_field_tag :id, workshop.id
= button :deschedule, value: :deschedule_workshop, class: [:delete, :small]
.workshop-container
- if @can_edit
-if strip_tags(workshop.notes).strip.present?
= admin_notes(workshop.notes)
- if status[:errors].present?
= admin_status content_tag(:ul, (status[:errors].collect { |error| (_"errors.messages.schedule.#{error[:name].to_s}", vars: error[:i18nVars])}.join).html_safe).html_safe
= link_to view_workshop_path(@conference.slug, workshop.id), class: 'event-detail-link' do
.details
.title=_!workshop.title
%template.event-details{data: { href: view_workshop_path(@conference.slug, workshop.id) }}
%h1.title=_!workshop.title
%p.address
= _!("#{workshop.event_location.title}:")
= location_link workshop.event_location
.workshop-description= richtext workshop.info, 1
- if @can_edit
= form_tag administration_update_path(conference.slug, @admin_step), class: 'deschedule-workshop' do
.status
.conflict-score
%span.title Conflicts:
%span.value="#{status[:conflict_score]} / #{workshop.interested.size}"
= hidden_field_tag :id, workshop.id
= button :deschedule, value: :deschedule_workshop, class: [:delete, :small]
- elsif @can_edit
.title="Block #{time_data[:item][:block] + 1}"
- elsif time_data[:type] != :nil

4
config/locales/en.yml

@ -2630,6 +2630,10 @@ en:
projector: Projector
sound: Sound System
tools: Tools
amenity:
projector: a projector
sound: a sound system
tools: tools
space:
meeting_room: Meeting Room
outdoor_meeting: Outdoor Space

3
config/locales/fr.yml

@ -1716,6 +1716,9 @@ fr:
Leave: Se retirer
Make_Owner: Changer de responsable
Remove: Supprimer
conference:
edit_registration: Mon inscription
Translate: Modifier la version %{language}
datetime:
distance_in_words:
x_days:

Loading…
Cancel
Save