refactoring #3
147
src/App.vue
147
src/App.vue
|
@ -1,60 +1,82 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Sidebar from './components/Sidebar.vue';
|
import Sidebar from "./components/Sidebar.vue";
|
||||||
import Page from './components/Page.vue';
|
import SidebarBlock from "./components/SidebarBlock.vue";
|
||||||
import Input from './components/Input.vue';
|
import ButtonsBar from "./components/ButtonsBar.vue";
|
||||||
import Canvas from './components/Canvas.vue';
|
import Button from "./components/Button.vue";
|
||||||
import { ref } from 'vue';
|
import Page from "./components/Page.vue";
|
||||||
import { DEFAULT_HORIZONTAL_MARGIN, DEFAULT_IMAGE_HEIGHT, DEFAULT_IMAGE_WIDTH, DEFAULT_VERTICAL_MARGIN, DEFAULT_IMAGE_BACKGROUND_COLOR } from './const';
|
import Input from "./components/Input.vue";
|
||||||
|
import Canvas from "./components/Canvas.vue";
|
||||||
|
import { ref } from "vue";
|
||||||
|
import {
|
||||||
|
DEFAULT_HORIZONTAL_MARGIN,
|
||||||
|
DEFAULT_IMAGE_HEIGHT,
|
||||||
|
DEFAULT_IMAGE_WIDTH,
|
||||||
|
DEFAULT_VERTICAL_MARGIN,
|
||||||
|
DEFAULT_IMAGE_BACKGROUND_COLOR,
|
||||||
|
} from "./const";
|
||||||
|
import { ButtonSize, InputType } from "./types";
|
||||||
|
|
||||||
const vMargin = ref(DEFAULT_VERTICAL_MARGIN)
|
const vMargin = ref(DEFAULT_VERTICAL_MARGIN);
|
||||||
const hMargin = ref(DEFAULT_HORIZONTAL_MARGIN)
|
const hMargin = ref(DEFAULT_HORIZONTAL_MARGIN);
|
||||||
const imageWidth = ref(DEFAULT_IMAGE_WIDTH)
|
const imageWidth = ref(DEFAULT_IMAGE_WIDTH);
|
||||||
const imageHeight = ref(DEFAULT_IMAGE_HEIGHT)
|
const imageHeight = ref(DEFAULT_IMAGE_HEIGHT);
|
||||||
const imageBackgroundColor = ref(DEFAULT_IMAGE_BACKGROUND_COLOR)
|
const imageBackgroundColor = ref(DEFAULT_IMAGE_BACKGROUND_COLOR);
|
||||||
|
|
||||||
const savePng = async () => {
|
const savePng = async () => {
|
||||||
const canvas = document.getElementById("canvas") as HTMLCanvasElement;
|
const canvas = document.getElementById("canvas") as HTMLCanvasElement;
|
||||||
|
|
||||||
if (canvas) {
|
if (canvas) {
|
||||||
const image = canvas.toDataURL("image/png")
|
const image = canvas.toDataURL("image/png");
|
||||||
const link = document.createElement("a");
|
const link = document.createElement("a");
|
||||||
link.setAttribute("download", "image.png");
|
link.setAttribute("download", "image.png");
|
||||||
link.href = image
|
link.href = image;
|
||||||
link.click();
|
link.click();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
const rotatePage = () => {
|
||||||
|
const tmp = imageHeight.value;
|
||||||
|
imageHeight.value = imageWidth.value;
|
||||||
|
imageWidth.value = tmp;
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<Sidebar>
|
<Sidebar>
|
||||||
<div class="l-sidebar-block">
|
<SidebarBlock title="Фон">
|
||||||
<h1>Фон</h1>
|
<Input v-model="imageBackgroundColor" :type="InputType.Color">
|
||||||
<div class="input">
|
|
||||||
<label class="l-label">
|
|
||||||
Цвет {{ imageBackgroundColor }}
|
Цвет {{ imageBackgroundColor }}
|
||||||
</label>
|
</Input>
|
||||||
<br>
|
</SidebarBlock>
|
||||||
<input class="l-input" type="color" v-model="imageBackgroundColor">
|
<SidebarBlock title="Линии">
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="l-sidebar-block">
|
|
||||||
<h1>Линии</h1>
|
|
||||||
<Input v-model="vMargin">Отступ по горизонтали, мм</Input>
|
<Input v-model="vMargin">Отступ по горизонтали, мм</Input>
|
||||||
<Input v-model="hMargin">Отступ по вертикали, мм</Input>
|
<Input v-model="hMargin">Отступ по вертикали, мм</Input>
|
||||||
</div>
|
</SidebarBlock>
|
||||||
<div class="l-sidebar-block">
|
<SidebarBlock title="Изображение">
|
||||||
<h1>Изображение</h1>
|
|
||||||
<Input v-model="imageHeight">Высота, мм</Input>
|
<Input v-model="imageHeight">Высота, мм</Input>
|
||||||
<Input v-model="imageWidth">Ширина, мм</Input>
|
<Input v-model="imageWidth">Ширина, мм</Input>
|
||||||
<div class="l-mini-buttons-bar">
|
<ButtonsBar>
|
||||||
<button class="l-base-button l-mini-button" @click="imageWidth = 148; imageHeight = 210">A5</button>
|
<Button :size="ButtonSize.Small" :click="() => {
|
||||||
<button class="l-base-button l-mini-button" @click="imageWidth = 210; imageHeight = 297">A4</button>
|
imageWidth = 148;
|
||||||
<button class="l-base-button l-mini-button"
|
imageHeight = 210;
|
||||||
@click="var tmp; tmp = imageHeight; imageHeight = imageWidth; imageWidth = tmp">Повернуть</button>
|
}
|
||||||
</div>
|
">
|
||||||
<button class="l-base-button l-button" @click="savePng">Сохранить как png</button>
|
A5
|
||||||
</div>
|
</Button>
|
||||||
|
<Button :size="ButtonSize.Small" :click="() => {
|
||||||
|
imageWidth = 210;
|
||||||
|
imageHeight = 297;
|
||||||
|
}
|
||||||
|
">
|
||||||
|
A4
|
||||||
|
</Button>
|
||||||
|
<Button :size="ButtonSize.Small" :click="rotatePage">
|
||||||
|
Повернуть
|
||||||
|
</Button>
|
||||||
|
</ButtonsBar>
|
||||||
|
<Button :click="savePng">Сохранить как png</Button>
|
||||||
|
</SidebarBlock>
|
||||||
</Sidebar>
|
</Sidebar>
|
||||||
<Page>
|
<Page>
|
||||||
<Canvas :vMargin="vMargin" :hMargin="hMargin" :imageWidth="imageWidth" :imageHeight="imageHeight"
|
<Canvas :vMargin="vMargin" :hMargin="hMargin" :imageWidth="imageWidth" :imageHeight="imageHeight"
|
||||||
|
@ -83,57 +105,4 @@ html {
|
||||||
body {
|
body {
|
||||||
background-color: aqua;
|
background-color: aqua;
|
||||||
}
|
}
|
||||||
|
|
||||||
.l-base-button {
|
|
||||||
color: #22333B;
|
|
||||||
background-color: #EAE0D5;
|
|
||||||
border: 1px solid #5E503F;
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-base-button:hover {
|
|
||||||
background-color: #d7c7b6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-button {
|
|
||||||
border-radius: 10px;
|
|
||||||
margin: 5px;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-mini-button {
|
|
||||||
border-radius: 3px;
|
|
||||||
margin: 3px;
|
|
||||||
padding: 2px 10px;
|
|
||||||
font-size: 10pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'MPLUS1p';
|
|
||||||
font-style: normal;
|
|
||||||
src: local('MPLUS1p'), url(/fonts/ttf/MPLUS1p-Light.ttf) format('truetype');
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
color: #C6AC8F;
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-sidebar-block {
|
|
||||||
border: 1px solid #C6AC8F;
|
|
||||||
border-radius: 10px;
|
|
||||||
margin: 0 0 30px 0;
|
|
||||||
padding: 20px;
|
|
||||||
background-color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-mini-buttons-bar {
|
|
||||||
padding: 0 0 20px 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input {
|
|
||||||
margin: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-input {
|
|
||||||
margin: 10px 0;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ButtonSize } from '../types';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
click: (payload?: MouseEvent) => void;
|
||||||
|
size?: ButtonSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
withDefaults(defineProps<Props>(), {
|
||||||
|
size: ButtonSize.Medium,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<button
|
||||||
|
:class="{
|
||||||
|
button: true,
|
||||||
|
'button--small': size === ButtonSize.Small,
|
||||||
|
}"
|
||||||
|
@click="click"
|
||||||
|
>
|
||||||
|
<slot></slot>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.button {
|
||||||
|
border-radius: 10px;
|
||||||
|
margin: 5px;
|
||||||
|
padding: 10px;
|
||||||
|
color: #22333B;
|
||||||
|
background-color: #EAE0D5;
|
||||||
|
border: 1px solid #5E503F;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button:hover {
|
||||||
|
background-color: #d7c7b6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button--small {
|
||||||
|
border-radius: 3px;
|
||||||
|
margin: 3px;
|
||||||
|
padding: 2px 10px;
|
||||||
|
font-size: 10pt;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,11 @@
|
||||||
|
<template>
|
||||||
|
<div class="buttons-bar">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.buttons-bar {
|
||||||
|
padding: 0 0 20px 5px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,19 +1,33 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { InputType } from '../types';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
type: InputType;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
withDefaults(defineProps<Props>(), {
|
||||||
|
type: InputType.Number,
|
||||||
|
})
|
||||||
|
|
||||||
const modelValue = defineModel();
|
const modelValue = defineModel();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="input">
|
<div class="input-container">
|
||||||
<label class="l-label">
|
<label class="label">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</label>
|
</label>
|
||||||
<br>
|
<br />
|
||||||
<input class="l-input" type="number" v-model="modelValue" />
|
<input :class="{
|
||||||
|
input: true,
|
||||||
|
'input--color': type === InputType.Color,
|
||||||
|
}" :type="type" v-model="modelValue" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.input {
|
.input-container {
|
||||||
margin: 10px;
|
margin: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,10 +35,19 @@ input {
|
||||||
border: #333 1px solid;
|
border: #333 1px solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
.l-input {
|
.input {
|
||||||
margin: 10px 0;
|
margin: 10px 0;
|
||||||
border: 1px solid #C6AC8F;
|
border: 1px solid #c6ac8f;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.input--color {
|
||||||
|
padding: 0;
|
||||||
|
background-color: v-bind(modelValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.input--color::-webkit-color-swatch {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
defineProps<{
|
||||||
|
title: string;
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="sidebar-block">
|
||||||
|
<h1>{{ title }}</h1>
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.sidebar-block {
|
||||||
|
border: 1px solid #c6ac8f;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin: 0 0 30px 0;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
color: #c6ac8f;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,5 @@
|
||||||
|
@font-face {
|
||||||
|
font-family: "MPLUS1p";
|
||||||
|
font-style: normal;
|
||||||
|
src: local("MPLUS1p"), url(/fonts/ttf/MPLUS1p-Light.ttf) format("truetype");
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
export enum ButtonSize {
|
||||||
|
Small = 'small',
|
||||||
|
Medium = 'medium',
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum InputType {
|
||||||
|
Number = 'number',
|
||||||
|
Color = 'color',
|
||||||
|
}
|
Loading…
Reference in New Issue