Merge branch 'Client' into 'main'
besoin 9 besoin 12 besoin 14 finis See merge request pdl-l3/teams/2023/v1/v1d!8
This commit is contained in:
commit
20559a029e
18 files changed
+530
-198
No files matched your search
+2
-2
@@ -3,9 +3,9 @@
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<link rel="icon" href="/favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>PDL L3 - Galerie</title>
|
||||
<title>PDL L3 - Projet</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB |
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><defs><style>.cls-1{fill:#e4e6ea;}.cls-2{fill:#ffb85a;}.cls-3{opacity:0.12;}.cls-4{fill:#2b374f;}</style></defs><title>magic-wand-filled</title><path class="cls-1" d="M20.28,491.72h0a25.6,25.6,0,0,1,0-36.2L288.91,186.88l36.21,36.21L56.48,491.72A25.6,25.6,0,0,1,20.28,491.72Z"/><path class="cls-2" d="M445.95,213.51l-59.07-1.28-33.79,48.13a12.81,12.81,0,0,1-22.66-3.46l-18.18-57.15-57.15-18.18a12.81,12.81,0,0,1-3.46-22.66l48.13-33.79-1.28-59.07A12.82,12.82,0,0,1,319,55.55L366.78,91.4,423.1,72.71A12.78,12.78,0,0,1,439.29,88.9L420.6,145.22,456.45,193A12.82,12.82,0,0,1,445.95,213.51Z"/><g class="cls-3"><path d="M445.95,213.51l-59.07-1.28-33.79,48.13a12.81,12.81,0,0,1-22.66-3.46l-18.18-57.15,124-124a12.75,12.75,0,0,1,3.07,13.12L420.6,145.22,456.45,193A12.82,12.82,0,0,1,445.95,213.51Z"/></g><path class="cls-4" d="M434.87,142.92l16.57-50a25.6,25.6,0,0,0-32.35-32.35l-50,16.57L326.66,45.32a25.6,25.6,0,0,0-41,21l1.12,52.2-42.54,29.9a25.6,25.6,0,0,0,7,45.34l9.62,3.06L11.22,446.46a38.46,38.46,0,0,0,0,54.31h0a38.45,38.45,0,0,0,54.31,0L315.15,251.15l3.06,9.62a25.45,25.45,0,0,0,20.51,17.54,26.06,26.06,0,0,0,4,.3,25.43,25.43,0,0,0,20.88-10.89l29.9-42.54,52.2,1.12a25.6,25.6,0,0,0,21-41ZM47.44,482.67a12.8,12.8,0,1,1-18.11-18.1l259-259,1.8.57,15.74,15.74.57,1.79ZM387.18,199.44a12.81,12.81,0,0,0-10.75,5.44L342.61,253,324.41,195.9a12.81,12.81,0,0,0-8.31-8.31L259,169.39l48.12-33.82a12.8,12.8,0,0,0,5.44-10.75l-1.27-59,47.77,35.83a12.79,12.79,0,0,0,11.71,1.91l56.39-18.77,0,.08-18.68,56.36a12.81,12.81,0,0,0,1.91,11.71l35.84,47.78Z"/><circle class="cls-4" cx="486.4" cy="121.6" r="12.8"/><circle class="cls-4" cx="492.8" cy="19.2" r="19.2"/><circle class="cls-4" cx="364.79" cy="12.8" r="12.8"/><circle class="cls-4" cx="422.4" cy="281.61" r="19.2"/><circle class="cls-4" cx="223.99" cy="89.6" r="12.8"/></svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
+140
-53
@@ -1,60 +1,147 @@
|
||||
<script setup lang="ts">
|
||||
import Home from './components/Home.vue'
|
||||
import Gallery from './components/Gallery.vue';
|
||||
import NotFound from './components/NotFound.vue'
|
||||
import Upload from './components/Upload.vue'
|
||||
import { defineComponent } from 'vue'
|
||||
import { api } from '@/http-api'
|
||||
import { ImageType, ImageClass } from './image';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="app">
|
||||
<nav>
|
||||
<ul>
|
||||
<li>
|
||||
<router-link to="/">Home</router-link>
|
||||
</li>
|
||||
<li>
|
||||
<router-link to="/gallery">Gallery</router-link>
|
||||
</li>
|
||||
<li>
|
||||
<router-link to="/upload">Upload</router-link>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<div>
|
||||
<h1>PDL - L3</h1>
|
||||
<router-view />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
#app {
|
||||
text-align: center;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
color: #2c3e50;
|
||||
<script lang="ts">
|
||||
const routes: { [key: string]: string } = {
|
||||
'/': "Home",
|
||||
'Gallery': "Gallery",
|
||||
'Upload': "Upload"
|
||||
}
|
||||
export default defineComponent({
|
||||
components: {
|
||||
Home,
|
||||
Gallery,
|
||||
NotFound,
|
||||
Upload
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
images: new Map<Number, ImageType>(),
|
||||
currentPath: window.location.hash,
|
||||
sent: false,
|
||||
file: null as FileList | null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
currentView(): string {
|
||||
return routes[this.currentPath.slice(1) || '/'] || "notFound";
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async updateImageList(sleep: number) {
|
||||
setTimeout(() => {
|
||||
api.getImageList().then((newImages) => {
|
||||
const newImageList = new Map<number, ImageType>();
|
||||
for (const image of newImages.values())
|
||||
newImageList.set(image.id, image);
|
||||
this.images = newImageList;
|
||||
})
|
||||
}, sleep);
|
||||
},
|
||||
deleteFile(id: number) {
|
||||
api.deleteImage(id).then(() => {
|
||||
this.updateImageList(100);
|
||||
})
|
||||
},
|
||||
isActive(route: string) {
|
||||
if (route === undefined) {
|
||||
if (this.currentPath === "")
|
||||
return 'router active';
|
||||
route = "/";
|
||||
}
|
||||
return this.currentPath.endsWith(route) ? 'router active' : 'router';
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.updateImageList(0);
|
||||
window.addEventListener('hashchange', () => {
|
||||
this.currentPath = window.location.hash;
|
||||
});
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<header>
|
||||
<div class="navi">
|
||||
<nav>
|
||||
<ul>
|
||||
<li v-for="route in routes" :class="isActive(routes[route])">
|
||||
<a :href="'#' + (routes[route] || '/')"> <span>{{ route }}</span></a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
<component :is="currentView" :key="sent" :images="images" @delete="deleteFile"
|
||||
@updateImageList="updateImageList(100)" />
|
||||
</template>
|
||||
<style scoped>
|
||||
.navi {
|
||||
/* reduce size of children */
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
header {
|
||||
display: block;
|
||||
position: fixed;
|
||||
padding-top: 30px;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
ul>li+li {
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
ul>li {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 5px 15px;
|
||||
border-radius: 60px;
|
||||
}
|
||||
|
||||
.active {
|
||||
background-color: #09c7aa;
|
||||
}
|
||||
|
||||
.active>a {
|
||||
color: rgb(205, 201, 194);
|
||||
}
|
||||
|
||||
a {
|
||||
color: rgb(172, 165, 154);
|
||||
text-decoration-color: initial;
|
||||
font-family: "Aeonik", sans-serif;
|
||||
}
|
||||
|
||||
nav {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding-left: 20px;
|
||||
height: 60px;
|
||||
padding-right: 20px;
|
||||
border-radius: 60px;
|
||||
background-color: rgb(24, 26, 27);
|
||||
margin-right: 20px;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
li {
|
||||
float: left;
|
||||
}
|
||||
|
||||
li a {
|
||||
display: block;
|
||||
color: white;
|
||||
text-align: center;
|
||||
padding: 14px 16px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: red;
|
||||
font-weight: bold;
|
||||
list-style-type: none;
|
||||
margin-top: 1em;
|
||||
display: flex;
|
||||
list-style: none;
|
||||
padding-inline-start: 0;
|
||||
}
|
||||
</style>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 6.7 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 496 B |
@@ -1,25 +1,55 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { api } from '@/http-api';
|
||||
import { defineComponent } from 'vue'
|
||||
import { ImageType } from '@/image'
|
||||
import Image from './Image.vue';
|
||||
import Image from '@/components/Image.vue'
|
||||
</script>
|
||||
<script lang="ts">
|
||||
|
||||
const imageList = ref<ImageType[]>([]);
|
||||
|
||||
api.getImageList()
|
||||
.then((data) => {
|
||||
imageList.value = data;
|
||||
})
|
||||
.catch(e => {
|
||||
console.log(e.message);
|
||||
});
|
||||
export default defineComponent({
|
||||
props: {
|
||||
images: {
|
||||
type: Map<number, ImageType>,
|
||||
required: true
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h3>Gallery</h3>
|
||||
<Image v-for="image in imageList" :id="image.id" />
|
||||
<div class="flex" v-if="images.keys !== null">
|
||||
<div v-for="[id, image] in images" :key="id" class="image">
|
||||
<label>{{ image.name }}</label>
|
||||
<Image class="gallery" :id="id" />
|
||||
</div>
|
||||
</div>
|
||||
<h1 v-else>No image found</h1>
|
||||
</template>
|
||||
<style scoped>
|
||||
.flex {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
<style scoped></style>
|
||||
.image {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: 1.5em;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.gallery>img {
|
||||
margin: 5px;
|
||||
max-width: max(33vw, calc(90vw/v-bind('images.size')));
|
||||
max-height: max(33vh, calc(90vh/v-bind('images.size')));
|
||||
margin: 2vw;
|
||||
}
|
||||
</style>
|
||||
@@ -1,35 +1,81 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import router from "@/router";
|
||||
import { api } from '@/http-api';
|
||||
import Image from '@/components/Image.vue'
|
||||
import { defineComponent } from 'vue'
|
||||
import { ImageType } from '@/image'
|
||||
|
||||
const selectedId = ref(-1);
|
||||
const imageList = ref<ImageType[]>([]);
|
||||
getImageList();
|
||||
|
||||
function getImageList() {
|
||||
api.getImageList().then((data) => {
|
||||
imageList.value = data;
|
||||
}).catch(e => {
|
||||
console.log(e.message);
|
||||
});
|
||||
}
|
||||
|
||||
function showImage() {
|
||||
router.push({ name: 'image', params: { id: selectedId.value } })
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default defineComponent({
|
||||
emits: {
|
||||
delete(id: number) {
|
||||
return id >= 0;
|
||||
}
|
||||
},
|
||||
props: {
|
||||
images: {
|
||||
type: Map<number, ImageType>,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
imageSelectedId: 0 as number,
|
||||
sure: false as boolean
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.imageSelectedId = this.images.keys().next().value;
|
||||
},
|
||||
watch: {
|
||||
images() {
|
||||
this.imageSelectedId = this.images.keys().next().value;
|
||||
},
|
||||
imageSelectedId() {
|
||||
this.sure = false;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
confirmDelete() {
|
||||
if (this.sure)
|
||||
this.$emit('delete', this.imageSelectedId);
|
||||
else
|
||||
this.sure = true;
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<h3>Choose an image</h3>
|
||||
<div class="flex" v-if="images.keys != null">
|
||||
<div>
|
||||
<select v-model="selectedId" @change="showImage">
|
||||
<option v-for="image in imageList" :value="image.id" :key="image.id">{{ image.name }}</option>
|
||||
<label>Selectioner une image: </label>
|
||||
<select v-model="imageSelectedId" style="width: min-content;margin: 15px;">
|
||||
<option v-for="[id, image] in images" :key="id" :value="id">{{ image.name }}</option>
|
||||
</select>
|
||||
<button @mouseleave="sure = false" @click="confirmDelete()" :class="sure ? 'confirm' : ''">
|
||||
{{ sure ? "Confirmer" : "Supprimer" }}</button>
|
||||
</div>
|
||||
<Image class="home" v-if="imageSelectedId !== undefined" :id="imageSelectedId"></Image>
|
||||
</div>
|
||||
<h1 v-else>Aucune image trouvée</h1>
|
||||
</template>
|
||||
<style scoped>
|
||||
.flex {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
<style scoped></style>
|
||||
.confirm {
|
||||
background-color: red;
|
||||
color: white;
|
||||
}
|
||||
|
||||
label {
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.home>img {
|
||||
max-width: 60%;
|
||||
max-height: 60vh;
|
||||
}
|
||||
</style>
|
||||
@@ -1,31 +1,49 @@
|
||||
<script setup lang="ts">
|
||||
import { defineProps } from 'vue';
|
||||
import { defineComponent } from 'vue';
|
||||
import { api } from '@/http-api';
|
||||
|
||||
const props = defineProps<{ id: number }>()
|
||||
|
||||
api.getImage(props.id)
|
||||
.then((data: Blob) => {
|
||||
const reader = new window.FileReader();
|
||||
reader.readAsDataURL(data);
|
||||
reader.onload = () => {
|
||||
const galleryElt = document.getElementById("gallery-" + props.id);
|
||||
if (galleryElt !== null) {
|
||||
const imgElt = document.createElement("img");
|
||||
galleryElt.appendChild(imgElt);
|
||||
if (imgElt !== null && reader.result as string) {
|
||||
imgElt.setAttribute("src", (reader.result as string));
|
||||
}
|
||||
}
|
||||
};
|
||||
})
|
||||
.catch(e => {
|
||||
console.log(e.message);
|
||||
});
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default defineComponent({
|
||||
props: {
|
||||
id: {
|
||||
type: Number,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async getImage(id: number) {
|
||||
const data = await api.getImage(id);
|
||||
const reader = new window.FileReader();
|
||||
reader.readAsDataURL(data);
|
||||
reader.onload = () => {
|
||||
const imgElt = document.getElementById("img-" + id) as HTMLImageElement;
|
||||
if (imgElt !== null) {
|
||||
if (reader.result as string) {
|
||||
imgElt.setAttribute("src", (reader.result as string));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getImage(this.id);
|
||||
},
|
||||
watch: {
|
||||
id() {
|
||||
this.getImage(this.id);
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<figure :id="'gallery-' + id"></figure>
|
||||
<a :href="'./images/' + id" target="_blank">
|
||||
<img :id="'img-' + id" />
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<style></style>
|
||||
<style scoped>
|
||||
img:hover {
|
||||
transform: scale(1.1);
|
||||
transition: transform 0.5s;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>404 NOT FOUND</h1>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -1,40 +1,137 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { defineComponent } from 'vue';
|
||||
import { api } from '@/http-api';
|
||||
import { ImageType, ImageClass } from '@/image';
|
||||
|
||||
const target = ref<HTMLInputElement>();
|
||||
|
||||
function submitFile() {
|
||||
if (target.value !== null && target.value !== undefined && target.value.files !== null) {
|
||||
const file = target.value.files[0];
|
||||
if (file === undefined)
|
||||
return;
|
||||
let formData = new FormData();
|
||||
formData.append("file", file);
|
||||
api.createImage(formData).then(() => {
|
||||
if (target.value !== undefined)
|
||||
target.value.value = '';
|
||||
}).catch(e => {
|
||||
console.log(e.message);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function handleFileUpload(event: Event) {
|
||||
target.value = (event.target as HTMLInputElement);
|
||||
}
|
||||
</script>
|
||||
<script lang="ts">
|
||||
|
||||
interface InputFileEvent extends Event {
|
||||
target: HTMLInputElement;
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
emits: ['updateImageList', 'delete'],
|
||||
data() {
|
||||
return {
|
||||
sent: false,
|
||||
file: null as FileList | null
|
||||
}
|
||||
},
|
||||
props: {
|
||||
images: {
|
||||
type: Map<number, ImageType>,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async submitImage() {
|
||||
if (this.sent === true || this.file === null)
|
||||
return;
|
||||
Array.from(this.file).forEach((file, id) => {
|
||||
|
||||
let formData = new FormData();
|
||||
formData.append('file', file);
|
||||
api.createImage(formData);
|
||||
});
|
||||
this.sent = true;
|
||||
this.$emit('updateImageList');
|
||||
this.resetFile();
|
||||
},
|
||||
handleFilesUpload(event: InputFileEvent) {
|
||||
this.file = event.target.files;
|
||||
this.sent = false;
|
||||
},
|
||||
resetFile() {
|
||||
this.file = null;
|
||||
(document.getElementById('fileUpload') as HTMLInputElement).value = "";
|
||||
},
|
||||
titleSendButton() {
|
||||
if (this.sent === true)
|
||||
return "Envoyé";
|
||||
if (this.file === null)
|
||||
return "Aucune image sélectionnée";
|
||||
return "Envoyer (" + this.file.length + " image(s) sélectionnée(s))";
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
file() {
|
||||
if (this.file === null)
|
||||
return;
|
||||
Array.from(this.file).forEach((file, id) => {
|
||||
const reader = new window.FileReader();
|
||||
reader.readAsDataURL(file);
|
||||
reader.onload = () => {
|
||||
const imgElt = document.getElementById("preview-" + id) as HTMLImageElement;
|
||||
if (imgElt !== null) {
|
||||
if (reader.result as string) {
|
||||
imgElt.setAttribute("src", (reader.result as string));
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<h3>Upload an image</h3>
|
||||
<div>
|
||||
<input type="file" id="file" ref="file" @change="handleFileUpload" />
|
||||
</div>
|
||||
<div>
|
||||
<button @click="submitFile">Submit</button>
|
||||
</div>
|
||||
<label>Ajouter une ou plusieurs image(s):
|
||||
<input id="fileUpload" type="file" @change="handleFilesUpload($event as InputFileEvent)" accept="image/jpeg"
|
||||
multiple />
|
||||
</label>
|
||||
<button :class="sent ? 'green' : 'normal'" @click="submitImage()">{{ titleSendButton() }}</button>
|
||||
<button v-if="file !== null" @click="resetFile()">Reinitialiser</button>
|
||||
</div>
|
||||
<h2 v-if="file !== null">Preview :</h2>
|
||||
<div class="previewBox">
|
||||
<label v-for="(f, id) in (file as FileList)" :key="id" class="imageLabel">{{ (f as File).name }}:
|
||||
<img :id="'preview-' + id" />
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
<style scoped>
|
||||
img {
|
||||
max-width: 100%;
|
||||
max-height: 90%;
|
||||
border: 1px solid black;
|
||||
}
|
||||
|
||||
<style scoped></style>
|
||||
label {
|
||||
color: white;
|
||||
}
|
||||
|
||||
input {
|
||||
color: white;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.imageLabel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
max-width: 33%;
|
||||
height: 33vh;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.previewBox {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-evenly;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.green {
|
||||
color: green;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
Vendored
-8
@@ -1,8 +0,0 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
declare module '*.vue' {
|
||||
import { DefineComponent } from 'vue'
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
||||
@@ -1,4 +1,13 @@
|
||||
export interface ImageType {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export class ImageClass implements ImageType {
|
||||
id: number
|
||||
name: string
|
||||
constructor(id: number, title: string) {
|
||||
this.id = id
|
||||
this.name = title
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { createApp } from 'vue'
|
||||
import './style.css'
|
||||
import App from './App.vue'
|
||||
import router from './router';
|
||||
|
||||
createApp(App).use(router).mount('#app')
|
||||
createApp(App).mount('#app')
|
||||
@@ -1,36 +0,0 @@
|
||||
import { createWebHistory, createRouter } from "vue-router";
|
||||
import { RouteRecordRaw } from "vue-router";
|
||||
|
||||
const routes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: "/",
|
||||
name: "home",
|
||||
component: () => import("./components/Home.vue"),
|
||||
props: true
|
||||
},
|
||||
{
|
||||
path: "/gallery",
|
||||
name: "gallery",
|
||||
component: () => import("./components/Gallery.vue"),
|
||||
props: true
|
||||
},
|
||||
{
|
||||
path: "/image/:id",
|
||||
name: "image",
|
||||
component: () => import("./components/Image.vue"),
|
||||
props: ({ params }) => ({ id: Number(params.id) || 0 })
|
||||
},
|
||||
{
|
||||
path: "/upload",
|
||||
name: "upload",
|
||||
component: () => import("./components/Upload.vue"),
|
||||
props: true
|
||||
}
|
||||
];
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes,
|
||||
});
|
||||
|
||||
export default router;
|
||||
@@ -0,0 +1,73 @@
|
||||
:root {
|
||||
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
font-weight: 400;
|
||||
|
||||
color-scheme: light dark;
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
background-color: #242424;
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
place-items: center;
|
||||
min-width: 320px;
|
||||
min-height: 100vh;
|
||||
background-color: #242424;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3.2em;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
padding: 0.6em 1.2em;
|
||||
font-size: 1em;
|
||||
font-weight: 500;
|
||||
font-family: inherit;
|
||||
background-color: #1a1a1a;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.25s;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #646cff;
|
||||
}
|
||||
|
||||
button:focus,
|
||||
button:focus-visible {
|
||||
outline: 4px auto -webkit-focus-ring-color;
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 2em;
|
||||
}
|
||||
|
||||
#app {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
color: #213547;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
}
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
@@ -24,5 +24,5 @@
|
||||
"src/**/*.d.ts",
|
||||
"src/**/*.tsx",
|
||||
"src/**/*.vue"
|
||||
],
|
||||
]
|
||||
}
|
||||
Reference in new issue
Block a user