diff --git a/frontend/src/assets/previews/kamery.jpg b/frontend/src/assets/previews/kamery.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5765fc44b1c086bdde7970162a56acad5e2d5596 Binary files /dev/null and b/frontend/src/assets/previews/kamery.jpg differ diff --git a/frontend/src/assets/template/avatar/overlay.png b/frontend/src/assets/template/avatar/overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..1abbd4bef2ee0fb483ce7026c17ac5c3e7820ba0 Binary files /dev/null and b/frontend/src/assets/template/avatar/overlay.png differ diff --git a/frontend/src/components/Navbar.vue b/frontend/src/components/Navbar.vue index d8cd0150d6686b3c553292b7086b30ab7477ff79..3b97c13133ce10a224cbc3627128f20f55228e6c 100644 --- a/frontend/src/components/Navbar.vue +++ b/frontend/src/components/Navbar.vue @@ -9,10 +9,11 @@ import { RouterLink } from "vue-router"; <script> export default { components: { VueSelect }, - props: ["defaultTemplate"], + props: ["defaultTemplate", "sideText"], data() { return { currentTemplate: this.defaultTemplate, + sideText: this.sideText, }; }, watch: { @@ -43,6 +44,13 @@ export default { Generátor grafiky <img :src="v2Image" class="h-5" alt="Verze 2.0" /> </RouterLink> + + <div + v-if="sideText" + class="pl-8 text-white" + > + {{ sideText }} + </div> </div> <div> <div class="w-72" v-if="currentTemplate"> diff --git a/frontend/src/components/canvas/Canvas.vue b/frontend/src/components/canvas/Canvas.vue index cc21e1366dc40346bb5041699f27209d13818f60..e3f16c7f2b3126ea04566bd57cf07ba01ccea64e 100644 --- a/frontend/src/components/canvas/Canvas.vue +++ b/frontend/src/components/canvas/Canvas.vue @@ -41,7 +41,12 @@ export default { let link = document.createElement("a"); - link.download = "Vyhrajem.png"; + if (window.fileName !== undefined) { + link.download = window.fileName; + } else { + link.download = `Generator-${new Date().toLocaleString()}.png`; + } + link.href = this.$refs.canvas.toDataURL(); link.click(); diff --git a/frontend/src/views/angle_event_left/AngleEventLeft.vue b/frontend/src/views/angle_event_left/AngleEventLeft.vue index b5c4a7ababf5e74bfdab83bed7a8c14473776a98..9373f9d5280db51980e8896961f6a19a64bb9b5e 100644 --- a/frontend/src/views/angle_event_left/AngleEventLeft.vue +++ b/frontend/src/views/angle_event_left/AngleEventLeft.vue @@ -84,6 +84,10 @@ export default { colors: this.colors, }; + if (canvasProperties.mainText) { + window.fileName = canvasProperties.mainText; + } + await this.$refs.canvas.redraw(canvasProperties); delete canvasProperties.colors; diff --git a/frontend/src/views/angle_event_right/AngleEventRight.vue b/frontend/src/views/angle_event_right/AngleEventRight.vue index a63a96869d42c643c8d0f0ef0cb65b322a7c63e1..ac35c38e6ed24e098bac03c8bfc7634505f35f53 100644 --- a/frontend/src/views/angle_event_right/AngleEventRight.vue +++ b/frontend/src/views/angle_event_right/AngleEventRight.vue @@ -84,6 +84,10 @@ export default { colors: this.colors, }; + if (canvasProperties.mainText) { + window.fileName = canvasProperties.mainText; + } + await this.$refs.canvas.redraw(canvasProperties); delete canvasProperties.colors; diff --git a/frontend/src/views/angle_person_event_left/AnglePersonEventLeft.vue b/frontend/src/views/angle_person_event_left/AnglePersonEventLeft.vue index 0f093d6bcc947853f7775e84ff98c64d89b1dcb7..de248f8351b6ea308cc82dd60ab42f9049d157e5 100644 --- a/frontend/src/views/angle_person_event_left/AnglePersonEventLeft.vue +++ b/frontend/src/views/angle_person_event_left/AnglePersonEventLeft.vue @@ -89,6 +89,10 @@ export default { colors: this.colors, }; + if (canvasProperties.mainText) { + window.fileName = canvasProperties.mainText; + } + await this.$refs.canvas.redraw(canvasProperties); let canvasPropertiesToSave = structuredClone(toRawDeep(canvasProperties)); diff --git a/frontend/src/views/angle_person_event_right/AnglePersonEventRight.vue b/frontend/src/views/angle_person_event_right/AnglePersonEventRight.vue index 8b3ed61a378d3736b0f26ec8cfb0c88e0a7f41a0..8cf846e098cce617d0636a085f53244085618684 100644 --- a/frontend/src/views/angle_person_event_right/AnglePersonEventRight.vue +++ b/frontend/src/views/angle_person_event_right/AnglePersonEventRight.vue @@ -89,6 +89,10 @@ export default { colors: this.colors, }; + if (canvasProperties.mainText) { + window.fileName = canvasProperties.mainText; + } + await this.$refs.canvas.redraw(canvasProperties); let canvasPropertiesToSave = structuredClone(toRawDeep(canvasProperties)); diff --git a/frontend/src/views/avatar/Avatar.vue b/frontend/src/views/avatar/Avatar.vue index 2475db754ff1d75c6104f793d9445cb715128f71..1360403ca6ce06877f7088b6e99f676c99d1f28c 100644 --- a/frontend/src/views/avatar/Avatar.vue +++ b/frontend/src/views/avatar/Avatar.vue @@ -7,6 +7,8 @@ import redraw from "./canvas"; import Navbar from "../../components/Navbar.vue"; import MainContainer from "../../components/MainContainer.vue"; import ImageInput from "../../components/inputs/ImageInput.vue"; +import ReloadButton from "../../components/reload/ReloadButton.vue"; +import AutoReloadCheckbox from "../../components/reload/AutoReloadCheckbox.vue"; import { toRawDeep } from "../../utils"; </script> @@ -22,7 +24,7 @@ export default { data() { return { mainImage: null, - autoRedraw: false, + autoRedraw: true, }; }, methods: { @@ -31,15 +33,12 @@ export default { mainImage: this.mainImage, }; - let canvasPropertiesToSave = structuredClone(toRawDeep(canvasProperties)); - delete canvasPropertiesToSave.colors; - - setCanvasStorage(canvasPropertiesToSave); - await this.$refs.canvas.redraw(canvasProperties); }, }, mounted() { + window.fileName = "Profilovy obrazek.png"; + this.$watch( (vm) => [vm.mainImage], async (value) => { @@ -58,7 +57,7 @@ export default { <template> <header> - <Navbar></Navbar> + <Navbar sideText="Profilové obrázky"></Navbar> </header> <main> <MainContainer> @@ -88,14 +87,15 @@ export default { </p> </div> - <ReloadButton :parentRefs="$refs" @click="reloadCanvasProperties" /> - <AutoReloadCheckbox v-model="autoRedraw" /> <ImageInput name="Obrázek" v-model="mainImage" :important="true" zIndex="10" /> + + <ReloadButton :parentRefs="$refs" @click="reloadCanvasProperties" /> + <AutoReloadCheckbox v-model="autoRedraw" /> </template> </MainContainer> </main> diff --git a/frontend/src/views/avatar/canvas.js b/frontend/src/views/avatar/canvas.js index cc505bd8eb060a8526572d52cbabbee31788ed8d..fdcd2bd58fa0dddd7c5ae83e3f8f5876e5b59cc0 100644 --- a/frontend/src/views/avatar/canvas.js +++ b/frontend/src/views/avatar/canvas.js @@ -1,3 +1,141 @@ -const redraw = async (canvas, options) => {}; +import { sortObjects } from "../../components/canvas/utils"; + +import overlayURL from "../../assets/template/avatar/overlay.png"; + +let mainImage = null; +let overlayImage = null; +let mainImageSource = null; +let pointerDownEventAssigned = false; + +const removeDownEventListener = () => { + document + .getElementsByClassName("upper-canvas")[0] + .removeEventListener("pointerdown", canvasPointerDownEvent); +}; + +let upEventFunction = null; +let canvasPointerDownEvent = null; + +const redraw = async (canvas, options) => { + document + .getElementsByClassName("upper-canvas")[0] + .removeEventListener("pointerup", upEventFunction); + document + .getElementsByClassName("upper-canvas")[0] + .removeEventListener("pointerout", upEventFunction); + document + .getElementsByClassName("upper-canvas")[0] + .removeEventListener("pointercancel", upEventFunction); + + canvas.preserveObjectStacking = true; + + /* BEGIN Main image render */ + + if ( + options.mainImage !== null && + (!canvas.contains(mainImage) || + mainImage === null || + options.mainImage.src !== mainImageSource) + ) { + if (mainImage !== null) { + canvas.remove(mainImage); + } + + mainImage = new fabric.Image(options.mainImage, { + left: 0, + top: 0, + zIndex: 0, + }); + + mainImage.controls = { + ...fabric.Image.prototype.controls, + mtr: new fabric.Control({ visible: false }), + }; + + if (mainImage.width >= mainImage.height) { + mainImage.scaleToHeight(canvas.height); + } else { + mainImage.scaleToWidth(canvas.width); + } + + canvas.add(mainImage); + mainImageSource = options.mainImage.src; + + removeDownEventListener(); + pointerDownEventAssigned = false; + } else if (mainImage !== null && options.mainImage === null) { + canvas.remove(mainImage); + + removeDownEventListener(); + pointerDownEventAssigned = false; + } + + /* END Main image render */ + + /* BEGIN Overlay render */ + + if (overlayImage === null) { + overlayImage = new Image(); + + await new Promise((resolve) => { + overlayImage.onload = () => { + resolve(); + }; + + overlayImage.src = overlayURL; + }); + + overlayImage = new fabric.Image(overlayImage, { + selectable: false, + zIndex: 5, + }); + overlayImage.scaleToWidth(canvas.width); + + canvas.add(overlayImage); + } + + /* END Overlay render */ + + sortObjects(canvas); + + canvasPointerDownEvent = (event) => { + let activeObject = canvas.getActiveObject(); + + if (activeObject === null) { + return; + } + + // if (activeObject._element.src == mainImage._element.src) { + // return + // } + + canvas.remove(overlayImage); + overlayImage = null; + }; + + if (!pointerDownEventAssigned) { + document + .getElementsByClassName("upper-canvas")[0] + .addEventListener("pointerdown", canvasPointerDownEvent); + + pointerDownEventAssigned = true; + } + + upEventFunction = (event) => { + redraw(canvas, options); + }; + + document + .getElementsByClassName("upper-canvas")[0] + .addEventListener("pointerup", upEventFunction); + + document + .getElementsByClassName("upper-canvas")[0] + .addEventListener("pointerout", upEventFunction); + + document + .getElementsByClassName("upper-canvas")[0] + .addEventListener("pointercancel", upEventFunction); +}; export default redraw; diff --git a/frontend/src/views/base_event/BaseEvent.vue b/frontend/src/views/base_event/BaseEvent.vue index 44a4ee8c6a4abd575cb95a64625ef6b4a93c6818..d30940241ef0009d97c25f8879f3efebf2b23e45 100644 --- a/frontend/src/views/base_event/BaseEvent.vue +++ b/frontend/src/views/base_event/BaseEvent.vue @@ -84,6 +84,10 @@ export default { colors: this.colors, }; + if (canvasProperties.mainText) { + window.fileName = canvasProperties.mainText; + } + await this.$refs.canvas.redraw(canvasProperties); delete canvasProperties.colors; diff --git a/frontend/src/views/base_person_event/BasePersonEvent.vue b/frontend/src/views/base_person_event/BasePersonEvent.vue index ef354f6a22703b6e45040546393bf78ffe187f3c..12b50e3d289685fb84d563e65c44a4630d717673 100644 --- a/frontend/src/views/base_person_event/BasePersonEvent.vue +++ b/frontend/src/views/base_person_event/BasePersonEvent.vue @@ -89,6 +89,10 @@ export default { colors: this.colors, }; + if (canvasProperties.mainText) { + window.fileName = canvasProperties.mainText; + } + await this.$refs.canvas.redraw(canvasProperties); let canvasPropertiesToSave = structuredClone(toRawDeep(canvasProperties)); diff --git a/frontend/src/views/basic_photo_banner/BasicPhotoBanner.vue b/frontend/src/views/basic_photo_banner/BasicPhotoBanner.vue index ec3a3f89520aecf14e5000d64a86f323be2c5d67..96d0ae193cab4eb7c785f494623d7201e0bb2583 100644 --- a/frontend/src/views/basic_photo_banner/BasicPhotoBanner.vue +++ b/frontend/src/views/basic_photo_banner/BasicPhotoBanner.vue @@ -108,6 +108,10 @@ export default { colors: this.colors, }; + if (canvasProperties.mainText) { + window.fileName = canvasProperties.mainText; + } + await this.$refs.canvas.redraw(canvasProperties); delete canvasProperties.colors; diff --git a/frontend/src/views/facebook_survey/FacebookSurvey.vue b/frontend/src/views/facebook_survey/FacebookSurvey.vue index f25dfece67a63487055b6a1f28675567143d04c9..aa9c478bc37a980ddbe2af4a8509635f067dac1a 100644 --- a/frontend/src/views/facebook_survey/FacebookSurvey.vue +++ b/frontend/src/views/facebook_survey/FacebookSurvey.vue @@ -107,6 +107,10 @@ export default { gradientHeightMultiplier: this.gradientHeightMultiplier, }; + if (canvasProperties.mainText) { + window.fileName = canvasProperties.mainText; + } + await this.$refs.canvas.redraw(canvasProperties); delete canvasProperties.colors; diff --git a/frontend/src/views/newspaper_quote_bottom/NewspaperQuoteBottom.vue b/frontend/src/views/newspaper_quote_bottom/NewspaperQuoteBottom.vue index ff8b1ebaa7ee55510be5cda5181df347942693a9..2cec1a51180e0f3376c546c656cd52ce751d03ae 100644 --- a/frontend/src/views/newspaper_quote_bottom/NewspaperQuoteBottom.vue +++ b/frontend/src/views/newspaper_quote_bottom/NewspaperQuoteBottom.vue @@ -117,6 +117,10 @@ export default { colors: this.colors, }; + if (canvasProperties.mainText) { + window.fileName = canvasProperties.mainText; + } + await this.$refs.canvas.redraw(canvasProperties); delete canvasProperties.colors; diff --git a/frontend/src/views/newspaper_quote_middle/NewspaperQuoteMiddle.vue b/frontend/src/views/newspaper_quote_middle/NewspaperQuoteMiddle.vue index 20f01241566f9cc200fe9f55bcb15affbcb57466..68f7677efdffaed76525d6f911ca93a93566cb82 100644 --- a/frontend/src/views/newspaper_quote_middle/NewspaperQuoteMiddle.vue +++ b/frontend/src/views/newspaper_quote_middle/NewspaperQuoteMiddle.vue @@ -126,6 +126,10 @@ export default { colors: this.colors, }; + if (canvasProperties.mainText) { + window.fileName = canvasProperties.mainText; + } + await this.$refs.canvas.redraw(canvasProperties); delete canvasProperties.colors; diff --git a/frontend/src/views/people_banner_with_custom_text/PeopleBannerWithCustomText.vue b/frontend/src/views/people_banner_with_custom_text/PeopleBannerWithCustomText.vue index 0379ae5a109d7efe46a987a843f96ea7e2606483..84b98a3db4b872dcc601c7e37d9f78e408a9acb8 100644 --- a/frontend/src/views/people_banner_with_custom_text/PeopleBannerWithCustomText.vue +++ b/frontend/src/views/people_banner_with_custom_text/PeopleBannerWithCustomText.vue @@ -76,6 +76,10 @@ export default { colors: this.colors, }; + if (canvasProperties.mainText) { + window.fileName = canvasProperties.mainText; + } + await this.$refs.canvas.redraw(canvasProperties); let canvasPropertiesToSave = structuredClone(toRawDeep(canvasProperties)); diff --git a/frontend/src/views/people_banner_with_predefined_text/PeopleBannerWithPredefinedText.vue b/frontend/src/views/people_banner_with_predefined_text/PeopleBannerWithPredefinedText.vue index 4eea66903d5a74033d6370809c902fcd9bc81ac5..a58d6bbdec14506a6a98dd5bcd27fa104b089b27 100644 --- a/frontend/src/views/people_banner_with_predefined_text/PeopleBannerWithPredefinedText.vue +++ b/frontend/src/views/people_banner_with_predefined_text/PeopleBannerWithPredefinedText.vue @@ -73,6 +73,10 @@ export default { colors: this.colors, }; + if (canvasProperties.mainText) { + window.fileName = canvasProperties.mainText; + } + await this.$refs.canvas.redraw(canvasProperties); let canvasPropertiesToSave = structuredClone(toRawDeep(canvasProperties)); diff --git a/frontend/src/views/poster/Poster.vue b/frontend/src/views/poster/Poster.vue index 8c6f047a8429adfa815261642ef0249a989e4d94..a9eb4d22c2244d6e59dd74ba38e5289b242607eb 100644 --- a/frontend/src/views/poster/Poster.vue +++ b/frontend/src/views/poster/Poster.vue @@ -109,6 +109,10 @@ export default { colors: this.colors, }; + if (canvasProperties.mainText) { + window.fileName = canvasProperties.mainText; + } + await this.$refs.canvas.redraw(canvasProperties); let canvasPropertiesToSave = structuredClone(toRawDeep(canvasProperties)); diff --git a/frontend/src/views/regional_success/RegionalSuccess.vue b/frontend/src/views/regional_success/RegionalSuccess.vue index de7a657ae86e5952145ce4931bd08ec20560fea7..e842482290028ca42fa449528be6183e9f4f2f65 100644 --- a/frontend/src/views/regional_success/RegionalSuccess.vue +++ b/frontend/src/views/regional_success/RegionalSuccess.vue @@ -129,6 +129,10 @@ export default { colors: this.colors, }; + if (canvasProperties.mainText) { + window.fileName = canvasProperties.mainText; + } + await this.$refs.canvas.redraw(canvasProperties); let canvasPropertiesToSave = structuredClone(toRawDeep(canvasProperties)); diff --git a/frontend/src/views/right_event/RightEvent.vue b/frontend/src/views/right_event/RightEvent.vue index 1a47a42c34705e6728664caa017d13e60e021bbf..bda5df0e1014d5f018e05b2db43ef291141459ec 100644 --- a/frontend/src/views/right_event/RightEvent.vue +++ b/frontend/src/views/right_event/RightEvent.vue @@ -84,6 +84,10 @@ export default { colors: this.colors, }; + if (canvasProperties.mainText) { + window.fileName = canvasProperties.mainText; + } + await this.$refs.canvas.redraw(canvasProperties); delete canvasProperties.colors; diff --git a/frontend/src/views/right_person_event/RightPersonEvent.vue b/frontend/src/views/right_person_event/RightPersonEvent.vue index eaf41e8ac9d7fed7d4369257532bf980cc16a05b..6389b2824c5dc78c3b2bb36efde246d81a346abd 100644 --- a/frontend/src/views/right_person_event/RightPersonEvent.vue +++ b/frontend/src/views/right_person_event/RightPersonEvent.vue @@ -89,6 +89,10 @@ export default { colors: this.colors, }; + if (canvasProperties.mainText) { + window.fileName = canvasProperties.mainText; + } + await this.$refs.canvas.redraw(canvasProperties); let canvasPropertiesToSave = structuredClone(toRawDeep(canvasProperties)); diff --git a/frontend/src/views/text_banner/TextBanner.vue b/frontend/src/views/text_banner/TextBanner.vue index 3de496cd7ec834f80ce43f7e839c9ef710d97323..0bab40dbad04e24bfc44a6ae560c05dc3bb5e7cb 100644 --- a/frontend/src/views/text_banner/TextBanner.vue +++ b/frontend/src/views/text_banner/TextBanner.vue @@ -97,6 +97,10 @@ export default { colors: this.colors, }; + if (canvasProperties.mainText) { + window.fileName = canvasProperties.mainText; + } + await this.$refs.canvas.redraw(canvasProperties); delete canvasProperties.colors; diff --git a/frontend/src/views/twitter_banner/TwitterBanner.vue b/frontend/src/views/twitter_banner/TwitterBanner.vue index f492fcfbeee6795807a350fb64928078967c1f4f..ad6119ac3d2257ae609fe1344e545a4bc192fd69 100644 --- a/frontend/src/views/twitter_banner/TwitterBanner.vue +++ b/frontend/src/views/twitter_banner/TwitterBanner.vue @@ -119,6 +119,10 @@ export default { contractedBy: this.contractedBy, }; + if (canvasProperties.mainText) { + window.fileName = canvasProperties.mainText; + } + await this.$refs.canvas.redraw(canvasProperties); delete canvasProperties.colors; diff --git a/frontend/src/views/urgent_basic_photo_banner/UrgentBasicPhotoBanner.vue b/frontend/src/views/urgent_basic_photo_banner/UrgentBasicPhotoBanner.vue index a5ace52fb9dc95c0bc45b2914acaf784489c6a4e..5ce9f9fbab5815bcce16ce048ebc8570f3e1f390 100644 --- a/frontend/src/views/urgent_basic_photo_banner/UrgentBasicPhotoBanner.vue +++ b/frontend/src/views/urgent_basic_photo_banner/UrgentBasicPhotoBanner.vue @@ -107,6 +107,10 @@ export default { colors: this.colors, }; + if (canvasProperties.mainText) { + window.fileName = canvasProperties.mainText; + } + await this.$refs.canvas.redraw(canvasProperties); delete canvasProperties.colors; diff --git a/frontend/src/views/urgent_text_banner/UrgentTextBanner.vue b/frontend/src/views/urgent_text_banner/UrgentTextBanner.vue index 152c0b5d289aa9705be14053d096ec0ef578191e..5c4aab85966b521aafd5df1ed86a877aca38d603 100644 --- a/frontend/src/views/urgent_text_banner/UrgentTextBanner.vue +++ b/frontend/src/views/urgent_text_banner/UrgentTextBanner.vue @@ -97,6 +97,10 @@ export default { colors: this.colors, }; + if (canvasProperties.mainText) { + window.fileName = canvasProperties.mainText; + } + await this.$refs.canvas.redraw(canvasProperties); await delete canvasProperties.colors; diff --git a/server/server/templates/index.html b/server/server/templates/index.html index 64ec2c35023f665d201b123aa278f840ce1c4f06..374d18e9b4de71dfa2bda3249b259a8ee11e5fc0 100644 --- a/server/server/templates/index.html +++ b/server/server/templates/index.html @@ -21,10 +21,11 @@ })(); </script> <title>Generátor grafiky</title> - <script type="module" crossorigin src="/static/index-ec81bc4e.js"></script> - <link rel="stylesheet" href="/static/index-636cacf0.css" /> + <script type="module" crossorigin src="/static/index-a81f7de8.js"></script> + <link rel="stylesheet" href="/static/index-9938619d.css"> </head> <body> <div id="app"></div> + </body> </html> diff --git a/server/server/views/frontend.py b/server/server/views/frontend.py index adbef73d70cc5c1a6a78da6d4659ad20f747ed9d..a54a7c15bb3bafeb41dbbd1480dd3a6a0b635059 100644 --- a/server/server/views/frontend.py +++ b/server/server/views/frontend.py @@ -10,3 +10,8 @@ frontend_blueprint = flask.Blueprint("frontend", __name__) @authentication_required def index(path: str) -> flask.Response: return flask.render_template("index.html") + + +@frontend_blueprint.route("/avatar") +def avatars() -> flask.Response: + return flask.render_template("index.html")