mirror of
https://github.com/aelve/guide.git
synced 2024-11-26 03:08:37 +03:00
Adaptation for mobile screens (#340)
* Consistent headings and paragraph styles for entire app * Search adopted for mobile * Category item adapted for mobile * Consistent category header icon sizes and paddings, relatively rest of category page * Hide logo when search input displayed on mobile * removed excess css rule * font size and line height changed * Badge adjusted for new font size * Lists margins added * Footer padding and margins adapted for mobile * Markdown editor correct focus on open * Markdown editor autofocus now optionabe * Typo fix * Markdown editor component more props and styling * Markdown editor border stylings * Conflict dialog refactor and adapting for mobiles * Typo fix * Categories page restyled and adapted for mobiles * Categories page group titles allow break words * Removed excess comparison
This commit is contained in:
parent
bff3cac46e
commit
613ecf8c9a
@ -43,21 +43,93 @@ export default class RootComponent extends Vue {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
*,
|
||||
*:before,
|
||||
*:after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
/*
|
||||
Formula is: calc(
|
||||
[min-font-size] +
|
||||
([max-font-size] - [min-font-size] * (100vw - [min-vw]) / ([max-vw] - [min-vw])
|
||||
);
|
||||
*/
|
||||
font-size: calc(16px + (18 - 16) * (100vw - 320px) / (1920 - 320));
|
||||
}
|
||||
:root {
|
||||
--h1-font-size: 1.8rem;
|
||||
--h2-font-size: 1.4rem;
|
||||
--h3-font-size: 1.17rem;
|
||||
--h4-font-size: 1rem;
|
||||
--h5-font-size: 0.83rem;
|
||||
--h6-font-size: 0.75rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: var(--h1-font-size);
|
||||
margin: 1.95rem 0 0.6rem;
|
||||
}
|
||||
h2 {
|
||||
font-size: var(--h2-font-size);
|
||||
margin: 1.65rem 0 0.45rem;
|
||||
}
|
||||
h3 {
|
||||
font-size: var(--h3-font-size);
|
||||
margin: 1.35rem 0 0.35rem;
|
||||
}
|
||||
h4 {
|
||||
font-size: var(--h4-font-size);
|
||||
margin: 1rem 0 0.25rem;
|
||||
}
|
||||
h5 {
|
||||
font-size: var(--h5-font-size);
|
||||
margin: 0.8rem 0 0.2rem;
|
||||
}
|
||||
h6 {
|
||||
font-size: var(--h6-font-size);
|
||||
margin: 0.5rem 0 0;
|
||||
}
|
||||
|
||||
.text-h1 {
|
||||
font-size: var(--h1-font-size);
|
||||
}
|
||||
.text-h2 {
|
||||
font-size: var(--h2-font-size);
|
||||
}
|
||||
.text-h3 {
|
||||
font-size: var(--h3-font-size);
|
||||
}
|
||||
.text-h4 {
|
||||
font-size: var(--h4-font-size);
|
||||
}
|
||||
.text-h5 {
|
||||
font-size: var(--h5-font-size);
|
||||
}
|
||||
.text-h6 {
|
||||
font-size: var(--h6-font-size);
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: 10px;
|
||||
margin: 0.2rem 0 1.2rem 0;
|
||||
}
|
||||
|
||||
ul,
|
||||
ol {
|
||||
margin: 0.8rem 0;
|
||||
}
|
||||
|
||||
ul > li:not(:last-child),
|
||||
ol > li:not(:last-child) {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
li p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
ul li:not(:last-child) {
|
||||
margin-bottom: 2px;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
code {
|
||||
color: inherit;
|
||||
text-decoration: inherit;
|
||||
@ -88,7 +160,7 @@ code.sourceCode {
|
||||
padding: 8px;
|
||||
}
|
||||
.sourceCode:not(:last-child) code.sourceCode {
|
||||
margin: 0 0 5px;
|
||||
margin: 0 0 0.2rem;
|
||||
}
|
||||
a {
|
||||
text-decoration-line: none;
|
||||
@ -157,5 +229,6 @@ blockquote {
|
||||
/* Should be same padding on any screen cause it changes with toolbar and we fixed toolbar's height (see Toolbar.vue) height on each screen */
|
||||
.app-content {
|
||||
padding: 64px 0px 0px !important;
|
||||
line-height: 150%;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<v-footer
|
||||
class="pa-2"
|
||||
height="auto"
|
||||
color="lighten-1"
|
||||
>
|
||||
@ -8,8 +9,9 @@
|
||||
align-center
|
||||
row
|
||||
wrap
|
||||
class="footer"
|
||||
>
|
||||
<span class="mr-3">
|
||||
<span>
|
||||
made by
|
||||
<a-link
|
||||
openInNewTab
|
||||
@ -18,7 +20,7 @@
|
||||
Aelve
|
||||
</a-link>
|
||||
</span>
|
||||
<span class="mr-3">
|
||||
<span>
|
||||
<a-link
|
||||
openInNewTab
|
||||
url="https://github.com/aelve/guide"
|
||||
@ -49,8 +51,15 @@ import Component from 'vue-class-component'
|
||||
export default class AFooter extends Vue { }
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style lang="postcss" scoped>
|
||||
.footer-link {
|
||||
display: inline-block;
|
||||
}
|
||||
.footer {
|
||||
margin-right: -10px;
|
||||
|
||||
> * {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -1,95 +1,75 @@
|
||||
<template>
|
||||
<v-container grid-list-md>
|
||||
<v-layout
|
||||
row
|
||||
wrap
|
||||
justify-space-between
|
||||
>
|
||||
<v-flex
|
||||
class="mr-3 mt-3"
|
||||
column
|
||||
xs12
|
||||
sm5
|
||||
md3
|
||||
lg3
|
||||
xl1
|
||||
<div class="categories">
|
||||
<div class="categories-flex-container">
|
||||
|
||||
<div
|
||||
class="categories-column"
|
||||
v-for="(groupCategories, groupName, index) in groups"
|
||||
:key="index"
|
||||
>
|
||||
<div class="category-group">
|
||||
<h4 class="mb-2 display-1 font-weight-black category-group-name">
|
||||
<h2 class="mt-0 mb-2 group-title">
|
||||
{{ groupName }}
|
||||
</h4>
|
||||
</h2>
|
||||
|
||||
<router-link
|
||||
class="category-title"
|
||||
class="category-title ml-2"
|
||||
v-for="category in groupCategories[CategoryStatus.finished]"
|
||||
:key="category.id"
|
||||
:to="`/haskell/${getCategoryUrl(category)}`"
|
||||
>
|
||||
<h6
|
||||
class="ml-2 subheading font-weight-bold"
|
||||
>
|
||||
{{ category.title }}
|
||||
</h6>
|
||||
{{ category.title }}
|
||||
</router-link>
|
||||
|
||||
<h6
|
||||
class="ml-2 mb-1 body-2 font-weight-bold"
|
||||
v-if="groupCategories[CategoryStatus.inProgress]"
|
||||
>
|
||||
In progress
|
||||
</h6>
|
||||
<router-link
|
||||
class="category-title ml-3"
|
||||
v-for="category in groupCategories[CategoryStatus.inProgress]"
|
||||
:key="category.id"
|
||||
:to="`/haskell/${getCategoryUrl(category)}`"
|
||||
>
|
||||
<h6
|
||||
class="ml-2 body-1 font-weight-bold"
|
||||
<template v-if="groupCategories[CategoryStatus.inProgress]">
|
||||
<h3 class="status-title">
|
||||
In progress
|
||||
</h3>
|
||||
<router-link
|
||||
class="category-title ml-3"
|
||||
v-for="category in groupCategories[CategoryStatus.inProgress]"
|
||||
:key="category.id"
|
||||
:to="`/haskell/${getCategoryUrl(category)}`"
|
||||
>
|
||||
{{ category.title }}
|
||||
</h6>
|
||||
</router-link>
|
||||
</router-link>
|
||||
</template>
|
||||
|
||||
<h6
|
||||
class="ml-2 mb-1 body-2 font-weight-bold"
|
||||
v-if="groupCategories[CategoryStatus.toBeWritten]"
|
||||
>
|
||||
To be written
|
||||
</h6>
|
||||
<router-link
|
||||
class="category-title ml-3"
|
||||
v-for="category in groupCategories[CategoryStatus.toBeWritten]"
|
||||
:key="category.id"
|
||||
:to="`/haskell/${getCategoryUrl(category)}`"
|
||||
>
|
||||
<h6
|
||||
class="ml-2 body-1 font-weight-bold"
|
||||
<template v-if="groupCategories[CategoryStatus.toBeWritten]">
|
||||
<h3 class="status-title">
|
||||
To be written
|
||||
</h3>
|
||||
|
||||
<router-link
|
||||
class="category-title ml-3"
|
||||
v-for="category in groupCategories[CategoryStatus.toBeWritten]"
|
||||
:key="category.id"
|
||||
:to="`/haskell/${getCategoryUrl(category)}`"
|
||||
>
|
||||
{{ category.title }}
|
||||
</h6>
|
||||
</router-link>
|
||||
</router-link>
|
||||
</template>
|
||||
|
||||
<v-btn
|
||||
class="ma-0 px-1"
|
||||
flat
|
||||
class="ma-0 mt-1 px-1"
|
||||
color="grey darken-2"
|
||||
title="Add new category"
|
||||
flat
|
||||
@click="openAddCategoryDialog(groupName)"
|
||||
>
|
||||
<v-icon size="14" class="mr-1" left>$vuetify.icons.plus</v-icon>
|
||||
Add new category
|
||||
</v-btn>
|
||||
</div>
|
||||
</v-flex>
|
||||
<add-category-dialog
|
||||
v-model="isAddGroupDialogOpen"
|
||||
:groupName="addCategoryGroupName"
|
||||
/>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<add-category-dialog
|
||||
v-model="isAddGroupDialogOpen"
|
||||
:groupName="addCategoryGroupName"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@ -145,15 +125,82 @@ export default class Categories extends Vue {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style lang="postcss" scoped>
|
||||
.categories {
|
||||
margin-top: 30px;
|
||||
}
|
||||
.categories-flex-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
margin: -15px -15px 0 0;
|
||||
padding: 0 100px;
|
||||
|
||||
&:after {
|
||||
content: "";
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1150px) {
|
||||
padding: 0 60px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 830px) {
|
||||
padding: 0 40px;
|
||||
}
|
||||
}
|
||||
.categories-column {
|
||||
margin: 15px 15px 0 0;
|
||||
flex-shrink: 0;
|
||||
flex-grow: 99999;
|
||||
|
||||
@media screen and (min-width: 1904px) {
|
||||
flex-basis: calc(20% - 15px * 5);
|
||||
max-width: calc(20% - 15px);
|
||||
}
|
||||
@media screen and (max-width: 1904px) {
|
||||
flex-basis: calc(25% - 15px * 4);
|
||||
max-width: calc(25% - 15px);
|
||||
}
|
||||
@media screen and (max-width: 1150px) {
|
||||
flex-basis: calc(33.33333% - 15px * 3);
|
||||
max-width: calc(33.33333% - 15px);
|
||||
}
|
||||
@media screen and (max-width: 830px) {
|
||||
flex-basis: calc(50% - 15px * 2);
|
||||
max-width: calc(50% - 15px);
|
||||
}
|
||||
@media screen and (max-width: 480px) {
|
||||
flex-basis: calc(100% - 15px * 1);
|
||||
max-width: calc(100% - 15px);
|
||||
}
|
||||
}
|
||||
.category-group {
|
||||
text-align: left;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: baseline;
|
||||
}
|
||||
.group-title {
|
||||
font-weight: 900;
|
||||
font-size: 1.6rem;
|
||||
max-width: 90%;
|
||||
word-break: break-word;
|
||||
}
|
||||
.category-title {
|
||||
display: block;
|
||||
line-height: 1.2;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
.category-title:not(:last-child) {
|
||||
margin-bottom: 5px;
|
||||
.category-title:not(:first-child) {
|
||||
margin-top: 5px;
|
||||
}
|
||||
.status-title {
|
||||
font-size: 0.9rem;
|
||||
margin: 4px 0 0 8px;
|
||||
line-height: 1.7;
|
||||
|
||||
+ .category-title {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -94,7 +94,7 @@ export default class Category extends Vue {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
@media screend and (max-width: 768px) {
|
||||
@media screen and (max-width: 768px) {
|
||||
.category-item {
|
||||
margin: 0 0 30px;
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
<div class="category-description">
|
||||
<div v-if="!editDescriptionShown">
|
||||
<p v-if="!categoryDescription">This category has no description yet, you can contribute to the category by adding description</p>
|
||||
<div class="description-content" v-else v-html="categoryDescription" />
|
||||
<div class="category-description__content" v-else v-html="categoryDescription" />
|
||||
</div>
|
||||
|
||||
<markdown-editor
|
||||
@ -44,7 +44,7 @@ import CatchConflictDecorator from 'client/helpers/CatchConflictDecorator'
|
||||
},
|
||||
mixins: [conflictDialogMixin]
|
||||
})
|
||||
export default class CategoryDescriptiom extends Vue {
|
||||
export default class CategoryDescription extends Vue {
|
||||
editDescriptionShown: boolean = false
|
||||
originalDescription: string = _get(this, '$store.state.category.category.description.text')
|
||||
modified: string = ''
|
||||
@ -95,24 +95,11 @@ export default class CategoryDescriptiom extends Vue {
|
||||
.category-description {
|
||||
margin: 0 0 40px;
|
||||
}
|
||||
|
||||
.category-description {
|
||||
font-size: 16px;
|
||||
.category-description__content > :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.category-description >>> {
|
||||
h1 {
|
||||
font-size: 1.4rem;
|
||||
margin: 15px 0;
|
||||
}
|
||||
h2 {
|
||||
font-size: 1.2rem;
|
||||
margin: 10px 0;
|
||||
}
|
||||
h3 {
|
||||
font-size: 1rem;
|
||||
margin: 5px 0;
|
||||
}
|
||||
.category-description__content > :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
@ -1,26 +1,25 @@
|
||||
<template>
|
||||
<div class="category-header">
|
||||
<h2 class="category-name-title" :title="categoryTitle">
|
||||
<h1 class="category-name-title" :title="categoryTitle">
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<a-link
|
||||
openInNewTab
|
||||
aria-label="RSS feed for all new items in this category"
|
||||
:url="`https://guide.aelve.com/haskell/feed/category/${categoryId}`"
|
||||
class="rss-link mr-1"
|
||||
class="rss-link"
|
||||
v-on="on"
|
||||
>
|
||||
<v-icon
|
||||
size="24"
|
||||
class="rss-link-icon"
|
||||
>$vuetify.icons.rss</v-icon>
|
||||
</a-link>
|
||||
</template>
|
||||
<span>RSS feed for all new items in this category</span>
|
||||
</v-tooltip>{{categoryTitle}}
|
||||
</h2>
|
||||
</h1>
|
||||
|
||||
<div style="display: flex; align-items: center; justify-content: space-between;">
|
||||
<div class="category-header__second-row">
|
||||
<div class="category-group-title-wrap">
|
||||
in <span :title="categoryGroup" class="category-group-title"> {{ categoryGroup }} </span>
|
||||
</div>
|
||||
@ -56,29 +55,27 @@
|
||||
>
|
||||
<v-icon
|
||||
color="grey darken-2"
|
||||
size="16"
|
||||
size="18"
|
||||
>$vuetify.icons.bars</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
<v-list>
|
||||
<v-list-tile class="category-actions-menu-item">
|
||||
<v-list class="category-actions-menu-list">
|
||||
<v-list-tile>
|
||||
<CategoryHeaderBtn
|
||||
text="New item"
|
||||
icon="plus"
|
||||
class="mr-1"
|
||||
@click="openAddItemDialog"
|
||||
/>
|
||||
</v-list-tile>
|
||||
<v-list-tile class="category-actions-menu-item">
|
||||
<v-list-tile>
|
||||
<CategoryHeaderBtn
|
||||
text="Category settings"
|
||||
icon="cog"
|
||||
class="mr-1"
|
||||
@click="openCategorySettingsEditDialog"
|
||||
/>
|
||||
</v-list-tile>
|
||||
<v-list-tile class="category-actions-menu-item">
|
||||
<v-list-tile>
|
||||
<CategoryHeaderBtn
|
||||
text="Delete category"
|
||||
icon="trash-alt"
|
||||
@ -161,37 +158,33 @@ export default class CategoryHeader extends Vue {
|
||||
}
|
||||
}
|
||||
.category-name-title {
|
||||
font-size: 28px;
|
||||
margin-bottom: 5px;
|
||||
font-size: 1.9rem;
|
||||
font-weight: 700;
|
||||
margin: 0 0 5px;
|
||||
letter-spacing: -1px;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
@media (max-width: 425px) {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.rss-link {
|
||||
/* For vertical aligning on one line with category title */
|
||||
font-size: 1px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.rss-link-icon {
|
||||
@media (max-width: 768px) {
|
||||
height: 20px !important;
|
||||
}
|
||||
@media (max-width: 425px) {
|
||||
height: 18px !important;
|
||||
}
|
||||
height: calc(1.8rem - 5px) !important;
|
||||
width: auto;
|
||||
|
||||
&:hover {
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
|
||||
.category-header__second-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.category-group-title-wrap {
|
||||
padding-left: 4px;
|
||||
white-space: nowrap;
|
||||
@ -202,7 +195,6 @@ export default class CategoryHeader extends Vue {
|
||||
|
||||
.category-group-title {
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.category-actions-menu-btn {
|
||||
@ -215,11 +207,10 @@ export default class CategoryHeader extends Vue {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.category-actions-menu-item {
|
||||
height: 36px;
|
||||
|
||||
.category-actions-menu-list {
|
||||
>>> .v-list__tile {
|
||||
height: 36px;
|
||||
padding: 0 6px;
|
||||
}
|
||||
|
||||
>>> button {
|
||||
|
@ -7,7 +7,7 @@
|
||||
v-bind="$attrs"
|
||||
v-on="$listeners"
|
||||
>
|
||||
<v-icon size="14" class="mr-1" left>{{`$vuetify.icons.${icon}`}}</v-icon>
|
||||
<v-icon size="18" class="mr-1">{{`$vuetify.icons.${icon}`}}</v-icon>
|
||||
{{ text }}
|
||||
</v-btn>
|
||||
</template>
|
||||
@ -28,8 +28,6 @@ export default class CategoryHeaderBtn extends Vue {
|
||||
.category-header-btn {
|
||||
margin: 0;
|
||||
padding: 0 4px;
|
||||
height: 28px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
|
@ -23,7 +23,7 @@
|
||||
@save="updateSummary({original: summary.text, modified: $event})"
|
||||
>
|
||||
<div
|
||||
class="mb-2 category-item-summary"
|
||||
class="mb-2"
|
||||
v-html="summary.html"
|
||||
/>
|
||||
</category-item-section>
|
||||
@ -212,23 +212,11 @@ export default class CategoryItem extends Vue {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style lang="postcss" scoped>
|
||||
.category-item-body {
|
||||
padding: 15px 20px;
|
||||
}
|
||||
|
||||
.category-item-body >>> p {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.category-item-body >>> li {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.category-item-summary >>> h1 {
|
||||
margin: 25px 0 5px;
|
||||
}
|
||||
|
||||
.category-item {
|
||||
position: relative;
|
||||
background: #eeeeee;
|
||||
@ -237,6 +225,7 @@ export default class CategoryItem extends Vue {
|
||||
|
||||
.category-item-traits {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.category-item-traits > * {
|
||||
@ -246,14 +235,21 @@ export default class CategoryItem extends Vue {
|
||||
|
||||
.category-item-traits > *:not(:last-child) {
|
||||
margin-right: 20px;
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media screend and (max-width: 768px) {
|
||||
@media screen and (max-width: 768px) {
|
||||
.category-item-body {
|
||||
width: 100%;
|
||||
}
|
||||
.category-item {
|
||||
margin: 0 0 30px;
|
||||
}
|
||||
.category-item-traits {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -1,16 +1,21 @@
|
||||
<template>
|
||||
<v-btn
|
||||
:icon="!!icon"
|
||||
class="ma-0"
|
||||
:icon="!!icon && !showTitle"
|
||||
flat
|
||||
class="ma-0 font-weight-bold"
|
||||
color="grey darken-2"
|
||||
:style="style"
|
||||
:title="title"
|
||||
v-bind="$attrs"
|
||||
v-on="$listeners"
|
||||
>
|
||||
<v-icon
|
||||
v-if="icon"
|
||||
color="grey darken-2"
|
||||
:class="{ 'mr-1': showTitle }"
|
||||
:size="iconSizeValue"
|
||||
>{{ iconText }}</v-icon>
|
||||
<template v-if="showTitle"> {{ title }} </template>
|
||||
<slot />
|
||||
</v-btn>
|
||||
</template>
|
||||
@ -27,6 +32,8 @@ export default class CategoryItemBtn extends Vue {
|
||||
@Prop(Boolean) small: boolean
|
||||
@Prop(String) size: string
|
||||
@Prop(String) iconSize: string
|
||||
@Prop(String) title: string
|
||||
@Prop(Boolean) showTitle: boolean
|
||||
|
||||
get style () {
|
||||
// Size prop overlaps small prop
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="category-item-section">
|
||||
<h3 class="category-item-section__title title font-weight-bold mb-1">
|
||||
<h3 class="category-item-section__title title font-weight-bold mb-1 mt-0">
|
||||
{{ title }}
|
||||
<category-item-btn
|
||||
small
|
||||
|
@ -11,71 +11,168 @@
|
||||
class="elevation-2"
|
||||
@click.stop=""
|
||||
>
|
||||
<v-toolbar-title class="headline">
|
||||
<router-link
|
||||
:to="{hash:`item-${itemUid}`}"
|
||||
class="category-item-anchor"
|
||||
>#</router-link> <a-link
|
||||
v-if="itemLink"
|
||||
:url="itemLink"
|
||||
openInNewTab
|
||||
>{{ itemName }}</a-link>
|
||||
<span v-else>{{ itemName }}</span><template v-if="this.itemHackage"> (<a
|
||||
target="_blank"
|
||||
:href="`https://hackage.haskell.org/package/${this.itemHackage}`"
|
||||
>Hackage</a>)</template>
|
||||
<v-toolbar-title class="text-h2">
|
||||
<span class="category-item-toolbar-title">
|
||||
<router-link
|
||||
:to="{hash:`item-${itemUid}`}"
|
||||
class="category-item-anchor"
|
||||
>#</router-link>
|
||||
|
||||
<div class="category-item-name-and-badges">
|
||||
<a-link
|
||||
v-if="itemLink"
|
||||
class="category-item-name"
|
||||
:url="itemLink"
|
||||
openInNewTab
|
||||
>{{ itemName }}</a-link>
|
||||
<span class="category-item-name" v-else>{{ itemName }}</span>
|
||||
|
||||
<div class="category-item-badges">
|
||||
<a
|
||||
v-if="this.itemHackage"
|
||||
class="text-h6 hackage-link"
|
||||
target="_blank"
|
||||
:href="`https://hackage.haskell.org/package/${this.itemHackage}`"
|
||||
>
|
||||
<v-icon
|
||||
color="#fff"
|
||||
class="mr-1"
|
||||
size="12"
|
||||
>$vuetify.icons.link</v-icon>hackage</a>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</v-toolbar-title>
|
||||
|
||||
<v-spacer></v-spacer>
|
||||
<v-toolbar-items class="category-item-toolbar-btns">
|
||||
<category-item-btn
|
||||
title="Move item up"
|
||||
icon="arrow-up"
|
||||
@click="moveItem('up')"
|
||||
/>
|
||||
|
||||
<category-item-btn
|
||||
title="Move item down"
|
||||
icon="arrow-down"
|
||||
@click="moveItem('down')"
|
||||
/>
|
||||
<v-toolbar-items>
|
||||
<div class="category-item-toolbar-btns">
|
||||
<category-item-btn
|
||||
iconSize="18"
|
||||
title="Move item up"
|
||||
icon="arrow-up"
|
||||
@click="moveItem('up')"
|
||||
/>
|
||||
<category-item-btn
|
||||
iconSize="18"
|
||||
title="Move item down"
|
||||
icon="arrow-down"
|
||||
@click="moveItem('down')"
|
||||
/>
|
||||
<category-item-btn
|
||||
iconSize="18"
|
||||
title="Edit item info"
|
||||
icon="cog"
|
||||
@click="toggleEditItemInfoMenu"
|
||||
>
|
||||
<v-icon
|
||||
v-if="isItemInfoEdited"
|
||||
class="unsaved-changes-icon"
|
||||
color="#6495ed"
|
||||
size="8"
|
||||
>$vuetify.icons.circle</v-icon>
|
||||
</category-item-btn>
|
||||
|
||||
<category-item-btn
|
||||
title="Edit item info"
|
||||
icon="cog"
|
||||
@click="toggleEditItemInfoMenu"
|
||||
>
|
||||
<v-icon
|
||||
v-if="isItemInfoEdited"
|
||||
class="edit-item-info-changed-icon"
|
||||
color="#6495ed"
|
||||
size="8"
|
||||
>$vuetify.icons.circle</v-icon>
|
||||
</category-item-btn>
|
||||
<category-item-btn
|
||||
iconSize="18"
|
||||
title="Delete item"
|
||||
icon="trash-alt"
|
||||
@click="deleteItem"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<category-item-btn
|
||||
title="Delete item"
|
||||
icon="trash-alt"
|
||||
@click="deleteItem"
|
||||
/>
|
||||
<v-menu bottom left offset-y>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-btn
|
||||
flat
|
||||
icon
|
||||
title="Actions"
|
||||
class="category-toolbar-mobile-menu-btn"
|
||||
v-on="on"
|
||||
>
|
||||
<v-icon
|
||||
size="18"
|
||||
color="grey darken-2"
|
||||
>$vuetify.icons.bars</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
<v-list class="category-item-toolbar-mobile-menu-list">
|
||||
<v-list-tile>
|
||||
<category-item-btn
|
||||
showTitle
|
||||
iconSize="18"
|
||||
title="Move item up"
|
||||
icon="arrow-up"
|
||||
@click="moveItem('up')"
|
||||
/>
|
||||
</v-list-tile>
|
||||
<v-list-tile>
|
||||
<category-item-btn
|
||||
showTitle
|
||||
iconSize="18"
|
||||
title="Move item down"
|
||||
icon="arrow-down"
|
||||
@click="moveItem('down')"
|
||||
/>
|
||||
</v-list-tile>
|
||||
<v-list-tile>
|
||||
<category-item-btn
|
||||
showTitle
|
||||
iconSize="18"
|
||||
title="Edit item info"
|
||||
icon="cog"
|
||||
@click="toggleEditItemInfoMenu"
|
||||
>
|
||||
<v-icon
|
||||
v-if="isItemInfoEdited"
|
||||
class="unsaved-changes-icon"
|
||||
color="#6495ed"
|
||||
size="8"
|
||||
>$vuetify.icons.circle</v-icon>
|
||||
</category-item-btn>
|
||||
</v-list-tile>
|
||||
<v-list-tile>
|
||||
<category-item-btn
|
||||
showTitle
|
||||
iconSize="18"
|
||||
title="Delete item"
|
||||
icon="trash-alt"
|
||||
@click="deleteItem"
|
||||
/>
|
||||
</v-list-tile>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-toolbar-items>
|
||||
</v-toolbar>
|
||||
|
||||
<v-layout column class="pa-3">
|
||||
<v-flex>
|
||||
<v-text-field
|
||||
v-model="itemNameEdit"
|
||||
label="Name"
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="itemHackageEdit"
|
||||
label="Name on Hackage (optional)"
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="itemLinkEdit"
|
||||
label="Site (optional)"
|
||||
/>
|
||||
<v-form @keydown.native.enter.ctrl="updateItemInfo">
|
||||
<v-text-field
|
||||
v-model="itemNameEdit"
|
||||
label="Name"
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="itemHackageEdit"
|
||||
label="Name on Hackage (optional)"
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="itemLinkEdit"
|
||||
label="Site (optional)"
|
||||
/>
|
||||
</v-form>
|
||||
</v-flex>
|
||||
<v-flex align-self-end>
|
||||
<v-btn
|
||||
title="Cancel"
|
||||
@click="resetAndToggleEditItemInfoMenu"
|
||||
>
|
||||
Cancel
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="info"
|
||||
class="mr-0"
|
||||
title="Save"
|
||||
:disabled="!isInfoSaveEnabled"
|
||||
@ -135,7 +232,17 @@ export default class CategoryItemToolbar extends Vue {
|
||||
this.isEditItemInfoMenuOpen = !this.isEditItemInfoMenuOpen
|
||||
}
|
||||
|
||||
resetAndToggleEditItemInfoMenu () {
|
||||
this.itemNameEdit = this.itemName
|
||||
this.itemLinkEdit = this.itemLink
|
||||
this.itemHackageEdit = this.itemHackage
|
||||
this.toggleEditItemInfoMenu()
|
||||
}
|
||||
|
||||
async updateItemInfo (): Promise<void> {
|
||||
if (!this.isInfoSaveEnabled) {
|
||||
return
|
||||
}
|
||||
await this.$store.dispatch('categoryItem/updateItemInfo', {
|
||||
id: this.itemUid,
|
||||
body: {
|
||||
@ -172,31 +279,128 @@ export default class CategoryItemToolbar extends Vue {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style lang="postcss" scoped>
|
||||
.category-item-toolbar {
|
||||
display: flex;
|
||||
margin: 0;
|
||||
box-shadow: none;
|
||||
|
||||
>>> {
|
||||
.v-toolbar__content {
|
||||
justify-content: space-between;
|
||||
height: auto !important;
|
||||
min-height: 56px;
|
||||
|
||||
.v-toolbar__title {
|
||||
flex-wrap: wrap;
|
||||
flex: 1;
|
||||
overflow: visible;
|
||||
padding: 12px 0;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.v-toolbar__items {
|
||||
height: 100%;
|
||||
margin-top: 10px;
|
||||
align-self: baseline;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 959px) {
|
||||
padding: 0 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.v-expansion-panel__header {
|
||||
padding: 0;
|
||||
align-items: center;
|
||||
cursor: unset;
|
||||
}
|
||||
|
||||
.v-expansion-panel__body {
|
||||
background: rgb(222, 222, 222);
|
||||
}
|
||||
}
|
||||
}
|
||||
.category-item-toolbar-title {
|
||||
display: inline-flex;
|
||||
}
|
||||
.category-item-anchor {
|
||||
color: rgb(151, 151, 151);
|
||||
}
|
||||
.edit-item-info-changed-icon {
|
||||
.category-item-name-and-badges {
|
||||
margin-left: 0.4rem;
|
||||
}
|
||||
.category-item-name {
|
||||
white-space: pre-line;
|
||||
word-break: break-word;
|
||||
}
|
||||
.category-item-badges {
|
||||
display: inline-block;
|
||||
margin-left: 8px;
|
||||
|
||||
> * {
|
||||
vertical-align: middle;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 0.1px 5px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.hackage-link {
|
||||
background: #5e5184;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
.unsaved-changes-icon {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 5px;
|
||||
}
|
||||
.category-item-toolbar >>> .v-toolbar__title {
|
||||
overflow: visible;
|
||||
}
|
||||
.category-item-toolbar {
|
||||
|
||||
.category-item-toolbar-btns {
|
||||
display: flex;
|
||||
box-shadow: none;
|
||||
}
|
||||
.category-item-toolbar >>> .v-expansion-panel__header {
|
||||
padding: 0;
|
||||
align-items: center;
|
||||
cursor: unset;
|
||||
flex: 1;
|
||||
}
|
||||
.category-item-toolbar >>> .v-expansion-panel__body {
|
||||
background: #d6d6d6;
|
||||
.category-toolbar-mobile-menu-btn {
|
||||
display: none;
|
||||
margin: 0;
|
||||
}
|
||||
.category-item-toolbar-btns > * {
|
||||
margin: 0 2px;
|
||||
|
||||
.category-item-toolbar-mobile-menu-list {
|
||||
>>> .v-list__tile {
|
||||
height: 36px;
|
||||
padding: 0 6px;
|
||||
}
|
||||
|
||||
>>> button {
|
||||
width: 100%;
|
||||
padding: 5px;
|
||||
|
||||
.v-btn__content {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.category-toolbar-mobile-menu-btn {
|
||||
display: block;
|
||||
}
|
||||
.category-item-toolbar-btns {
|
||||
display: none;
|
||||
}
|
||||
.category-item-badges {
|
||||
display: block;
|
||||
margin: 5px 0 0 0;
|
||||
}
|
||||
.unsaved-changes-icon {
|
||||
right: unset;
|
||||
left: 13px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -202,9 +202,6 @@ export default class CategoryItemTraits extends Vue {
|
||||
.category-item-trait {
|
||||
padding-right: 24px;
|
||||
}
|
||||
.category-item-trait:not(:last-child) {
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.category-item-edit-trait-menu {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
@ -1,24 +1,22 @@
|
||||
<template>
|
||||
<v-dialog
|
||||
lazy
|
||||
:value="value"
|
||||
persistent
|
||||
max-width="99vw"
|
||||
:value="value"
|
||||
>
|
||||
<slot slot="activator" />
|
||||
|
||||
<div class="conflict-box">
|
||||
<div class="conflict-item">
|
||||
<p class="title mb-2">Your version</p>
|
||||
<v-card
|
||||
<h2 class="mt-0">Your version</h2>
|
||||
<v-card
|
||||
color="#fdd"
|
||||
class="conflict-content"
|
||||
>
|
||||
<v-card-text>{{modified}}</v-card-text>
|
||||
</v-card>
|
||||
<v-btn
|
||||
depressed
|
||||
small
|
||||
class="conflict-dialog-btn"
|
||||
title="Submit this version, disregard changes on server"
|
||||
@click="save(modified)"
|
||||
>
|
||||
@ -26,37 +24,48 @@
|
||||
</v-btn>
|
||||
</div>
|
||||
<div class="conflict-item">
|
||||
<p class="title mb-2">Version on server</p>
|
||||
<h2 class="mt-0">Version on server</h2>
|
||||
<v-card
|
||||
color="#cfc"
|
||||
class="conflict-content"
|
||||
>
|
||||
<v-card-text>{{serverModified}}</v-card-text>
|
||||
</v-card>
|
||||
<v-btn
|
||||
depressed
|
||||
small
|
||||
title="Accept this version, disregard my changes"
|
||||
<v-btn
|
||||
class="conflict-dialog-btn"
|
||||
title="Submit this version, disregard my changes"
|
||||
@click="save(serverModified)"
|
||||
>
|
||||
Accept this version, disregard my changes
|
||||
</v-btn>
|
||||
</div>
|
||||
<div class="conflict-item">
|
||||
<p class="title mb-2">Merged version</p>
|
||||
<h2 class="mt-0">Merged version</h2>
|
||||
<markdown-editor
|
||||
class="mb-2"
|
||||
toolbar
|
||||
:value="merged"
|
||||
class="conflict-content_markdown"
|
||||
height="auto"
|
||||
v-model="mergedEdit"
|
||||
:autofocus="false"
|
||||
:bottomToolbar="false"
|
||||
@save="save"
|
||||
/>
|
||||
<v-btn
|
||||
class="conflict-dialog-btn"
|
||||
title="Submit merged version"
|
||||
@click="save(mergedEdit)"
|
||||
>
|
||||
Submit the merged version
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Vue, Component, Prop, Watch } from 'vue-property-decorator';
|
||||
import Vue from 'vue'
|
||||
import Component from 'vue-class-component'
|
||||
import { Prop, Watch } from 'vue-property-decorator'
|
||||
import MarkdownEditor from 'client/components/MarkdownEditor.vue'
|
||||
|
||||
@Component({
|
||||
@ -70,6 +79,13 @@ export default class ConflictDialog extends Vue {
|
||||
@Prop(String) modified!: string
|
||||
@Prop(String) merged!: string
|
||||
|
||||
mergedEdit = this.merged
|
||||
|
||||
@Watch('merged')
|
||||
onMergedChange (newVal) {
|
||||
this.mergedEdit = newVal
|
||||
}
|
||||
|
||||
save (newValue: string) {
|
||||
this.$emit('save', newValue)
|
||||
}
|
||||
@ -77,45 +93,88 @@ export default class ConflictDialog extends Vue {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style lang="postcss" scoped>
|
||||
>>> .v-dialog {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
.conflict-box {
|
||||
display: flex;
|
||||
background: #fff;
|
||||
padding: 20px;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.conflict-content {
|
||||
flex: 1;
|
||||
margin-bottom: 16px;
|
||||
white-space: pre-wrap;
|
||||
max-height: 90vh;
|
||||
|
||||
> *:not(:last-child) {
|
||||
margin-right: 1.65rem;
|
||||
}
|
||||
}
|
||||
.conflict-item {
|
||||
width: 32%;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
}
|
||||
max-height: 100%;
|
||||
overflow: hidden;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
|
||||
@media screen and (max-width: 1200px) {
|
||||
.conflict-box {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.conflict-item {
|
||||
width: 49%;
|
||||
}
|
||||
|
||||
.conflict-item:nth-last-child(1) {
|
||||
width: 98%;
|
||||
> h2 {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
.conflict-content,
|
||||
.conflict-content_markdown {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
margin-bottom: 16px;
|
||||
white-space: pre-wrap;
|
||||
overflow: auto;
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
>>> {
|
||||
.CodeMirror {
|
||||
flex: 1;
|
||||
}
|
||||
.v-card__text {
|
||||
word-break: break-word;
|
||||
}
|
||||
}
|
||||
}
|
||||
.conflict-dialog-btn {
|
||||
display: block;
|
||||
margin: 0;
|
||||
min-height: 60px;
|
||||
min-width: 220px;
|
||||
max-height: 60px;
|
||||
max-width: 220px;
|
||||
padding: 6px 16px;
|
||||
font-weight: bold;
|
||||
font-size: 0.7rem;
|
||||
|
||||
>>> .v-btn__content {
|
||||
width: unset;
|
||||
white-space: normal;
|
||||
}
|
||||
}
|
||||
/* Without this styling codemirror input area scrolling breaks */
|
||||
.conflict-content_markdown >>> .CodeMirror-scroll {
|
||||
min-height: 0 !important;
|
||||
}
|
||||
@media screen and (max-width: 900px) {
|
||||
.conflict-box {
|
||||
flex-flow: column;
|
||||
flex-direction: column;
|
||||
max-height: unset;
|
||||
|
||||
> *:not(:last-child) {
|
||||
margin-right: 0;
|
||||
margin-bottom: 1.65rem;
|
||||
}
|
||||
}
|
||||
|
||||
.conflict-item {
|
||||
width: 100%;
|
||||
/* For every content area to be the same */
|
||||
.conflict-content,
|
||||
.conflict-content_markdown {
|
||||
max-height: 350px;
|
||||
/* Without height setting codemirror input area is not scrollable */
|
||||
height: 350px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -3,8 +3,12 @@
|
||||
cause easyMDE adds new html elements next to textarea -->
|
||||
<div
|
||||
class="elevation-2"
|
||||
:class="{
|
||||
'markdown-editor_has-bottom-toolbar': bottomToolbar,
|
||||
'markdown-editor_has-top-toolbar': toolbar
|
||||
}"
|
||||
@keydown.capture.enter="onEnterDown"
|
||||
@keydown.ctrl.enter="save"
|
||||
@keydown.ctrl.enter="onCtrlEnterDown"
|
||||
@keydown.esc="cancel"
|
||||
v-show="editor && isReady"
|
||||
>
|
||||
@ -14,7 +18,8 @@
|
||||
flat
|
||||
height="30"
|
||||
color="#e5e5e5"
|
||||
class="pa-2 markdown-editor-bottom-toolbar"
|
||||
class="pa-2 markdown-editor__bottom-toolbar"
|
||||
v-if="bottomToolbar"
|
||||
v-show="editor"
|
||||
>
|
||||
<v-toolbar-items>
|
||||
@ -55,11 +60,23 @@ export default class MarkdownEditor extends Vue {
|
||||
default: ''
|
||||
}) value: string
|
||||
@Prop({
|
||||
type: Number,
|
||||
type: [Number, String],
|
||||
default: 300
|
||||
}) height: number
|
||||
}) height: number | string
|
||||
@Prop(Boolean) toolbar: boolean
|
||||
@Prop(Boolean) saveOnEnter: boolean
|
||||
@Prop({
|
||||
type: Boolean,
|
||||
default: true
|
||||
}) saveOnCtrlEnter: boolean
|
||||
@Prop({
|
||||
type: Boolean,
|
||||
default: true
|
||||
}) autofocus: boolean
|
||||
@Prop({
|
||||
type: Boolean,
|
||||
default: true
|
||||
}) bottomToolbar: boolean
|
||||
|
||||
editor: object = null
|
||||
isReady: boolean = false
|
||||
@ -68,6 +85,12 @@ export default class MarkdownEditor extends Vue {
|
||||
return `press${this.saveOnEnter ? ' Enter or' : ''} Ctrl+Enter to save`
|
||||
}
|
||||
|
||||
get heightValue () {
|
||||
return Number(this.height)
|
||||
? this.height
|
||||
: `${this.height}px`
|
||||
}
|
||||
|
||||
@Watch('value')
|
||||
onValueChange (newVal: string): void {
|
||||
if (!this.editor || this.editor.value() === newVal) {
|
||||
@ -91,7 +114,7 @@ export default class MarkdownEditor extends Vue {
|
||||
initialValue: this.value,
|
||||
spellChecker: false,
|
||||
status: false,
|
||||
minHeight: `${this.height}px`,
|
||||
// minHeight: this.heightValue,
|
||||
toolbar: this.toolbar
|
||||
? [
|
||||
'bold',
|
||||
@ -168,14 +191,17 @@ export default class MarkdownEditor extends Vue {
|
||||
if (!inputAreaEl) {
|
||||
return
|
||||
}
|
||||
inputAreaEl.style.height = `${this.height}px`
|
||||
inputAreaEl.style.height = this.heightValue
|
||||
}
|
||||
|
||||
focusInputArea () {
|
||||
if (!this.autofocus) {
|
||||
return
|
||||
}
|
||||
// this function is triggered right after isReady set to true
|
||||
// isReady controls v-show of entire markup of component
|
||||
// nextTick is used cause html needs to be rendered after v-show triggered so focus will work
|
||||
this.$nextTick(() => document.querySelector('.CodeMirror textarea').focus())
|
||||
this.$nextTick(() => this.editor.codemirror.focus())
|
||||
}
|
||||
|
||||
onEnterDown (event: KeyboardEvent) {
|
||||
@ -185,6 +211,13 @@ export default class MarkdownEditor extends Vue {
|
||||
}
|
||||
}
|
||||
|
||||
onCtrlEnterDown (event) {
|
||||
if (this.saveOnCtrlEnter) {
|
||||
event.preventDefault()
|
||||
this.save()
|
||||
}
|
||||
}
|
||||
|
||||
save () {
|
||||
this.$emit('save', this.editor.value())
|
||||
}
|
||||
@ -196,18 +229,15 @@ export default class MarkdownEditor extends Vue {
|
||||
</script>
|
||||
|
||||
<style lang="postcss" scoped>
|
||||
>>> .editor-toolbar,
|
||||
>>> .CodeMirror {
|
||||
border: none;
|
||||
border: 1px solid #bbb;
|
||||
border-radius: 0;
|
||||
border-bottom: 1px solid #bbb;
|
||||
}
|
||||
>>> .CodeMirror {
|
||||
|
||||
/* Fixes cutting of bottom edge of input
|
||||
https://github.com/sparksuite/simplemde-markdown-editor/issues/619
|
||||
*/
|
||||
box-sizing: content-box;
|
||||
font-size: 16px;
|
||||
font-size: 1rem;
|
||||
|
||||
.cm-header-1 {
|
||||
font-size: 2rem;
|
||||
@ -229,10 +259,21 @@ export default class MarkdownEditor extends Vue {
|
||||
background: unset;
|
||||
}
|
||||
}
|
||||
.markdown-editor_has-top-toolbar >>> .CodeMirror {
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
.markdown-editor_has-bottom-toolbar >>> .CodeMirror {
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
.markdown-editor__bottom-toolbar {
|
||||
border: 1px solid #bbb !important;
|
||||
border-top: none !important;
|
||||
}
|
||||
>>> .v-toolbar__content {
|
||||
padding-left: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.markdown-editor-save-tip {
|
||||
font-size: 11px;
|
||||
line-height: 14px;
|
||||
}
|
||||
</style>
|
@ -28,6 +28,10 @@ export default class SearchField extends Vue {
|
||||
setSearchInput (value: string) {
|
||||
this.$store.commit('wiki/setSearchInput', value)
|
||||
}
|
||||
|
||||
focus () {
|
||||
this.$children[0].focus()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -1,16 +1,31 @@
|
||||
<template>
|
||||
<v-toolbar dark app>
|
||||
<v-toolbar-title>
|
||||
<logo />
|
||||
<logo
|
||||
:class="{ 'mobile-hidden': !isSearchFieldHidden }"
|
||||
/>
|
||||
</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<search-field />
|
||||
<search-field
|
||||
:class="{ 'mobile-hidden': isSearchFieldHidden }"
|
||||
ref="searchField"
|
||||
/>
|
||||
<v-btn
|
||||
flat
|
||||
icon
|
||||
title="Search"
|
||||
color="#fff"
|
||||
class="mobile-displayed"
|
||||
@click="toggleSearchField"
|
||||
>
|
||||
<v-icon size="20">$vuetify.icons.search</v-icon>
|
||||
</v-btn>
|
||||
</v-toolbar>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
import SearchField from 'client/components/Search.vue'
|
||||
import SearchField from 'client/components/SearchField.vue'
|
||||
import Logo from 'client/components/Logo.vue'
|
||||
import Component from 'vue-class-component'
|
||||
import axios from 'axios'
|
||||
@ -21,11 +36,34 @@ import axios from 'axios'
|
||||
Logo
|
||||
}
|
||||
})
|
||||
export default class Toolbar extends Vue {}
|
||||
export default class Toolbar extends Vue {
|
||||
isSearchFieldHidden: boolean = true
|
||||
|
||||
toggleSearchField () {
|
||||
this.isSearchFieldHidden = !this.isSearchFieldHidden
|
||||
if (!this.isSearchFieldHidden) {
|
||||
this.$nextTick(() => this.$refs.searchField.focus())
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style lang="postcss" scoped>
|
||||
>>> .v-toolbar__content {
|
||||
height: 64px !important;
|
||||
}
|
||||
.mobile-hidden {
|
||||
display: block;
|
||||
}
|
||||
.mobile-displayed {
|
||||
display: none;
|
||||
}
|
||||
@media screen and (max-width: 475px) {
|
||||
.mobile-hidden {
|
||||
display: none;
|
||||
}
|
||||
.mobile-displayed {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
Loading…
Reference in New Issue
Block a user