deleted comments styling

This commit is contained in:
Luna D. 2024-06-06 20:21:21 +02:00
parent 8ca3902005
commit 4eeee71b48
No known key found for this signature in database
GPG key ID: 4B1C63448394F688
9 changed files with 236 additions and 136 deletions

View file

@ -6,7 +6,7 @@
} }
.button--$(type) a { .button--$(type) a {
color: var(--$(type)-link-color); color: inherit;
} }
.button--$(type).button--important { .button--$(type).button--important {
@ -17,7 +17,8 @@
.button--$(type):hover, .button--$(type):hover,
.button--$(type):active, .button--$(type):active,
.button--$(type).selected { .button--$(type).selected {
background: var(--$(type)-dark-color) !important; color: var(--text-color) !important;
background: var(--$(type)-dark-color);
border-radius: var(--border-radius-inner); border-radius: var(--border-radius-inner);
} }
@ -38,6 +39,63 @@
} }
} }
@define-mixin button-block-type $type {
.block--$(type) .button:not([class*="button--"]) {
color: var(--$(type)-link-color) !important;
border-color: var(--$(type)-border-color);
background: var(--$(type)-muted-color);
}
.block--$(type) .button:not([class*="button--"]) a {
color: inherit;
}
.block--$(type) .button--important:not([class*="button--"]) {
color: var(--text-color) !important;
background: var(--$(type)-color);
}
.block--$(type) .button:not([class*="button--"]):hover,
.block--$(type) .button:not([class*="button--"]):active,
.block--$(type) .button:not([class*="button--"]).selected {
color: var(--text-color) !important;
background: var(--$(type)-dark-color);
border-radius: var(--border-radius-inner);
}
.block--$(type) .button__group:not([class*="button--"]),
.block--$(type)
.button__group--single:not([class*="button--"])
.block--$(type)
.button__group--standalone:not([class*="button--"]) {
border-color: var(--$(type)-color);
background: var(--$(type)-dark-color);
}
.block--$(type) .button__group:not([class*="button--"]) a,
.block--$(type)
.button__group--single:not([class*="button--"])
a
.block--$(type)
.button__group--standalone:not([class*="button--"])
a {
color: var(--$(type)-link-color);
}
.block--$(type) .button__group:not([class*="button--"]) a:hover,
.block--$(type)
.button__group--single:not([class*="button--"])
a:hover
.block--$(type)
.button__group--standalone:not([class*="button--"])
a:hover {
@mixin animated-transition;
color: var(--text-color);
background: var(--$(type)-color);
border-radius: var(--border-radius-inner);
}
}
.button { .button {
@mixin animated-transition; @mixin animated-transition;
display: flex; display: flex;
@ -45,8 +103,8 @@
width: fit-content; width: fit-content;
font-weight: bold; font-weight: bold;
font-size: var(--font-size); font-size: var(--font-size);
background: var(--primary-dark-color); background: var(--primary-muted-color);
color: var(--text-color); color: var(--link-color);
border-radius: var(--border-radius-inner); border-radius: var(--border-radius-inner);
padding: 0 var(--padding-small); padding: 0 var(--padding-small);
overflow: hidden; overflow: hidden;
@ -58,6 +116,7 @@
.button:hover, .button:hover,
.button:active { .button:active {
@mixin animated-transition; @mixin animated-transition;
color: var(--text-color);
background: var(--primary-dark-color); background: var(--primary-dark-color);
border-radius: var(--border-radius-inner); border-radius: var(--border-radius-inner);
cursor: pointer; cursor: pointer;
@ -99,6 +158,7 @@
margin-right: var(--padding-normal); margin-right: var(--padding-normal);
background: var(--secondary-dark-color); background: var(--secondary-dark-color);
line-height: var(--button-group-height); line-height: var(--button-group-height);
padding: 0 var(--padding-small);
} }
.button__group:last-child, .button__group:last-child,
@ -115,11 +175,6 @@
line-height: var(--button-group-small-height); line-height: var(--button-group-small-height);
} }
.block__header__buttons .button {
color: var(--link-color);
border-width: 0 !important;
}
.button__group .button { .button__group .button {
border: 0; border: 0;
border-right: var(--secondary-color); border-right: var(--secondary-color);
@ -145,15 +200,19 @@
border-width: 0; border-width: 0;
} }
.block__header__buttons .button:hover { .button--transparent,
background: var(--primary-muted-color); .button--transparent:hover {
border-radius: var(--border-radius-inner);
}
.button--transparent {
background: 0 !important; background: 0 !important;
} }
@mixin button-block-type primary;
@mixin button-block-type secondary;
@mixin button-block-type success;
@mixin button-block-type warning;
@mixin button-block-type danger;
@mixin button-block-type information;
@mixin button-block-type special;
@mixin button-type primary; @mixin button-type primary;
@mixin button-type secondary; @mixin button-type secondary;
@mixin button-type success; @mixin button-type success;

