Compare commits
19 Commits
2.1.3
...
feat/new-u
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8a7dc6d07d | ||
|
|
fd8d3168a8 | ||
|
|
db29dfdc4c | ||
|
|
e27c68c46c | ||
|
|
403188eea1 | ||
|
|
b48acd231d | ||
|
|
86d2ad76cb | ||
|
|
a68a08f909 | ||
|
|
cbe3f8e7be | ||
|
|
da67295896 | ||
|
|
62acc345c2 | ||
|
|
9162a3a600 | ||
|
|
dcb9b1eb8e | ||
|
|
3e2ea47f74 | ||
|
|
4bb802acbc | ||
|
|
12ef180e90 | ||
|
|
7ef22ea09d | ||
|
|
0e9ec753da | ||
|
|
ad60792020 |
@@ -1,7 +0,0 @@
|
||||
docs/
|
||||
.git/
|
||||
.idea/
|
||||
dist/
|
||||
node_modules/
|
||||
*.md
|
||||
LICENSE
|
||||
5
.gitignore
vendored
@@ -90,6 +90,5 @@ sw.*
|
||||
*.swp
|
||||
|
||||
# Cypress generated screen and videos files
|
||||
cypress/screenshot/
|
||||
cypress/videos/
|
||||
*.cy.ts.mp4
|
||||
src/tests/cypress/screenshot/
|
||||
src/tests/cypress/videos/
|
||||
@@ -5,12 +5,6 @@ stages:
|
||||
|
||||
variables:
|
||||
CYPRESS_CACHE_FOLDER: '$CI_PROJECT_DIR/cache/Cypress'
|
||||
DOCKER_BUILDKIT: 1 # use buildkit for better performance
|
||||
DOCKER_DRIVER: overlay2 # better docker driver to avoid copying too many files on each run
|
||||
GITLAB_REGISTRY: registry.gitlab.com # We use docker.io for official images and gitlab's registry to store temporary images
|
||||
IMAGE_NAME: geovisio/api
|
||||
CI_IMAGE_CACHE: $GITLAB_REGISTRY/$IMAGE_NAME:build_cache
|
||||
DOCKER_TLS_CERTDIR: ""
|
||||
|
||||
before_script:
|
||||
## chmod is unfortunately currently mandatory : https://github.com/nodejs/docker-node/issues/661
|
||||
@@ -63,71 +57,3 @@ deploy:
|
||||
script:
|
||||
- yarn install
|
||||
- yarn build
|
||||
|
||||
deploy:develop:
|
||||
rules:
|
||||
# run job only for fork that have the credentials to pull images from the gitlab-registry
|
||||
# and only for merge on 'develop' branch
|
||||
- if: $CI_DEPLOY_PASSWORD == null || $CI_DEPLOY_USER == null
|
||||
when: never
|
||||
- if: $CI_COMMIT_REF_SLUG == "develop"
|
||||
stage: Deploy
|
||||
image: docker:latest
|
||||
services:
|
||||
- docker:dind
|
||||
before_script:
|
||||
# login to the gitlab docker registry to use the cache and to publish
|
||||
- echo $CI_DEPLOY_PASSWORD | docker login -u $CI_DEPLOY_USER --password-stdin $GITLAB_REGISTRY
|
||||
- docker buildx create --use --name "geovisio-image-builder" --driver=docker-container # use docker-container driver to be able to publish a full cache
|
||||
# login to dockerhub
|
||||
- echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY
|
||||
script:
|
||||
# build image using repository as cache
|
||||
- docker buildx build
|
||||
--cache-from "type=registry,ref=$CI_IMAGE_CACHE"
|
||||
--cache-to "type=registry,mode=max,ref=$CI_IMAGE_CACHE"
|
||||
--tag "$CI_REGISTRY_IMAGE:develop"
|
||||
--label "org.opencontainers.image.title=$CI_PROJECT_TITLE"
|
||||
--label "org.opencontainers.image.url=$CI_PROJECT_URL"
|
||||
--label "org.opencontainers.image.created=$CI_JOB_STARTED_AT"
|
||||
--label "org.opencontainers.image.revision=$CI_COMMIT_SHORT_SHA"
|
||||
--load
|
||||
--progress=plain
|
||||
.
|
||||
|
||||
# publish image to dockerhub with the develop tag
|
||||
- docker push "$CI_REGISTRY_IMAGE:develop"
|
||||
|
||||
deploy:latest:
|
||||
# we consider that tag always land on main
|
||||
# and they always should publish a tagged image and the `latest` docker image
|
||||
only:
|
||||
- tags
|
||||
stage: Deploy
|
||||
image: docker:latest
|
||||
services:
|
||||
- docker:dind
|
||||
before_script:
|
||||
# login to the gitlab docker registry to use the cache and to publish
|
||||
- echo $CI_DEPLOY_PASSWORD | docker login -u $CI_DEPLOY_USER --password-stdin $GITLAB_REGISTRY
|
||||
- docker buildx create --use --name "geovisio-image-builder" --driver=docker-container # use docker-container driver to be able to publish a full cache
|
||||
# login to dockerhub
|
||||
- echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY
|
||||
script:
|
||||
# build image using repository as cache
|
||||
- docker buildx build
|
||||
--cache-from "type=registry,ref=$CI_IMAGE_CACHE"
|
||||
--cache-to "type=registry,mode=max,ref=$CI_IMAGE_CACHE"
|
||||
--tag "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME"
|
||||
--tag "$CI_REGISTRY_IMAGE:latest"
|
||||
--label "org.opencontainers.image.title=$CI_PROJECT_TITLE"
|
||||
--label "org.opencontainers.image.url=$CI_PROJECT_URL"
|
||||
--label "org.opencontainers.image.created=$CI_JOB_STARTED_AT"
|
||||
--label "org.opencontainers.image.revision=$GIT_DESCRIBE"
|
||||
--load
|
||||
--progress=plain
|
||||
.
|
||||
|
||||
# publish image to dockerhub
|
||||
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME
|
||||
- docker push $CI_REGISTRY_IMAGE:latest
|
||||
|
||||
64
CHANGELOG.md
@@ -2,61 +2,9 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
Before _0.1.0_ Changelog didn't exist.
|
||||
|
||||
Before _0.1.0_, website development was on rolling release, meaning there are no version tags.
|
||||
|
||||
## [2.1.3] - 2023-09-25
|
||||
|
||||
### Changed
|
||||
|
||||
- fix the format date from YY to YYYY in a sequence page
|
||||
|
||||
### Added
|
||||
|
||||
- Add a first version of a footer
|
||||
- Add a ay11 page
|
||||
|
||||
## [2.1.2] - 2023-09-12
|
||||
|
||||
### Changed
|
||||
|
||||
- add a fix to center the map with ENV variables
|
||||
|
||||
## [2.1.1] - 2023-09-06
|
||||
|
||||
### Changed
|
||||
|
||||
- GeoVisio web viewer upgraded to 2.1.4, [with alls its changes embedded](https://gitlab.com/geovisio/web-viewer/-/blob/develop/CHANGELOG.md?ref_type=heads#213-2023-08-30).
|
||||
- Dockerfile creates smaller and faster containers, using pre-built website and Nginx for HTTP serving.
|
||||
- In the upload input you can now choose between gallery and camera on mobile IOS
|
||||
- Some CSS fix for the responsive of one Sequence
|
||||
- Insert the report button in the viewer by passing a params
|
||||
|
||||
### Added
|
||||
|
||||
- Get the License with the API route
|
||||
- Add ENV var for maxZoom params of the viewer
|
||||
|
||||
## [2.1.0] - 2023-08-29
|
||||
|
||||
### Added
|
||||
|
||||
- A new page `/envoyer` to upload picture with an interface ([#13](https://gitlab.com/geovisio/website/-/issues/13)) :
|
||||
- the user can upload multiples pictures with the interface
|
||||
- the pictures are sorted by name
|
||||
- the user can see all the pictures uploaded and all the errors
|
||||
|
||||
### Changed
|
||||
|
||||
- Website releases now follow the synced `MAJOR.MINOR` API version rule, meaning that any version >= 2.1 of the website will be compatible with corresponding [GeoVisio API](https://gitlab.com/geovisio/api) version.
|
||||
|
||||
### Fixed
|
||||
|
||||
- fix a bug in the header hidden sub menu when authentication is not with keycloak
|
||||
|
||||
## [0.1.0] - 2023-07-04
|
||||
## [0.1.0] -
|
||||
|
||||
### Added
|
||||
|
||||
@@ -72,14 +20,10 @@ Before _0.1.0_, website development was on rolling release, meaning there are no
|
||||
- the user can see all the sequence's photos
|
||||
- the user can disable and delete one or many photo(s) of the sequence
|
||||
|
||||
|
||||
### Changed
|
||||
|
||||
- Header have now a new entry `Mes photos` when the user is logged to access to the sequence list
|
||||
- The router guard for logged pages has been changed to not call the api to check the token
|
||||
|
||||
[unreleased]: https://gitlab.com/geovisio/website/-/compare/2.1.3...develop
|
||||
[2.1.3]: https://gitlab.com/geovisio/website/-/compare/2.1.2...2.1.3
|
||||
[2.1.2]: https://gitlab.com/geovisio/website/-/compare/2.1.1...2.1.2
|
||||
[2.1.1]: https://gitlab.com/geovisio/website/-/compare/2.1.0...2.1.1
|
||||
[2.1.0]: https://gitlab.com/geovisio/website/-/compare/0.1.0...2.1.0
|
||||
[0.1.0]: https://gitlab.com/geovisio/website/-/commits/0.1.0
|
||||
### Fixed
|
||||
|
||||
59
Dockerfile
@@ -1,59 +0,0 @@
|
||||
#--------------------------------------------------------------
|
||||
#- Build image
|
||||
#-
|
||||
|
||||
FROM node:18.16.0-alpine AS build
|
||||
|
||||
WORKDIR /opt/geovisio
|
||||
|
||||
# Import dependencies files
|
||||
COPY package.json yarn.lock ./
|
||||
|
||||
# Install NodeJS dependencies
|
||||
RUN yarn install --frozen-lockfile
|
||||
|
||||
# Import source code
|
||||
COPY static ./static
|
||||
COPY src ./src
|
||||
COPY *.json *.js *.ts *.html ./
|
||||
|
||||
# Replace env variables by placeholder for dynamic change on container start
|
||||
ENV VITE_INSTANCE_NAME=DOCKER_VITE_INSTANCE_NAME
|
||||
ENV VITE_API_URL=DOCKER_VITE_API_URL
|
||||
ENV VITE_TILES=DOCKER_VITE_TILES
|
||||
ENV VITE_MAX_ZOOM=DOCKER_VITE_MAX_ZOOM
|
||||
ENV VITE_ZOOM=DOCKER_VITE_ZOOM
|
||||
ENV VITE_CENTER=DOCKER_VITE_CENTER
|
||||
|
||||
# Build code
|
||||
ENV PORT=3000
|
||||
RUN yarn deploy
|
||||
|
||||
|
||||
#--------------------------------------------------------------
|
||||
#- Final image
|
||||
#-
|
||||
|
||||
FROM nginx:1-alpine
|
||||
RUN apk add bash
|
||||
|
||||
# Retrieve files from build
|
||||
COPY --from=build /opt/geovisio/dist /usr/share/nginx/html
|
||||
|
||||
# Add Docker scripts and Nginx conf
|
||||
COPY docker/nginx.conf /etc/nginx/nginx.conf
|
||||
COPY docker/docker-entrypoint.sh /etc/nginx/docker-entrypoint.sh
|
||||
RUN chmod +x /etc/nginx/docker-entrypoint.sh
|
||||
|
||||
# Define env variables defaults
|
||||
ENV VITE_INSTANCE_NAME="GeoVisio/Docker"
|
||||
ENV VITE_API_URL="https://panoramax.openstreetmap.fr"
|
||||
ENV VITE_TILES="https://tile-vect.openstreetmap.fr/styles/basic/style.json"
|
||||
ENV VITE_MAX_ZOOM=""
|
||||
ENV VITE_ZOOM=""
|
||||
ENV VITE_CENTER=""
|
||||
|
||||
# Start Nginx
|
||||
EXPOSE 3000
|
||||
ENTRYPOINT ["/etc/nginx/docker-entrypoint.sh"]
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
@@ -12,6 +12,11 @@ export default defineConfig({
|
||||
setupNodeEvents(on, config) {
|
||||
// implement node event listeners here
|
||||
},
|
||||
baseUrl: 'http://localhost:5173'
|
||||
baseUrl: 'http://localhost:5173',
|
||||
supportFile: 'src/tests/cypress/support/e2e.{js,jsx,ts,tsx}',
|
||||
specPattern: 'src/tests/cypress/**/*.cy.{js,jsx,ts,tsx}',
|
||||
fixturesFolder: 'src/tests/cypress/fixtures',
|
||||
videosFolder: 'src/tests/cypress/videos',
|
||||
screenshotsFolder: 'src/tests/cypress/screenshot'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
ROOT_DIR=/usr/share/nginx/html
|
||||
DOCKER_VARS=(VITE_INSTANCE_NAME VITE_API_URL VITE_TILES VITE_MAX_ZOOM VITE_ZOOM VITE_CENTER )
|
||||
|
||||
echo "Setting env variables in web files"
|
||||
for file in $ROOT_DIR/assets/*.js $ROOT_DIR/index.html; do
|
||||
echo "Processing $file...";
|
||||
|
||||
for i in ${!DOCKER_VARS[@]}; do
|
||||
sed -i "s|DOCKER_${DOCKER_VARS[i]}|${!DOCKER_VARS[i]}|g" $file
|
||||
done
|
||||
done
|
||||
|
||||
echo "GeoVisio website is now ready !"
|
||||
exec "$@"
|
||||
@@ -1,22 +0,0 @@
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include mime.types;
|
||||
sendfile on;
|
||||
|
||||
server {
|
||||
listen 3000;
|
||||
listen [::]:3000;
|
||||
|
||||
resolver 127.0.0.11;
|
||||
autoindex off;
|
||||
|
||||
server_name _;
|
||||
server_tokens off;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
gzip_static on;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,6 @@
|
||||
# Setup
|
||||
|
||||
GeoVisio website can be installed through classic method, or using Docker.
|
||||
|
||||
__Contents__
|
||||
|
||||
[[_TOC_]]
|
||||
|
||||
|
||||
## Classic install
|
||||
|
||||
### System requirements
|
||||
## System requirements
|
||||
|
||||
**You need to have [Nodejs installed](https://nodejs.org/en/download)**
|
||||
Node version : >=18.13.0
|
||||
@@ -18,7 +9,7 @@ Node version : >=18.13.0
|
||||
|
||||
You can use npm or [yarn](https://yarnpkg.com/) as package manager
|
||||
|
||||
### Install
|
||||
## Install
|
||||
|
||||
The website can be installed locally by retrieving this repository and installing dependencies:
|
||||
|
||||
@@ -31,7 +22,7 @@ cd website/
|
||||
npm install
|
||||
```
|
||||
|
||||
### Build for production
|
||||
## Build for production
|
||||
|
||||
Before building, you need to define a bit of settings. At least, you have to create a `.env` file and edit its content.
|
||||
|
||||
@@ -50,33 +41,6 @@ PORT=3000 npm run start
|
||||
|
||||
The website is now available at [localhost:3000](http://localhost:3000).
|
||||
|
||||
|
||||
## Docker setup
|
||||
|
||||
The [Docker](https://docs.docker.com/get-docker/) deployment is a really convenient way to have a Geovisio website running in an easy and fast way. Note that this setup documentation only covers __GeoVisio front-end__ (website), if you also need an API running, please refer to [Docker API deployment](https://gitlab.com/geovisio/api/-/blob/develop/docs/14_Running_Docker.md).
|
||||
|
||||
You can use the provided __Docker Hub__ `geovisio/website:latest` image directly:
|
||||
|
||||
```bash
|
||||
docker run \
|
||||
-e VITE_API_URL="https://your.geovisio.api/" \
|
||||
-e VITE_INSTANCE_NAME="My Own GeoVisio" \
|
||||
-e VITE_TILES="https://your.geovisio.api/vector/tiles/style.json" \
|
||||
-p 3000:3000 \
|
||||
--name geovisio-website \
|
||||
-d \
|
||||
geovisio/website:latest
|
||||
```
|
||||
|
||||
This will run a container bound on [localhost:3000](http://localhost:3000).
|
||||
|
||||
You can also build the image from the local source with:
|
||||
|
||||
```bash
|
||||
docker build -t geovisio/website:latest .
|
||||
```
|
||||
|
||||
|
||||
## Next steps
|
||||
|
||||
You can check out [the available settings for your instance](./03_Settings.md).
|
||||
|
||||
@@ -11,9 +11,6 @@ Available parameters are:
|
||||
- `VITE_API_URL`: the URL to the GeoVisio API (with trailing `/`, example: `https://geovisio.fr/`)
|
||||
- `VITE_INSTANCE_NAME`: the name of the instance (example: `IGN`)
|
||||
- `VITE_TILES`: the URL of your tiles : default tiles are the Open Street Map Tiles (example: `https://wxs.ign.fr/essentiels/static/vectorTiles/styles/PLAN.IGN/attenue.json`)
|
||||
- `VITE_MAX_ZOOM`: the max zoom to use on the map (defaults to 24).
|
||||
- `VITE_ZOOM`: the zoom to use at the initialization of the map (defaults to 0).
|
||||
- `VITE_CENTER`: the center position to use at the initialization of the map (defaults to 0).
|
||||
- Settings for the work environment:
|
||||
- `NPM_CONFIG_PRODUCTION`: is it production environment (`true`, `false`)
|
||||
- `YARN_PRODUCTION`: same as below, but if you use Yarn instead of NPM
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
# Make a release
|
||||
|
||||
The web site uses [semantic versioning](https://semver.org/) for its release numbers.
|
||||
|
||||
__Note__ : make sure that versions are in-sync with other Website components. Each component can have different `PATCH` versions, but compatibility __must__ be ensured between `MAJOR.MINOR` versions.
|
||||
|
||||
Run these commands in order to issue a new release:
|
||||
|
||||
```bash
|
||||
git checkout develop
|
||||
|
||||
vim package.json # Change version
|
||||
npm run doc
|
||||
|
||||
vim CHANGELOG.md # Replace unreleased to version number and update versions links (at bottom)
|
||||
|
||||
git add *
|
||||
git commit -m "Release x.x.x"
|
||||
git tag -a x.x.x -m "Release x.x.x"
|
||||
git push origin develop
|
||||
git checkout main
|
||||
git merge develop
|
||||
git push origin main --tags
|
||||
```
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "geovisio-website",
|
||||
"version": "2.1.3",
|
||||
"version": "1.0.0",
|
||||
"engines": {
|
||||
"node": "18.16.0"
|
||||
},
|
||||
@@ -25,13 +25,13 @@
|
||||
"axios": "^1.2.3",
|
||||
"bootstrap": "^5.2.3",
|
||||
"bootstrap-icons": "^1.10.3",
|
||||
"geovisio": "2.1.4",
|
||||
"geovisio": "2.1.1",
|
||||
"moment": "^2.29.4",
|
||||
"pinia": "^2.1.4",
|
||||
"vue": "^3.2.45",
|
||||
"vue-axios": "^3.5.2",
|
||||
"vue-eslint-parser": "^9.1.0",
|
||||
"vue-i18n": "9.2.2",
|
||||
"vue-i18n": "^9.2.2",
|
||||
"vue-meta": "^3.0.0-alpha.10",
|
||||
"vue-router": "^4.1.6",
|
||||
"vue3-cookies": "^1.0.6",
|
||||
|
||||
19
src/App.vue
@@ -1,10 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import Header from '@/components/Header.vue'
|
||||
import Footer from '@/components/Footer.vue'
|
||||
import { RouterView } from 'vue-router'
|
||||
import { useMeta } from 'vue-meta'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { title } from '@/utils/index'
|
||||
import title from '@/utils/index'
|
||||
import authConfig from './composables/auth'
|
||||
const { authConf } = authConfig()
|
||||
const { t } = useI18n()
|
||||
@@ -27,21 +26,9 @@ useMeta({
|
||||
<template v-slot:title="{ content }">{{ content }}</template>
|
||||
</metainfo>
|
||||
<Header
|
||||
:auth-enabled="
|
||||
authConf && authConf.auth && authConf.auth.enabled
|
||||
? authConf.auth.enabled
|
||||
: true
|
||||
"
|
||||
:user-profile-url="
|
||||
authConf &&
|
||||
authConf.auth &&
|
||||
authConf.auth.user_profile &&
|
||||
authConf.auth.user_profile.url
|
||||
? authConf.auth.user_profile.url
|
||||
: ''
|
||||
"
|
||||
:auth-enabled="authConf.enabled"
|
||||
:user-profile-url="authConf.user_profile ? authConf.user_profile.url : ''"
|
||||
/>
|
||||
<RouterView />
|
||||
<Footer />
|
||||
</template>
|
||||
<style scoped></style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
@mixin text($size) {
|
||||
@if $size == h1 {
|
||||
font-weight: normal;
|
||||
font-size: toRem(4);
|
||||
font-size: toRem(3);
|
||||
|
||||
@media (max-width: toRem(50)) {
|
||||
font-size: toRem(2.6);
|
||||
@@ -15,6 +15,14 @@
|
||||
font-size: toRem(1.8);
|
||||
}
|
||||
}
|
||||
@if $size == h3 {
|
||||
font-weight: normal;
|
||||
font-size: toRem(1.8);
|
||||
|
||||
@media (max-width: toRem(50)) {
|
||||
font-size: toRem(1.6);
|
||||
}
|
||||
}
|
||||
@if $size == h4 {
|
||||
font-weight: normal;
|
||||
font-size: toRem(1.6);
|
||||
|
||||
BIN
src/assets/images/360.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
src/assets/images/building.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
@@ -1,3 +0,0 @@
|
||||
<svg width="21" height="21" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10.873 0.179993C5.35013 0.179993 0.873047 4.65708 0.873047 10.18C0.873047 15.7029 5.35013 20.18 10.873 20.18C16.396 20.18 20.873 15.7029 20.873 10.18C20.873 4.65708 16.396 0.179993 10.873 0.179993ZM8.42513 14.3248H6.40013V7.80812H8.42513V14.3248ZM7.40013 7.00812C6.76055 7.00812 6.347 6.55499 6.347 5.99458C6.347 5.4227 6.77305 4.98312 7.42617 4.98312C8.0793 4.98312 8.4793 5.4227 8.4918 5.99458C8.4918 6.55499 8.0793 7.00812 7.40013 7.00812ZM15.821 14.3248H13.796V10.7133C13.796 9.8727 13.5022 9.30187 12.7699 9.30187C12.2105 9.30187 11.8783 9.68833 11.7314 10.0602C11.6772 10.1925 11.6637 10.38 11.6637 10.5665V14.3237H9.63763V9.88624C9.63763 9.0727 9.61159 8.39249 9.58451 7.80708H11.3439L11.4366 8.71228H11.4772C11.7439 8.28728 12.397 7.6602 13.4897 7.6602C14.822 7.6602 15.821 8.55291 15.821 10.4717V14.3248Z" fill="#0A1F69"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 945 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="19" height="21" viewBox="0 0 19 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13.4847 15.4241C16.0048 15.1241 18.1973 13.5803 18.4723 12.1703C18.9073 9.94774 18.8723 6.74641 18.8723 6.74641C18.8723 2.4088 16.0148 1.13627 16.0148 1.13627C14.5747 0.4775 12.1009 0.201243 9.53086 0.179993H9.46836C6.89705 0.201243 4.42448 0.4775 2.98445 1.13627C2.98445 1.13627 0.128126 2.40755 0.128126 6.74641L0.125626 7.57393C0.120626 8.37395 0.116876 9.26147 0.139377 10.1877C0.243129 14.4303 0.921896 18.613 4.86449 19.6505C6.68204 20.1292 8.24333 20.2292 9.50086 20.1605C11.7797 20.0355 13.0597 19.3517 13.0597 19.3517L12.9847 17.7054C12.9847 17.7054 11.3559 18.2179 9.52586 18.1554C7.71332 18.0929 5.80077 17.9604 5.50701 15.7454C5.47905 15.5399 5.46526 15.3327 5.46576 15.1254C5.46576 15.1254 7.2458 15.5579 9.50086 15.6604C10.8796 15.7229 12.1722 15.5804 13.486 15.4241H13.4847ZM15.501 12.3365H13.4097V7.23642C13.4097 6.16264 12.9547 5.61763 12.0459 5.61763C11.0409 5.61763 10.5371 6.26389 10.5371 7.54393V10.3352H8.45708V7.54268C8.45708 6.26264 7.95332 5.61638 6.9483 5.61638C6.03952 5.61638 5.58451 6.16139 5.58451 7.23642V12.3353H3.49321V7.08266C3.49321 6.00889 3.76822 5.15637 4.31823 4.5251C4.88825 3.89384 5.63326 3.57008 6.55954 3.57008C7.62956 3.57008 8.43958 3.98009 8.97585 4.79886L9.49711 5.66763L10.0184 4.79886C10.5546 3.98009 11.3647 3.57008 12.4359 3.57008C13.361 3.57008 14.106 3.89384 14.6747 4.5251C15.2273 5.15637 15.501 6.00889 15.501 7.08266V12.3365Z" fill="#0A1F69"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB |
BIN
src/assets/images/person-map.png
Normal file
|
After Width: | Height: | Size: 71 KiB |
BIN
src/assets/images/pointer-map.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
src/assets/images/pointer.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
src/assets/images/uploading.png
Normal file
|
After Width: | Height: | Size: 54 KiB |
@@ -1,3 +0,0 @@
|
||||
<svg width="23" height="21" viewBox="0 0 23 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M18.2989 0.179993H21.6917L14.2792 8.65277L23 20.18H16.172L10.8246 13.1879L4.7047 20.18H1.31005L9.23888 11.1172L0.873047 0.180915H7.87438L12.7082 6.57192L18.2989 0.179993ZM17.1087 18.1498H18.9886L6.85286 2.10412H4.83562L17.1087 18.1498Z" fill="#0A1F69"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 366 B |
@@ -40,6 +40,7 @@ h5 {
|
||||
--blue-semi: rgba(207, 226, 255, 0.5);
|
||||
--blue-pale: #f9fafd;
|
||||
--beige: #f5f3ec;
|
||||
--beige-pale: #ececec80;
|
||||
--yellow: #fec868;
|
||||
--orange: #ff6f00;
|
||||
--green: #59ce8f;
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
export function createLink(href: string, text: string): string {
|
||||
return `<a href='mailto:signalement.ign@panoramax.fr${href}' target='_blank' title='${text}' class='gvs-btn gvs-widget-bg gvs-btn-large' style='font-size: 1.6em;display: block'><i class="bi bi-exclamation-triangle"></i></a>`
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { title } from '@/utils/index'
|
||||
import title from '@/utils/index'
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
<template>
|
||||
<footer class="footer">
|
||||
<div class="wrapper-footer">
|
||||
<div class="wrapper-section">
|
||||
<h3 class="title">{{ $t('general.footer.panoramax_title') }}</h3>
|
||||
<ul class="link-list">
|
||||
<li class="link">
|
||||
<Link
|
||||
:text="$t('general.footer.panoramax_site')"
|
||||
type="external"
|
||||
path-external="https://panoramax.fr/"
|
||||
look="link"
|
||||
/>
|
||||
</li>
|
||||
<li class="link">
|
||||
<Link
|
||||
:text="$t('general.footer.panoramax_faq')"
|
||||
type="external"
|
||||
path-external="https://panoramax.fr/foire-aux-questions"
|
||||
look="link"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="wrapper-section">
|
||||
<h3 class="title">{{ $t('general.footer.information_title') }}</h3>
|
||||
<ul class="link-list">
|
||||
<li class="link">
|
||||
<Link
|
||||
:text="$t('general.footer.information_forum')"
|
||||
type="external"
|
||||
path-external="https://forum.geocommuns.fr/c/panoramax/6"
|
||||
look="link"
|
||||
/>
|
||||
</li>
|
||||
<li class="link">
|
||||
<Link
|
||||
:text="$t('general.footer.information_gitlab')"
|
||||
type="external"
|
||||
path-external="https://gitlab.com/geovisio"
|
||||
look="link"
|
||||
/>
|
||||
</li>
|
||||
<li class="link">
|
||||
<Link
|
||||
:text="$t('general.footer.information_github')"
|
||||
type="external"
|
||||
path-external="https://github.com/panoramax-project/"
|
||||
look="link"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="wrapper-section">
|
||||
<h3 class="title">{{ $t('general.footer.rs_title') }}</h3>
|
||||
<ul class="logo-list">
|
||||
<li class="logo">
|
||||
<Link
|
||||
:image="{
|
||||
url: 'mastodon.svg',
|
||||
alt: $t('general.footer.mastodon_alt')
|
||||
}"
|
||||
type="external"
|
||||
path-external="https://mapstodon.space/@panoramax"
|
||||
/>
|
||||
</li>
|
||||
<li class="logo">
|
||||
<Link
|
||||
:image="{
|
||||
url: 'linkedin.svg',
|
||||
alt: $t('general.footer.linkedin_alt')
|
||||
}"
|
||||
type="external"
|
||||
path-external="https://github.com/panoramax-project/"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<Link
|
||||
:image="{
|
||||
url: 'x.svg',
|
||||
alt: $t('general.footer.twitter_alt')
|
||||
}"
|
||||
type="external"
|
||||
path-external="https://twitter.com/panoramax_"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ay11-text">
|
||||
<Link
|
||||
:text="$t('general.footer.ay11_text')"
|
||||
:route="{ name: 'ay11' }"
|
||||
look="link"
|
||||
/>
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Link from './Link.vue'
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
ul {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.footer {
|
||||
padding: toRem(2);
|
||||
border-top: toRem(0.1) solid var(--grey);
|
||||
}
|
||||
.wrapper-footer {
|
||||
display: flex;
|
||||
}
|
||||
.wrapper-section {
|
||||
width: 33%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.title {
|
||||
@include text(m-regular);
|
||||
color: var(--blue);
|
||||
margin-bottom: toRem(1.5);
|
||||
}
|
||||
.link-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: initial;
|
||||
}
|
||||
.logo-list {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.link {
|
||||
margin-bottom: toRem(0.3);
|
||||
width: fit-content;
|
||||
}
|
||||
.logo {
|
||||
margin-right: toRem(2);
|
||||
height: toRem(3);
|
||||
}
|
||||
.ay11-text {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
@media (max-width: toRem(50)) {
|
||||
.footer {
|
||||
padding: toRem(2);
|
||||
}
|
||||
.wrapper-footer {
|
||||
flex-direction: column;
|
||||
}
|
||||
.ay11-text {
|
||||
margin-top: toRem(2);
|
||||
justify-content: initial;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -7,9 +7,14 @@
|
||||
<div class="wrapper-logo desktop">
|
||||
<Link
|
||||
:image="{ url: 'logo.jpeg', alt: $t('general.header.alt_logo') }"
|
||||
:text="title($t('general.header.title'))"
|
||||
:route="{ name: 'home' }"
|
||||
/>
|
||||
<span class="title-text"
|
||||
>{{ $t('general.header.title') }}
|
||||
<span v-if="instanceName" class="instance-text">{{
|
||||
instanceName
|
||||
}}</span></span
|
||||
>
|
||||
</div>
|
||||
<div class="wrapper-logo responsive">
|
||||
<Link
|
||||
@@ -109,7 +114,6 @@ import { useCookies } from 'vue3-cookies'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { getAuthRoute } from '@/utils/auth'
|
||||
import { title } from '@/utils/index'
|
||||
import Link from '@/components/Link.vue'
|
||||
import BetaText from '@/components/BetaText.vue'
|
||||
|
||||
@@ -133,6 +137,7 @@ function toggleMenu(): void {
|
||||
menuIsClosed.value = !menuIsClosed.value
|
||||
}
|
||||
const isLogged = computed((): boolean => !!cookies.get('user_id'))
|
||||
const instanceName = computed((): string => import.meta.env.VITE_INSTANCE_NAME)
|
||||
const ariaLabel = computed((): string =>
|
||||
menuIsClosed.value
|
||||
? t('general.header.burger_menu_aria_label_open')
|
||||
@@ -164,7 +169,16 @@ const userName = computed((): string =>
|
||||
.wrapper-logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: toRem(4);
|
||||
color: var(--blue-dark);
|
||||
}
|
||||
.title-text {
|
||||
font-weight: bolder;
|
||||
}
|
||||
.instance-text {
|
||||
font-weight: normal;
|
||||
border-left: toRem(0.1) solid var(--blue-dark);
|
||||
padding-left: toRem(0.7);
|
||||
margin-left: toRem(0.5);
|
||||
}
|
||||
.wrapper-entries {
|
||||
display: flex;
|
||||
@@ -173,7 +187,7 @@ const userName = computed((): string =>
|
||||
display: none;
|
||||
}
|
||||
.desktop {
|
||||
display: block;
|
||||
display: flex;
|
||||
}
|
||||
.wrapper-logo p {
|
||||
@include text(m-r-regular);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
@click="$emit('trigger')"
|
||||
>
|
||||
<div
|
||||
v-if="status.length && (status === 'ready' || status === 'hidden')"
|
||||
v-if="status.length && status !== 'waiting-for-process'"
|
||||
class="photo-img-wrapper"
|
||||
>
|
||||
<i v-if="status === 'hidden'" class="bi bi-eye-slash icon-hidden"></i>
|
||||
@@ -20,18 +20,8 @@
|
||||
class="photo-img"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="status.length && status === 'broken'"
|
||||
class="waiting-wrapper error"
|
||||
>
|
||||
<i class="bi bi-exclamation-octagon icon-waiting"></i>
|
||||
<span class="waiting info">{{ $t('pages.sequence.broken') }}</span>
|
||||
</div>
|
||||
<div v-else class="waiting-wrapper">
|
||||
<i class="bi bi-card-image icon-waiting"></i>
|
||||
<span class="waiting info">{{
|
||||
$t('pages.sequence.waiting_process')
|
||||
}}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="selectedOnMap && !selected"
|
||||
@@ -46,10 +36,12 @@
|
||||
>
|
||||
<i class="bi bi-check-lg" />
|
||||
</div>
|
||||
<div
|
||||
v-if="status.length && (status === 'ready' || status === 'hidden')"
|
||||
class="photo-info"
|
||||
>
|
||||
<div v-if="status === 'waiting-for-process'" class="photo-info">
|
||||
<span class="waiting info">{{
|
||||
$t('pages.sequence.waiting_process')
|
||||
}}</span>
|
||||
</div>
|
||||
<div v-else class="photo-info">
|
||||
<span v-if="created" class="info"
|
||||
><i class="bi bi-clock"></i> {{ created }}</span
|
||||
>
|
||||
@@ -80,7 +72,7 @@ defineProps({
|
||||
status: {
|
||||
type: String,
|
||||
validator: (value: string): boolean =>
|
||||
['waiting-for-process', 'ready', 'hidden', 'broken', ''].includes(value),
|
||||
['waiting-for-process', 'ready', 'hidden', ''].includes(value),
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
@@ -125,32 +117,13 @@ defineProps({
|
||||
.waiting-wrapper {
|
||||
height: toRem(16);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: var(--blue);
|
||||
margin-right: toRem(1);
|
||||
margin-left: toRem(1);
|
||||
&.error {
|
||||
color: var(--red);
|
||||
}
|
||||
}
|
||||
.icon-waiting {
|
||||
font-size: toRem(3);
|
||||
margin-bottom: toRem(1);
|
||||
}
|
||||
.waiting-info {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
color: var(--black);
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.info {
|
||||
@include text(xs-r-regular);
|
||||
padding: toRem(0.5) toRem(0.8);
|
||||
background-color: var(--white);
|
||||
border-radius: toRem(0.5);
|
||||
height: toRem(4);
|
||||
font-size: toRem(4);
|
||||
}
|
||||
.icon-img {
|
||||
top: toRem(1);
|
||||
@@ -183,6 +156,19 @@ defineProps({
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.waiting {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
color: var(--black);
|
||||
}
|
||||
|
||||
.info {
|
||||
padding: toRem(0.5) toRem(0.8);
|
||||
background-color: var(--white);
|
||||
border-radius: toRem(0.5);
|
||||
color: var(--blue);
|
||||
}
|
||||
|
||||
.button-image-item:hover {
|
||||
.photo-img {
|
||||
opacity: 0.5;
|
||||
|
||||
@@ -77,5 +77,6 @@ function updateValue(value: boolean): void {
|
||||
.label {
|
||||
cursor: pointer;
|
||||
margin-left: toRem(0.5);
|
||||
@include text(s-regular);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
type="file"
|
||||
multiple
|
||||
:accept="accept"
|
||||
capture="environment"
|
||||
class="input-file"
|
||||
@change="changeFile"
|
||||
/>
|
||||
@@ -67,7 +68,9 @@ function drop(event: DragEvent): void | boolean {
|
||||
}
|
||||
|
||||
function checkPicturesType(files: FileList): number {
|
||||
const picturesToUpload = [...files].filter((p) => p.type == 'image/jpeg')
|
||||
const picturesToUpload = [...files]
|
||||
.filter((p) => p.type == 'image/jpeg')
|
||||
.sort((a, b) => a.name.localeCompare(b.name))
|
||||
return picturesToUpload.length
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -61,9 +61,8 @@ const titleImg = computed<string>(() =>
|
||||
@include text(s-regular);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--black);
|
||||
color: var(--blue-dark);
|
||||
text-decoration: none;
|
||||
height: inherit;
|
||||
.icon {
|
||||
margin-right: toRem(1);
|
||||
}
|
||||
@@ -76,9 +75,9 @@ const titleImg = computed<string>(() =>
|
||||
font-size: toRem(2.4);
|
||||
}
|
||||
.logo {
|
||||
height: toRem(4);
|
||||
border-radius: toRem(0.5);
|
||||
margin-right: toRem(1);
|
||||
height: inherit;
|
||||
}
|
||||
.button {
|
||||
height: toRem(4);
|
||||
@@ -95,10 +94,6 @@ const titleImg = computed<string>(() =>
|
||||
background-color: transparent;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.link--grey {
|
||||
color: var(--grey-semi-dark);
|
||||
text-decoration: underline;
|
||||
}
|
||||
.button--white {
|
||||
background-color: var(--white);
|
||||
color: var(--black);
|
||||
|
||||
38
src/components/share-pictures/ShareCard.vue
Normal file
@@ -0,0 +1,38 @@
|
||||
<template>
|
||||
<div class="share-card">
|
||||
<img v-if="image" :src="img(image.url)" :alt="image.alt" class="image" />
|
||||
<h2 class="title">{{ title }}</h2>
|
||||
<p class="text">{{ text }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { img } from '../../utils/image'
|
||||
import type { PropType } from 'vue'
|
||||
interface ImageInterface {
|
||||
url: string
|
||||
alt: string
|
||||
}
|
||||
defineProps({
|
||||
image: { type: Object as PropType<ImageInterface>, default: null },
|
||||
title: { type: String, default: '' },
|
||||
text: { type: String, default: '' }
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.share-card {
|
||||
color: var(--blue-dark);
|
||||
}
|
||||
.title {
|
||||
@include text(h2);
|
||||
}
|
||||
.text {
|
||||
@include text(s-regular);
|
||||
color: var(--grey-semi-dark);
|
||||
}
|
||||
.image {
|
||||
height: toRem(8);
|
||||
margin-bottom: toRem(1);
|
||||
}
|
||||
</style>
|
||||
@@ -1,9 +1,6 @@
|
||||
<template>
|
||||
<section :class="['information-section', { 'first-sequence': index === 0 }]">
|
||||
<div :class="['imported', { 'first-sequence': index === 0 }]">
|
||||
<div class="uploaded-pictures">
|
||||
<p v-if="index === 0" class="title-current-upload">
|
||||
{{ $t('pages.upload.sequence_uploading_title') }}
|
||||
</p>
|
||||
<p v-if="sequence.pictures" class="uploaded-title">
|
||||
<span
|
||||
>{{ $t('pages.upload.import') }} {{ sequence.title }} -
|
||||
@@ -42,7 +39,7 @@
|
||||
/>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -66,16 +63,11 @@ defineProps({
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.information-section {
|
||||
.imported {
|
||||
display: flex;
|
||||
margin-bottom: toRem(4);
|
||||
padding-top: toRem(2);
|
||||
padding-bottom: toRem(2);
|
||||
width: 80%;
|
||||
box-shadow: 0px 6.45694px 8.60925px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
.first-sequence {
|
||||
background-color: var(--blue-pale);
|
||||
border-radius: toRem(0.5);
|
||||
}
|
||||
.uploaded-pictures,
|
||||
@@ -89,7 +81,6 @@ defineProps({
|
||||
margin-left: toRem(2);
|
||||
}
|
||||
.uploaded-title {
|
||||
margin-left: toRem(2);
|
||||
margin-bottom: toRem(2);
|
||||
width: 100%;
|
||||
color: var(--grey-semi-dark);
|
||||
@@ -101,9 +92,11 @@ defineProps({
|
||||
}
|
||||
.uploaded-picture-list,
|
||||
.uploaded-error-list {
|
||||
padding: 0rem toRem(2) toRem(2);
|
||||
padding-top: 0rem;
|
||||
padding-right: toRem(2);
|
||||
padding-bottom: toRem(2);
|
||||
overflow-y: auto;
|
||||
max-height: toRem(35);
|
||||
max-height: toRem(50);
|
||||
}
|
||||
.bi-check-circle {
|
||||
color: var(--green);
|
||||
@@ -128,4 +121,13 @@ defineProps({
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: toRem(50)) {
|
||||
.imported {
|
||||
flex-direction: column;
|
||||
}
|
||||
.uploaded-error-list {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -34,8 +34,9 @@ const itemUploadedText = computed<string | null>(
|
||||
margin-top: toRem(1);
|
||||
border-radius: toRem(0.5);
|
||||
width: 100%;
|
||||
@include text(s-regular);
|
||||
@include text(xs-r-regular);
|
||||
}
|
||||
|
||||
.success {
|
||||
background-color: var(--white);
|
||||
border: toRem(0.1) solid var(--grey);
|
||||
|
||||
46
src/components/upload/TooltipBanner.vue
Normal file
@@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<div v-if="isDisplayed" class="tooltip-banner">
|
||||
<div class="top-banner">
|
||||
<span
|
||||
><i class="bi bi-info-circle"></i>
|
||||
{{ $t('pages.upload.tooltip_banner_title') }}</span
|
||||
>
|
||||
<Button look="no-text" icon="bi bi-x-lg" @trigger="isDisplayed = false" />
|
||||
</div>
|
||||
<p class="text-banner">{{ $t('pages.upload.tooltip_banner_text') }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import Button from '@/components/Button.vue'
|
||||
|
||||
let isDisplayed = ref<boolean>(true)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.tooltip-banner {
|
||||
border-left: toRem(1) solid var(--blue);
|
||||
border-radius: toRem(1);
|
||||
padding: toRem(2);
|
||||
background-color: var(--white);
|
||||
}
|
||||
.top-banner {
|
||||
@include text(h2);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: toRem(0.5);
|
||||
color: var(--blue-dark);
|
||||
}
|
||||
.text-banner {
|
||||
@include text(s-regular);
|
||||
margin-bottom: 0;
|
||||
margin-right: 3rem;
|
||||
color: var(--grey-semi-dark);
|
||||
}
|
||||
@media (max-width: toRem(76.8)) {
|
||||
.text-banner {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -57,7 +57,6 @@ const uploadPendingTitle = computed<string>(() => {
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-top: toRem(4);
|
||||
}
|
||||
.loader {
|
||||
position: relative;
|
||||
|
||||
@@ -3,15 +3,14 @@ import { onMounted, ref } from 'vue'
|
||||
import type { AuthConfigInterface } from './interfaces/Auth'
|
||||
|
||||
export default function authConfig() {
|
||||
const authConf = ref<AuthConfigInterface>()
|
||||
const authConf = ref<AuthConfigInterface>({})
|
||||
|
||||
async function getConfig(): Promise<AuthConfigInterface> {
|
||||
async function getConfig(): Promise<object> {
|
||||
const { data } = await axios.get('api/configuration', {
|
||||
withCredentials: false
|
||||
})
|
||||
return data
|
||||
return data.auth
|
||||
}
|
||||
|
||||
onMounted(async () => (authConf.value = await getConfig()))
|
||||
return { authConf }
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export interface AuthConfigInterface {
|
||||
license?: { id: string; url: string }
|
||||
auth?: {
|
||||
enabled?: boolean
|
||||
user_profile?: { url?: string }
|
||||
}
|
||||
interface UserProfileInterface {
|
||||
url?: string
|
||||
}
|
||||
export interface AuthConfigInterface {
|
||||
enabled?: boolean
|
||||
user_profile?: UserProfileInterface
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
"description": "Panoramax, l’alternative libre pour photo-cartographier les territoires"
|
||||
},
|
||||
"header": {
|
||||
"contribute_text": "À propos",
|
||||
"upload_text": "Contribuer",
|
||||
"contribute_text": "Comment contribuer ?",
|
||||
"upload_text": "Partager des photos",
|
||||
"sequences_text": "Mes photos",
|
||||
"alt_logo": "Logo de l'instance",
|
||||
"title": "Instance\nPanoramax",
|
||||
"title": "Panoramax",
|
||||
"beta_text": "Version beta",
|
||||
"logout_text": "Déconnexion",
|
||||
"my_information_text": "Mes informations",
|
||||
@@ -19,26 +19,13 @@
|
||||
"burger_menu_aria_label_open": "Afficher le menu",
|
||||
"burger_menu_aria_label_closed": "Masquer le menu"
|
||||
},
|
||||
"footer": {
|
||||
"panoramax_title": "Panoramax",
|
||||
"panoramax_site": "Site vitrine",
|
||||
"panoramax_faq": "FAQ",
|
||||
"information_title": "Ressources",
|
||||
"information_forum": "Forum",
|
||||
"information_gitlab": "Gitlab",
|
||||
"information_github": "Github",
|
||||
"rs_title": "Suivez-nous",
|
||||
"mastodon_alt": "Logo Mastodon",
|
||||
"linkedin_alt": "Logo Linkedin",
|
||||
"twitter_alt": "Logo Twitter",
|
||||
"ay11_text": "Accessibilité : non conforme"
|
||||
},
|
||||
"error_text": "Une erreur est survenue",
|
||||
"success_text": "Mise à jour réussie"
|
||||
},
|
||||
"pages": {
|
||||
"home": {
|
||||
"report_mail": "?subject=⚠️ Signalement sur l`image {picId}&body=Bonjour, %0D%0A%0D%0A Problème sur l`image (garder le type de problème signalé) : %0D%0A%0D%0A contenu inapproprié / absence de floutage sur un élément à anonymiser ou flouter pour des raisons de sécurité /surfloutage (floutage en trop) %0D%0A%0D%0A Lien vers la photo concernée : {link} %0D%0A%0D%0A Précision sur les éléments concernés (en particulier pour les problèmes de floutage - que faut-il flouter ou déflouter?) :",
|
||||
"report_mail_subject": "⚠️ Signalement sur l'image {id}",
|
||||
"report_mail_body": "Bonjour, %0D%0A%0D%0A Problème sur l'image (garder le type de problème signalé) : %0D%0A%0D%0A contenu inapproprié / absence de floutage sur un élément à anonymiser ou flouter pour des raisons de sécurité /surfloutage (floutage en trop) %0D%0A%0D%0A Lien vers la photo concernée : {link} %0D%0A%0D%0A Précision sur les éléments concernés (en particulier pour les problèmes de floutage - que faut-il flouter ou déflouter?) : ",
|
||||
"report_button_text": "Signaler la photo"
|
||||
},
|
||||
"settings": {
|
||||
@@ -46,9 +33,9 @@
|
||||
"setting_tooltip": "Afficher ou masquer le token"
|
||||
},
|
||||
"sequence": {
|
||||
"sequence_published": "Publiée",
|
||||
"sequence_published": "Séquence publiée",
|
||||
"sequence_waiting": "En cours de publication",
|
||||
"sequence_hidden": "Masquée",
|
||||
"sequence_hidden": "Séquence masquée",
|
||||
"hide_sequence_tooltip": "Masque la séquence sur la carte",
|
||||
"delete_sequence_tooltip": "Supprime définitivement la séquence",
|
||||
"hide_photo_tooltip": "Masque les photos sur la carte",
|
||||
@@ -72,7 +59,6 @@
|
||||
"unselect_text": "Tout désélectionner",
|
||||
"select_shift_text": "Sélectionnez plusieurs photos avec shift",
|
||||
"waiting_process": "Photo en cours de traitement",
|
||||
"broken": "Traitement de la photo en erreur",
|
||||
"no_image": "Aucune photo dans cette séquence"
|
||||
},
|
||||
"sequences": {
|
||||
@@ -89,18 +75,25 @@
|
||||
"sequence_deleted": "La séquence a bien été supprimée"
|
||||
},
|
||||
"share_pictures": {
|
||||
"title": "Partagez vos photos",
|
||||
"sub_title": "Un compte utilisateur est obligatoire pour partager des photos",
|
||||
"photo_type1": "Des lieux visibles depuis la voie publique",
|
||||
"photo_type2": "360° ou non",
|
||||
"photo_type3": "Vues du sol",
|
||||
"photo_type4": "Géolocalisées",
|
||||
"description": "Ici, vos photos sont accessibles à tous :\n\n{check} automatiquement floutées dans le respect de <a href='https://panoramax.fr/foire-aux-questions' target='_blank' style='color:black'>la législation</a>\n{check} libres de droit, <a href={licenseUrl} target='_blank' style='color:black'>sous licence {licenseName}</a>\n{check} sous forme «brute» pour des réutilisations variées (ex: préparation des chantiers)\n\n",
|
||||
"footer_block": "⚠️️️ Aujourd'hui, le versement de grands volumes d'images est possible via une ligne de commande et via une interface web.",
|
||||
"title": "Pourquoi partager ses photos sur Panoramax ?",
|
||||
"description": "Avec Panoramax, vos photos sont accessibles à tous. Elles seront automatiquement floutées grâce à notre algorithme de floutage dans le respect de <a href='https://panoramax.fr/foire-aux-questions' target='_blank' style='color:black'>la législation</a> et libres de droit.\nLa mise en ligne se fera <a href='https://www.etalab.gouv.fr/licence-ouverte-open-licence/' target='_blank' style='color:black'>sous licence ouverte</a> sous forme «brute» pour des réutilisations variées (ex: préparation des chantiers, gestion de la voirie etc).",
|
||||
"arg_title1": "Des lieux visibles depuis la voie publique",
|
||||
"arg_title2": "Une gestion des photos au format 360° ou non",
|
||||
"arg_title3": "Une fonctionnalité de visualisation de vue du sol",
|
||||
"arg_title4": "Des photos automatiquement géolocalisées",
|
||||
"arg_text1": "Le lorem ipsum est, en imprimerie, une suite de mots sans signification utilisée à titre provisoire pour calibrer une mise en page, le texte définitif venant remplacer le faux-texte dès qu'il est prêt ou que la",
|
||||
"arg_text2": "Le lorem ipsum est, en imprimerie, une suite de mots sans signification utilisée à titre provisoire pour calibrer une mise en page, le texte définitif venant remplacer le faux-texte dès qu'il est prêt ou que la",
|
||||
"arg_text3": "Le lorem ipsum est, en imprimerie, une suite de mots sans signification utilisée à titre provisoire pour calibrer une mise en page, le texte définitif venant remplacer le faux-texte dès qu'il est prêt ou que la",
|
||||
"arg_text4": "Le lorem ipsum est, en imprimerie, une suite de mots sans signification utilisée à titre provisoire pour calibrer une mise en page, le texte définitif venant remplacer le faux-texte dès qu'il est prêt ou que la",
|
||||
"arg_alt1": "Image d'un immeuble",
|
||||
"arg_alt2": "Image d'un signe 360",
|
||||
"arg_alt3": "Image d'un pointer de localisation sur une carte",
|
||||
"arg_alt4": "Image d'un pointer de localisation",
|
||||
"footer_block": "⚠️️️ Aujourd'hui, le versement de grands volumes d'images est possible via une ligne de commande. Bientôt, d'autres moyens de versement seront disponibles, notamment via une interface web.",
|
||||
"button": "Accéder à l'outil",
|
||||
"alt_img_upload": "Image qui représente plusieurs photos en cours de téléchargement",
|
||||
"title_terminal": "Utilisez la ligne de commande",
|
||||
"footer_description_terminal": "Les données déposées seront sous {word}",
|
||||
"footer_description_terminal": "Les données déposées seront sous <a href='https://www.etalab.gouv.fr/licence-ouverte-open-licence/' target='_blank' style='color:#808080'>la licence ouverte</a>.",
|
||||
"cli_title": "Vous voulez accéder à plus de documentation ?",
|
||||
"user_account_button": "Créer un compte",
|
||||
"description_terminal": "<a href='https://gitlab.com/geovisio/cli' target='_blank' style='color:black'>L'outil en ligne de commande</a> vous permet de partager de grands volumes de photos. La procédure est simple et vous devez disposer <a target='_blank' href='https://www.python.org/downloads/' style='color:black'>de python (au moins la version 3.8)</a>.\n\n1. Installer l’outil en ligne de commande geovisio\n2. Lancez la commande de versement d’images sur le dossier choisi. Après '--api-url', renseignez l'url de l'api de l'instance où partager les photos et le chemin vers votre dossier de photos sur votre machine. L’outil demandera vos informations de connexion avant l'import. Une fois les données chargées, un temps de traitement est nécessaire pour les rendre disponibles.",
|
||||
@@ -110,11 +103,16 @@
|
||||
},
|
||||
"upload": {
|
||||
"title": "Déposez vos photos",
|
||||
"input_label": "Déposez des photos dans la zone ou ",
|
||||
"import_word": "importez",
|
||||
"title_uploading": "Traitement des images",
|
||||
"text": "Déposez vos fichiers dans cet espace. Chaque photo ou groupe de photos envoyé constituera une 'séquence'. Vous pourrez retrouver ensuite toutes vos séquences dans la section 'Mes images'. Déposez vos fichiers dans cet espace. Chaque photo ou groupe de photos envoyé",
|
||||
"no_picture_uploading_text": "Aucune photo en cours de téléchargement actuellement",
|
||||
"tooltip_banner_title": "Contribuez à la base de photos de Panoramax",
|
||||
"tooltip_banner_text": "Déposez vos fichiers dans cet espace. Chaque photo ou groupe de photos envoyé constituera une 'séquence'. Vous pourrez retrouver ensuite toutes vos séquences dans la section 'Mes images'.",
|
||||
"input_label": "Glissez vos images ici ou cliquez sur ",
|
||||
"import_word": "importer",
|
||||
"import_type": "Format JPEG uniquement",
|
||||
"sequence_title": "Séquence du ",
|
||||
"button_text": "Envoyer",
|
||||
"button_text": "Télécharger",
|
||||
"uploaded_files": "{count} fichier| {count} fichiers",
|
||||
"no_uploaded_files": "Aucun fichier sélectionné",
|
||||
"uploaded_word": " Image téléchargée",
|
||||
@@ -125,7 +123,7 @@
|
||||
"upload_done": "Transfert terminé !",
|
||||
"upload_pending_pictures": "Envoi de {count} photo en cours |Envoi de {count} photos en cours",
|
||||
"sequence_link": "Voir la sequence",
|
||||
"button_new_upload": "Nouvel envoi",
|
||||
"button_new_upload": "Nouveau téléchargement",
|
||||
"leave_message": "⚠️ Attention, le téléchargement sera interrompu si vous quittez la page avant la fin."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ import MySequencesView from '../views/MySequencesView.vue'
|
||||
import MySequenceView from '../views/MySequenceView.vue'
|
||||
import SharePicturesView from '../views/SharePicturesView.vue'
|
||||
import UploadPicturesView from '../views/UploadPicturesView.vue'
|
||||
import Ay11View from '../views/Ay11View.vue'
|
||||
const { cookies } = useCookies()
|
||||
const routes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
@@ -37,11 +36,6 @@ const routes: Array<RouteRecordRaw> = [
|
||||
name: 'my-sequences',
|
||||
component: MySequencesView
|
||||
},
|
||||
{
|
||||
path: '/accessibilite',
|
||||
name: 'ay11',
|
||||
component: Ay11View
|
||||
},
|
||||
{ path: '/sequence/:id', name: 'sequence', component: MySequenceView },
|
||||
{
|
||||
path: '/partager-des-photos',
|
||||
@@ -49,7 +43,7 @@ const routes: Array<RouteRecordRaw> = [
|
||||
component: SharePicturesView
|
||||
},
|
||||
{
|
||||
path: '/envoyer',
|
||||
path: '/telecharger',
|
||||
name: 'upload-pictures',
|
||||
component: UploadPicturesView
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
describe('In the home page', () => {
|
||||
it('click on the link in the header to go to the upload page', () => {
|
||||
it('click on the link in the header to go to the utils page', () => {
|
||||
cy.visit('/')
|
||||
cy.fixture('home').then((homeData) => {
|
||||
cy.contains(homeData.textLinkUpload).click()
|
||||
22
src/tests/cypress/e2e/upload.cy.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
describe('In the utils page', () => {
|
||||
it('go to the login page', () => {
|
||||
cy.visit('partager-des-photos')
|
||||
cy.fixture('upload').then((uploadData) => {
|
||||
cy.contains(uploadData.textButtonUpload).click()
|
||||
})
|
||||
})
|
||||
it('go to the login page', () => {
|
||||
cy.visit('partager-des-photos')
|
||||
cy.fixture('upload').then((uploadData) => {
|
||||
cy.contains(uploadData.textButtonUpload).click()
|
||||
})
|
||||
})
|
||||
it('go to the cli page', () => {
|
||||
cy.visit('partager-des-photos')
|
||||
cy.fixture('upload').then((uploadData) => {
|
||||
cy.contains(uploadData.textButtonCli).click()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
export {}
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"addressToSearch": "97 boulevard Voltaire 75011 paris",
|
||||
"textAddressToSelect": "Boulevard Voltaire, Quartier de la Folie-Méricourt, Paris 11e Arrondissement, Paris, Île-de-France, France métropolitaine, 75011, France",
|
||||
"textLinkUpload": "À propos"
|
||||
"textLinkUpload": "Aide"
|
||||
}
|
||||
4
src/tests/cypress/fixtures/upload.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"textButtonUpload": "Créer un compte",
|
||||
"textButtonCli": "Accéder à l'outil"
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { test, describe, vi, expect } from 'vitest'
|
||||
import { shallowMount } from '@vue/test-utils'
|
||||
import { mount, shallowMount } from '@vue/test-utils'
|
||||
import Link from '../../../components/Link.vue'
|
||||
import { createI18n } from 'vue-i18n'
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
|
||||
@@ -29,7 +29,7 @@ describe('Template', () => {
|
||||
}
|
||||
})
|
||||
expect(wrapper.html()).contains('button-stub')
|
||||
expect(wrapper.html()).contains('text="Nouvel envoi"')
|
||||
expect(wrapper.html()).contains('text="Nouveau téléchargement"')
|
||||
})
|
||||
})
|
||||
describe('When the component have an uploaded sequence', () => {
|
||||
@@ -59,7 +59,7 @@ describe('Template', () => {
|
||||
loadPercentage: '100%'
|
||||
}
|
||||
})
|
||||
expect(wrapper.html()).contains('text="Nouvel envoi"')
|
||||
expect(wrapper.html()).contains('text="Nouveau téléchargement"')
|
||||
expect(wrapper.html()).contains('Transfert terminé !')
|
||||
expect(wrapper.html()).contains('2345 Mo/2345 Mo')
|
||||
})
|
||||
|
||||
@@ -6,7 +6,6 @@ const i18n = createI18n({
|
||||
fallbackLocale: 'fr',
|
||||
globalInjection: true,
|
||||
legacy: false,
|
||||
warnHtmlMessage: false,
|
||||
messages: {
|
||||
fr
|
||||
}
|
||||
|
||||
@@ -7,12 +7,11 @@ import {
|
||||
} from '../../views/utils/sequence/index'
|
||||
import {
|
||||
formatPictureSize,
|
||||
formatTextSize,
|
||||
sortByName
|
||||
formatTextSize
|
||||
} from '../../views/utils/upload/index'
|
||||
import { getAuthRoute } from '../../utils/auth'
|
||||
import { img } from '../../utils/image'
|
||||
import { title } from '../../utils/index'
|
||||
import { img, getPicId } from '../../utils/image'
|
||||
import title from '../../utils/index'
|
||||
|
||||
describe('imageStatus', () => {
|
||||
it('should render the "status" value', () => {
|
||||
@@ -157,6 +156,19 @@ describe('img', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('getPicId', () => {
|
||||
it('should return the Id of the picture in the url', () => {
|
||||
const url = 'http://dummy.com?pic=3205340583&test'
|
||||
Object.defineProperty(window, 'location', {
|
||||
value: {
|
||||
href: url
|
||||
},
|
||||
writable: true // possibility to override
|
||||
})
|
||||
expect(getPicId()).toEqual('3205340583')
|
||||
})
|
||||
})
|
||||
|
||||
describe('title', () => {
|
||||
it('should return the formated title with instance name', () => {
|
||||
import.meta.env.VITE_INSTANCE_NAME = 'my instance'
|
||||
@@ -169,36 +181,3 @@ describe('title', () => {
|
||||
expect(title(myTitle)).toEqual('my title')
|
||||
})
|
||||
})
|
||||
|
||||
describe('sortByName', () => {
|
||||
it('should return the the list sorted by name', () => {
|
||||
const list1 = [
|
||||
{ name: 'd_1_ct.jpg' },
|
||||
{ name: 'd_11_ct.jpg' },
|
||||
{ name: 'd_2_ct.jpg' }
|
||||
]
|
||||
expect(sortByName(list1)).toEqual([
|
||||
{ name: 'd_1_ct.jpg' },
|
||||
{ name: 'd_2_ct.jpg' },
|
||||
{ name: 'd_11_ct.jpg' }
|
||||
])
|
||||
|
||||
const list2 = [{ name: 'A.jpg' }, { name: 'Z.jpg' }, { name: 'B.jpg' }]
|
||||
expect(sortByName(list2)).toEqual([
|
||||
{ name: 'A.jpg' },
|
||||
{ name: 'B.jpg' },
|
||||
{ name: 'Z.jpg' }
|
||||
])
|
||||
|
||||
const list3 = [
|
||||
{ name: 'CAM1_001.jpg' },
|
||||
{ name: 'CAM2_002.jpg' },
|
||||
{ name: 'CAM1_011.jpg' }
|
||||
]
|
||||
expect(sortByName(list3)).toEqual([
|
||||
{ name: 'CAM1_001.jpg' },
|
||||
{ name: 'CAM1_011.jpg' },
|
||||
{ name: 'CAM2_002.jpg' }
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
import { it, describe, expect } from 'vitest'
|
||||
import { shallowMount } from '@vue/test-utils'
|
||||
import SharePicturesView from '../../../views/SharePicturesView.vue'
|
||||
import i18n from '../config'
|
||||
import { createI18n } from 'vue-i18n'
|
||||
import fr from '../../../locales/fr.json'
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
|
||||
const i18n = createI18n({
|
||||
locale: 'fr',
|
||||
fallbackLocale: 'fr',
|
||||
globalInjection: true,
|
||||
legacy: false,
|
||||
messages: {
|
||||
fr
|
||||
}
|
||||
})
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes: []
|
||||
@@ -22,7 +32,8 @@ describe('Template', () => {
|
||||
}
|
||||
})
|
||||
expect(wrapper.html()).contains('<link')
|
||||
expect(wrapper.html()).contains('pathexternal=')
|
||||
expect(wrapper.html()).contains('path="')
|
||||
expect(wrapper.html()).contains('/auth/login')
|
||||
expect(wrapper.html()).contains('look="button button--blue"')
|
||||
expect(wrapper.html()).contains('type="external"')
|
||||
})
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
import { it, describe, expect, vi } from 'vitest'
|
||||
import { shallowMount, mount, flushPromises } from '@vue/test-utils'
|
||||
import { shallowMount } from '@vue/test-utils'
|
||||
import UploadPicturesView from '../../../views/UploadPicturesView.vue'
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import i18n from '../config'
|
||||
import InputUpload from '../../../components/InputUpload.vue'
|
||||
import * as createAPictureToASequence from '@/views/utils/upload/request'
|
||||
import * as createASequence from '@/views/utils/upload/request'
|
||||
import { formatDate } from '../../../utils/dates'
|
||||
import * as sortByName from '../../../views/utils/upload/index'
|
||||
import Button from '../../../components/Button.vue'
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes: []
|
||||
@@ -42,91 +39,12 @@ describe('Template', () => {
|
||||
}
|
||||
})
|
||||
const spy = vi.spyOn(wrapper.vm, 'addPictures')
|
||||
const sortByNameMock = vi.spyOn(sortByName, 'sortByName')
|
||||
sortByNameMock.mockReturnValue([{}, {}])
|
||||
const wrapperInputUpload = await wrapper.findComponent(InputUpload)
|
||||
const wrapperInputUpload = wrapper.findComponent(InputUpload)
|
||||
await wrapperInputUpload.trigger('trigger')
|
||||
await wrapperInputUpload.vm.$emit('trigger', [{}, {}])
|
||||
|
||||
expect(spy).toHaveBeenCalledTimes(1)
|
||||
expect(wrapper.html()).contains('2 fichiers')
|
||||
})
|
||||
describe('submit uploadPicture', () => {
|
||||
it('should trigger to uploadPictures', async () => {
|
||||
const wrapper = mount(UploadPicturesView, {
|
||||
global: {
|
||||
plugins: [i18n, router],
|
||||
mocks: {
|
||||
$t: (msg) => msg
|
||||
},
|
||||
components: {
|
||||
InputUpload
|
||||
}
|
||||
}
|
||||
})
|
||||
const spy = vi.spyOn(wrapper.vm, 'uploadPicture')
|
||||
const wrapperInputUpload = wrapper.findComponent(InputUpload)
|
||||
await wrapperInputUpload.trigger('trigger')
|
||||
await wrapperInputUpload.vm.$emit('trigger', [{}, {}])
|
||||
const buttonWrapper = await wrapper.find('[data-test="button-upload"]')
|
||||
await buttonWrapper.trigger('submit.prevent')
|
||||
|
||||
expect(spy).toHaveBeenCalledTimes(1)
|
||||
expect(wrapper.html()).contains('class="loader-percentage"')
|
||||
expect(wrapper.html()).contains('class="lds-ring lg"')
|
||||
})
|
||||
})
|
||||
describe('one sequence has been imported', () => {
|
||||
it('should render a sequence with a list of uploaded pictures', async () => {
|
||||
const wrapper = mount(UploadPicturesView, {
|
||||
global: {
|
||||
plugins: [i18n, router],
|
||||
mocks: {
|
||||
$t: (msg) => msg
|
||||
}
|
||||
}
|
||||
})
|
||||
const picture = {
|
||||
lastModified: 1599133968750,
|
||||
name: '100MSDCF_DSC02790.JPG',
|
||||
size: 2345,
|
||||
type: 'image/jpeg'
|
||||
}
|
||||
const spyASequence = vi.spyOn(createASequence, 'createASequence')
|
||||
const spyPicture = vi.spyOn(
|
||||
createAPictureToASequence,
|
||||
'createAPictureToASequence'
|
||||
)
|
||||
const sortByNameMock = vi.spyOn(sortByName, 'sortByName')
|
||||
sortByNameMock.mockReturnValue([picture])
|
||||
const sequenceId = 'my-id'
|
||||
spyASequence.mockReturnValue({ data: { id: sequenceId } })
|
||||
spyPicture.mockReturnValue({ data: {} })
|
||||
const sequenceTitle = `Séquence du ${formatDate(
|
||||
new Date(),
|
||||
'Do MMMM YYYY, HH:mm:ss'
|
||||
)}`
|
||||
const body = new FormData()
|
||||
body.append('position', '1')
|
||||
body.append('picture', picture)
|
||||
const wrapperInputUpload = wrapper.findComponent(InputUpload)
|
||||
await wrapperInputUpload.trigger('trigger')
|
||||
await wrapperInputUpload.vm.$emit('trigger', [picture])
|
||||
const buttonWrapper = await wrapper.find('[data-test="button-upload"]')
|
||||
await buttonWrapper.trigger('submit.prevent')
|
||||
|
||||
expect(spyASequence).toHaveBeenCalledWith(sequenceTitle)
|
||||
expect(spyPicture).toHaveBeenCalledWith(sequenceId, body)
|
||||
|
||||
expect(wrapper.html()).contains('class="uploaded-picture-list"')
|
||||
expect(wrapper.html()).contains('class="uploaded-picture-item success"')
|
||||
expect(wrapper.html()).contains(
|
||||
'100MSDCF_DSC02790.JPG - pages.upload.uploaded_word'
|
||||
)
|
||||
expect(wrapper.html()).contains('<router-link')
|
||||
expect(wrapper.html()).contains(
|
||||
'class="default button button--white" title="pages.upload.sequence_link"'
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -3,7 +3,7 @@ import 'moment/dist/locale/fr'
|
||||
|
||||
function formatDate(date: Date, formatType: string): string {
|
||||
const formatDate = moment(date)
|
||||
return formatDate.locale(window.navigator.language).format(formatType)
|
||||
return formatDate.locale('fr').format(formatType)
|
||||
}
|
||||
|
||||
function durationCalc(duration1: Date, duration2: Date, type: string): number {
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
export function img(name: string): string {
|
||||
return new URL(`../assets/images/${name}`, import.meta.url).toString()
|
||||
}
|
||||
|
||||
export function getPicId(): string {
|
||||
return window.location.href.substring(
|
||||
window.location.href.indexOf('pic=') + 4,
|
||||
window.location.href.lastIndexOf('&')
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
export function title(title: string): string {
|
||||
export default function title(title: string): string {
|
||||
const instanceName = import.meta.env.VITE_INSTANCE_NAME
|
||||
if (instanceName) return `${title} ${instanceName}`
|
||||
return title
|
||||
}
|
||||
|
||||
export function createUrlLink(picId: string): string {
|
||||
return encodeURIComponent(`${window.location.origin}/#focus=pic&pic=${picId}`)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,44 @@
|
||||
import axios from 'axios'
|
||||
import type {
|
||||
ViewerMapInterface,
|
||||
OptionalViewerMapInterface
|
||||
} from '@/views/interfaces/common'
|
||||
import GeoVisio from 'geovisio'
|
||||
|
||||
async function fetchMapAndViewer(params?: OptionalViewerMapInterface) {
|
||||
const tiles = import.meta.env.VITE_TILES
|
||||
let paramsGeovisio: ViewerMapInterface = {
|
||||
map: {
|
||||
startWide: true,
|
||||
maxZoom: 19
|
||||
}
|
||||
}
|
||||
if (tiles) {
|
||||
const style = tiles.includes('wxs.ign.fr') ? await getIgnTiles() : tiles
|
||||
paramsGeovisio = {
|
||||
map: {
|
||||
...paramsGeovisio.map,
|
||||
style
|
||||
}
|
||||
}
|
||||
}
|
||||
if (params) {
|
||||
const { picId } = params
|
||||
const { fetchOptions } = params
|
||||
if (picId) paramsGeovisio = { ...paramsGeovisio, picId: picId }
|
||||
if (fetchOptions) {
|
||||
paramsGeovisio = {
|
||||
...paramsGeovisio,
|
||||
fetchOptions: fetchOptions
|
||||
}
|
||||
}
|
||||
}
|
||||
return new GeoVisio(
|
||||
'viewer', // Div ID
|
||||
`${import.meta.env.VITE_API_URL}api/search`,
|
||||
paramsGeovisio
|
||||
)
|
||||
}
|
||||
|
||||
async function getIgnTiles(): Promise<object> {
|
||||
const { data } = await axios.get(
|
||||
@@ -18,4 +58,4 @@ async function getIgnTiles(): Promise<object> {
|
||||
return data
|
||||
}
|
||||
|
||||
export { getIgnTiles }
|
||||
export { fetchMapAndViewer }
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
<template>
|
||||
<main class="entry-page">
|
||||
<h1>Déclaration d’accessibilité</h1>
|
||||
<p>Établie le <span>18 septembre 2023</span>.</p>
|
||||
<p>
|
||||
<span>IGN</span> s’engage à rendre son service accessible, conformément à
|
||||
l’article 47 de la loi n° 2005-102 du 11 février 2005.
|
||||
</p>
|
||||
<p>
|
||||
Cette déclaration d’accessibilité s’applique à
|
||||
<strong>Panoramax Instance IGN</strong
|
||||
><span> (<span>https://panoramax.ign.fr</span>)</span>.
|
||||
</p>
|
||||
<h2>État de conformité</h2>
|
||||
<p>
|
||||
<strong>Panoramax Instance IGN</strong> est
|
||||
<strong><span data-printfilter="lowercase">non conforme</span></strong>
|
||||
avec le
|
||||
<abbr title="Référentiel général d’amélioration de l’accessibilité"
|
||||
>RGAA</abbr
|
||||
>. <span>Le site n’a encore pas été audité.</span>
|
||||
</p>
|
||||
<h2>Contenus non accessibles</h2>
|
||||
<h2>Amélioration et contact</h2>
|
||||
<p>
|
||||
Si vous n’arrivez pas à accéder à un contenu ou à un service, vous pouvez
|
||||
contacter le responsable de <span>Panoramax Instance IGN</span> pour être
|
||||
orienté vers une alternative accessible ou obtenir le contenu sous une
|
||||
autre forme.
|
||||
</p>
|
||||
<ul class="basic-information feedback h-card">
|
||||
<li>Téléphone : <span>+33 14 398 84 61</span></li>
|
||||
<li>
|
||||
E-mail :
|
||||
<a
|
||||
href="mailto:camille.salou@ign.frpanoramax@panoramax.frsignalement.ign@panoramax.fr"
|
||||
>signalement.ign@panoramax.fr</a
|
||||
>
|
||||
</li>
|
||||
|
||||
<li>Adresse : <span>IGN, Saint-Mandé</span></li>
|
||||
</ul>
|
||||
<p>Nous essayons de répondre dans les <span>5 jours ouvrés</span>.</p>
|
||||
<h2>Voie de recours</h2>
|
||||
<p>
|
||||
Cette procédure est à utiliser dans le cas suivant : vous avez
|
||||
signalé au responsable du site internet un défaut d’accessibilité qui vous
|
||||
empêche d’accéder à un contenu ou à un des services du portail et vous
|
||||
n’avez pas obtenu de réponse satisfaisante.
|
||||
</p>
|
||||
<p>Vous pouvez :</p>
|
||||
<ul>
|
||||
<li>
|
||||
Écrire un message au
|
||||
<a href="https://formulaire.defenseurdesdroits.fr/"
|
||||
>Défenseur des droits</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
Contacter
|
||||
<a href="https://www.defenseurdesdroits.fr/saisir/delegues"
|
||||
>le délégué du Défenseur des droits dans votre région</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
Envoyer un courrier par la poste (gratuit, ne pas mettre de
|
||||
timbre) :<br />
|
||||
Défenseur des droits<br />
|
||||
Libre réponse 71120 75342 Paris CEDEX 07
|
||||
</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<p>
|
||||
Cette déclaration d’accessibilité a été créé le
|
||||
<span>18 septembre 2023</span> grâce au
|
||||
<a href="https://betagouv.github.io/a11y-generateur-declaration/#create"
|
||||
>Générateur de Déclaration d’Accessibilité de BetaGouv</a
|
||||
>.
|
||||
</p>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.entry-page {
|
||||
padding: toRem(5) toRem(2);
|
||||
}
|
||||
@media (max-width: toRem(50)) {
|
||||
.entry-page {
|
||||
padding-top: toRem(15);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,93 +1,45 @@
|
||||
<template>
|
||||
<main class="entry-page">
|
||||
<section id="viewer" class="entry-viewer"></section>
|
||||
<section id="viewer" class="entry-viewer">
|
||||
<div v-if="mapIsLoaded" class="entry-report-button">
|
||||
<Button
|
||||
:text="$t('pages.home.report_button_text')"
|
||||
look="button--black"
|
||||
@trigger="triggerMailto"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import 'geovisio/build/index.css'
|
||||
import GeoVisio from 'geovisio'
|
||||
import { createLink } from '@/components-viewer/reportLink'
|
||||
import { createUrlLink } from '@/utils/index'
|
||||
import type { ViewerMapInterface } from '@/views/interfaces/common'
|
||||
import { getIgnTiles } from '@/utils/mapAndViewer'
|
||||
import { onMounted, computed, ref } from 'vue'
|
||||
import Button from '@/components/Button.vue'
|
||||
import { fetchMapAndViewer } from '@/utils/mapAndViewer'
|
||||
import { getPicId } from '@/utils/image'
|
||||
|
||||
const { t } = useI18n()
|
||||
let mapIsLoaded = ref<boolean>(false)
|
||||
let viewer = ref()
|
||||
const mailtoPath = computed<string>(() => {
|
||||
return `mailto:signalement.ign@panoramax.fr?subject=${t(
|
||||
'pages.home.report_mail_subject',
|
||||
{
|
||||
id: getPicId()
|
||||
}
|
||||
)}&body=${t('pages.home.report_mail_body', {
|
||||
id: getPicId(),
|
||||
link: encodeURIComponent(window.location.href)
|
||||
})}`
|
||||
})
|
||||
|
||||
function triggerMailto(): void {
|
||||
window.location.href = mailtoPath.value
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
const reportLink = document.createElement('div')
|
||||
reportLink.className = 'gvs-group gvs-group-large gvs-group-btnpanel'
|
||||
const tiles = import.meta.env.VITE_TILES
|
||||
const maxZoom = import.meta.env.VITE_MAX_ZOOM
|
||||
const zoom = import.meta.env.VITE_ZOOM
|
||||
const center = import.meta.env.VITE_CENTER
|
||||
let paramsGeovisio: ViewerMapInterface = {
|
||||
map: {
|
||||
startWide: true
|
||||
}
|
||||
}
|
||||
if (center && center !== '') {
|
||||
const centerMap = center.split(',').map((el: string) => parseInt(el))
|
||||
paramsGeovisio = {
|
||||
map: {
|
||||
...paramsGeovisio.map,
|
||||
center: centerMap
|
||||
}
|
||||
}
|
||||
}
|
||||
if (zoom && zoom !== '') {
|
||||
paramsGeovisio = {
|
||||
map: {
|
||||
...paramsGeovisio.map,
|
||||
zoom: parseFloat(zoom)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (maxZoom && maxZoom !== '') {
|
||||
paramsGeovisio = {
|
||||
map: {
|
||||
...paramsGeovisio.map,
|
||||
maxZoom: parseInt(maxZoom)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tiles) {
|
||||
const style = tiles.includes('wxs.ign.fr') ? await getIgnTiles() : tiles
|
||||
paramsGeovisio = {
|
||||
map: {
|
||||
...paramsGeovisio.map,
|
||||
style
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
viewer.value = await new GeoVisio(
|
||||
'viewer', // Div ID
|
||||
`${import.meta.env.VITE_API_URL}/api/search`,
|
||||
{
|
||||
...paramsGeovisio,
|
||||
widgets: { customWidget: reportLink }
|
||||
}
|
||||
)
|
||||
if (viewer.value && viewer.value.addEventListener) {
|
||||
viewer.value.addEventListener(
|
||||
'picture-loaded',
|
||||
async (e: { detail: { picId: string } }): Promise<void> => {
|
||||
const href = t('pages.home.report_mail', {
|
||||
picId: e.detail.picId,
|
||||
link: createUrlLink(e.detail.picId)
|
||||
})
|
||||
reportLink.innerHTML = createLink(
|
||||
href,
|
||||
t('pages.home.report_button_text')
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
await fetchMapAndViewer()
|
||||
mapIsLoaded.value = true
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
@@ -102,7 +54,14 @@ onMounted(async () => {
|
||||
font-size: initial;
|
||||
width: 100vw;
|
||||
position: relative;
|
||||
min-height: calc(100vh - #{toRem(27.42)});
|
||||
min-height: calc(100vh - #{toRem(8)});
|
||||
}
|
||||
.gvs-has-map .entry-report-button {
|
||||
display: block;
|
||||
position: absolute;
|
||||
right: toRem(1);
|
||||
top: toRem(2);
|
||||
z-index: 1;
|
||||
}
|
||||
.gvs-focus-map .entry-report-button {
|
||||
display: none;
|
||||
|
||||
@@ -17,42 +17,38 @@
|
||||
class="button-collapse"
|
||||
@click="toggleMenu"
|
||||
>
|
||||
<div class="wrapper-title">
|
||||
<span :class="[sequence.status, 'sequence-status']">{{
|
||||
sequenceStatus
|
||||
}}</span>
|
||||
<h1 class="title desktop">
|
||||
{{ sequence.title }}
|
||||
</h1>
|
||||
</div>
|
||||
<span :class="[sequence.status, 'sequence-status']">{{
|
||||
sequenceStatus
|
||||
}}</span>
|
||||
<h1 class="title">
|
||||
{{ sequence.title }}
|
||||
</h1>
|
||||
<i :class="headerPanelIsOpen ? 'bi bi-dash' : 'bi bi-plus'"></i>
|
||||
</button>
|
||||
<h1 class="title responsive">
|
||||
{{ sequence.title }}
|
||||
</h1>
|
||||
</div>
|
||||
<div class="wrapper-button">
|
||||
<Button
|
||||
:tooltip="$t('pages.sequence.hide_sequence_tooltip')"
|
||||
:text="
|
||||
sequence.status === 'ready'
|
||||
? $t('pages.sequence.button_disable')
|
||||
: $t('pages.sequence.button_enable')
|
||||
"
|
||||
look="button--white"
|
||||
:icon="
|
||||
sequence.status === 'ready' ? 'bi bi-eye-slash' : 'bi bi-eye'
|
||||
"
|
||||
class="disable-button"
|
||||
@trigger="patchCollection"
|
||||
/>
|
||||
<Button
|
||||
:tooltip="$t('pages.sequence.delete_sequence_tooltip')"
|
||||
:text="$t('pages.sequence.button_delete')"
|
||||
look="button--red"
|
||||
icon="bi bi-trash"
|
||||
@trigger="deleteCollection"
|
||||
/>
|
||||
<div class="wrapper-button">
|
||||
<div class="disable-button">
|
||||
<Button
|
||||
:tooltip="$t('pages.sequence.hide_sequence_tooltip')"
|
||||
:text="
|
||||
sequence.status === 'ready'
|
||||
? $t('pages.sequence.button_disable')
|
||||
: $t('pages.sequence.button_enable')
|
||||
"
|
||||
look="button--white"
|
||||
:icon="
|
||||
sequence.status === 'ready' ? 'bi bi-eye-slash' : 'bi bi-eye'
|
||||
"
|
||||
@trigger="patchCollection"
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
:tooltip="$t('pages.sequence.delete_sequence_tooltip')"
|
||||
:text="$t('pages.sequence.button_delete')"
|
||||
look="button--red"
|
||||
icon="bi bi-trash"
|
||||
@trigger="deleteCollection"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
:class="[sequence.status, 'collapse py-2 show']"
|
||||
@@ -62,9 +58,7 @@
|
||||
<div class="wrapper-info-top">
|
||||
<span v-if="sequence.created"
|
||||
>{{ $t('pages.sequence.created') }}
|
||||
{{
|
||||
formatDate(new Date(sequence.created), 'Do MMMM YYYY')
|
||||
}}</span
|
||||
{{ formatDate(new Date(sequence.created), 'Do MMMM YY') }}</span
|
||||
>
|
||||
<span v-if="sequence.duration"
|
||||
>{{ $t('pages.sequence.duration') }}
|
||||
@@ -72,7 +66,7 @@
|
||||
>
|
||||
<span v-if="sequence.taken"
|
||||
>{{ $t('pages.sequence.taken') }}
|
||||
{{ formatDate(sequence.taken, 'Do MMMM YYYY') }}</span
|
||||
{{ formatDate(sequence.taken, 'Do MMMM YY') }}</span
|
||||
>
|
||||
</div>
|
||||
<div class="wrapper-info-top">
|
||||
@@ -81,7 +75,7 @@
|
||||
{{
|
||||
formatDate(
|
||||
sequence.extent.temporal.interval[0][0],
|
||||
'Do MMMM YYYY, HH:mm:ss'
|
||||
'Do MMMM YY, hh:mm:ss'
|
||||
)
|
||||
}}</span
|
||||
>
|
||||
@@ -90,7 +84,7 @@
|
||||
{{
|
||||
formatDate(
|
||||
sequence.extent.temporal.interval[0][1],
|
||||
'Do MMMM YYYY, HH:mm:ss'
|
||||
'Do MMMM YY, hh:mm:ss'
|
||||
)
|
||||
}}</span
|
||||
>
|
||||
@@ -194,7 +188,6 @@ import Pagination from '@/components/Pagination.vue'
|
||||
import InputCheckbox from '@/components/InputCheckbox.vue'
|
||||
import Loader from '@/components/Loader.vue'
|
||||
import ImageItem from '@/components/ImageItem.vue'
|
||||
import 'geovisio/build/index.css'
|
||||
import { durationCalc, formatDate } from '@/utils/dates'
|
||||
import {
|
||||
deleteACollectionItem,
|
||||
@@ -213,7 +206,7 @@ import {
|
||||
spliceIntoChunks,
|
||||
formatPaginationItems
|
||||
} from '@/views/utils/sequence/index'
|
||||
import { getIgnTiles } from '@/utils/mapAndViewer'
|
||||
import { fetchMapAndViewer } from '@/utils/mapAndViewer'
|
||||
import type {
|
||||
ResponseUserPhotoInterface,
|
||||
ResponseUserPhotoLinksInterface,
|
||||
@@ -221,10 +214,6 @@ import type {
|
||||
UserSequenceInterface,
|
||||
ResponseUserSequenceInterface
|
||||
} from './interfaces/MySequenceView'
|
||||
import type { ViewerMapInterface } from '@/views/interfaces/common'
|
||||
import GeoVisio from 'geovisio'
|
||||
import { createUrlLink } from '@/utils'
|
||||
import { createLink } from '@/components-viewer/reportLink'
|
||||
|
||||
const { t } = useI18n()
|
||||
const route = useRoute()
|
||||
@@ -264,58 +253,11 @@ onMounted(async () => {
|
||||
(el) => el.properties['geovisio:status'] === 'ready'
|
||||
)
|
||||
pictures.value = collectionItems
|
||||
const tiles = import.meta.env.VITE_TILES
|
||||
const maxZoom = import.meta.env.VITE_MAX_ZOOM
|
||||
let paramsGeovisio: ViewerMapInterface = {
|
||||
map: {
|
||||
startWide: true
|
||||
viewer.value = await fetchMapAndViewer({
|
||||
fetchOptions: {
|
||||
credentials: 'include'
|
||||
}
|
||||
}
|
||||
if (maxZoom) {
|
||||
paramsGeovisio = {
|
||||
map: {
|
||||
...paramsGeovisio.map,
|
||||
maxZoom: parseInt(maxZoom)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tiles) {
|
||||
const style = tiles.includes('wxs.ign.fr') ? await getIgnTiles() : tiles
|
||||
paramsGeovisio = {
|
||||
map: {
|
||||
...paramsGeovisio.map,
|
||||
style
|
||||
}
|
||||
}
|
||||
}
|
||||
const reportLink = document.createElement('div')
|
||||
reportLink.className = 'gvs-group gvs-group-large gvs-group-btnpanel'
|
||||
viewer.value = await new GeoVisio(
|
||||
'viewer', // Div ID
|
||||
`${import.meta.env.VITE_API_URL}/api/search`,
|
||||
{
|
||||
...paramsGeovisio,
|
||||
fetchOptions: {
|
||||
credentials: 'include'
|
||||
},
|
||||
widgets: { customWidget: reportLink }
|
||||
}
|
||||
)
|
||||
if (viewer.value && viewer.value.addEventListener) {
|
||||
viewer.value.addEventListener(
|
||||
'picture-loaded',
|
||||
async (e: { detail: { picId: string } }): Promise<void> => {
|
||||
const href = t('pages.home.report_mail', {
|
||||
picId: e.detail.picId,
|
||||
link: createUrlLink(e.detail.picId)
|
||||
})
|
||||
reportLink.innerHTML = createLink(
|
||||
href,
|
||||
t('pages.home.report_button_text')
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
setHeightValue()
|
||||
if (itemSelected.value.length || !collectionItemsReady[0]) return
|
||||
viewer.value._api.onceReady().then(() => {
|
||||
@@ -601,9 +543,6 @@ async function patchOrDeleteCollectionItems(
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.responsive {
|
||||
display: none;
|
||||
}
|
||||
.entry-page {
|
||||
display: flex;
|
||||
}
|
||||
@@ -611,21 +550,19 @@ async function patchOrDeleteCollectionItems(
|
||||
width: 50vw;
|
||||
position: relative;
|
||||
height: calc(100vh - #{toRem(8)});
|
||||
font-size: 137.5%;
|
||||
}
|
||||
.menu-right {
|
||||
width: 50vw;
|
||||
height: calc(100vh - #{toRem(8)});
|
||||
overflow: hidden;
|
||||
box-shadow: 0px 4px 20px 0px #00000033;
|
||||
}
|
||||
.wrapper-loader {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.wrapper-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.wrapper-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -663,10 +600,9 @@ async function patchOrDeleteCollectionItems(
|
||||
}
|
||||
}
|
||||
.title {
|
||||
@include text(h4);
|
||||
@include text(h2);
|
||||
color: var(--grey-dark);
|
||||
margin-right: toRem(1);
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.button-close {
|
||||
display: none;
|
||||
@@ -683,10 +619,9 @@ async function patchOrDeleteCollectionItems(
|
||||
justify-content: space-between;
|
||||
}
|
||||
.sequence-status {
|
||||
@include text(xs-r-regular);
|
||||
border-radius: toRem(3);
|
||||
padding: toRem(0.5) toRem(1);
|
||||
margin-right: toRem(1);
|
||||
margin-right: toRem(2);
|
||||
color: var(--white);
|
||||
&.ready {
|
||||
background-color: var(--orange);
|
||||
@@ -707,9 +642,6 @@ async function patchOrDeleteCollectionItems(
|
||||
padding: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
margin-bottom: toRem(1);
|
||||
}
|
||||
.bi-plus,
|
||||
.bi-dash {
|
||||
@@ -718,7 +650,7 @@ async function patchOrDeleteCollectionItems(
|
||||
}
|
||||
|
||||
.photos-wrapper {
|
||||
padding: toRem(1) 0 toRem(2) toRem(1);
|
||||
padding: toRem(1) 0rem toRem(2) toRem(1);
|
||||
height: calc(100vh - v-bind(menuHeight));
|
||||
}
|
||||
.delete-all {
|
||||
@@ -728,7 +660,6 @@ async function patchOrDeleteCollectionItems(
|
||||
margin-left: toRem(1);
|
||||
margin-right: toRem(2);
|
||||
margin-bottom: toRem(1);
|
||||
@include text(xs-r-regular);
|
||||
}
|
||||
.wrapper-select {
|
||||
display: flex;
|
||||
@@ -745,6 +676,9 @@ async function patchOrDeleteCollectionItems(
|
||||
margin-right: toRem(1);
|
||||
margin-left: toRem(1);
|
||||
}
|
||||
.delete-all-text {
|
||||
@include text(xs-r-regular);
|
||||
}
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -780,6 +714,7 @@ async function patchOrDeleteCollectionItems(
|
||||
.header-menu {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
margin-bottom: toRem(1);
|
||||
}
|
||||
.block-collapse {
|
||||
flex-direction: column;
|
||||
@@ -800,29 +735,6 @@ async function patchOrDeleteCollectionItems(
|
||||
}
|
||||
}
|
||||
@media (max-width: toRem(76.8)) {
|
||||
.desktop {
|
||||
display: none;
|
||||
}
|
||||
.responsive {
|
||||
display: initial;
|
||||
}
|
||||
.title {
|
||||
margin-right: 0;
|
||||
margin-bottom: toRem(1);
|
||||
}
|
||||
.wrapper-button {
|
||||
flex-direction: column;
|
||||
align-items: initial;
|
||||
}
|
||||
.disable-button {
|
||||
margin-right: 0;
|
||||
margin-bottom: toRem(1);
|
||||
}
|
||||
.button-collapse {
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.photo-item {
|
||||
width: 100%;
|
||||
margin-right: 0;
|
||||
@@ -880,17 +792,13 @@ async function patchOrDeleteCollectionItems(
|
||||
right: 0;
|
||||
top: toRem(22);
|
||||
z-index: 3;
|
||||
background-color: var(--black);
|
||||
height: toRem(5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-top-left-radius: toRem(0.5);
|
||||
border-bottom-left-radius: toRem(0.5);
|
||||
background-color: var(--white);
|
||||
border: toRem(0.1) solid var(--black);
|
||||
}
|
||||
.menu-top {
|
||||
padding: toRem(1);
|
||||
}
|
||||
.menu-is-open {
|
||||
.menu-right {
|
||||
|
||||
@@ -1,5 +1,63 @@
|
||||
<template>
|
||||
<main class="entry-page">
|
||||
<section>
|
||||
<div class="information-wrapper">
|
||||
<div class="information">
|
||||
<h1 class="page-title">{{ $t('pages.share_pictures.title') }}</h1>
|
||||
<p
|
||||
class="page-description"
|
||||
v-html="$t('pages.share_pictures.description')"
|
||||
></p>
|
||||
</div>
|
||||
<img
|
||||
src="@/assets/images/person-map.png"
|
||||
alt=""
|
||||
class="information-image"
|
||||
/>
|
||||
</div>
|
||||
<ul class="card-list">
|
||||
<li class="card-list-item">
|
||||
<ShareCard
|
||||
:image="{
|
||||
url: 'building.png',
|
||||
alt: $t('pages.share_pictures.arg_alt1')
|
||||
}"
|
||||
:title="$t('pages.share_pictures.arg_title1')"
|
||||
:text="$t('pages.share_pictures.arg_text1')"
|
||||
/>
|
||||
</li>
|
||||
<li class="card-list-item">
|
||||
<ShareCard
|
||||
:image="{
|
||||
url: '360.png',
|
||||
alt: $t('pages.share_pictures.arg_alt2')
|
||||
}"
|
||||
:title="$t('pages.share_pictures.arg_title2')"
|
||||
:text="$t('pages.share_pictures.arg_text2')"
|
||||
/>
|
||||
</li>
|
||||
<li class="card-list-item">
|
||||
<ShareCard
|
||||
:image="{
|
||||
url: 'pointer-map.png',
|
||||
alt: $t('pages.share_pictures.arg_alt3')
|
||||
}"
|
||||
:title="$t('pages.share_pictures.arg_title3')"
|
||||
:text="$t('pages.share_pictures.arg_text3')"
|
||||
/>
|
||||
</li>
|
||||
<li class="card-list-item">
|
||||
<ShareCard
|
||||
:image="{
|
||||
url: 'pointer.png',
|
||||
alt: $t('pages.share_pictures.arg_alt4')
|
||||
}"
|
||||
:title="$t('pages.share_pictures.arg_title4')"
|
||||
:text="$t('pages.share_pictures.arg_text4')"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section id="sec-1" class="section-upload">
|
||||
<div class="wrapper-upload">
|
||||
<div class="wrapper-upload-text">
|
||||
@@ -28,25 +86,17 @@
|
||||
</div>
|
||||
</div>
|
||||
<p
|
||||
v-if="authConf && authConf.license && authConf.license.url"
|
||||
class="upload-text"
|
||||
v-html="
|
||||
$t('pages.share_pictures.description', {
|
||||
check: checkImg,
|
||||
licenseUrl: authConf.license.url,
|
||||
licenseName: authConf.license.id
|
||||
check: checkImg
|
||||
})
|
||||
"
|
||||
/>
|
||||
<p class="upload-text">
|
||||
{{ $t('pages.share_pictures.footer_block') }}
|
||||
</p>
|
||||
<div
|
||||
v-if="
|
||||
!isLogged && authConf && authConf.auth && authConf.auth.enabled
|
||||
"
|
||||
class="wrapper-account"
|
||||
>
|
||||
<div v-if="!isLogged && authConf.enabled" class="wrapper-account">
|
||||
<h4 class="account-subtitle">
|
||||
{{ $t('pages.share_pictures.sub_title') }}
|
||||
</h4>
|
||||
@@ -99,26 +149,10 @@
|
||||
class="upload-text"
|
||||
v-html="$t('pages.share_pictures.description_terminal')"
|
||||
></p>
|
||||
<div
|
||||
v-if="authConf && authConf.license && authConf.license.url"
|
||||
<p
|
||||
class="upload-text grey"
|
||||
>
|
||||
<p>
|
||||
{{
|
||||
$t('pages.share_pictures.footer_description_terminal', {
|
||||
word: 'la license'
|
||||
})
|
||||
}}
|
||||
</p>
|
||||
<Link
|
||||
:href="authConf.license.url"
|
||||
:text="authConf.license.id"
|
||||
target="_blank"
|
||||
type="external"
|
||||
look="link--grey"
|
||||
@trigger="triggerHref"
|
||||
/>
|
||||
</div>
|
||||
v-html="$t('pages.share_pictures.footer_description_terminal')"
|
||||
></p>
|
||||
<div class="wrapper-account">
|
||||
<h4 class="account-subtitle">
|
||||
{{ $t('pages.share_pictures.cli_title') }}
|
||||
@@ -128,7 +162,7 @@
|
||||
:text="$t('pages.share_pictures.button')"
|
||||
type="external"
|
||||
look="button button--blue"
|
||||
path-external="https://gitlab.com/geovisio/cli"
|
||||
path="https://gitlab.com/geovisio/cli"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -141,6 +175,7 @@
|
||||
<script lang="ts" setup>
|
||||
import Link from '@/components/Link.vue'
|
||||
import Terminal from '@/components/Terminal.vue'
|
||||
import ShareCard from '@/components/share-pictures/ShareCard.vue'
|
||||
import { useCookies } from 'vue3-cookies'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
@@ -175,6 +210,46 @@ function triggerHref(): void {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.entry-page {
|
||||
margin: auto;
|
||||
background-color: var(--beige-pale);
|
||||
padding: toRem(2) 5%;
|
||||
}
|
||||
.information-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: toRem(4);
|
||||
background-color: var(--white);
|
||||
border-radius: toRem(1);
|
||||
}
|
||||
.information {
|
||||
width: 50%;
|
||||
}
|
||||
.information-image {
|
||||
margin: auto;
|
||||
}
|
||||
.page-title {
|
||||
@include text(h1);
|
||||
color: var(--blue-dark);
|
||||
}
|
||||
.page-description {
|
||||
color: var(--grey-semi-dark);
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
.card-list {
|
||||
display: flex;
|
||||
padding: toRem(4);
|
||||
background-color: var(--white);
|
||||
border-radius: toRem(1);
|
||||
margin-top: toRem(2);
|
||||
}
|
||||
.card-list-item {
|
||||
margin-right: toRem(3);
|
||||
&:last-child {
|
||||
margin-right: toRem(0);
|
||||
}
|
||||
}
|
||||
|
||||
.upload-title {
|
||||
@include text(h1);
|
||||
}
|
||||
@@ -248,7 +323,7 @@ function triggerHref(): void {
|
||||
min-height: 80vh;
|
||||
}
|
||||
.section-upload:first-child {
|
||||
background-color: rgba(236, 236, 236, 0.5);
|
||||
background-color: var(--beige-pale);
|
||||
}
|
||||
.wrapper-upload {
|
||||
display: flex;
|
||||
@@ -260,14 +335,7 @@ function triggerHref(): void {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
.grey {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
color: var(--grey-semi-dark);
|
||||
p {
|
||||
margin-bottom: 0;
|
||||
margin-right: toRem(0.5);
|
||||
}
|
||||
}
|
||||
.wrapper-account {
|
||||
display: flex;
|
||||
@@ -312,6 +380,23 @@ function triggerHref(): void {
|
||||
bottom: calc(20vh - #{toRem(10.5)});
|
||||
}
|
||||
@media (max-width: toRem(102.4)) {
|
||||
.information-wrapper {
|
||||
flex-direction: column;
|
||||
}
|
||||
.information {
|
||||
width: 100%;
|
||||
}
|
||||
.card-list {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.card-list-item {
|
||||
width: calc(50% - #{toRem(2)});
|
||||
margin-right: 0;
|
||||
&:nth-child(1),
|
||||
&:nth-child(3) {
|
||||
margin-right: toRem(2);
|
||||
}
|
||||
}
|
||||
.section-upload {
|
||||
height: initial;
|
||||
}
|
||||
@@ -336,6 +421,17 @@ function triggerHref(): void {
|
||||
}
|
||||
}
|
||||
@media (max-width: toRem(76.8)) {
|
||||
.card-list-item {
|
||||
width: 100%;
|
||||
margin-bottom: toRem(2);
|
||||
&:nth-child(1),
|
||||
&:nth-child(3) {
|
||||
margin-right: 0;
|
||||
}
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
.entry-page {
|
||||
padding-top: toRem(11);
|
||||
}
|
||||
|
||||
@@ -1,50 +1,77 @@
|
||||
<template>
|
||||
<main class="entry-page">
|
||||
<div class="entry-banner">
|
||||
<TooltipBanner />
|
||||
</div>
|
||||
<section class="upload-section">
|
||||
<h1 class="settings-title">{{ $t('pages.upload.title') }}</h1>
|
||||
<form v-if="!isLoading" @submit.prevent="uploadPicture">
|
||||
<InputUpload
|
||||
:text="$t('pages.upload.input_label')"
|
||||
:text-second-part="$t('pages.upload.import_word')"
|
||||
:text-picture-type="$t('pages.upload.import_type')"
|
||||
accept="image/jpeg"
|
||||
data-test="input-add-pictures"
|
||||
@trigger="addPictures"
|
||||
/>
|
||||
<div class="footer-form">
|
||||
<span v-if="fileUploaded" class="number-file-text">{{
|
||||
fileUploaded
|
||||
}}</span>
|
||||
<span v-else class="number-file-text">{{
|
||||
t('pages.upload.no_uploaded_files')
|
||||
}}</span>
|
||||
<Button
|
||||
:text="$t('pages.upload.button_text')"
|
||||
:disabled="!pictures || pictures.length < 1"
|
||||
type="submit"
|
||||
data-test="button-upload"
|
||||
look="button button--blue"
|
||||
<div class="form-upload">
|
||||
<h1 class="settings-title">{{ $t('pages.upload.title') }}</h1>
|
||||
<p class="settings-text">{{ $t('pages.upload.text') }}</p>
|
||||
<form v-if="!isLoading" @submit.prevent="uploadPicture">
|
||||
<InputUpload
|
||||
:text="$t('pages.upload.input_label')"
|
||||
:text-second-part="$t('pages.upload.import_word')"
|
||||
:text-picture-type="$t('pages.upload.import_type')"
|
||||
accept="image/jpeg"
|
||||
data-test="input-add-pictures"
|
||||
@trigger="addPictures"
|
||||
/>
|
||||
<div class="footer-form">
|
||||
<span v-if="fileUploaded" class="number-file-text">{{
|
||||
fileUploaded
|
||||
}}</span>
|
||||
<span v-else class="number-file-text">{{
|
||||
t('pages.upload.no_uploaded_files')
|
||||
}}</span>
|
||||
<Button
|
||||
:text="$t('pages.upload.button_text')"
|
||||
:disabled="!pictures || pictures.length < 1"
|
||||
type="submit"
|
||||
look="button button--blue"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
<UploadLoader
|
||||
v-else
|
||||
:load-percentage="loadPercentage"
|
||||
:load-text-size="loadTextSize"
|
||||
:is-loaded="isLoaded"
|
||||
:uploaded-sequences="uploadedSequences"
|
||||
:pictures-count="picturesCount"
|
||||
@triggerNewUpload="triggerNewUpload"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-upload">
|
||||
<h1 class="settings-title">{{ $t('pages.upload.title_uploading') }}</h1>
|
||||
<div v-if="!uploadedSequences.length" class="uploading-information">
|
||||
<img src="@/assets/images/uploading.png" class="uploading-img" />
|
||||
<p class="settings-text">
|
||||
{{ $t('pages.upload.no_picture_uploading_text') }}
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
<UploadLoader
|
||||
v-else
|
||||
:load-percentage="loadPercentage"
|
||||
:load-text-size="loadTextSize"
|
||||
:is-loaded="isLoaded"
|
||||
:uploaded-sequences="uploadedSequences"
|
||||
:pictures-count="picturesCount"
|
||||
@triggerNewUpload="triggerNewUpload"
|
||||
/>
|
||||
<template v-for="(sequence, i) in uploadedSequences">
|
||||
<ImportedSection
|
||||
v-if="i === 0"
|
||||
:index="i"
|
||||
:sequence="sequence"
|
||||
:pictures-count="picturesCount"
|
||||
:upload-errors="sequence.picturesOnError"
|
||||
:upload-pictures="sequence.pictures"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</section>
|
||||
<ImportedSection
|
||||
v-for="(sequence, i) in uploadedSequences"
|
||||
:index="i"
|
||||
:sequence="sequence"
|
||||
:pictures-count="picturesCount"
|
||||
:upload-errors="sequence.picturesOnError"
|
||||
:upload-pictures="sequence.pictures"
|
||||
/>
|
||||
<template v-for="(sequence, i) in uploadedSequences">
|
||||
<section v-if="i !== 0" class="information-section">
|
||||
<ImportedSection
|
||||
:index="i"
|
||||
:sequence="sequence"
|
||||
:pictures-count="picturesCount"
|
||||
:upload-errors="sequence.picturesOnError"
|
||||
:upload-pictures="sequence.pictures"
|
||||
/>
|
||||
</section>
|
||||
</template>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
@@ -55,6 +82,7 @@ import { useI18n } from 'vue-i18n'
|
||||
import InputUpload from '@/components/InputUpload.vue'
|
||||
import Button from '@/components/Button.vue'
|
||||
import ImportedSection from '@/components/upload/ImportedSection.vue'
|
||||
import TooltipBanner from '@/components/upload/TooltipBanner.vue'
|
||||
import UploadLoader from '@/components/upload/UploadLoader.vue'
|
||||
import type { sequenceInterface } from './interfaces/UploadPicturesView'
|
||||
import { formatDate } from '@/utils/dates'
|
||||
@@ -62,13 +90,9 @@ import {
|
||||
createAPictureToASequence,
|
||||
createASequence
|
||||
} from '@/views/utils/upload/request'
|
||||
import {
|
||||
formatPictureSize,
|
||||
formatTextSize,
|
||||
sortByName
|
||||
} from '@/views/utils/upload/index'
|
||||
import { formatPictureSize, formatTextSize } from '@/views/utils/upload/index'
|
||||
const { t } = useI18n()
|
||||
let pictures = ref<File[] | []>([])
|
||||
let pictures = ref<FileList | []>([])
|
||||
let picturesCount = ref<number>(0)
|
||||
let isLoading = ref<boolean>(false)
|
||||
let isLoaded = ref<boolean>(false)
|
||||
@@ -128,8 +152,7 @@ function triggerNewUpload(): void {
|
||||
picturesCount.value = 0
|
||||
}
|
||||
function addPictures(value: FileList): void {
|
||||
const files = sortByName([].slice.call(value))
|
||||
pictures.value = files
|
||||
pictures.value = value
|
||||
picturesCount.value = pictures.value.length
|
||||
picturesUploadingSize.value = 0
|
||||
picturesToUploadSize.value = 0
|
||||
@@ -154,7 +177,7 @@ async function uploadPicture(): Promise<void> {
|
||||
|
||||
const sequenceTitle = `${t('pages.upload.sequence_title')}${formatDate(
|
||||
new Date(),
|
||||
'Do MMMM YYYY, hh:mm:ss'
|
||||
'Do MMMM YY, hh:mm:ss'
|
||||
)}`
|
||||
const { data } = await createASequence(sequenceTitle)
|
||||
const sequence: sequenceInterface = {
|
||||
@@ -207,21 +230,61 @@ ul {
|
||||
.entry-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: calc(100vh - #{toRem(27.42)});
|
||||
background-color: var(--beige-pale);
|
||||
min-height: calc(100vh - #{toRem(8)});
|
||||
padding-top: toRem(2);
|
||||
padding-bottom: toRem(2);
|
||||
overflow: hidden;
|
||||
}
|
||||
.entry-banner {
|
||||
width: 90%;
|
||||
margin-bottom: toRem(2);
|
||||
}
|
||||
.upload-section {
|
||||
width: 80%;
|
||||
padding: toRem(4);
|
||||
margin-top: toRem(6);
|
||||
margin-bottom: toRem(4);
|
||||
box-shadow: 0px 6.45694px 8.60925px rgba(0, 0, 0, 0.05);
|
||||
display: flex;
|
||||
width: 90%;
|
||||
}
|
||||
.information-section {
|
||||
width: 90%;
|
||||
background-color: var(--white);
|
||||
border-radius: toRem(1);
|
||||
margin-top: toRem(2);
|
||||
padding: toRem(2);
|
||||
}
|
||||
.uploading-information {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
.uploading-img {
|
||||
height: toRem(20);
|
||||
margin-bottom: toRem(2);
|
||||
}
|
||||
.form-upload {
|
||||
height: toRem(70);
|
||||
padding: toRem(2);
|
||||
width: 50%;
|
||||
background-color: var(--white);
|
||||
border-radius: toRem(1);
|
||||
&:first-child {
|
||||
margin-right: toRem(1);
|
||||
}
|
||||
&:last-child {
|
||||
margin-left: toRem(1);
|
||||
}
|
||||
}
|
||||
.settings-title {
|
||||
text-align: center;
|
||||
@include text(h1);
|
||||
margin-bottom: toRem(4);
|
||||
color: var(--blue-dark);
|
||||
@include text(h3);
|
||||
margin-bottom: toRem(2);
|
||||
}
|
||||
.settings-text {
|
||||
color: var(--grey-semi-dark);
|
||||
margin-bottom: toRem(2);
|
||||
@include text(s-regular);
|
||||
}
|
||||
.footer-form {
|
||||
display: flex;
|
||||
@@ -235,9 +298,6 @@ ul {
|
||||
color: var(--blue-dark);
|
||||
@include text(s-regular);
|
||||
}
|
||||
::-webkit-scrollbar {
|
||||
width: toRem(2);
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
background: var(--grey-pale);
|
||||
}
|
||||
@@ -246,22 +306,36 @@ ul {
|
||||
border-radius: toRem(5);
|
||||
}
|
||||
@media (max-width: toRem(76.8)) {
|
||||
.entry-page {
|
||||
overflow-x: hidden;
|
||||
.upload-section {
|
||||
flex-direction: column;
|
||||
}
|
||||
.form-upload {
|
||||
width: 100%;
|
||||
&:first-child,
|
||||
&:last-child {
|
||||
margin: toRem(0);
|
||||
}
|
||||
&:first-child {
|
||||
margin-bottom: toRem(2);
|
||||
}
|
||||
}
|
||||
.information-section {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
@media (max-width: toRem(50)) {
|
||||
.upload-section {
|
||||
margin-top: toRem(15);
|
||||
.entry-page {
|
||||
margin-top: toRem(11);
|
||||
overflow-y: hidden;
|
||||
}
|
||||
.upload-section,
|
||||
.information-section {
|
||||
width: 100%;
|
||||
padding-right: toRem(2);
|
||||
padding-left: toRem(2);
|
||||
}
|
||||
.information-section {
|
||||
width: 100%;
|
||||
width: 90%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3,17 +3,12 @@ export interface OptionalViewerMapInterface {
|
||||
credentials: string
|
||||
}
|
||||
picId?: string
|
||||
widgets?: {
|
||||
customWidget: HTMLAnchorElement
|
||||
}
|
||||
}
|
||||
|
||||
export interface ViewerMapInterface extends OptionalViewerMapInterface {
|
||||
map: {
|
||||
startWide: boolean
|
||||
style?: object | string
|
||||
maxZoom?: number
|
||||
zoom?: number
|
||||
center?: number[]
|
||||
maxZoom: number
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,4 @@ function formatTextSize(size: number, i: number): string {
|
||||
const sizes = ['0', 'Ko', 'Mo', 'Go', 'To', 'Po', 'Eo', 'Zo', 'o']
|
||||
return `${parseFloat((size / Math.pow(1024, i)).toFixed(2))} ${sizes[i]}`
|
||||
}
|
||||
function sortByName(fileList: File[]): File[] {
|
||||
return fileList.sort((a: File, b: File) =>
|
||||
a.name.localeCompare(b.name, navigator.languages[0] || navigator.language, {
|
||||
numeric: true,
|
||||
ignorePunctuation: true
|
||||
})
|
||||
)
|
||||
}
|
||||
export { formatPictureSize, formatTextSize, sortByName }
|
||||
export { formatPictureSize, formatTextSize }
|
||||
|
||||