integración del editor :D

This commit is contained in:
f 2020-11-13 18:38:02 -03:00
parent ef66f6ad5a
commit d69fdfe364
7 changed files with 328 additions and 72 deletions

View file

@ -1,4 +1,4 @@
const origin = "http://panel.sutty.local:3000" || location.origin const origin = location.origin
function uploadFile (file) { function uploadFile (file) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -439,7 +439,7 @@ function stringifyAllowedStyle (element) {
return element.style.cssText return element.style.cssText
} }
document.addEventListener("DOMContentLoaded", () => { document.addEventListener("turbolinks:load", () => {
for (const editorEl of document.querySelectorAll(".editor")) { for (const editorEl of document.querySelectorAll(".editor")) {
setupEditor(editorEl) setupEditor(editorEl)
} }

View file

@ -1,11 +1,16 @@
//= require_tree .
$black: black; $black: black;
$white: white; $white: white;
$grey: grey; $grey: grey;
$cyan: #13fefe; $cyan: #13fefe;
$magenta: #f206f9; $magenta: #f206f9;
$colors: (
"black": $black,
"white": $white,
"cyan": $cyan,
"magenda": $magenta
);
// Redefinir variables de Bootstrap // Redefinir variables de Bootstrap
$primary: $magenta; $primary: $magenta;
$jumbotron-bg: transparent; $jumbotron-bg: transparent;
@ -16,6 +21,9 @@ $form-feedback-icon-valid-color: $black;
$component-active-bg: $magenta; $component-active-bg: $magenta;
@import "bootstrap"; @import "bootstrap";
@import "editor";
@import "actiontext";
@import "helpers";
:root { :root {
--foreground: #{$black}; --foreground: #{$black};

View file

@ -0,0 +1,187 @@
// Viene de sutty-base-jekyll-theme
$prefixes: ("", "-webkit-", "-ms-", "-o-", "-moz-");
$overflows: auto, hidden, scroll;
/*
* Usar en animaciones, empiezan rápido y desaceleran hacia el final.
*/
$bezier: cubic-bezier(0.75, 0, 0.25, 1);
/*
* Ocultar la barra de scroll, útil para sliders horizontales.
*/
.no-scrollbar {
scrollbar-width: none;
-webkit-overflow-scrolling: touch;
&::-webkit-scrollbar { display: none; }
}
@each $cursor in (pointer none) {
.cursor-#{$cursor} {
cursor: $cursor;
}
}
@each $direction in (top, right, bottom, left) {
.#{$direction}-0 {
#{$direction}: 0
}
}
@each $value in $overflows {
.overflow-#{$value} { overflow: $value !important; }
}
@each $axis in (y, x) {
@each $value in $overflows {
.overflow-#{$axis}-#{$value} { overflow-#{$axis}: $value !important; }
}
}
/*
* Poder aumentar o disminuir el alto de la tipografía, se usa de la
* misma forma que los modificadores de padding y margin.
*/
@each $size, $length in $spacers {
.f-#{$size} {
font-size: $length !important;
}
.text-column-#{$size} {
column-count: $size;
}
}
/*
* Modificadores de Bootstrap que no tienen versión responsive.
*/
@each $grid-breakpoint, $_ in $grid-breakpoints {
@include media-breakpoint-up($grid-breakpoint) {
// border
.border-#{$grid-breakpoint} { border: $border-width solid $border-color !important; }
.border-#{$grid-breakpoint}-top { border-top: $border-width solid $border-color !important; }
.border-#{$grid-breakpoint}-right { border-right: $border-width solid $border-color !important; }
.border-#{$grid-breakpoint}-bottom { border-bottom: $border-width solid $border-color !important; }
.border-#{$grid-breakpoint}-left { border-left: $border-width solid $border-color !important; }
.border-#{$grid-breakpoint}-0 { border: 0 !important; }
.border-#{$grid-breakpoint}-top-0 { border-top: 0 !important; }
.border-#{$grid-breakpoint}-right-0 { border-right: 0 !important; }
.border-#{$grid-breakpoint}-bottom-0 { border-bottom: 0 !important; }
.border-#{$grid-breakpoint}-left-0 { border-left: 0 !important; }
// alineación
.text-#{$grid-breakpoint}-left { text-align: left !important; }
.text-#{$grid-breakpoint}-right { text-align: right !important; }
.text-#{$grid-breakpoint}-center { text-align: center !important; }
// posición
@each $position in $positions {
.position-#{$grid-breakpoint}-#{$position} { position: $position !important; }
}
// anchos y altos
@each $prop, $abbrev in (width: w, height: h) {
@each $size, $length in $sizes {
.#{$abbrev}-#{$grid-breakpoint}-#{$size} { #{$prop}: $length !important; }
}
}
// versión responsive de f
@each $size, $length in $spacers {
.f-#{$grid-breakpoint}-#{$size} {
font-size: $length !important;
}
.text-column-#{$grid-breakpoint}-#{$size} {
column-count: $size;
}
}
}
}
/*
* Crea una propiedad con prefijos de navegador
*/
@mixin vendor-prefix($property, $definition...) {
@each $prefix in $prefixes {
#{$prefix}$property: $definition;
}
}
/*
* Crea clases para asignar colores según la lista de colores.
*/
@each $color, $_ in $colors {
.background-#{$color} {
background-color: var(--#{$color});
&:focus {
background-color: var(--#{$color});
}
}
.scrollbar-#{$color} {
scrollbar-color: var(--#{$color}) transparent;
scrollbar-width: thin;
&::-webkit-scrollbar {
width: 5px;
height: 8px;
background-color: transparent;
}
&::-webkit-scrollbar-thumb {
background: var(--#{$color});
}
}
.border-#{$color} {
border-color: var(--#{$color}) !important;
}
.hover-bg-#{$color} {
&:hover {
background-color: var(--#{$color});
}
}
.hover-#{$color} {
&:hover {
color: var(--#{$color});
}
}
.#{$color} {
color: var(--#{$color});
&:focus {
color: var(--#{$color});
}
::-moz-selection,
::selection {
background: var(--#{$color});
color: white;
}
svg {
* {
fill: var(--#{$color});
}
}
.form-control {
border-color: var(--#{$color});
color: var(--#{$color});
}
hr {
border-color: var(--#{$color});
}
a {
color: var(--#{$color});
}
}
}

View file

@ -1,63 +0,0 @@
= form_with do
.editor
.editor-toolbar
.editor-primary-toolbar
%button.btn{:data => {:button => "bold"}} Bold
%button.btn{:data => {:button => "italic"}} Italic
%button.btn{:data => {:button => "deleted"}} Deleted
%button.btn{:data => {:button => "underline"}} Underline
%button.btn{:data => {:button => "mark"}} Subrayar
%button.btn{:data => {:button => "h1"}} H1
%button.btn{:data => {:button => "h2"}} H2
%button.btn{:data => {:button => "h3"}} H3
%button.btn{:data => {:button => "h4"}} H4
%button.btn{:data => {:button => "h5"}} H5
%button.btn{:data => {:button => "h6"}} H6
%button.btn{:data => {:button => "ul"}} Lista desordenada
%button.btn{:data => {:button => "ol"}} Lista ordenada
%button.btn{:data => {:button => "left"}} Left
%button.btn{:data => {:button => "center"}} Center
%button.btn{:data => {:button => "right"}} Right
%button.btn{:data => {:button => "img"}} Imágen
%button.btn{:data => {:button => "video"}} Video
%button.btn{:data => {:button => "audio"}} Audio
%button.btn{:data => {:button => "pdf"}} PDF
// TODO: generar IDs para labels
// HAML cringe
.editor-auxiliary-toolbar{:data => {:editor => {:auxiliary => {:toolbar => ""}}}}
%div{:data => {:editor => {:auxiliary => "mark"}}}
%label{:for => "mark-color"} Color de resaltado:
%input{:type => "color", :data => {:prop => "mark-color"}}/
%div{:data => {:editor => {:auxiliary => "img"}}}
%label{:for => "img-file"} Archivo de la imágen:
%input{:type => "file", :data => {:prop => "img-file"}}/
%label{:for => "img-alt"} Descripción de imágen:
%input{:placeholder => "Un álbum", :type => "text", :data => {:prop => "img-alt"}}/
%div{:data => {:editor => {:auxiliary => "audio"}}}
%label{:for => "audio-file"} Archivo de la audio:
%input{:type => "file", :data => {:prop => "audio-file"}}/
%div{:data => {:editor => {:auxiliary => "video"}}}
%label{:for => "video-file"} Archivo de la video:
%input{:type => "file", :data => {:prop => "video-file"}}/
%div{:data => {:editor => {:auxiliary => "pdf"}}}
%label{:for => "pdf-file"} Archivo de la PDF:
%input{:type => "file", :data => {:prop => "pdf-file"}}/
%div{:data => {:editor => {:auxiliary => "link"}}}
%label{:for => "link-href"} URL de link:
%input{:type => "url", :data => {:prop => "link-href"}}/
.editor-content{:contenteditable => "true"}
%h1
Hola
%em mundo
%p Como te va?
%div{:data => {:align => "right"}}
%p Esto está a la derecha
%textarea{:cols => "80", :disabled => "disabled", :rows => "15"}

View file

@ -1,8 +1,72 @@
.form-group.markdown-content .form-group
= label_tag "post_#{attribute}", post_label_t(attribute, post: post) = label_tag "post_#{attribute}", post_label_t(attribute, post: post)
= render 'posts/attribute_feedback', = render 'posts/attribute_feedback',
post: post, attribute: attribute, metadata: metadata post: post, attribute: attribute, metadata: metadata
.editor
= text_area_tag "post[#{attribute}]", metadata.value, = text_area_tag "post[#{attribute}]", metadata.value,
dir: dir, lang: locale, dir: dir, lang: locale,
**field_options(attribute, metadata, class: 'content') **field_options(attribute, metadata), class: 'd-none'
.editor.mt-1
.editor-toolbar
.editor-primary-toolbar.scrollbar-black
%button.btn{ data: { button: 'bold' } }= t('editor.bold')
%button.btn{ data: { button: 'italic' } }= t('editor.italic')
%button.btn{ data: { button: 'deleted' } }= t('editor.deleted')
%button.btn{ data: { button: 'underline' } }= t('editor.underline')
%button.btn{ data: { button: 'mark' } }= t('editor.mark')
%button.btn{ data: { button: 'h1' } }= t('editor.h1')
%button.btn{ data: { button: 'h2' } }= t('editor.h2')
%button.btn{ data: { button: 'h3' } }= t('editor.h3')
%button.btn{ data: { button: 'h4' } }= t('editor.h4')
%button.btn{ data: { button: 'h5' } }= t('editor.h5')
%button.btn{ data: { button: 'h6' } }= t('editor.h6')
%button.btn{ data: { button: 'ul' } }= t('editor.ul')
%button.btn{ data: { button: 'ol' } }= t('editor.ol')
%button.btn{ data: { button: 'left' } }= t('editor.left')
%button.btn{ data: { button: 'center' } }= t('editor.center')
%button.btn{ data: { button: 'right' } }= t('editor.right')
%button.btn{ data: { button: 'img' } }= t('editor.img')
%button.btn{ data: { button: 'video' } }= t('editor.video')
%button.btn{ data: { button: 'audio' } }= t('editor.audio')
%button.btn{ data: { button: 'pdf' } }= t('editor.pdf')
-#
HAML cringe
TODO: generar IDs para labels
.editor-auxiliary-toolbar.scrollbar-black{ data: { editor: { auxiliary: { toolbar: '' } } } }
.form-group{ data: { editor: { auxiliary: 'mark' } } }
%label{ for: 'mark-color' }= t('editor.color')
%input{ type: 'color', data: { prop: 'mark-color' } }/
%div{ data: { editor: { auxiliary: 'img' } } }
.row
.col.form-group.d-flex.align-items-end
.custom-file
%input.custom-file-input{ type: 'file', data: { prop: 'img-file' }, accept: 'image/*' }/
%label.custom-file-label{ for: 'img-file' }= t('editor.file.img')
.col.form-group
%label{ for: 'img-alt' }= t('editor.description')
%input.form-control{ type: 'text', data: { prop: 'img-alt' } }/
-# https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Containers
.form-group{ data: { editor: { auxiliary: 'audio' } } }
.custom-file
%input.custom-file-input{ type: 'file', data: { prop: 'audio-file' }, accept: 'audio/flac,audio/mp4,audio/ogg,audio/webm,audio/mp3' }/
%label.custom-file-label{ for: 'audio-file' }= t('editor.file.audio')
.form-group{ data: { editor: { auxiliary: 'video' } } }
.custom-file
%input.custom-file-input{ type: 'file', data: { prop: 'video-file' }, accept: 'video/mp4,video/ogg,video/webm' }/
%label.custom-file-label{ for: 'video-file' }= t('editor.file.video')
.form-group{ data: { editor: { auxiliary: 'pdf' } } }
.custom-file
%input.custom-file-input{ type: 'file', data: { prop: 'pdf-file' }, accept: 'application/pdf' }/
%label.custom-file-label{ for: 'pdf-file' }= t('editor.file.pdf')
.form-group{ data: { editor: { auxiliary: 'link' } } }
%label{ for: 'link-href' }= t('editor.url')
%input.form-control{ type: 'url', data: { prop: 'link-href' } }/
.editor-content.form-control.h-auto{ contenteditable: 'true' }

View file

@ -551,3 +551,33 @@ en:
title: Encrypted content title: Encrypted content
description: The field contents are encrypted before being stored and won't be available on the public website or its source code. You can save private information here and it will only be readable to this site's users through Sutty's panel. description: The field contents are encrypted before being stored and won't be available on the public website or its source code. You can save private information here and it will only be readable to this site's users through Sutty's panel.
decryption_error: There was an error trying to decrypt the content, Sutty's team has been notified! decryption_error: There was an error trying to decrypt the content, Sutty's team has been notified!
editor:
bold: Bold
italic: Emphasis
deleted: Strikethrough
underline: Underline
mark: Mark
h1: Heading 1
h2: Heading 2
h3: Heading 3
h4: Heading 4
h5: Heading 5
h6: Heading 6
ul: Unordered list
ol: Ordered list
left: Left
right: Right
center: Center
img: Image
video: Video
audio: Audio
pdf: PDF
color: Color
img: Image
file:
img: Select and upload image
video: Select and upload video
audio: Select and upload audio
pdf: Select and upload PDF
description: Description for blind people and search engines
url: Address

View file

@ -564,3 +564,33 @@ es:
title: Contenido cifrado title: Contenido cifrado
description: El contenido de este campo se guarda cifrado y no estará disponible en el sitio ni en su código fuente. Puedes guardar información privada aquí y sólo estará disponible para quienes tengan acceso a ese sitio en el panel de Sutty. description: El contenido de este campo se guarda cifrado y no estará disponible en el sitio ni en su código fuente. Puedes guardar información privada aquí y sólo estará disponible para quienes tengan acceso a ese sitio en el panel de Sutty.
decryption_error: Hubo un error al decifrar la información, ¡el equipo de Sutty ya fue notificado! decryption_error: Hubo un error al decifrar la información, ¡el equipo de Sutty ya fue notificado!
editor:
bold: Fuerte
italic: Énfasis
deleted: Tachado
underline: Subrayado
mark: Resaltado
h1: Título 1
h2: Título 2
h3: Título 3
h4: Título 4
h5: Título 5
h6: Título 6
ul: Lista itemizada
ol: Lista numerada
left: Izquierda
right: Derecha
center: Centro
img: Imágen
video: Video
audio: Audio
pdf: PDF
color: Color
img: Imágen
file:
img: Seleccionar y subir imágen
video: Seleccionar y subir video
audio: Seleccionar y subir audio
pdf: Seleccionar y subir archivo PDF
description: Descripción para personas no videntes y buscadores
url: Dirección