View file

@ -105,6 +105,19 @@
white-space: nowrap; white-space: nowrap;
} }
.communication--deleted .communication__sender-block {
background: var(--danger-color);
}
.communication__body__text--deleted {
display: flex;
flex-flow: column;
margin-top: var(--padding-normal);
background: var(--danger-muted-color);
padding: var(--padding-normal) var(--padding-small);
gap: var(--padding-small);
}
@mixin if-mobile { @mixin if-mobile {
.communication__options { .communication__options {
flex-flow: column; flex-flow: column;
@ -146,4 +159,16 @@
flex-direction: column; flex-direction: column;
gap: var(--padding-small); gap: var(--padding-small);
} }
.communication__body__text--deleted {
margin-top: 0;
}
.communication__body__text--deleted:first-child {
margin-bottom: var(--padding-normal);
}
.communication--deleted > .communication__post-time {
background: var(--danger-dark-color);
}
} }

View file

@ -4,22 +4,20 @@
line-height: inherit; line-height: inherit;
} }
.pagination span { /* A hack to center icons */
padding: 0 var(--padding-small);
}
.pagination i { .pagination i {
font-size: 0.8rem !important; font-size: 0.8rem !important;
height: 0.7rem;
} }
.pagination a, .pagination a,
.pagination span { .pagination span {
display: grid; display: grid;
grid-template-columns: auto; grid-template-columns: auto;
gap: var(--padding-tiny); gap: var(--padding-small);
align-items: center; align-items: center;
padding: 0 var(--padding-small);
font-weight: bold; font-weight: bold;
padding: 0 var(--padding-small);
} }
.pagination .with-icon { .pagination .with-icon {

View file

@ -1,9 +1,8 @@
// This is a manifest file that'll be compiled into including all the files listed below. // This is the Vite entry point of Philomena's clientside code.
// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically // It is used as a sort of 'manifest' for what to include, and shouldn't
// be included in the compiled file accessible from http://example.com/assets/application.js // have any code on its own.
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
// //
// Only edit this file as described by the comment about CSS development below.
// Our code // Our code
import './ujs'; import './ujs';

View file

@ -1,6 +1,7 @@
- options = render PhilomenaWeb.CommentView, "_comment_link.html", comment: @comment, conn: @conn - options = render PhilomenaWeb.CommentView, "_comment_link.html", comment: @comment, conn: @conn
- block_class = if @comment.hidden_from_users, do: "block--danger", else: ""
article.block.communication id="comment_#{@comment.id}" article.block.communication id="comment_#{@comment.id}" class=block_class
= if not @comment.approved and not @comment.hidden_from_users and (can?(@conn, :hide, @comment) or @comment.user_id == @conn.assigns.current_user.id) do = if not @comment.approved and not @comment.hidden_from_users and (can?(@conn, :hide, @comment) or @comment.user_id == @conn.assigns.current_user.id) do
.block__content .block__content
.block.block--fixed.block--danger .block.block--fixed.block--danger
@ -26,38 +27,39 @@ article.block.communication id="comment_#{@comment.id}"
.block__content.flex.flex--no-wrap class=communication_body_class(@comment) .block__content.flex.flex--no-wrap class=communication_body_class(@comment)
= render PhilomenaWeb.CommunicationView, "_body.html", object: @comment, body: @body, conn: @conn, name: "comment", options: options = render PhilomenaWeb.CommunicationView, "_body.html", object: @comment, body: @body, conn: @conn, name: "comment", options: options
.block__content.communication__options = if not @comment.hidden_from_users or can?(@conn, :edit, @comment) do
.flex.flex--wrap.flex--spaced-out .block__content.communication__options
= render PhilomenaWeb.CommentView, "_comment_options.html", comment: @comment, conn: @conn .flex.flex--wrap.flex--spaced-out
= render PhilomenaWeb.CommentView, "_comment_options.html", comment: @comment, conn: @conn
= if can?(@conn, :hide, @comment) do = if can?(@conn, :hide, @comment) do
.flex__spacer .flex__spacer
.js-staff-action .js-staff-action
.communication__options__staff .communication__options__staff
= cond do = cond do
- @comment.hidden_from_users and not @comment.destroyed_content -> - @comment.hidden_from_users and not @comment.destroyed_content ->
= link(to: Routes.image_comment_hide_path(@conn, :delete, @comment.image_id, @comment), data: [confirm: "Are you sure?"], method: "delete", class: "communication__interaction") do = link(to: Routes.image_comment_hide_path(@conn, :delete, @comment.image_id, @comment), data: [confirm: "Are you sure?"], method: "delete", class: "communication__interaction") do
i.fas.fa-check> i.fas.fa-check>
' Restore ' Restore
= if can?(@conn, :delete, @comment) do = if can?(@conn, :delete, @comment) do
= link(to: Routes.image_comment_delete_path(@conn, :create, @comment.image_id, @comment), data: [confirm: "Are you sure?"], method: "post", class: "communication__interaction") do = link(to: Routes.image_comment_delete_path(@conn, :create, @comment.image_id, @comment), data: [confirm: "Are you sure?"], method: "post", class: "communication__interaction") do
i.fas.fa-times>
' Delete Contents
- not @comment.hidden_from_users and not @comment.destroyed_content ->
a.button.button--danger.button--transparent.togglable-delete-form-link href="#" data-click-toggle="#inline-del-form-comment-#{@comment.id}"
i.fas.fa-times> i.fas.fa-times>
' Delete Contents ' Delete
- not @comment.hidden_from_users and not @comment.destroyed_content -> - true ->
a.button.button--danger.button--transparent.togglable-delete-form-link href="#" data-click-toggle="#inline-del-form-comment-#{@comment.id}"
i.fas.fa-times>
' Delete
- true -> = if can?(@conn, :show, :ip_address) do
.button.button--warning.button--transparent.js-staff-action
=<> link_to_ip(@conn, @comment.ip)
.button.button--warning.button--transparent.js-staff-action
=<> link_to_fingerprint(@conn, @comment.fingerprint)
= if can?(@conn, :show, :ip_address) do = form_for :comment, Routes.image_comment_hide_path(@conn, :create, @comment.image_id, @comment), [class: "togglable-delete-form hidden flex", id: "inline-del-form-comment-#{@comment.id}"], fn f ->
.button.button--warning.button--transparent.js-staff-action = text_input f, :deletion_reason, class: "input input--wide", placeholder: "Deletion Reason", id: "inline-del-reason-comment-#{@comment.id}", required: true
=<> link_to_ip(@conn, @comment.ip) = submit "Delete", class: "button"
.button.button--warning.button--transparent.js-staff-action
=<> link_to_fingerprint(@conn, @comment.fingerprint)
= form_for :comment, Routes.image_comment_hide_path(@conn, :create, @comment.image_id, @comment), [class: "togglable-delete-form hidden flex", id: "inline-del-form-comment-#{@comment.id}"], fn f ->
= text_input f, :deletion_reason, class: "input input--wide", placeholder: "Deletion Reason", id: "inline-del-reason-comment-#{@comment.id}", required: true
= submit "Delete", class: "button"

View file

@ -1,23 +1,23 @@
.flex.flex--normal-gap.flex--centered = if not @comment.hidden_from_users or can?(@conn, :hide, @comment) do
- link_path = Routes.image_path(@conn, :show, @comment.image) <> "#comment_#{@comment.id}" .flex.flex--normal-gap.flex--centered
- safe_author = PhilomenaWeb.PostView.markdown_safe_author(@comment) = if not @comment.hidden_from_users do
- quote_body = if @comment.hidden_from_users, do: "", else: @comment.body - link_path = Routes.image_path(@conn, :show, @comment.image) <> "#comment_#{@comment.id}"
- safe_author = PhilomenaWeb.PostView.markdown_safe_author(@comment)
- quote_body = if @comment.hidden_from_users, do: "", else: @comment.body
a.button.button--primary href=Routes.image_comment_report_path(@conn, :new, @comment.image, @comment) a.button href=Routes.image_comment_report_path(@conn, :new, @comment.image, @comment)
i.fa.fa-flag> i.fa.fa-flag>
' Report ' Report
a.button.button--primary.post-reply.post-reply-quote href=link_path data-reply-url=link_path data-author=safe_author data-post=quote_body a.button.post-reply.post-reply-quote href=link_path data-reply-url=link_path data-author=safe_author data-post=quote_body
i.fa.fa-quote-right i.fa.fa-quote-right
' Quote ' Quote
a.button.button--primary.post-reply href=link_path data-reply-url=link_path data-author=safe_author a.button.post-reply href=link_path data-reply-url=link_path data-author=safe_author
i.fa.fa-reply i.fa.fa-reply
' Reply ' Reply
= if can?(@conn, :edit, @comment) do = if not @comment.destroyed_content and can?(@conn, :edit, @comment) do
span.owner-options a.button href=Routes.image_comment_path(@conn, :edit, @comment.image, @comment)
strong i.fas.fa-edit
a.button.button--primary href=Routes.image_comment_path(@conn, :edit, @comment.image, @comment) ' Edit
i.fas.fa-edit
' Edit

View file

@ -1,39 +1,41 @@
- options = render PhilomenaWeb.CommentView, "_comment_link.html", comment: @comment, conn: @conn - options = render PhilomenaWeb.CommentView, "_comment_link.html", comment: @comment, conn: @conn
- block_class = if @comment.hidden_from_users, do: "block--danger", else: ""
article.block.communication id="comment_#{@comment.id}" article.block.communication id="comment_#{@comment.id}" class=block_class
.block__content.flex.flex--no-wrap class=communication_body_class(@comment) .block__content.flex.flex--no-wrap class=communication_body_class(@comment)
= render PhilomenaWeb.CommunicationView, "_body.html", object: @comment, image: @comment.image, body: @body, conn: @conn, name: "comment", options: options = render PhilomenaWeb.CommunicationView, "_body.html", object: @comment, image: @comment.image, body: @body, conn: @conn, name: "comment", options: options
.block__content.communication__options = if not @comment.hidden_from_users or can?(@conn, :edit, @comment) do
.flex.flex--wrap.flex--spaced-out .block__content.communication__options
= render PhilomenaWeb.CommentView, "_comment_options.html", comment: @comment, conn: @conn .flex.flex--wrap.flex--spaced-out
= render PhilomenaWeb.CommentView, "_comment_options.html", comment: @comment, conn: @conn
= if can?(@conn, :hide, @comment) do = if can?(@conn, :hide, @comment) do
.flex.flex--normal-gap.flex--centered.js-staff-action .flex.flex--normal-gap.flex--centered.js-staff-action
= cond do = cond do
- @comment.hidden_from_users and not @comment.destroyed_content -> - @comment.hidden_from_users and not @comment.destroyed_content ->
= link(to: Routes.image_comment_hide_path(@conn, :delete, @comment.image_id, @comment), data: [confirm: "Are you sure?"], method: "delete", class: "button button--success") do = link(to: Routes.image_comment_hide_path(@conn, :delete, @comment.image_id, @comment), data: [confirm: "Are you sure?"], method: "delete", class: "button button--success") do
i.fas.fa-check> i.fas.fa-check>
' Restore ' Restore
= if can?(@conn, :delete, @comment) do = if can?(@conn, :delete, @comment) do
= link(to: Routes.image_comment_delete_path(@conn, :create, @comment.image_id, @comment), data: [confirm: "Are you sure?"], method: "post", class: "button button--danger button--transparent") do = link(to: Routes.image_comment_delete_path(@conn, :create, @comment.image_id, @comment), data: [confirm: "Are you sure?"], method: "post", class: "button button--danger button--transparent") do
i.fas.fa-times>
' Delete Contents
- not @comment.hidden_from_users and not @comment.destroyed_content ->
a.button.button--danger.button--transparent.togglable-delete-form-link href="#" data-click-toggle="#inline-del-form-comment-#{@comment.id}"
i.fas.fa-times> i.fas.fa-times>
' Delete Contents ' Delete
- not @comment.hidden_from_users and not @comment.destroyed_content -> - true ->
a.button.button--danger.button--transparent.togglable-delete-form-link href="#" data-click-toggle="#inline-del-form-comment-#{@comment.id}"
i.fas.fa-times>
' Delete
- true -> = if can?(@conn, :show, :ip_address) do
.button.button--warning.button--transparent.js-staff-action
=<> link_to_ip(@conn, @comment.ip)
.button.button--warning.button--transparent.js-staff-action
=<> link_to_fingerprint(@conn, @comment.fingerprint)
= if can?(@conn, :show, :ip_address) do = form_for :comment, Routes.image_comment_hide_path(@conn, :create, @comment.image_id, @comment), [class: "togglable-delete-form hidden flex", id: "inline-del-form-comment-#{@comment.id}"], fn f ->
.button.button--warning.button--transparent.js-staff-action = text_input f, :deletion_reason, class: "input input--wide", placeholder: "Deletion Reason", id: "inline-del-reason-comment-#{@comment.id}", required: true
=<> link_to_ip(@conn, @comment.ip) = submit "Delete", class: "button"
.button.button--warning.button--transparent.js-staff-action
=<> link_to_fingerprint(@conn, @comment.fingerprint)
= form_for :comment, Routes.image_comment_hide_path(@conn, :create, @comment.image_id, @comment), [class: "togglable-delete-form hidden flex", id: "inline-del-form-comment-#{@comment.id}"], fn f ->
= text_input f, :deletion_reason, class: "input input--wide", placeholder: "Deletion Reason", id: "inline-del-reason-comment-#{@comment.id}", required: true
= submit "Delete", class: "button"

View file

@ -1,5 +1,6 @@
- anon = is_nil(assigns[:noanon]) or @noanon == false - anon = is_nil(assigns[:noanon]) or @noanon == false
- options = if is_nil(assigns[:options]), do: "", else: @options - options = if is_nil(assigns[:options]), do: "", else: @options
- deleted = Map.has_key?(@object, :hidden_from_users) and @object.hidden_from_users == true
- avatar = cond do - avatar = cond do
- not is_nil(assigns[:image]) -> - not is_nil(assigns[:image]) ->
@ -20,27 +21,38 @@
- else - else
= render PhilomenaWeb.UserAttributionView, "_user_title.html", object: @object, conn: @conn = render PhilomenaWeb.UserAttributionView, "_user_title.html", object: @object, conn: @conn
- contents = if Map.has_key?(@object, :hidden_from_users) and @object.hidden_from_users == true do - contents = if deleted do
strong.comment_deleted = if @object.destroyed_content and can?(@conn, :hide, @object) do
' Deletion reason: div.communication__body__text--deleted
=<> @object.deletion_reason span
i.fa.fa-eye-slash>
strong
' Not shown to users, this
=> @name
| is destroyed.
div.communication__body__text--deleted
span
i.fa.fa-trash-can>
strong This #{@name} has been deleted.
span
i.fa.fa-circle-info>
strong Reason:
=<> @object.deletion_reason
= if can?(@conn, :hide, @object) and not is_nil(@object.deleted_by) do = if can?(@conn, :hide, @object) and not is_nil(@object.deleted_by) do
| ( span
= @object.deleted_by.name i.fa.fa-user>
| ) strong Moderator:
= if can?(@conn, :hide, @object) do =<> @object.deleted_by.name
= if @object.destroyed_content do = if not @object.destroyed_content and can?(@conn, :hide, @object) do
br =<> @body
strong.comment_deleted>
| This #{@name}'s contents have been destroyed.
- else
br
=<> @body
- else - else
=<> @body =<> @body
.flex.flex__grow.hidden--mobile - hidden_if_deleted = if deleted, do: "hidden", else: ""
.flex.flex__fixed.spacing--right - deleted_class = if deleted, do: "communication--deleted", else: ""
.flex.flex__grow.hidden--mobile class=deleted_class
.flex.flex__fixed.spacing--right class=hidden_if_deleted
= avatar = avatar
.flex__grow.communication__body .flex__grow.communication__body
.communication__sender-block .communication__sender-block
@ -51,16 +63,19 @@
' Posted ' Posted
=< pretty_time(@object.created_at) =< pretty_time(@object.created_at)
= options = options
= title div class=hidden_if_deleted
= title
.communication__body__text .communication__body__text
= contents = contents
.flex.flex__column.flex__grow.hidden--desktop .flex.flex__column.flex__grow.hidden--desktop class=deleted_class
.communication__sender-block .communication__sender-block
= avatar div class=hidden_if_deleted
= avatar
.flex__column.flex--small-gap .flex__column.flex--small-gap
span.communication__sender-name span.communication__sender-name
= username = username
= title div class=hidden_if_deleted
= title
span.communication__post-time span.communication__post-time
' Posted ' Posted
= pretty_time(@object.created_at) = pretty_time(@object.created_at)

View file

@ -4,11 +4,11 @@
nav.pagination.hidden--mobile nav.pagination.hidden--mobile
= if not first_page?(@page) do = if not first_page?(@page) do
= link to: first_page_path(@page, @route, params), class: "with-icon" do = link to: first_page_path(@page, @route, params), class: "with-icon" do
i.fa.fa-backward> i.fa.fa-angles-left>
' First ' First
.separator--vertical.separator--secondary .separator--vertical.separator--secondary
= link to: prev_page_path(@page, @route, params), class: "js-prev with-icon" do = link to: prev_page_path(@page, @route, params), class: "js-prev with-icon" do
i.fa.fa-chevron-left> i.fa.fa-angle-left>
' Prev ' Prev
.separator--vertical.separator--secondary .separator--vertical.separator--secondary
@ -32,29 +32,29 @@
.separator--vertical.separator--secondary .separator--vertical.separator--secondary
= link to: next_page_path(@page, @route, params), class: "js-next with-icon" do = link to: next_page_path(@page, @route, params), class: "js-next with-icon" do
' Next ' Next
i.fa.fa-chevron-right i.fa.fa-angle-right
.separator--vertical.separator--secondary .separator--vertical.separator--secondary
= link to: last_page_path(@page, @route, params), class: "with-icon" do = link to: last_page_path(@page, @route, params), class: "with-icon" do
' Last ' Last
i.fa.fa-fast-forward i.fa.fa-angles-right
nav.pagination.hidden--desktop nav.pagination.hidden--desktop
= if first_page?(@page) do = if first_page?(@page) do
span.with-icon span.with-icon
i.fa.fa-backward> i.fa.fa-angles-left>
' First ' First
.separator--vertical.separator--secondary .separator--vertical.separator--secondary
span.with-icon span.with-icon
i.fa.fa-chevron-left> i.fa.fa-angle-left>
' Prev ' Prev
.separator--vertical.separator--secondary .separator--vertical.separator--secondary
- else - else
= link to: first_page_path(@page, @route, params), class: "with-icon" do = link to: first_page_path(@page, @route, params), class: "with-icon" do
i.fa.fa-backward> i.fa.fa-angles-left>
' First ' First
.separator--vertical.separator--secondary .separator--vertical.separator--secondary
= link to: prev_page_path(@page, @route, params), class: "js-prev with-icon" do = link to: prev_page_path(@page, @route, params), class: "js-prev with-icon" do
i.fa.fa-chevron-left> i.fa.fa-angle-left>
' Prev ' Prev
.separator--vertical.separator--secondary .separator--vertical.separator--secondary
@ -84,17 +84,17 @@
.separator--vertical.separator--secondary .separator--vertical.separator--secondary
span.with-icon span.with-icon
' Next ' Next
i.fa.fa-chevron-right i.fa.fa-angle-right
.separator--vertical.separator--secondary .separator--vertical.separator--secondary
span.with-icon span.with-icon
' Last ' Last
i.fa.fa-fast-forward i.fa.fa-angles-right
- else - else
.separator--vertical.separator--secondary .separator--vertical.separator--secondary
= link to: next_page_path(@page, @route, params), class: "js-next with-icon" do = link to: next_page_path(@page, @route, params), class: "js-next with-icon" do
' Next ' Next
i.fa.fa-chevron-right i.fa.fa-angle-right
.separator--vertical.separator--secondary .separator--vertical.separator--secondary
= link to: last_page_path(@page, @route, params), class: "with-icon" do = link to: last_page_path(@page, @route, params), class: "with-icon" do
' Last ' Last
i.fa.fa-fast-forward i.fa.fa-angles-right