diff --git a/lib/models/Courseware/BlockTypes/Headline.json b/lib/models/Courseware/BlockTypes/Headline.json index c2b9a22f1b4537c78e9ca355de672b96c136c07c..1e759e478fc0a95aed7e123231746bf9bfe0b079 100644 --- a/lib/models/Courseware/BlockTypes/Headline.json +++ b/lib/models/Courseware/BlockTypes/Headline.json @@ -8,6 +8,9 @@ "subtitle": { "type": "string" }, + "second_subtitle": { + "type": "string" + }, "style": { "type": "string" }, @@ -17,6 +20,9 @@ "background_color": { "type": "string" }, + "gradient": { + "type": "string" + }, "background_image_id": { "type": "string" }, @@ -26,6 +32,9 @@ "text_color": { "type": "string" }, + "text_background_color": { + "type": "string" + }, "icon": { "type": "string" }, diff --git a/lib/models/Courseware/BlockTypes/Headline.php b/lib/models/Courseware/BlockTypes/Headline.php index d70390f7a5ba7685878e5bc0a8d2ae75c8fa125c..0c821386b82dee191489486bb10b5e2213596bc6 100644 --- a/lib/models/Courseware/BlockTypes/Headline.php +++ b/lib/models/Courseware/BlockTypes/Headline.php @@ -35,12 +35,15 @@ class Headline extends BlockType return [ 'title' => 'Courseware', 'subtitle' => '', + 'second_subtitle' => '', 'style' => 'bigicon_before', 'height' => 'half', 'background_color' => '#28497c', + 'gradient' => '', 'background_image_id' => '', 'background_type' => 'color', 'text_color' => '#ffffff', + 'text_background_color' => '#000000', 'icon' => 'learnmodule', 'icon_color' => 'white', ]; diff --git a/resources/assets/stylesheets/scss/courseware.scss b/resources/assets/stylesheets/scss/courseware.scss index ce2a2096bfd921972a46eed7e694469baabaf278..1d3c1fe948b56ce981e00ef18f2a023ced52bae5 100644 --- a/resources/assets/stylesheets/scss/courseware.scss +++ b/resources/assets/stylesheets/scss/courseware.scss @@ -1,3 +1,6 @@ +@import "courseware_gradients.scss"; + + /* definitions */ $companion-types: ( @@ -47,12 +50,23 @@ $tile-colors: ( ); $icon-colors:( + icon-white: #ffffff, + icon-black: #000000, icon-red: #cb1800, icon-blue: #24437c, icon-green: #00962d, icon-gray: #6e6e6e, icon-yellow: #ffad00 ); +$border-colors:( + white: #ffffff, + black: #000000, + studip-red: #cb1800, + studip-blue: #24437c, + studip-green: #00962d, + studip-gray: #6e6e6e, + studip-yellow: #ffad00 +); $blockadder-items: ( before-after: block-comparison, @@ -4191,6 +4205,10 @@ dialog cards block end /* headline block */ +$big-icon-size: 196; +$big-icon-size-px: $big-icon-size + px; +$large-icon-size: 128; +$large-icon-size-px: $large-icon-size + px; .cw-block-headline { .cw-block-headline-content { @@ -4204,21 +4222,42 @@ headline block min-height: 300px; } + &.quarter { + min-height: 150px; + } + &.heavy { - padding: 2em; - h1, h2 { - display: inline; - border: none; - padding: 0.25em 0; - } - h1 { - font-size: 10em; - line-height: 1.2em; + + .cw-block-headline-iconbox { + display: none; } - h2 { - font-size: 2em; - line-height: 1em; + .cw-block-headline-textbox { + margin: 2em; + h1, h2 { + display: inline; + border: none; + padding: 0.25em 0; + } + h1 { + font-size: 10em; + line-height: 1.2em; + } + h2 { + font-size: 2em; + line-height: 1em; + } + + &.quarter { + margin: 1.5em; + h1 { + font-size: 5em; + } + h2 { + font-size: 1.5em; + } + } } + } &.bigicon_top { .icon-layer { @@ -4226,27 +4265,30 @@ headline block background-position: center; margin-top: 8em; margin-bottom: 1em; - background-size: 196px; - height: 196px; + background-size: $big-icon-size-px; + height: $big-icon-size-px; @each $icon in $icons { &.icon-black-#{$icon} { - @include background-icon($icon, info, 196); + @include background-icon($icon, info, $big-icon-size); } &.icon-white-#{$icon} { - @include background-icon($icon, info-alt, 196); + @include background-icon($icon, info-alt, $big-icon-size); } &.icon-studip-blue-#{$icon} { - @include background-icon($icon, clickable, 196); + @include background-icon($icon, clickable, $big-icon-size); } &.icon-studip-red-#{$icon} { - @include background-icon($icon, status-red, 196); + @include background-icon($icon, status-red, $big-icon-size); } &.icon-studip-yellow-#{$icon} { - @include background-icon($icon, status-yellow, 196); + @include background-icon($icon, status-yellow, $big-icon-size); } &.icon-studip-green-#{$icon} { - @include background-icon($icon, status-green, 196); + @include background-icon($icon, status-green, $big-icon-size); + } + &.icon-studip-gray-#{$icon} { + @include background-icon($icon, inactive, $big-icon-size); } }; @@ -4257,6 +4299,13 @@ headline block margin-top: 2em; margin-bottom: 0; } + &.quarter { + height: 72px; + background-size: 72px; + background-position: center; + margin-top: 1em; + margin-bottom: 0; + } } .cw-block-headline-textbox { @@ -4279,40 +4328,64 @@ headline block margin-top: 10px; } } + + &.quarter { + padding-bottom: 1em; + .cw-block-headline-title { + h1 { + font-size: 2.25em; + margin: 0; + } + } + .cw-block-headline-subtitle { + h2 { + font-size: 1em; + margin: 0; + } + } + } } } &.bigicon_before { display: flex; align-items: center; - min-height: 600px; .icon-layer { - min-height: 196px; - min-width: 196px; + min-height: $big-icon-size-px; + min-width: $big-icon-size-px; margin:0 28px 0 28px; background-repeat: no-repeat; background-position: left center; @each $icon in $icons { &.icon-black-#{$icon} { - @include background-icon($icon, info, 196); + @include background-icon($icon, info, $big-icon-size); } &.icon-white-#{$icon} { - @include background-icon($icon, info-alt, 196); + @include background-icon($icon, info-alt, $big-icon-size); } &.icon-studip-blue-#{$icon} { - @include background-icon($icon, clickable, 196); + @include background-icon($icon, clickable, $big-icon-size); } &.icon-studip-red-#{$icon} { - @include background-icon($icon, status-red, 196); + @include background-icon($icon, status-red, $big-icon-size); } &.icon-studip-yellow-#{$icon} { - @include background-icon($icon, status-yellow, 196); + @include background-icon($icon, status-yellow, $big-icon-size); } &.icon-studip-green-#{$icon} { - @include background-icon($icon, status-green, 196); + @include background-icon($icon, status-green, $big-icon-size); + } + &.icon-studip-gray-#{$icon} { + @include background-icon($icon, inactive, $big-icon-size); } }; + + &.quarter { + min-height: $large-icon-size-px; + min-width: $large-icon-size-px; + background-size: $large-icon-size-px; + } } .cw-block-headline-textbox { @@ -4329,44 +4402,291 @@ headline block display: none; } } + } + + &.ribbon { + display: flex; + align-items: center; + + .cw-block-headline-textbox { + width: 100%; + padding: 1em 0; + margin: 3em 0; + background-color: fade-out($black, 0.5); + .cw-block-headline-title { + h1 { + border: none; + font-size: 5em; + text-align: center; + margin-bottom: 0; + } + } + + .cw-block-headline-subtitle { + h2 { + border: none; + font-size: 18px; + text-align: center; + margin-top: 10px; + } + } + } + } + + &.vertical { + .cw-block-headline-textbox { + + .cw-block-headline-title { + position: relative; + top: 0; + left: 5em; + height: 5em; + text-align: center; + width: 600px; + transform-origin: 0 0; + transform: rotate(90deg); + h1 { + text-transform: uppercase; + border: none; + font-size: 2em; + line-height: 2.5em; + } + } + .cw-block-headline-subtitle { + margin: 0 8em; + padding: 2em; + h2 { + margin: 0; + font-weight: 400; + } + } + } &.half { - min-height: 300px; + .cw-block-headline-title { + width: 300px; + } + } + &.quarter { + .cw-block-headline-title { + width: 150px; + h1 { + font-size: 1em; + line-height: 5em; + } + } + .cw-block-headline-subtitle { + margin: -2em 8em 0 8em; + padding: 1em; + } } } - &.ribbon { - display: flex; - align-items: center; - min-height: 600px; + &.skew_text { + min-height: 600px; - &.half { - min-height: 300px; + .cw-block-headline-textbox { + font-size: 7em; + text-align: left; + text-transform: uppercase; + font-weight: 800; + font-family: sans-serif; + font-style: normal; + letter-spacing: -6px; + margin: 1.25em 0 1.5em 1em; + div { + overflow: hidden; + font-size: 1em; + margin: -1px 0; + white-space: nowrap; + height: .8em; + width: calc(100% - 1em); + + h1, h2 { + font-size: 0.8em; + margin: 0; + white-space: nowrap; + overflow: hidden; + line-height: .8em; + height: .8em; + } } + .cw-block-headline-title, + .cw-block-headline-second-subtitle { + transform: skew(60deg,-15deg) scaley(.66667); + } + .cw-block-headline-subtitle { + transform: skew(0deg,-15deg) scaley(1.33333); + } + .cw-block-headline-subtitle { + position: relative; + left: 0.48em; + } + .cw-block-headline-second-subtitle { + position: relative; + left: 0.92em; + } + } + &.half { + min-height: 300px; + height: 300px; .cw-block-headline-textbox { - width: 100%; - padding: 1em 0; - margin: 3em 0; - background-color: fade-out($black, 0.5); - .cw-block-headline-title { + font-size: 4em; + margin: 1.5em 0 1.5em 1em; + div { + width: calc(100% - 9em); + } + } + } + &.quarter { + min-height: 150px; + height: 150px; + .cw-block-headline-textbox { + font-size: 2em; + margin: 0.75em 0 0.75em 1em; + letter-spacing: -2px; + div { + width: calc(100% - 18em); + } + } + } + } - h1 { - border: none; - font-size: 5em; - text-align: center; + &.icon_top_lines { + .cw-block-headline-iconbox { + margin: 32px; + &::before, + &::after { + width: calc(50% - 96px); + height: 64px; + display: inline-block; + border-top: solid 4px; + content: ''; + } + @each $name, $hex in $border-colors { + &.border-#{""+$name}::before, + &.border-#{""+$name}::after { + border-color: $hex; + } + } + .icon-layer { + background-repeat: no-repeat; + background-position: center; + background-size: 128px; + height: 128px; + width: 192px; + display: inline-block; + margin: auto; + + @each $icon in $icons { + &.icon-black-#{$icon} { + @include background-icon($icon, info, 128); + } + &.icon-white-#{$icon} { + @include background-icon($icon, info-alt, 128); + } + &.icon-studip-blue-#{$icon} { + @include background-icon($icon, clickable, 128); + } + &.icon-studip-red-#{$icon} { + @include background-icon($icon, status-red, 128); + } + &.icon-studip-yellow-#{$icon} { + @include background-icon($icon, status-yellow, 128); } + &.icon-studip-green-#{$icon} { + @include background-icon($icon, status-green, 128); + } + &.icon-studip-gray-#{$icon} { + @include background-icon($icon, inactive, 128); + } + }; + + &.half { + height: 128px; + background-size: 128px; + } + &.quarter { + height: 64px; + width: 96px; + background-size: 64px; } + } + &.half { + margin: 16px 32px; + } + &.quarter { + margin: 8px 32px 0 32px; + &::before, + &::after { + width: calc(50% - 48px); + height: 32px; + } + } + } + .cw-block-headline-textbox { + width: calc(100% - 64px); + margin-bottom: 64px; + min-height: 350px; + margin: 0 auto; + border-bottom: solid 4px; + @each $name, $hex in $border-colors { + &.border-#{""+$name} { + border-color: $hex; + } + } + .cw-block-headline-title { + h1 { + border: none; + font-size: 5em; + text-align: center; + } + } + .cw-block-headline-subtitle { + h2 { + border: none; + font-size: 18px; + text-align: center; + margin: 22px 64px; + } + } + + &.half { + min-height: 0px; + margin-bottom: 32px; + .cw-block-headline-title { + h1 { + font-size: 4em; + } + } + + .cw-block-headline-subtitle { + h2 { + font-size: 1em; + margin: 1em 64px; + } + } + } + &.quarter { + min-height: 0; + margin-bottom: 0; + border: none; + .cw-block-headline-title { + h1 { + font-size: 2em; + } + } + .cw-block-headline-subtitle { h2 { - border: none; - font-size: 18px; - text-align: center; - margin-top: 10px; + font-size: 1em; + margin: 8px 64px; } } } + } } } } @@ -4413,6 +4733,9 @@ headline block &.icon-studip-green-#{$icon} { @include background-icon($icon, status-green, 98); } + &.icon-studip-gray-#{$icon} { + @include background-icon($icon, inactive, 98); + } }; &.half { @@ -4465,6 +4788,9 @@ headline block &.icon-studip-green-#{$icon} { @include background-icon($icon, status-green, 92); } + &.icon-studip-gray-#{$icon} { + @include background-icon($icon, inactive, 92); + } }; } @@ -4519,6 +4845,13 @@ headline block font-size: 4em; } } + &.skew_text { + min-height: 300px; + .cw-block-headline-textbox { + font-size: 4em; + letter-spacing: -4px; + } + } } } } diff --git a/resources/assets/stylesheets/scss/courseware_gradients.scss b/resources/assets/stylesheets/scss/courseware_gradients.scss new file mode 100644 index 0000000000000000000000000000000000000000..97f8c7d889221492c1f9cfe5b95a297b9e964490 --- /dev/null +++ b/resources/assets/stylesheets/scss/courseware_gradients.scss @@ -0,0 +1,150 @@ +.faded-sun { + background: radial-gradient( + ellipse farthest-side at 76% 77%, + rgba(245, 228, 212, 0.25) 4%, + rgba(255, 255, 255, 0) calc(4% + 1px) + ), + radial-gradient(circle at 76% 40%, #fef6ec 4%, rgba(255, 255, 255, 0) 4.18%), + linear-gradient(135deg, #ff0000 0%, #000036 100%), + radial-gradient(ellipse at 28% 0%, #ffcfac 0%, rgba(98, 149, 144, 0.5) 100%), + linear-gradient(180deg, #cd6e8a 0%, #f5eab0 69%, #d6c8a2 70%, #a2758d 100%); + background-blend-mode: normal, normal, screen, overlay, normal; +} + +.romantic-sun { + background: linear-gradient(180deg, #ffb7b7 0%, #727272 100%), + radial-gradient(60.91% 100% at 50% 0%, #ffd1d1 0%, #260000 100%), + linear-gradient(238.72deg, #ffdddd 0%, #720066 100%), + linear-gradient(127.43deg, #00ffff 0%, #ff4444 100%), + radial-gradient(100.22% 100% at 70.57% 0%, #ff0000 0%, #00ffe0 100%), + linear-gradient(127.43deg, #b7d500 0%, #3300ff 100%); + background-blend-mode: screen, overlay, hard-light, color-burn, color-dodge, normal; +} + +.bright-rain { + background: radial-gradient(50% 123.47% at 50% 50%, #00ff94 0%, #720059 100%), + linear-gradient(121.28deg, #669600 0%, #ff0000 100%), + linear-gradient(360deg, #0029ff 0%, #8fff00 100%), + radial-gradient(100% 164.72% at 100% 100%, #6100ff 0%, #00ff57 100%), + radial-gradient(100% 148.07% at 0% 0%, #fff500 0%, #51d500 100%); + background-blend-mode: screen, color-dodge, overlay, difference, normal; +} + +.soft-weather { + background: radial-gradient(80.99% 100% at 50% 0%, #00ff0a 0%, #36008e 100%), + radial-gradient(50% 123.47% at 50% 50%, #efe7c8 0%, #36008e 100%), + linear-gradient(301.28deg, #ff006b 0%, #48dd9e 100%), + linear-gradient(294.84deg, #5a60e4 0%, #d30000 100%), + linear-gradient(52.29deg, #000000 0%, #00ff85 100%), + radial-gradient(100% 138.69% at 100% 0%, #0007a5 0%, #ff7a00 100%), + radial-gradient(70.41% 100% at 50% 0%, #d5b300 0%, #2200aa 100%); + background-blend-mode: screen, screen, lighten, overlay, lighten, difference, normal; +} + +.blue-bar { + background: linear-gradient( + 123deg, + #e7ebf1 0%, + #e7ebf1 40%, + #d4dbe5 calc(40% + 1px), + #d4dbe5 60%, + #7e92b0 calc(60% + 1px), + #7e92b0 75%, + #28497c calc(75% + 1px), + #28497c 100% + ); +} +.green-bar { + background: linear-gradient( + 123deg, + #c5dea0 0%, + #c5dea0 40%, + #8bbd40 calc(40% + 1px), + #8bbd40 60%, + #129c94 calc(60% + 1px), + #129c94 75%, + #66b570 calc(75% + 1px), + #66b570 100% + ); +} + +.paper { + background-image: repeating-linear-gradient(0deg, #d8dadc 0px, #d8dadc 1px, transparent 1px, transparent 23px), + repeating-linear-gradient(90deg, #d8dadc 0px, #d8dadc 1px, transparent 1px, transparent 23px), + linear-gradient(#ffffff, #ffffff); +} +.blueprint { + background: #28497c; + background-image: + radial-gradient(circle at center center, transparent 0%, #28497c 200%), + repeating-linear-gradient(0deg, #536d96 0px, #536d96 1px, transparent 1px, transparent 12px), + repeating-linear-gradient(90deg, #536d96 0px, #536d96 1px, transparent 1px, transparent 12px), + repeating-linear-gradient(0deg, #536d96 0px, #536d96 2px, transparent 1px, transparent 60px), + repeating-linear-gradient(90deg, #536d96 0px, #536d96 2px, transparent 1px, transparent 60px), + linear-gradient(#1f3f70, #1f3f70); +} + +.color-blue { + background: #28497c; + background: -webkit-linear-gradient(90deg, #28497c, #28497c, #7e92b0); + background: linear-gradient(90deg, #28497c, #28497c, #7e92b0); +} +.color-purple { + background: #682c8b; + background: -webkit-linear-gradient(90deg, #682c8b, #682c8b, #a480b9); + background: linear-gradient(90deg, #682c8b, #682c8b, #a480b9); +} +.color-violet { + background: #af2d7b; + background: -webkit-linear-gradient(90deg, #af2d7b, #af2d7b, #cf81b0); + background: linear-gradient(90deg, #af2d7b, #af2d7b, #cf81b0); +} +.color-red { + background: #d60000; + background: -webkit-linear-gradient(90deg, #d60000, #d60000, #e76666); + background: linear-gradient(90deg, #d60000, #d60000, #e76666); +} +.color-orange { + background: #f26e00; + background: -webkit-linear-gradient(90deg, #f26e00, #f26e00, #f7a866); + background: linear-gradient(90deg, #f26e00, #f26e00, #f7a866); +} +.color-yellow { + background: #ffbd33; + background: -webkit-linear-gradient(90deg, #ffbd33, #ffbd33, #ffd785); + background: linear-gradient(90deg, #ffbd33, #ffbd33, #ffd785); +} +.color-green { + background: #6ead10; + background: -webkit-linear-gradient(90deg, #6ead10, #6ead10, #a8ce70); + background: linear-gradient(90deg, #6ead10, #6ead10, #a8ce70); +} +.color-petrol { + background: #129c94; + background: -webkit-linear-gradient(90deg, #129c94, #129c94, #70c3bf); + background: linear-gradient(90deg, #129c94, #129c94, #70c3bf); +} +.color-grey { + background: #3c454e; + background: -webkit-linear-gradient(90deg, #3c454e, #3c454e, #898f94); + background: linear-gradient(90deg, #3c454e, #3c454e, #898f94); +} + +.grid { + background-image: radial-gradient(circle at center center, transparent 0%, #000000 95%), + repeating-linear-gradient( + 45deg, + #3c454e 0, + #3c454e 1px, + transparent 1px, + transparent 7px + ), + repeating-linear-gradient( + 135deg, + #3c454e 0, + #3c454e 1px, + transparent 1px, + transparent 14px + ), + linear-gradient(135deg, #000000, #000000); +} diff --git a/resources/vue/components/courseware/CoursewareHeadlineBlock.vue b/resources/vue/components/courseware/CoursewareHeadlineBlock.vue index 21179bf0aae408283c27f296283d8a7d0073d9bc..abce90bbce0cccc7db2d9e69da7d0e57d9670d40 100644 --- a/resources/vue/components/courseware/CoursewareHeadlineBlock.vue +++ b/resources/vue/components/courseware/CoursewareHeadlineBlock.vue @@ -12,154 +12,251 @@ <template #content> <div class="cw-block-headline-content" - :class="[currentStyle, currentHeight === 'half' ? 'half' : 'full']" + :class="[ + currentStyle, + currentHeight, + hasGradient ? currentGradient : '' + ]" :style="headlineStyle" > <div - class="icon-layer" - :class="['icon-' + currentIconColor + '-' + currentIcon, currentHeight === 'half' ? 'half' : 'full']" + class="cw-block-headline-iconbox" + :class="['border-' + currentIconColor, currentHeight]" > + <div + class="icon-layer" + :class="['icon-' + currentIconColor + '-' + currentIcon, currentHeight]" + > + </div> </div> - <div class="cw-block-headline-textbox"> - <div class="cw-block-headline-title"> + <div + class="cw-block-headline-textbox" + :class="['border-' + currentIconColor, currentHeight]" + :style="currentStyle === 'ribbon' ? headlineTextboxStyle.rgba : {}" + > + <div class="cw-block-headline-title" :style="currentStyle === 'vertical' ? headlineTextboxStyle.hex : {}"> <h1 :style="textStyle">{{ currentTitle }}</h1> </div> - <div class="cw-block-headline-subtitle"> + <div v-show="hasSubtitle && subtitleIsSet" class="cw-block-headline-subtitle" :style="currentStyle === 'vertical' ? headlineTextboxStyle.rgba : {}"> <h2 :style="textStyle">{{ currentSubtitle }}</h2> </div> + <div v-show="hasSecondSubtitle" class="cw-block-headline-second-subtitle"> + <h2 :style="textStyle">{{ currentSecondSubtitle }}</h2> + </div> </div> </div> </template> <template v-if="canEdit" #edit> - <form class="default" @submit.prevent=""> - <label> - <translate>Layout</translate> - <select v-model="currentStyle"> - <option value="heavy"><translate>Große Schrift</translate></option> - <option value="ribbon"><translate>Band</translate></option> - <option value="bigicon_top"><translate>Großes Icon oben</translate></option> - <option value="bigicon_before"><translate>Großes Icon davor</translate></option> - </select> - </label> - <label> - <translate>Höhe</translate> - <select v-model="currentHeight"> - <option value="full"><translate>Voll</translate></option> - <option value="half"><translate>Halb</translate></option> - </select> - </label> - <label> - <translate>Haupttitel</translate> - <input type="text" v-model="currentTitle" /> - </label> - <label v-if="hasSubtitle"> - <translate>Untertitel</translate> - <input type="text" v-model="currentSubtitle" /> - </label> - <label> - <translate>Textfarbe</translate> - <studip-select - :options="colors" - label="hex" - :reduce="color => color.hex" - :clearable="false" - v-model="currentTextColor" - > - <template #open-indicator="selectAttributes"> - <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span> - </template> - <template #no-options> - <translate>Es steht keine Auswahl zur Verfügung.</translate> - </template> - <template #selected-option="{name, hex}"> - <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span> - </template> - <template #option="{name, hex}"> - <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span> - </template> - </studip-select> - </label> - <label> - <translate>Icon</translate> - <studip-select :clearable="false" :options="icons" v-model="currentIcon"> - <template #open-indicator="selectAttributes"> - <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span> - </template> - <template #no-options> - <translate>Es steht keine Auswahl zur Verfügung.</translate> - </template> - <template #selected-option="option"> - <studip-icon :shape="option.label"/> <span class="vs__option-with-icon">{{option.label}}</span> - </template> - <template #option="option"> - <studip-icon :shape="option.label"/> <span class="vs__option-with-icon">{{option.label}}</span> - </template> - </studip-select> - </label> - <label> - <translate>Icon-Farbe</translate> - <studip-select - :options="iconColors" - label="name" - :reduce="iconColor => iconColor.class" - :clearable="false" - v-model="currentIconColor" - > - <template #open-indicator="selectAttributes"> - <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span> - </template> - <template #no-options> - <translate>Es steht keine Auswahl zur Verfügung.</translate> - </template> - <template #selected-option="{name, hex}"> - <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span> - </template> - <template #option="{name, hex}"> - <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span> - </template> - </studip-select> - </label> - <label> - <translate>Hintergrundtyp</translate> - <select v-model="currentBackgroundType"> - <option value="color"><translate>Farbe</translate></option> - <option value="image"><translate>Bild</translate></option> - </select> - </label> - <label v-if="currentBackgroundType === 'color'"> - <translate>Hintergrundfarbe</translate> - <studip-select - :options="colors" - label="hex" - :reduce="color => color.hex" - v-model="currentBackgroundColor" - :clearable="false" - > - <template #open-indicator="selectAttributes"> - <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span> - </template> - <template #no-options> - <translate>Es steht keine Auswahl zur Verfügung.</translate> - </template> - <template #selected-option="{name, hex}"> - <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span> - </template> - <template #option="{name, hex}"> - <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span> + <courseware-tabs> + <courseware-tab + :index="0" + :name="$gettext('Layout')" + :selected="true" + > + <form class="default" @submit.prevent=""> + <label> + {{ $gettext('Typ') }} + <select v-model="currentStyle"> + <option value="heavy">{{ $gettext('Große Schrift') }}</option> + <option value="ribbon">{{ $gettext('Band') }}</option> + <option value="vertical">{{ $gettext('Vertikal') }}</option> + <option value="bigicon_top">{{ $gettext('Großes Icon oben') }}</option> + <option value="bigicon_before">{{ $gettext('Großes Icon davor') }}</option> + <option value="icon_top_lines">{{ $gettext('Icon oben mit Linien') }}</option> + <option value="skew_text">{{ $gettext('Schief') }}</option> + </select> + </label> + <label> + {{ $gettext('Höhe') }} + <select v-model="currentHeight"> + <option value="full">{{ $gettext('Voll') }}</option> + <option value="half">{{ $gettext('Halb') }}</option> + <option value="quarter">{{ $gettext('Viertel') }}</option> + </select> + </label> + </form> + </courseware-tab> + <courseware-tab + :index="1" + :name="$gettext('Inhalt')" + > + <form class="default" @submit.prevent=""> + <label> + {{ $gettext('Haupttitel') }} + <input type="text" v-model="currentTitle" /> + </label> + <label v-if="hasSubtitle"> + {{ $gettext('Untertitel') }} + <input type="text" v-model="currentSubtitle" /> + </label> + <label v-if="hasSecondSubtitle"> + {{ $gettext('2. Untertitel') }} + <input type="text" v-model="currentSecondSubtitle" /> + </label> + <label> + {{ $gettext('Textfarbe') }} + <studip-select + :options="colors" + label="hex" + :reduce="color => color.hex" + :clearable="false" + v-model="currentTextColor" + > + <template #open-indicator="selectAttributes"> + <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span> + </template> + <template #no-options> + {{ $gettext('Es steht keine Auswahl zur Verfügung.') }} + </template> + <template #selected-option="{name, hex}"> + <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span> + </template> + <template #option="{name, hex}"> + <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span> + </template> + </studip-select> + </label> + <label v-if="hasTextBackgroundColor"> + {{ $gettext('Texthintergrundfarbe') }} + <studip-select + :options="colors" + label="hex" + :reduce="color => color.hex" + :clearable="false" + v-model="currentTextBackgroundColor" + > + <template #open-indicator="selectAttributes"> + <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span> + </template> + <template #no-options> + {{ $gettext('Es steht keine Auswahl zur Verfügung.') }} + </template> + <template #selected-option="{name, hex}"> + <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span> + </template> + <template #option="{name, hex}"> + <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span> + </template> + </studip-select> + </label> + <template v-if="hasIcon"> + <label> + {{ $gettext('Icon') }} + <studip-select :clearable="false" :options="icons" v-model="currentIcon"> + <template #open-indicator="selectAttributes"> + <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span> + </template> + <template #no-options> + {{ $gettext('Es steht keine Auswahl zur Verfügung.') }} + </template> + <template #selected-option="option"> + <studip-icon :shape="option.label"/> <span class="vs__option-with-icon">{{option.label}}</span> + </template> + <template #option="option"> + <studip-icon :shape="option.label"/> <span class="vs__option-with-icon">{{option.label}}</span> + </template> + </studip-select> + </label> + <label> + {{ $gettext('Icon-Farbe') }} + <studip-select + :options="iconColors" + label="name" + :reduce="iconColor => iconColor.class" + :clearable="false" + v-model="currentIconColor" + > + <template #open-indicator="selectAttributes"> + <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span> + </template> + <template #no-options> + {{ $gettext('Es steht keine Auswahl zur Verfügung.') }} + </template> + <template #selected-option="{name, hex}"> + <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span> + </template> + <template #option="{name, hex}"> + <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span> + </template> + </studip-select> + </label> </template> - </studip-select> - </label> - <label v-if="currentBackgroundType === 'image'"> - <translate>Hintergrundbild</translate> - <courseware-file-chooser - v-model="currentBackgroundImageId" - :isImage="true" - @selectFile="updateCurrentBackgroundImage" - /> - </label> - </form> + </form> + </courseware-tab> + <courseware-tab + :index="2" + :name="$gettext('Hintergrund')" + > + <form class="default" @submit.prevent=""> + <label> + {{ $gettext('Hintergrundtyp') }} + <select v-model="currentBackgroundType"> + <option value="color">{{ $gettext('Farbe') }}</option> + <option value="gradient">{{ $gettext('Farbverlauf') }}</option> + <option value="image">{{ $gettext('Bild') }}</option> + <option value="structural-element-image">{{ $gettext('Seiten-Bild') }}</option> + </select> + </label> + <label v-if="currentBackgroundType === 'color'"> + {{ $gettext('Hintergrundfarbe') }} + <studip-select + :options="colors" + label="hex" + :reduce="color => color.hex" + v-model="currentBackgroundColor" + :clearable="false" + > + <template #open-indicator="selectAttributes"> + <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span> + </template> + <template #no-options> + {{ $gettext('Es steht keine Auswahl zur Verfügung.') }} + </template> + <template #selected-option="{name, hex}"> + <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span> + </template> + <template #option="{name, hex}"> + <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span> + </template> + </studip-select> + </label> + <label v-if="currentBackgroundType === 'image'"> + {{ $gettext('Hintergrundbild') }} + <courseware-file-chooser + v-model="currentBackgroundImageId" + :isImage="true" + @selectFile="updateCurrentBackgroundImage" + /> + </label> + <label v-if="currentBackgroundType === 'gradient'"> + {{ $gettext('Hintergrundfarbverlauf') }} + <select v-model="currentGradient"> + <option value="color-blue">{{ $gettext('Blau') }}</option> + <option value="color-purple">{{ $gettext('Purpur') }}</option> + <option value="color-violet">{{ $gettext('Violet') }}</option> + <option value="color-red">{{ $gettext('Rot') }}</option> + <option value="color-orange">{{ $gettext('Orange') }}</option> + <option value="color-yellow">{{ $gettext('Gelb') }}</option> + <option value="color-green">{{ $gettext('Grün') }}</option> + <option value="color-petrol">{{ $gettext('Petrol') }}</option> + <option value="color-grey">{{ $gettext('Grau') }}</option> + <option value="paper">{{ $gettext('Papier') }}</option> + <option value="blueprint">{{ $gettext('Blueprint') }}</option> + <option value="grid">{{ $gettext('Gitter') }}</option> + <option value="blue-bar">{{ $gettext('Blaue Balken') }}</option> + <option value="green-bar">{{ $gettext('Grüne Balken') }}</option> + <option value="faded-sun">{{ $gettext('Faded Sun') }}</option> + <option value="romantic-sun">{{ $gettext('Romantic Sun') }}</option> + <option value="bright-rain">{{ $gettext('Bright Rain') }}</option> + <option value="soft-weather">{{ $gettext('Soft Weather') }}</option> + </select> + </label> + </form> + </courseware-tab> + </courseware-tabs> + </template> - <template #info><translate>Informationen zum Blickfang-Block</translate></template> + <template #info>{{ $gettext('Informationen zum Blickfang-Block') }}</template> </courseware-default-block> </div> </template> @@ -167,6 +264,8 @@ <script> import CoursewareDefaultBlock from './CoursewareDefaultBlock.vue'; import CoursewareFileChooser from './CoursewareFileChooser.vue'; +import CoursewareTabs from './CoursewareTabs.vue'; +import CoursewareTab from './CoursewareTab.vue'; import { blockMixin } from './block-mixin.js'; import colorMixin from '@/vue/mixins/courseware/colors.js'; import { mapGetters, mapActions } from 'vuex'; @@ -178,6 +277,8 @@ export default { components: { CoursewareDefaultBlock, CoursewareFileChooser, + CoursewareTabs, + CoursewareTab, }, props: { block: Object, @@ -188,16 +289,19 @@ export default { return { currentTitle: '', currentSubtitle: '', + currentSecondSubtitle: '', currentStyle: '', currentHeight: '', currentBackgroundColor: '', currentTextColor: '', + currentTextBackgroundColor: '', currentIcon: '', currentIconColor: '', currentBackgroundType: '', currentBackgroundImageId: '', currentBackgroundImage: {}, currentBackgroundURL: '', + currentGradient: '' }; }, computed: { @@ -205,6 +309,7 @@ export default { fileRefById: 'file-refs/byId', urlHelper: 'urlHelper', relatedTermOfUse: 'terms-of-use/related', + currentStructuralElementImageURL: 'currentStructuralElementImageURL' }), title() { return this.block?.attributes?.payload?.title; @@ -212,6 +317,9 @@ export default { subtitle() { return this.block?.attributes?.payload?.subtitle; }, + secondSubtitle() { + return this.block?.attributes?.payload?.second_subtitle; + }, style() { return this.block?.attributes?.payload?.style; }, @@ -221,9 +329,15 @@ export default { backgroundColor() { return this.block?.attributes?.payload?.background_color; }, + gradient() { + return this.block?.attributes?.payload?.gradient; + }, textColor() { return this.block?.attributes?.payload?.text_color; }, + textBackgroundColor() { + return this.block?.attributes?.payload?.text_background_color ?? '#000000'; + }, icon() { return this.block?.attributes?.payload?.icon; }, @@ -259,19 +373,50 @@ export default { }, headlineStyle() { let style = {}; - if (this.currentBackgroundType === 'color') { - style['background-color'] = this.currentBackgroundColor; - } + style['background-color'] = this.currentBackgroundColor; if (this.currentBackgroundType === 'image') { - style['background-color'] = this.currentBackgroundColor; style['background-image'] = 'url(' + this.currentBackgroundURL + ')'; + style['background-color'] = 'transparent'; + } + if (this.currentBackgroundType === 'structural-element-image') { + if (this.currentStructuralElementImageURL) { + style['background-image'] = 'url(' + this.currentStructuralElementImageURL + ')'; + style['background-color'] = 'transparent'; + } else { + style['background-color'] = '#28497c'; + } + + } + if (this.hasGradient) { + style['background-color'] = 'transparent'; } return style; }, + headlineTextboxStyle() { + return { + rgba: { 'background-color': this.hexToRgbA(this.currentTextBackgroundColor, '0.5') }, + hex: { 'background-color': this.currentTextBackgroundColor } + }; + }, hasSubtitle() { return !['bigicon_before'].includes(this.currentStyle); - } + }, + subtitleIsSet() { + return this.currentSubtitle !== ''; + }, + hasSecondSubtitle() { + return ['skew_text'].includes(this.currentStyle); + }, + hasIcon() { + return ['bigicon_top', 'bigicon_before', 'icon_top_lines'].includes(this.currentStyle); + }, + hasTextBackgroundColor() { + return ['ribbon', 'vertical'].includes(this.currentStyle); + }, + hasGradient() { + return this.currentBackgroundType === 'gradient'; + }, }, mounted() { this.initCurrentData(); @@ -284,10 +429,13 @@ export default { initCurrentData() { this.currentTitle = this.title; this.currentSubtitle = this.subtitle; + this.currentSecondSubtitle = this.secondSubtitle; this.currentStyle = this.style; this.currentHeight = this.height; this.currentBackgroundColor = this.backgroundColor; + this.currentGradient = this.gradient !== '' ? this.gradient : 'color-blue'; this.currentTextColor = this.textColor; + this.currentTextBackgroundColor = this.textBackgroundColor; this.currentIcon = this.icon; this.currentIconColor = this.iconColor; this.currentBackgroundType = this.backgroundType; @@ -323,13 +471,16 @@ export default { attributes.payload = {}; attributes.payload.title = this.currentTitle; attributes.payload.subtitle = this.currentSubtitle; + attributes.payload.second_subtitle = this.currentSecondSubtitle; attributes.payload.style = this.currentStyle; attributes.payload.height = this.currentHeight; attributes.payload.text_color = this.currentTextColor; + attributes.payload.text_background_color = this.currentTextBackgroundColor; attributes.payload.icon = this.currentIcon; attributes.payload.icon_color = this.currentIconColor; attributes.payload.background_type = this.currentBackgroundType; attributes.payload.background_color = ''; + attributes.payload.gradient = ''; attributes.payload.background_image_id = ''; if (this.currentBackgroundType === 'color') { @@ -338,6 +489,9 @@ export default { if (this.currentBackgroundType === 'image') { attributes.payload.background_image_id = this.currentBackgroundImageId; } + if (this.currentBackgroundType === 'gradient') { + attributes.payload.gradient = this.currentGradient; + } this.updateBlock({ attributes: attributes, @@ -346,12 +500,12 @@ export default { }); }, calcComplement(color) { - let RGB = this.calcRGB(color); + const RGB = this.calcRGB(color); return '#' + this.compToHex(255 - RGB.r) + this.compToHex(255 - RGB.g) + this.compToHex(255 - RGB.b); }, calcIconColor(color) { - let RGB = this.calcRGB(color); + const RGB = this.calcRGB(color); return (RGB.r + RGB.g + RGB.b) / 3 > 129 ? 'black' : 'white'; }, @@ -379,6 +533,11 @@ export default { let hex = comp.toString(16); return hex.length === 1 ? '0' + hex : hex; }, + hexToRgbA(hex, a){ + const RGB = this.calcRGB(hex); + + return 'rgba(' + RGB.r + ',' + RGB.g + ',' + RGB.b + ',' + a +')'; + } }, }; </script> diff --git a/resources/vue/store/courseware/courseware.module.js b/resources/vue/store/courseware/courseware.module.js index 5eb40a00855bb9764194d44e443ecb1fd04b3954..5c408b9c3f01dd08a9dd7124473dec72f807e2db 100644 --- a/resources/vue/store/courseware/courseware.module.js +++ b/resources/vue/store/courseware/courseware.module.js @@ -99,6 +99,9 @@ const getters = { currentElementisLink(state, getters, rootState, rootGetters) { return getters.currentStructuralElement?.attributes?.['is-link'] === 1; }, + currentStructuralElementImageURL(state, getters) { + return getters.currentStructuralElement?.relationships?.image?.meta?.['download-url']; + }, oerEnabled(state) { return state.oerEnabled; },