mirror of
https://github.com/dedicatedcode/reitti.git
synced 2026-01-09 09:27:58 -05:00
365 feature request add a thank you section to the about page (#404)
This commit is contained in:
6
.github/workflows/main.yml
vendored
6
.github/workflows/main.yml
vendored
@@ -19,6 +19,12 @@ jobs:
|
||||
java-version: '24'
|
||||
distribution: 'temurin'
|
||||
cache: maven
|
||||
- name: Generate acknowledgments data
|
||||
run: |
|
||||
chmod +x scripts/generate-acknowledgments.sh
|
||||
./scripts/generate-acknowledgments.sh
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build
|
||||
run: mvn verify -DskipTests
|
||||
- name: Login to Docker Hub
|
||||
|
||||
12
.github/workflows/release.yml
vendored
12
.github/workflows/release.yml
vendored
@@ -19,6 +19,16 @@ jobs:
|
||||
java-version: '24'
|
||||
distribution: 'temurin'
|
||||
cache: maven
|
||||
- name: Install dependencies for acknowledgments script
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y jq curl
|
||||
- name: Generate acknowledgments data
|
||||
run: |
|
||||
chmod +x scripts/generate-acknowledgments.sh
|
||||
./scripts/generate-acknowledgments.sh
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build
|
||||
run: mvn verify -DskipTests
|
||||
- name: Create bundle
|
||||
@@ -66,4 +76,4 @@ jobs:
|
||||
staging/*.jar
|
||||
LICENSE
|
||||
- name: Update dependency graph
|
||||
uses: advanced-security/maven-dependency-submission-action@571e99aab1055c2e71a1e2309b9691de18d6b7d6
|
||||
uses: advanced-security/maven-dependency-submission-action@571e99aab1055c2e71a1e2309b9691de18d6b7d6
|
||||
|
||||
132
scripts/generate-acknowledgments.sh
Executable file
132
scripts/generate-acknowledgments.sh
Executable file
@@ -0,0 +1,132 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script to generate contributors.json and translators.json for the acknowledgments page
|
||||
# This script should be run before building the application
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
RESOURCES_DIR="$SCRIPT_DIR/../src/main/resources"
|
||||
|
||||
# GitHub API settings
|
||||
GITHUB_REPO="${GITHUB_REPOSITORY:-dedicatedcode/reitti}"
|
||||
GITHUB_TOKEN="${GITHUB_TOKEN:-}"
|
||||
|
||||
|
||||
echo "Generating acknowledgments data..."
|
||||
|
||||
# Function to fetch GitHub contributors
|
||||
fetch_contributors() {
|
||||
echo "Fetching contributors from GitHub..."
|
||||
|
||||
local api_url="https://api.github.com/repos/$GITHUB_REPO/contributors"
|
||||
local headers=""
|
||||
|
||||
if [ -n "$GITHUB_TOKEN" ]; then
|
||||
headers="-H \"Authorization: token $GITHUB_TOKEN\""
|
||||
fi
|
||||
|
||||
# Fetch contributors and format as JSON
|
||||
local contributors_data=$(eval "curl -s $headers \"$api_url\"" | jq '[
|
||||
.[] |
|
||||
select(.type == "User") |
|
||||
select(.login != "dependabot[bot]") |
|
||||
select(.login != "github-actions[bot]") |
|
||||
select(.login != "weblate") |
|
||||
select(.login != "dgraf-gh") |
|
||||
{
|
||||
name: (.name // .login),
|
||||
role: "Contributor",
|
||||
avatar: .avatar_url,
|
||||
github: .login
|
||||
}
|
||||
]')
|
||||
|
||||
# Create contributors.json
|
||||
echo "{\"contributors\": $contributors_data}" > "$RESOURCES_DIR/contributors.json"
|
||||
echo "✓ Contributors data saved to contributors.json"
|
||||
}
|
||||
|
||||
|
||||
# Function to create projects.json with open source dependencies
|
||||
create_projects_data() {
|
||||
echo "Creating projects acknowledgments..."
|
||||
|
||||
local projects_json='[
|
||||
{
|
||||
"name": "Spring Boot",
|
||||
"description": "Java-based framework for building production-ready applications",
|
||||
"url": "https://spring.io/projects/spring-boot",
|
||||
"license": "Apache 2.0",
|
||||
"category": "Framework"
|
||||
},
|
||||
{
|
||||
"name": "PostgreSQL",
|
||||
"description": "Advanced open source relational database",
|
||||
"url": "https://www.postgresql.org/",
|
||||
"license": "PostgreSQL License",
|
||||
"category": "Database"
|
||||
},
|
||||
{
|
||||
"name": "Leaflet",
|
||||
"description": "Open-source JavaScript library for mobile-friendly interactive maps",
|
||||
"url": "https://leafletjs.com/",
|
||||
"license": "BSD-2-Clause",
|
||||
"category": "Frontend"
|
||||
},
|
||||
{
|
||||
"name": "HTMX",
|
||||
"description": "High power tools for HTML",
|
||||
"url": "https://htmx.org/",
|
||||
"license": "BSD-2-Clause",
|
||||
"category": "Frontend"
|
||||
},
|
||||
{
|
||||
"name": "Thymeleaf",
|
||||
"description": "Modern server-side Java template engine",
|
||||
"url": "https://www.thymeleaf.org/",
|
||||
"license": "Apache 2.0",
|
||||
"category": "Template Engine"
|
||||
},
|
||||
{
|
||||
"name": "Chart.js",
|
||||
"description": "Simple yet flexible JavaScript charting library",
|
||||
"url": "https://www.chartjs.org/",
|
||||
"license": "MIT",
|
||||
"category": "Frontend"
|
||||
}
|
||||
]'
|
||||
|
||||
echo "{\"projects\": $projects_json}" > "$RESOURCES_DIR/projects.json"
|
||||
echo "✓ Projects data saved to projects.json"
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
# Check if jq is available
|
||||
if ! command -v jq &> /dev/null; then
|
||||
echo "Error: jq is required but not installed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if curl is available
|
||||
if ! command -v curl &> /dev/null; then
|
||||
echo "Error: curl is required but not installed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create resources directory if it doesn't exist
|
||||
mkdir -p "$RESOURCES_DIR"
|
||||
|
||||
# Generate all acknowledgment files
|
||||
fetch_contributors
|
||||
create_projects_data
|
||||
|
||||
echo "✅ Acknowledgments data generation completed!"
|
||||
echo "Generated files:"
|
||||
echo " - $RESOURCES_DIR/contributors.json"
|
||||
echo " - $RESOURCES_DIR/projects.json"
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
@@ -4,23 +4,33 @@ package com.dedicatedcode.reitti.controller.settings;
|
||||
import com.dedicatedcode.reitti.model.Role;
|
||||
import com.dedicatedcode.reitti.model.security.User;
|
||||
import com.dedicatedcode.reitti.service.VersionService;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/settings")
|
||||
public class AboutController {
|
||||
private final VersionService versionService;
|
||||
private final boolean dataManagementEnabled;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
public AboutController(VersionService versionService,
|
||||
@Value("${reitti.data-management.enabled:false}") boolean dataManagementEnabled) {
|
||||
@Value("${reitti.data-management.enabled:false}") boolean dataManagementEnabled,
|
||||
ObjectMapper objectMapper) {
|
||||
this.versionService = versionService;
|
||||
this.dataManagementEnabled = dataManagementEnabled;
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
@GetMapping("/about")
|
||||
@@ -31,7 +41,31 @@ public class AboutController {
|
||||
model.addAttribute("buildVersion", this.versionService.getVersion());
|
||||
model.addAttribute("gitCommitDetails", this.versionService.getCommitDetails());
|
||||
model.addAttribute("buildTime", this.versionService.getBuildTime());
|
||||
|
||||
// Load acknowledgments data
|
||||
try {
|
||||
model.addAttribute("contributors", loadContributors());
|
||||
model.addAttribute("projects", loadProjects());
|
||||
} catch (IOException e) {
|
||||
// Log error and continue without acknowledgments
|
||||
model.addAttribute("contributors", List.of());
|
||||
model.addAttribute("projects", List.of());
|
||||
}
|
||||
|
||||
return "settings/about";
|
||||
}
|
||||
|
||||
private List<Map<String, Object>> loadContributors() throws IOException {
|
||||
var resource = new ClassPathResource("contributors.json");
|
||||
var data = objectMapper.readValue(resource.getInputStream(), new TypeReference<Map<String, Object>>() {});
|
||||
return (List<Map<String, Object>>) data.get("contributors");
|
||||
}
|
||||
|
||||
|
||||
private List<Map<String, Object>> loadProjects() throws IOException {
|
||||
var resource = new ClassPathResource("projects.json");
|
||||
var data = objectMapper.readValue(resource.getInputStream(), new TypeReference<Map<String, Object>>() {});
|
||||
return (List<Map<String, Object>>) data.get("projects");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
3
src/main/resources/contributors.json
Normal file
3
src/main/resources/contributors.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"contributors": []
|
||||
}
|
||||
@@ -1280,3 +1280,12 @@ transportation.modes.reclassify.button=Reclassify All Trips
|
||||
transportation.modes.reclassify.processing=Processing...
|
||||
transportation.modes.reclassify.started=Reclassification started successfully. This process will run in the background.
|
||||
transportation.modes.reclassify.error=Failed to start reclassification. Please try again.
|
||||
|
||||
about.acknowledgments.title=Acknowledgments
|
||||
about.acknowledgments.subtitle=Reitti wouldn't be possible without the amazing contributions from our community and the incredible open-source projects we build upon.
|
||||
about.contributors.title=Contributors
|
||||
about.translators.title=Translators
|
||||
about.projects.title=Open Source Projects
|
||||
about.projects.visit=Visit Project
|
||||
about.thankyou.title=Thank You!
|
||||
about.thankyou.message=Every contribution, no matter how small, helps make Reitti better for everyone. We're grateful for your support and dedication to the open-source community.
|
||||
@@ -1210,5 +1210,15 @@ memory.processing.step.accommodation=Unterkunft wird bestimmt...
|
||||
memory.processing.step.texts=Texte werden generiert...
|
||||
memory.processing.step.images=Bilder werden kopiert...
|
||||
memory.processing.step.counter=Schritt {0} von {1}
|
||||
memory.block.trip.empty=Es sind keine Reisen für diesen Block ausgewählt.
|
||||
memory.block.visit.empty=Es sind keine Besuche für diesen Block ausgewählt.
|
||||
memory.block.trip.empty=Es sind keine Reisen f\u00FCr diesen Block ausgew\u00E4hlt.
|
||||
memory.block.visit.empty=Es sind keine Besuche f\u00FCr diesen Block ausgew\u00E4hlt.
|
||||
|
||||
|
||||
about.acknowledgments.title=Danksagungen
|
||||
about.acknowledgments.subtitle=Reitti w\u00E4re ohne die gro\u00DFartigen Beitr\u00E4ge unserer Community und die unglaublichen Open-Source-Projekte, auf denen wir aufbauen, nicht m\u00F6glich.
|
||||
about.contributors.title=Mitwirkende
|
||||
about.translators.title=\u00DCbersetzer
|
||||
about.projects.title=Open-Source-Projekte
|
||||
about.projects.visit=Projekt besuchen
|
||||
about.thankyou.title=Vielen Dank!
|
||||
about.thankyou.message=Jeder Beitrag, egal wie klein, hilft dabei, Reitti f\u00FCr alle besser zu machen. Wir sind dankbar f\u00FCr Ihre Unterst\u00FCtzung und Ihr Engagement f\u00FCr die Open-Source-Community.
|
||||
@@ -606,4 +606,14 @@ memory.processing.step.visits=Luodaan vierailutietueita...
|
||||
memory.processing.step.accommodation=M\u00E4\u00E4ritet\u00E4\u00E4n majoitusta...
|
||||
memory.processing.step.texts=Generoidaan tekstej\u00E4...
|
||||
memory.processing.step.images=Kopioidaan kuvia...
|
||||
memory.processing.step.counter=Vaihe {0}/{1}
|
||||
memory.processing.step.counter=Vaihe {0}/{1}
|
||||
|
||||
|
||||
about.acknowledgments.title=Kiitokset
|
||||
about.acknowledgments.subtitle=Reitti ei olisi mahdollinen ilman yhteis\u00F6mme upeita panoksia ja uskomattomia avoimen l\u00E4hdekoodin projekteja, joiden varaan rakennamme.
|
||||
about.contributors.title=Avustajat
|
||||
about.translators.title=K\u00E4\u00E4nt\u00E4j\u00E4t
|
||||
about.projects.title=Avoimen L\u00E4hdekoodin Projektit
|
||||
about.projects.visit=Vieraile Projektissa
|
||||
about.thankyou.title=Kiitos!
|
||||
about.thankyou.message=Jokainen panos, oli se kuinka pieni tahansa, auttaa tekem\u00E4\u00E4n Reitist\u00E4 paremman kaikille. Olemme kiitollisia tuestanne ja omistautumisestanne avoimen l\u00E4hdekoodin yhteis\u00F6lle.
|
||||
@@ -269,7 +269,7 @@ integrations.owntracks.recorder.device.id.placeholder=Entrez l'ID de l'appareil
|
||||
integrations.owntracks.recorder.enabled=Activer l'int\u00E9gration
|
||||
integrations.owntracks.recorder.save=Sauvegarder la configuration
|
||||
integrations.owntracks.recorder.test.connection=Tester la connexion
|
||||
integrations.owntracks.recorder.connection.success=Connexion réussie
|
||||
integrations.owntracks.recorder.connection.success=Connexion r\u00E9ussie
|
||||
integrations.owntracks.recorder.connection.failed=Connexion \u00E9chou\u00E9e : {0}
|
||||
integrations.owntracks.recorder.config.saved=Configuration OwnTracks Recorder sauvegard\u00E9e avec succ\u00E8s
|
||||
integrations.owntracks.recorder.config.error=Erreur lors de la sauvegarde de la configuration : {0}
|
||||
@@ -608,4 +608,14 @@ memory.processing.step.visits=Cr\u00E9ation des enregistrements de visite...
|
||||
memory.processing.step.accommodation=D\u00E9termination de l'h\u00E9bergement...
|
||||
memory.processing.step.texts=G\u00E9n\u00E9ration des textes...
|
||||
memory.processing.step.images=Copie des images...
|
||||
memory.processing.step.counter=\u00C9tape {0} sur {1}
|
||||
memory.processing.step.counter=\u00C9tape {0} sur {1}
|
||||
|
||||
|
||||
about.acknowledgments.title=Remerciements
|
||||
about.acknowledgments.subtitle=Reitti ne serait pas possible sans les contributions extraordinaires de notre communaut\u00E9 et les incroyables projets open-source sur lesquels nous nous appuyons.
|
||||
about.contributors.title=Contributeurs
|
||||
about.translators.title=Traducteurs
|
||||
about.projects.title=Projets Open Source
|
||||
about.projects.visit=Visiter le Projet
|
||||
about.thankyou.title=Merci !
|
||||
about.thankyou.message=Chaque contribution, aussi petite soit-elle, aide \u00E0 am\u00E9liorer Reitti pour tout le monde. Nous sommes reconnaissants pour votre soutien et votre d\u00E9vouement \u00E0 la communaut\u00E9 open-source.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,114 +1,123 @@
|
||||
nav.statistics=Статистика
|
||||
nav.settings=Настройки
|
||||
nav.logout=Выход
|
||||
nav.logout.tooltip=Выход
|
||||
timeline.loading=Загрузка…
|
||||
timeline.distance=Дистанция
|
||||
timeline.duration=Продолжительность
|
||||
datepicker.today=Сегодня
|
||||
datepicker.days.sun=Вс
|
||||
datepicker.days.mon=Пон
|
||||
datepicker.days.tue=Вт
|
||||
datepicker.days.wed=Ср
|
||||
datepicker.days.thu=Чт
|
||||
datepicker.days.fri=Пт
|
||||
datepicker.days.sat=Сб
|
||||
datepicker.months.jan=Янв
|
||||
datepicker.months.feb=Фев
|
||||
datepicker.months.mar=Мар
|
||||
datepicker.months.apr=Апр
|
||||
datepicker.months.may=Май
|
||||
datepicker.months.jun=Июнь
|
||||
datepicker.months.jul=Июль
|
||||
datepicker.months.aug=Авг
|
||||
datepicker.months.sep=Сен
|
||||
datepicker.months.oct=Окт
|
||||
datepicker.months.nov=Нояб
|
||||
datepicker.months.dec=Дек
|
||||
settings.title=Настройки
|
||||
settings.api.tokens=API токены
|
||||
settings.user.management=Управление пользователем
|
||||
tokens.title=API токены
|
||||
tokens.create.title=Создать новый токен
|
||||
map.auto-update.latest-location=Последнее местоположение
|
||||
export.title=Экспорт данных
|
||||
export.date.range=Диапазон дат
|
||||
export.start.date=Начальная дата
|
||||
export.end.date=Конечная дата
|
||||
export.gpx.button=Экспорт как GPX
|
||||
export.raw.data.title=Raw данные местоположения
|
||||
export.raw.data.table.latitude=Широта
|
||||
export.raw.data.table.longitude=Долгота
|
||||
export.raw.data.table.accuracy=Точность (м)
|
||||
export.raw.data.no.data=Не найдено мест в выбранном диапазоне дат
|
||||
export.gpx.success=GPX файл экспортирован удачно
|
||||
export.gpx.error=Ошибка экспорта GPX: {0}
|
||||
error.page.title=Ошибка - Reitti
|
||||
error.title=Упс! Что то пошло не так
|
||||
error.generic.message=Неожиданная ошибка. Попробуйте еще раз позже.
|
||||
error.technical.details=Технические детали
|
||||
error.action.home=Домой
|
||||
error.action.back=Назад
|
||||
error.action.retry=Еще раз
|
||||
share-access.title=Поделиться доступом
|
||||
magic.links.new.token.value=Только токен:
|
||||
magic.links.info.security.title=Вопросы безопасности
|
||||
magic.links.info.security.point1=Любой, у кого есть ссылка, может получить доступ к вашим данным, относитесь к ним как к паролю
|
||||
magic.links.info.security.point2=Ссылки не могут быть восстановлены, если потеряете, надо будет создать новые
|
||||
magic.links.info.security.point3=Установите даты истечения срока действия временного общего доступа, чтобы ограничить продолжительность доступа
|
||||
magic.links.info.security.point4=Немедленно ссылки удалите, когда они станут не нужны
|
||||
magic.links.info.security.point5=Мониторинг столбца 'Последний используемый' для отслеживания доступа
|
||||
magic.links.info.access.levels.title=Уровни доступа
|
||||
magic.links.info.access.full.description=Полный доступ ко всем данным и истории вашего местоположения
|
||||
magic.links.info.access.live.description=Доступ только к данным о текущем/недавнем местоположении
|
||||
form.cancel=Отмена
|
||||
form.previous=Предыдущий
|
||||
form.next=Следующий
|
||||
form.refresh=Обновить
|
||||
message.success.token.created=Токен успешно создан
|
||||
message.success.token.deleted=Токен успешно удален
|
||||
message.success.user.created=Пользователь успешно создан
|
||||
message.success.user.updated=Пользователь успешно обновлен
|
||||
message.success.user.deleted=Пользователь успешно удален
|
||||
message.success.place.updated=Место успешно обновлено
|
||||
message.error.token.creation=Ошибка создания токена: {0}
|
||||
message.error.token.deletion=Ошибка удаления токена:{0}
|
||||
message.error.user.creation=Ошибка при создании пользователя: {0}
|
||||
message.error.user.update=Ошибка обновления пользователя: {0}
|
||||
message.error.user.deletion=Ошибка удаления пользователя: {0}
|
||||
message.error.user.self.delete=Вы не можете удалить свой аккаунт
|
||||
message.error.place.update=Ошибка обновления места: {0}
|
||||
message.relogin.required=Ваше имя пользователя было изменено на : {0}. Вам необходимо выйти и зайти снова с вашим новым именем пользователя.
|
||||
message.error.access.denied=Доступ запрещен. У вас нет разрешения на выполнение этого действия.
|
||||
upload.title=Импорт данных локаций
|
||||
nav.statistics=\u0421\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043A\u0430
|
||||
nav.settings=\u041D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438
|
||||
nav.logout=\u0412\u044B\u0445\u043E\u0434
|
||||
nav.logout.tooltip=\u0412\u044B\u0445\u043E\u0434
|
||||
timeline.loading=\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430\u2026
|
||||
timeline.distance=\u0414\u0438\u0441\u0442\u0430\u043D\u0446\u0438\u044F
|
||||
timeline.duration=\u041F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0441\u0442\u044C
|
||||
datepicker.today=\u0421\u0435\u0433\u043E\u0434\u043D\u044F
|
||||
datepicker.days.sun=\u0412\u0441
|
||||
datepicker.days.mon=\u041F\u043E\u043D
|
||||
datepicker.days.tue=\u0412\u0442
|
||||
datepicker.days.wed=\u0421\u0440
|
||||
datepicker.days.thu=\u0427\u0442
|
||||
datepicker.days.fri=\u041F\u0442
|
||||
datepicker.days.sat=\u0421\u0431
|
||||
datepicker.months.jan=\u042F\u043D\u0432
|
||||
datepicker.months.feb=\u0424\u0435\u0432
|
||||
datepicker.months.mar=\u041C\u0430\u0440
|
||||
datepicker.months.apr=\u0410\u043F\u0440
|
||||
datepicker.months.may=\u041C\u0430\u0439
|
||||
datepicker.months.jun=\u0418\u044E\u043D\u044C
|
||||
datepicker.months.jul=\u0418\u044E\u043B\u044C
|
||||
datepicker.months.aug=\u0410\u0432\u0433
|
||||
datepicker.months.sep=\u0421\u0435\u043D
|
||||
datepicker.months.oct=\u041E\u043A\u0442
|
||||
datepicker.months.nov=\u041D\u043E\u044F\u0431
|
||||
datepicker.months.dec=\u0414\u0435\u043A
|
||||
settings.title=\u041D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438
|
||||
settings.api.tokens=API \u0442\u043E\u043A\u0435\u043D\u044B
|
||||
settings.user.management=\u0423\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u043C
|
||||
tokens.title=API \u0442\u043E\u043A\u0435\u043D\u044B
|
||||
tokens.create.title=\u0421\u043E\u0437\u0434\u0430\u0442\u044C \u043D\u043E\u0432\u044B\u0439 \u0442\u043E\u043A\u0435\u043D
|
||||
map.auto-update.latest-location=\u041F\u043E\u0441\u043B\u0435\u0434\u043D\u0435\u0435 \u043C\u0435\u0441\u0442\u043E\u043F\u043E\u043B\u043E\u0436\u0435\u043D\u0438\u0435
|
||||
export.title=\u042D\u043A\u0441\u043F\u043E\u0440\u0442 \u0434\u0430\u043D\u043D\u044B\u0445
|
||||
export.date.range=\u0414\u0438\u0430\u043F\u0430\u0437\u043E\u043D \u0434\u0430\u0442
|
||||
export.start.date=\u041D\u0430\u0447\u0430\u043B\u044C\u043D\u0430\u044F \u0434\u0430\u0442\u0430
|
||||
export.end.date=\u041A\u043E\u043D\u0435\u0447\u043D\u0430\u044F \u0434\u0430\u0442\u0430
|
||||
export.gpx.button=\u042D\u043A\u0441\u043F\u043E\u0440\u0442 \u043A\u0430\u043A GPX
|
||||
export.raw.data.title=Raw \u0434\u0430\u043D\u043D\u044B\u0435 \u043C\u0435\u0441\u0442\u043E\u043F\u043E\u043B\u043E\u0436\u0435\u043D\u0438\u044F
|
||||
export.raw.data.table.latitude=\u0428\u0438\u0440\u043E\u0442\u0430
|
||||
export.raw.data.table.longitude=\u0414\u043E\u043B\u0433\u043E\u0442\u0430
|
||||
export.raw.data.table.accuracy=\u0422\u043E\u0447\u043D\u043E\u0441\u0442\u044C (\u043C)
|
||||
export.raw.data.no.data=\u041D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E \u043C\u0435\u0441\u0442 \u0432 \u0432\u044B\u0431\u0440\u0430\u043D\u043D\u043E\u043C \u0434\u0438\u0430\u043F\u0430\u0437\u043E\u043D\u0435 \u0434\u0430\u0442
|
||||
export.gpx.success=GPX \u0444\u0430\u0439\u043B \u044D\u043A\u0441\u043F\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u043D \u0443\u0434\u0430\u0447\u043D\u043E
|
||||
export.gpx.error=\u041E\u0448\u0438\u0431\u043A\u0430 \u044D\u043A\u0441\u043F\u043E\u0440\u0442\u0430 GPX: {0}
|
||||
error.page.title=\u041E\u0448\u0438\u0431\u043A\u0430 - Reitti
|
||||
error.title=\u0423\u043F\u0441! \u0427\u0442\u043E \u0442\u043E \u043F\u043E\u0448\u043B\u043E \u043D\u0435 \u0442\u0430\u043A
|
||||
error.generic.message=\u041D\u0435\u043E\u0436\u0438\u0434\u0430\u043D\u043D\u0430\u044F \u043E\u0448\u0438\u0431\u043A\u0430. \u041F\u043E\u043F\u0440\u043E\u0431\u0443\u0439\u0442\u0435 \u0435\u0449\u0435 \u0440\u0430\u0437 \u043F\u043E\u0437\u0436\u0435.
|
||||
error.technical.details=\u0422\u0435\u0445\u043D\u0438\u0447\u0435\u0441\u043A\u0438\u0435 \u0434\u0435\u0442\u0430\u043B\u0438
|
||||
error.action.home=\u0414\u043E\u043C\u043E\u0439
|
||||
error.action.back=\u041D\u0430\u0437\u0430\u0434
|
||||
error.action.retry=\u0415\u0449\u0435 \u0440\u0430\u0437
|
||||
share-access.title=\u041F\u043E\u0434\u0435\u043B\u0438\u0442\u044C\u0441\u044F \u0434\u043E\u0441\u0442\u0443\u043F\u043E\u043C
|
||||
magic.links.new.token.value=\u0422\u043E\u043B\u044C\u043A\u043E \u0442\u043E\u043A\u0435\u043D:
|
||||
magic.links.info.security.title=\u0412\u043E\u043F\u0440\u043E\u0441\u044B \u0431\u0435\u0437\u043E\u043F\u0430\u0441\u043D\u043E\u0441\u0442\u0438
|
||||
magic.links.info.security.point1=\u041B\u044E\u0431\u043E\u0439, \u0443 \u043A\u043E\u0433\u043E \u0435\u0441\u0442\u044C \u0441\u0441\u044B\u043B\u043A\u0430, \u043C\u043E\u0436\u0435\u0442 \u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C \u0434\u043E\u0441\u0442\u0443\u043F \u043A \u0432\u0430\u0448\u0438\u043C \u0434\u0430\u043D\u043D\u044B\u043C, \u043E\u0442\u043D\u043E\u0441\u0438\u0442\u0435\u0441\u044C \u043A \u043D\u0438\u043C \u043A\u0430\u043A \u043A \u043F\u0430\u0440\u043E\u043B\u044E
|
||||
magic.links.info.security.point2=\u0421\u0441\u044B\u043B\u043A\u0438 \u043D\u0435 \u043C\u043E\u0433\u0443\u0442 \u0431\u044B\u0442\u044C \u0432\u043E\u0441\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u044B, \u0435\u0441\u043B\u0438 \u043F\u043E\u0442\u0435\u0440\u044F\u0435\u0442\u0435, \u043D\u0430\u0434\u043E \u0431\u0443\u0434\u0435\u0442 \u0441\u043E\u0437\u0434\u0430\u0442\u044C \u043D\u043E\u0432\u044B\u0435
|
||||
magic.links.info.security.point3=\u0423\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u0435 \u0434\u0430\u0442\u044B \u0438\u0441\u0442\u0435\u0447\u0435\u043D\u0438\u044F \u0441\u0440\u043E\u043A\u0430 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044F \u0432\u0440\u0435\u043C\u0435\u043D\u043D\u043E\u0433\u043E \u043E\u0431\u0449\u0435\u0433\u043E \u0434\u043E\u0441\u0442\u0443\u043F\u0430, \u0447\u0442\u043E\u0431\u044B \u043E\u0433\u0440\u0430\u043D\u0438\u0447\u0438\u0442\u044C \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0441\u0442\u044C \u0434\u043E\u0441\u0442\u0443\u043F\u0430
|
||||
magic.links.info.security.point4=\u041D\u0435\u043C\u0435\u0434\u043B\u0435\u043D\u043D\u043E \u0441\u0441\u044B\u043B\u043A\u0438 \u0443\u0434\u0430\u043B\u0438\u0442\u0435, \u043A\u043E\u0433\u0434\u0430 \u043E\u043D\u0438 \u0441\u0442\u0430\u043D\u0443\u0442 \u043D\u0435 \u043D\u0443\u0436\u043D\u044B
|
||||
magic.links.info.security.point5=\u041C\u043E\u043D\u0438\u0442\u043E\u0440\u0438\u043D\u0433 \u0441\u0442\u043E\u043B\u0431\u0446\u0430 '\u041F\u043E\u0441\u043B\u0435\u0434\u043D\u0438\u0439 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u043C\u044B\u0439' \u0434\u043B\u044F \u043E\u0442\u0441\u043B\u0435\u0436\u0438\u0432\u0430\u043D\u0438\u044F \u0434\u043E\u0441\u0442\u0443\u043F\u0430
|
||||
magic.links.info.access.levels.title=\u0423\u0440\u043E\u0432\u043D\u0438 \u0434\u043E\u0441\u0442\u0443\u043F\u0430
|
||||
magic.links.info.access.full.description=\u041F\u043E\u043B\u043D\u044B\u0439 \u0434\u043E\u0441\u0442\u0443\u043F \u043A\u043E \u0432\u0441\u0435\u043C \u0434\u0430\u043D\u043D\u044B\u043C \u0438 \u0438\u0441\u0442\u043E\u0440\u0438\u0438 \u0432\u0430\u0448\u0435\u0433\u043E \u043C\u0435\u0441\u0442\u043E\u043F\u043E\u043B\u043E\u0436\u0435\u043D\u0438\u044F
|
||||
magic.links.info.access.live.description=\u0414\u043E\u0441\u0442\u0443\u043F \u0442\u043E\u043B\u044C\u043A\u043E \u043A \u0434\u0430\u043D\u043D\u044B\u043C \u043E \u0442\u0435\u043A\u0443\u0449\u0435\u043C/\u043D\u0435\u0434\u0430\u0432\u043D\u0435\u043C \u043C\u0435\u0441\u0442\u043E\u043F\u043E\u043B\u043E\u0436\u0435\u043D\u0438\u0438
|
||||
form.cancel=\u041E\u0442\u043C\u0435\u043D\u0430
|
||||
form.previous=\u041F\u0440\u0435\u0434\u044B\u0434\u0443\u0449\u0438\u0439
|
||||
form.next=\u0421\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u0439
|
||||
form.refresh=\u041E\u0431\u043D\u043E\u0432\u0438\u0442\u044C
|
||||
message.success.token.created=\u0422\u043E\u043A\u0435\u043D \u0443\u0441\u043F\u0435\u0448\u043D\u043E \u0441\u043E\u0437\u0434\u0430\u043D
|
||||
message.success.token.deleted=\u0422\u043E\u043A\u0435\u043D \u0443\u0441\u043F\u0435\u0448\u043D\u043E \u0443\u0434\u0430\u043B\u0435\u043D
|
||||
message.success.user.created=\u041F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C \u0443\u0441\u043F\u0435\u0448\u043D\u043E \u0441\u043E\u0437\u0434\u0430\u043D
|
||||
message.success.user.updated=\u041F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C \u0443\u0441\u043F\u0435\u0448\u043D\u043E \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D
|
||||
message.success.user.deleted=\u041F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C \u0443\u0441\u043F\u0435\u0448\u043D\u043E \u0443\u0434\u0430\u043B\u0435\u043D
|
||||
message.success.place.updated=\u041C\u0435\u0441\u0442\u043E \u0443\u0441\u043F\u0435\u0448\u043D\u043E \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u043E
|
||||
message.error.token.creation=\u041E\u0448\u0438\u0431\u043A\u0430 \u0441\u043E\u0437\u0434\u0430\u043D\u0438\u044F \u0442\u043E\u043A\u0435\u043D\u0430: {0}
|
||||
message.error.token.deletion=\u041E\u0448\u0438\u0431\u043A\u0430 \u0443\u0434\u0430\u043B\u0435\u043D\u0438\u044F \u0442\u043E\u043A\u0435\u043D\u0430:{0}
|
||||
message.error.user.creation=\u041E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438 \u0441\u043E\u0437\u0434\u0430\u043D\u0438\u0438 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F: {0}
|
||||
message.error.user.update=\u041E\u0448\u0438\u0431\u043A\u0430 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F: {0}
|
||||
message.error.user.deletion=\u041E\u0448\u0438\u0431\u043A\u0430 \u0443\u0434\u0430\u043B\u0435\u043D\u0438\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F: {0}
|
||||
message.error.user.self.delete=\u0412\u044B \u043D\u0435 \u043C\u043E\u0436\u0435\u0442\u0435 \u0443\u0434\u0430\u043B\u0438\u0442\u044C \u0441\u0432\u043E\u0439 \u0430\u043A\u043A\u0430\u0443\u043D\u0442
|
||||
message.error.place.update=\u041E\u0448\u0438\u0431\u043A\u0430 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u044F \u043C\u0435\u0441\u0442\u0430: {0}
|
||||
message.relogin.required=\u0412\u0430\u0448\u0435 \u0438\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u0431\u044B\u043B\u043E \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u043E \u043D\u0430 : {0}. \u0412\u0430\u043C \u043D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E \u0432\u044B\u0439\u0442\u0438 \u0438 \u0437\u0430\u0439\u0442\u0438 \u0441\u043D\u043E\u0432\u0430 \u0441 \u0432\u0430\u0448\u0438\u043C \u043D\u043E\u0432\u044B\u043C \u0438\u043C\u0435\u043D\u0435\u043C \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F.
|
||||
message.error.access.denied=\u0414\u043E\u0441\u0442\u0443\u043F \u0437\u0430\u043F\u0440\u0435\u0449\u0435\u043D. \u0423 \u0432\u0430\u0441 \u043D\u0435\u0442 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043D\u0438\u044F \u043D\u0430 \u0432\u044B\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u0435 \u044D\u0442\u043E\u0433\u043E \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044F.
|
||||
upload.title=\u0418\u043C\u043F\u043E\u0440\u0442 \u0434\u0430\u043D\u043D\u044B\u0445 \u043B\u043E\u043A\u0430\u0446\u0438\u0439
|
||||
upload.gpx.title=GPX Files
|
||||
upload.gpx.description=Загрузите файлы GPX с устройств GPS или приложения для отслеживания. Файлы GPX содержат путевые точки, треки и маршруты с временными метками, которые могут быть обработаны в историю вашего местоположения.
|
||||
upload.gpx.description=\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u0435 \u0444\u0430\u0439\u043B\u044B GPX \u0441 \u0443\u0441\u0442\u0440\u043E\u0439\u0441\u0442\u0432 GPS \u0438\u043B\u0438 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u044F \u0434\u043B\u044F \u043E\u0442\u0441\u043B\u0435\u0436\u0438\u0432\u0430\u043D\u0438\u044F. \u0424\u0430\u0439\u043B\u044B GPX \u0441\u043E\u0434\u0435\u0440\u0436\u0430\u0442 \u043F\u0443\u0442\u0435\u0432\u044B\u0435 \u0442\u043E\u0447\u043A\u0438, \u0442\u0440\u0435\u043A\u0438 \u0438 \u043C\u0430\u0440\u0448\u0440\u0443\u0442\u044B \u0441 \u0432\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u043C\u0438 \u043C\u0435\u0442\u043A\u0430\u043C\u0438, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u043C\u043E\u0433\u0443\u0442 \u0431\u044B\u0442\u044C \u043E\u0431\u0440\u0430\u0431\u043E\u0442\u0430\u043D\u044B \u0432 \u0438\u0441\u0442\u043E\u0440\u0438\u044E \u0432\u0430\u0448\u0435\u0433\u043E \u043C\u0435\u0441\u0442\u043E\u043F\u043E\u043B\u043E\u0436\u0435\u043D\u0438\u044F.
|
||||
upload.google.title=Google Takeout
|
||||
units.metric.description=(км, м)
|
||||
units.imperial=Имперская
|
||||
units.imperial.description=(ми, фт)
|
||||
places.title=Значительные места
|
||||
places.no.places=Никаких значительных мест.
|
||||
places.page.info=Страница {0} из {1}
|
||||
places.name.label=Имя
|
||||
places.address.label=Адрес
|
||||
places.category.label=Категория
|
||||
places.coordinates.label=Координаты
|
||||
places.address.not.available=Недоступен
|
||||
places.category.not.categorized=Не категоризирован
|
||||
units.metric.description=(\u043A\u043C, \u043C)
|
||||
units.imperial=\u0418\u043C\u043F\u0435\u0440\u0441\u043A\u0430\u044F
|
||||
units.imperial.description=(\u043C\u0438, \u0444\u0442)
|
||||
places.title=\u0417\u043D\u0430\u0447\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0435 \u043C\u0435\u0441\u0442\u0430
|
||||
places.no.places=\u041D\u0438\u043A\u0430\u043A\u0438\u0445 \u0437\u043D\u0430\u0447\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0445 \u043C\u0435\u0441\u0442.
|
||||
places.page.info=\u0421\u0442\u0440\u0430\u043D\u0438\u0446\u0430 {0} \u0438\u0437 {1}
|
||||
places.name.label=\u0418\u043C\u044F
|
||||
places.address.label=\u0410\u0434\u0440\u0435\u0441
|
||||
places.category.label=\u041A\u0430\u0442\u0435\u0433\u043E\u0440\u0438\u044F
|
||||
places.coordinates.label=\u041A\u043E\u043E\u0440\u0434\u0438\u043D\u0430\u0442\u044B
|
||||
places.address.not.available=\u041D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D
|
||||
places.category.not.categorized=\u041D\u0435 \u043A\u0430\u0442\u0435\u0433\u043E\u0440\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u043D
|
||||
places.geocode.button=Geocode
|
||||
places.geocode.confirm=Вы уверены, что хотите перекодировать это место? Это позволит очистить текущий адрес и запросить новый.
|
||||
places.geocode.success=Место, запланированное для геокодирования
|
||||
places.address.placeholder=Введите адрес
|
||||
places.geocoding.response.button=Вид Geocoding
|
||||
places.geocoding.response.back=Назад в Места
|
||||
places.geocoding.response.provider=Поставщик
|
||||
places.geocoding.response.status=Статус
|
||||
places.geocoding.response.fetched.at=На
|
||||
places.geocode.confirm=\u0412\u044B \u0443\u0432\u0435\u0440\u0435\u043D\u044B, \u0447\u0442\u043E \u0445\u043E\u0442\u0438\u0442\u0435 \u043F\u0435\u0440\u0435\u043A\u043E\u0434\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u044D\u0442\u043E \u043C\u0435\u0441\u0442\u043E? \u042D\u0442\u043E \u043F\u043E\u0437\u0432\u043E\u043B\u0438\u0442 \u043E\u0447\u0438\u0441\u0442\u0438\u0442\u044C \u0442\u0435\u043A\u0443\u0449\u0438\u0439 \u0430\u0434\u0440\u0435\u0441 \u0438 \u0437\u0430\u043F\u0440\u043E\u0441\u0438\u0442\u044C \u043D\u043E\u0432\u044B\u0439.
|
||||
places.geocode.success=\u041C\u0435\u0441\u0442\u043E, \u0437\u0430\u043F\u043B\u0430\u043D\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u043E\u0435 \u0434\u043B\u044F \u0433\u0435\u043E\u043A\u043E\u0434\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u044F
|
||||
places.address.placeholder=\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0430\u0434\u0440\u0435\u0441
|
||||
places.geocoding.response.button=\u0412\u0438\u0434 Geocoding
|
||||
places.geocoding.response.back=\u041D\u0430\u0437\u0430\u0434 \u0432 \u041C\u0435\u0441\u0442\u0430
|
||||
places.geocoding.response.provider=\u041F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A
|
||||
places.geocoding.response.status=\u0421\u0442\u0430\u0442\u0443\u0441
|
||||
places.geocoding.response.fetched.at=\u041D\u0430
|
||||
places.geocoding.response.raw.data=Raw Data
|
||||
places.geocoding.response.error.details=Детали ошибки
|
||||
visit.sensitivity.level.help=Низкая чувствительность обнаруживает меньше, более длительные посещения. Высокая чувствительность обнаруживает больше, более короткие визиты. Регулируйте на основе ваших потребностей отслеживания: используйте низкий уровень для отслеживания общего местоположения, высокий для подробного анализа движения. Это сильно зависит от того, как часто ваша интеграция отправляет данные в Reitti. Чем меньше интервал входящих данных, тем выше должен быть уровень чувствительности.
|
||||
visit.detection.max.merge.time.help=Максимальный временной интервал между посещениями одного и того же места, прежде чем они будут считаться отдельными посещениями. Если вы покинете одно и то же место и вернетесь в течение этого времени, это будет рассматриваться как одно непрерывное посещение. Типичные значения: 1800 с (30 минут) для коротких поручений, 3600 с (1 час) для длительных перерывов.
|
||||
visit.merging.max.merge.time.help=Максимальное время между посещением того же места до того, как они будут считаться отдельными событиями. Это помогает объединить посещения, которые были неправильно разделены из-за неточностей GPS или кратких вылетов. Типичные значения: 3600S (1 час) для строгого разделения, 7200S (2 часа) для более мягкого слияния.
|
||||
visit.detection.minimum.stay.help=Минимальная продолжительность, чтобы считать это место посещением, а не просто проездом. Более низкие значения (60–300 с) определяют короткие остановки, более высокие значения (600–1800 с) обнаруживают только значительные остановки. Типичные значения: 300 с (5 минут) для подробного отслеживания, 900 с (15 минут) только для основных местоположений.
|
||||
share-with.info.description=Когда вы поделитесь своими данными с другими пользователями, они смогут просматривать ваше время и историю местоположения вместе со своими собственными данными. Это полезно для семей или команд, которые хотят координировать и делиться информацией о местоположении.
|
||||
places.geocoding.response.error.details=\u0414\u0435\u0442\u0430\u043B\u0438 \u043E\u0448\u0438\u0431\u043A\u0438
|
||||
visit.sensitivity.level.help=\u041D\u0438\u0437\u043A\u0430\u044F \u0447\u0443\u0432\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0441\u0442\u044C \u043E\u0431\u043D\u0430\u0440\u0443\u0436\u0438\u0432\u0430\u0435\u0442 \u043C\u0435\u043D\u044C\u0448\u0435, \u0431\u043E\u043B\u0435\u0435 \u0434\u043B\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0435 \u043F\u043E\u0441\u0435\u0449\u0435\u043D\u0438\u044F. \u0412\u044B\u0441\u043E\u043A\u0430\u044F \u0447\u0443\u0432\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0441\u0442\u044C \u043E\u0431\u043D\u0430\u0440\u0443\u0436\u0438\u0432\u0430\u0435\u0442 \u0431\u043E\u043B\u044C\u0448\u0435, \u0431\u043E\u043B\u0435\u0435 \u043A\u043E\u0440\u043E\u0442\u043A\u0438\u0435 \u0432\u0438\u0437\u0438\u0442\u044B. \u0420\u0435\u0433\u0443\u043B\u0438\u0440\u0443\u0439\u0442\u0435 \u043D\u0430 \u043E\u0441\u043D\u043E\u0432\u0435 \u0432\u0430\u0448\u0438\u0445 \u043F\u043E\u0442\u0440\u0435\u0431\u043D\u043E\u0441\u0442\u0435\u0439 \u043E\u0442\u0441\u043B\u0435\u0436\u0438\u0432\u0430\u043D\u0438\u044F: \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439\u0442\u0435 \u043D\u0438\u0437\u043A\u0438\u0439 \u0443\u0440\u043E\u0432\u0435\u043D\u044C \u0434\u043B\u044F \u043E\u0442\u0441\u043B\u0435\u0436\u0438\u0432\u0430\u043D\u0438\u044F \u043E\u0431\u0449\u0435\u0433\u043E \u043C\u0435\u0441\u0442\u043E\u043F\u043E\u043B\u043E\u0436\u0435\u043D\u0438\u044F, \u0432\u044B\u0441\u043E\u043A\u0438\u0439 \u0434\u043B\u044F \u043F\u043E\u0434\u0440\u043E\u0431\u043D\u043E\u0433\u043E \u0430\u043D\u0430\u043B\u0438\u0437\u0430 \u0434\u0432\u0438\u0436\u0435\u043D\u0438\u044F. \u042D\u0442\u043E \u0441\u0438\u043B\u044C\u043D\u043E \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043E\u0442 \u0442\u043E\u0433\u043E, \u043A\u0430\u043A \u0447\u0430\u0441\u0442\u043E \u0432\u0430\u0448\u0430 \u0438\u043D\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044F \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u044F\u0435\u0442 \u0434\u0430\u043D\u043D\u044B\u0435 \u0432 Reitti. \u0427\u0435\u043C \u043C\u0435\u043D\u044C\u0448\u0435 \u0438\u043D\u0442\u0435\u0440\u0432\u0430\u043B \u0432\u0445\u043E\u0434\u044F\u0449\u0438\u0445 \u0434\u0430\u043D\u043D\u044B\u0445, \u0442\u0435\u043C \u0432\u044B\u0448\u0435 \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0443\u0440\u043E\u0432\u0435\u043D\u044C \u0447\u0443\u0432\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0441\u0442\u0438.
|
||||
visit.detection.max.merge.time.help=\u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u044B\u0439 \u0432\u0440\u0435\u043C\u0435\u043D\u043D\u043E\u0439 \u0438\u043D\u0442\u0435\u0440\u0432\u0430\u043B \u043C\u0435\u0436\u0434\u0443 \u043F\u043E\u0441\u0435\u0449\u0435\u043D\u0438\u044F\u043C\u0438 \u043E\u0434\u043D\u043E\u0433\u043E \u0438 \u0442\u043E\u0433\u043E \u0436\u0435 \u043C\u0435\u0441\u0442\u0430, \u043F\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043C \u043E\u043D\u0438 \u0431\u0443\u0434\u0443\u0442 \u0441\u0447\u0438\u0442\u0430\u0442\u044C\u0441\u044F \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u044B\u043C\u0438 \u043F\u043E\u0441\u0435\u0449\u0435\u043D\u0438\u044F\u043C\u0438. \u0415\u0441\u043B\u0438 \u0432\u044B \u043F\u043E\u043A\u0438\u043D\u0435\u0442\u0435 \u043E\u0434\u043D\u043E \u0438 \u0442\u043E \u0436\u0435 \u043C\u0435\u0441\u0442\u043E \u0438 \u0432\u0435\u0440\u043D\u0435\u0442\u0435\u0441\u044C \u0432 \u0442\u0435\u0447\u0435\u043D\u0438\u0435 \u044D\u0442\u043E\u0433\u043E \u0432\u0440\u0435\u043C\u0435\u043D\u0438, \u044D\u0442\u043E \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0441\u0441\u043C\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044C\u0441\u044F \u043A\u0430\u043A \u043E\u0434\u043D\u043E \u043D\u0435\u043F\u0440\u0435\u0440\u044B\u0432\u043D\u043E\u0435 \u043F\u043E\u0441\u0435\u0449\u0435\u043D\u0438\u0435. \u0422\u0438\u043F\u0438\u0447\u043D\u044B\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F: 1800 \u0441 (30 \u043C\u0438\u043D\u0443\u0442) \u0434\u043B\u044F \u043A\u043E\u0440\u043E\u0442\u043A\u0438\u0445 \u043F\u043E\u0440\u0443\u0447\u0435\u043D\u0438\u0439, 3600 \u0441 (1 \u0447\u0430\u0441) \u0434\u043B\u044F \u0434\u043B\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0445 \u043F\u0435\u0440\u0435\u0440\u044B\u0432\u043E\u0432.
|
||||
visit.merging.max.merge.time.help=\u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u0432\u0440\u0435\u043C\u044F \u043C\u0435\u0436\u0434\u0443 \u043F\u043E\u0441\u0435\u0449\u0435\u043D\u0438\u0435\u043C \u0442\u043E\u0433\u043E \u0436\u0435 \u043C\u0435\u0441\u0442\u0430 \u0434\u043E \u0442\u043E\u0433\u043E, \u043A\u0430\u043A \u043E\u043D\u0438 \u0431\u0443\u0434\u0443\u0442 \u0441\u0447\u0438\u0442\u0430\u0442\u044C\u0441\u044F \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u044B\u043C\u0438 \u0441\u043E\u0431\u044B\u0442\u0438\u044F\u043C\u0438. \u042D\u0442\u043E \u043F\u043E\u043C\u043E\u0433\u0430\u0435\u0442 \u043E\u0431\u044A\u0435\u0434\u0438\u043D\u0438\u0442\u044C \u043F\u043E\u0441\u0435\u0449\u0435\u043D\u0438\u044F, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0431\u044B\u043B\u0438 \u043D\u0435\u043F\u0440\u0430\u0432\u0438\u043B\u044C\u043D\u043E \u0440\u0430\u0437\u0434\u0435\u043B\u0435\u043D\u044B \u0438\u0437-\u0437\u0430 \u043D\u0435\u0442\u043E\u0447\u043D\u043E\u0441\u0442\u0435\u0439 GPS \u0438\u043B\u0438 \u043A\u0440\u0430\u0442\u043A\u0438\u0445 \u0432\u044B\u043B\u0435\u0442\u043E\u0432. \u0422\u0438\u043F\u0438\u0447\u043D\u044B\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F: 3600S (1 \u0447\u0430\u0441) \u0434\u043B\u044F \u0441\u0442\u0440\u043E\u0433\u043E\u0433\u043E \u0440\u0430\u0437\u0434\u0435\u043B\u0435\u043D\u0438\u044F, 7200S (2 \u0447\u0430\u0441\u0430) \u0434\u043B\u044F \u0431\u043E\u043B\u0435\u0435 \u043C\u044F\u0433\u043A\u043E\u0433\u043E \u0441\u043B\u0438\u044F\u043D\u0438\u044F.
|
||||
visit.detection.minimum.stay.help=\u041C\u0438\u043D\u0438\u043C\u0430\u043B\u044C\u043D\u0430\u044F \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0441\u0442\u044C, \u0447\u0442\u043E\u0431\u044B \u0441\u0447\u0438\u0442\u0430\u0442\u044C \u044D\u0442\u043E \u043C\u0435\u0441\u0442\u043E \u043F\u043E\u0441\u0435\u0449\u0435\u043D\u0438\u0435\u043C, \u0430 \u043D\u0435 \u043F\u0440\u043E\u0441\u0442\u043E \u043F\u0440\u043E\u0435\u0437\u0434\u043E\u043C. \u0411\u043E\u043B\u0435\u0435 \u043D\u0438\u0437\u043A\u0438\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F (60\u2013300 \u0441) \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u044F\u044E\u0442 \u043A\u043E\u0440\u043E\u0442\u043A\u0438\u0435 \u043E\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0438, \u0431\u043E\u043B\u0435\u0435 \u0432\u044B\u0441\u043E\u043A\u0438\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F (600\u20131800 \u0441) \u043E\u0431\u043D\u0430\u0440\u0443\u0436\u0438\u0432\u0430\u044E\u0442 \u0442\u043E\u043B\u044C\u043A\u043E \u0437\u043D\u0430\u0447\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0435 \u043E\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0438. \u0422\u0438\u043F\u0438\u0447\u043D\u044B\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F: 300\u00A0\u0441 (5\u00A0\u043C\u0438\u043D\u0443\u0442) \u0434\u043B\u044F \u043F\u043E\u0434\u0440\u043E\u0431\u043D\u043E\u0433\u043E \u043E\u0442\u0441\u043B\u0435\u0436\u0438\u0432\u0430\u043D\u0438\u044F, 900\u00A0\u0441 (15\u00A0\u043C\u0438\u043D\u0443\u0442) \u0442\u043E\u043B\u044C\u043A\u043E \u0434\u043B\u044F \u043E\u0441\u043D\u043E\u0432\u043D\u044B\u0445 \u043C\u0435\u0441\u0442\u043E\u043F\u043E\u043B\u043E\u0436\u0435\u043D\u0438\u0439.
|
||||
share-with.info.description=\u041A\u043E\u0433\u0434\u0430 \u0432\u044B \u043F\u043E\u0434\u0435\u043B\u0438\u0442\u0435\u0441\u044C \u0441\u0432\u043E\u0438\u043C\u0438 \u0434\u0430\u043D\u043D\u044B\u043C\u0438 \u0441 \u0434\u0440\u0443\u0433\u0438\u043C\u0438 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F\u043C\u0438, \u043E\u043D\u0438 \u0441\u043C\u043E\u0433\u0443\u0442 \u043F\u0440\u043E\u0441\u043C\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044C \u0432\u0430\u0448\u0435 \u0432\u0440\u0435\u043C\u044F \u0438 \u0438\u0441\u0442\u043E\u0440\u0438\u044E \u043C\u0435\u0441\u0442\u043E\u043F\u043E\u043B\u043E\u0436\u0435\u043D\u0438\u044F \u0432\u043C\u0435\u0441\u0442\u0435 \u0441\u043E \u0441\u0432\u043E\u0438\u043C\u0438 \u0441\u043E\u0431\u0441\u0442\u0432\u0435\u043D\u043D\u044B\u043C\u0438 \u0434\u0430\u043D\u043D\u044B\u043C\u0438. \u042D\u0442\u043E \u043F\u043E\u043B\u0435\u0437\u043D\u043E \u0434\u043B\u044F \u0441\u0435\u043C\u0435\u0439 \u0438\u043B\u0438 \u043A\u043E\u043C\u0430\u043D\u0434, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0445\u043E\u0442\u044F\u0442 \u043A\u043E\u043E\u0440\u0434\u0438\u043D\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0438 \u0434\u0435\u043B\u0438\u0442\u044C\u0441\u044F \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u0435\u0439 \u043E \u043C\u0435\u0441\u0442\u043E\u043F\u043E\u043B\u043E\u0436\u0435\u043D\u0438\u0438.
|
||||
|
||||
about.acknowledgments.title=\u0411\u043B\u0430\u0433\u043E\u0434\u0430\u0440\u043D\u043E\u0441\u0442\u0438
|
||||
about.acknowledgments.subtitle=Reitti \u0431\u044B\u043B \u0431\u044B \u043D\u0435\u0432\u043E\u0437\u043C\u043E\u0436\u0435\u043D \u0431\u0435\u0437 \u0443\u0434\u0438\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0433\u043E \u0432\u043A\u043B\u0430\u0434\u0430 \u043D\u0430\u0448\u0435\u0433\u043E \u0441\u043E\u043E\u0431\u0449\u0435\u0441\u0442\u0432\u0430 \u0438 \u043D\u0435\u0432\u0435\u0440\u043E\u044F\u0442\u043D\u044B\u0445 \u043F\u0440\u043E\u0435\u043A\u0442\u043E\u0432 \u0441 \u043E\u0442\u043A\u0440\u044B\u0442\u044B\u043C \u0438\u0441\u0445\u043E\u0434\u043D\u044B\u043C \u043A\u043E\u0434\u043E\u043C, \u043D\u0430 \u043A\u043E\u0442\u043E\u0440\u044B\u0445 \u043C\u044B \u0441\u0442\u0440\u043E\u0438\u043C.
|
||||
about.contributors.title=\u0423\u0447\u0430\u0441\u0442\u043D\u0438\u043A\u0438
|
||||
about.translators.title=\u041F\u0435\u0440\u0435\u0432\u043E\u0434\u0447\u0438\u043A\u0438
|
||||
about.projects.title=\u041F\u0440\u043E\u0435\u043A\u0442\u044B \u0441 \u041E\u0442\u043A\u0440\u044B\u0442\u044B\u043C \u0418\u0441\u0445\u043E\u0434\u043D\u044B\u043C \u041A\u043E\u0434\u043E\u043C
|
||||
about.projects.visit=\u041F\u043E\u0441\u0435\u0442\u0438\u0442\u044C \u041F\u0440\u043E\u0435\u043A\u0442
|
||||
about.thankyou.title=\u0421\u043F\u0430\u0441\u0438\u0431\u043E!
|
||||
about.thankyou.message=\u041A\u0430\u0436\u0434\u044B\u0439 \u0432\u043A\u043B\u0430\u0434, \u043A\u0430\u043A\u0438\u043C \u0431\u044B \u043C\u0430\u043B\u0435\u043D\u044C\u043A\u0438\u043C \u043E\u043D \u043D\u0438 \u0431\u044B\u043B, \u043F\u043E\u043C\u043E\u0433\u0430\u0435\u0442 \u0441\u0434\u0435\u043B\u0430\u0442\u044C Reitti \u043B\u0443\u0447\u0448\u0435 \u0434\u043B\u044F \u0432\u0441\u0435\u0445. \u041C\u044B \u0431\u043B\u0430\u0433\u043E\u0434\u0430\u0440\u043D\u044B \u0437\u0430 \u0432\u0430\u0448\u0443 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u043A\u0443 \u0438 \u043F\u0440\u0435\u0434\u0430\u043D\u043D\u043E\u0441\u0442\u044C \u0441\u043E\u043E\u0431\u0449\u0435\u0441\u0442\u0432\u0443 \u043E\u0442\u043A\u0440\u044B\u0442\u043E\u0433\u043E \u0438\u0441\u0445\u043E\u0434\u043D\u043E\u0433\u043E \u043A\u043E\u0434\u0430.
|
||||
44
src/main/resources/projects.json
Normal file
44
src/main/resources/projects.json
Normal file
@@ -0,0 +1,44 @@
|
||||
{"projects": [
|
||||
{
|
||||
"name": "Spring Boot",
|
||||
"description": "Java-based framework for building production-ready applications",
|
||||
"url": "https://spring.io/projects/spring-boot",
|
||||
"license": "Apache 2.0",
|
||||
"category": "Framework"
|
||||
},
|
||||
{
|
||||
"name": "PostgreSQL",
|
||||
"description": "Advanced open source relational database",
|
||||
"url": "https://www.postgresql.org/",
|
||||
"license": "PostgreSQL License",
|
||||
"category": "Database"
|
||||
},
|
||||
{
|
||||
"name": "Leaflet",
|
||||
"description": "Open-source JavaScript library for mobile-friendly interactive maps",
|
||||
"url": "https://leafletjs.com/",
|
||||
"license": "BSD-2-Clause",
|
||||
"category": "Frontend"
|
||||
},
|
||||
{
|
||||
"name": "HTMX",
|
||||
"description": "High power tools for HTML",
|
||||
"url": "https://htmx.org/",
|
||||
"license": "BSD-2-Clause",
|
||||
"category": "Frontend"
|
||||
},
|
||||
{
|
||||
"name": "Thymeleaf",
|
||||
"description": "Modern server-side Java template engine",
|
||||
"url": "https://www.thymeleaf.org/",
|
||||
"license": "Apache 2.0",
|
||||
"category": "Template Engine"
|
||||
},
|
||||
{
|
||||
"name": "Chart.js",
|
||||
"description": "Simple yet flexible JavaScript charting library",
|
||||
"url": "https://www.chartjs.org/",
|
||||
"license": "MIT",
|
||||
"category": "Frontend"
|
||||
}
|
||||
]}
|
||||
697
src/main/resources/static/css/acknowledgments.css
Normal file
697
src/main/resources/static/css/acknowledgments.css
Normal file
@@ -0,0 +1,697 @@
|
||||
/* Acknowledgments Section Styles */
|
||||
:root {
|
||||
--trail-color: #ffffff;
|
||||
}
|
||||
|
||||
.acknowledgments-section {
|
||||
margin-top: 2rem;
|
||||
background: linear-gradient(135deg, var(--color-background-dark) 0%, var(--color-background-dark-light) 100%);
|
||||
border-radius: 8px;
|
||||
padding: 2rem;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--color-highlight);
|
||||
}
|
||||
|
||||
.acknowledgments-section::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background:
|
||||
radial-gradient(circle at 20% 20%, rgba(245, 222, 179, 0.1) 0%, transparent 50%),
|
||||
radial-gradient(circle at 80% 80%, rgba(245, 222, 179, 0.05) 0%, transparent 50%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.acknowledgments-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
font-size: 2rem;
|
||||
font-weight: 700;
|
||||
color: var(--color-highlight);
|
||||
margin-bottom: 0.5rem;
|
||||
font-family: var(--serif-font), serif;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.acknowledgments-title i {
|
||||
color: var(--color-highlight);
|
||||
font-size: 1.5rem;
|
||||
animation: gentle-pulse 3s ease-in-out infinite;
|
||||
filter: drop-shadow(0 2px 4px rgba(245, 222, 179, 0.3));
|
||||
}
|
||||
|
||||
.acknowledgments-subtitle {
|
||||
color: var(--color-text-white);
|
||||
margin-bottom: 2rem;
|
||||
line-height: 1.6;
|
||||
font-size: 1.1rem;
|
||||
opacity: 0.9;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 2rem;
|
||||
color: var(--color-highlight);
|
||||
font-family: var(--serif-font), serif;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.section-title i {
|
||||
color: var(--color-highlight);
|
||||
font-size: 1.25rem;
|
||||
filter: drop-shadow(0 2px 4px rgba(245, 222, 179, 0.3));
|
||||
animation: gentle-glow 4s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* Contributors Section */
|
||||
.contributors-section {
|
||||
margin-bottom: 4rem;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.contributors-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.contributor-card {
|
||||
background: linear-gradient(145deg, var(--color-background-dark-light), var(--color-background-dark));
|
||||
border: 2px solid rgba(245, 222, 179, 0.2);
|
||||
border-radius: 15px;
|
||||
padding: 1.5rem;
|
||||
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.contributor-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 6px;
|
||||
background: linear-gradient(90deg, var(--color-highlight), rgba(245, 222, 179, 0.8), var(--color-highlight));
|
||||
background-size: 300% 100%;
|
||||
animation: shimmer 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.contributor-card::after {
|
||||
content: '✨';
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
font-size: 1.5rem;
|
||||
opacity: 0;
|
||||
transition: all 0.3s ease;
|
||||
color: var(--color-highlight);
|
||||
}
|
||||
|
||||
.contributor-card:hover {
|
||||
transform: translateY(-8px) scale(1.02);
|
||||
box-shadow:
|
||||
0 20px 40px rgba(0, 0, 0, 0.3),
|
||||
0 0 30px rgba(245, 222, 179, 0.2);
|
||||
border-color: var(--color-highlight);
|
||||
}
|
||||
|
||||
.contributor-card:hover::after {
|
||||
opacity: 1;
|
||||
transform: scale(1.2);
|
||||
}
|
||||
|
||||
.contributor-avatar {
|
||||
position: relative;
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
margin: 0 auto 1rem;
|
||||
}
|
||||
|
||||
.contributor-avatar img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
border: 4px solid var(--color-highlight);
|
||||
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.3);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.contributor-card:hover .contributor-avatar img {
|
||||
transform: scale(1.1);
|
||||
box-shadow: 0 12px 30px rgba(245, 222, 179, 0.4);
|
||||
}
|
||||
|
||||
.contributor-badge {
|
||||
position: absolute;
|
||||
bottom: -3px;
|
||||
right: -3px;
|
||||
background: linear-gradient(135deg, var(--color-highlight), #ffd700);
|
||||
color: var(--color-background-dark);
|
||||
border-radius: 50%;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 0.8rem;
|
||||
font-weight: bold;
|
||||
border: 2px solid var(--color-background-dark-light);
|
||||
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.contributor-info {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.contributor-name {
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 1rem;
|
||||
color: var(--color-highlight);
|
||||
font-family: var(--serif-font), serif;
|
||||
}
|
||||
|
||||
.contributor-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
color: var(--color-text-white);
|
||||
text-decoration: none;
|
||||
font-size: 0.8rem;
|
||||
transition: all 0.3s ease;
|
||||
padding: 0.4rem 0.8rem;
|
||||
border-radius: 12px;
|
||||
background: rgba(245, 222, 179, 0.1);
|
||||
border: 1px solid rgba(245, 222, 179, 0.2);
|
||||
}
|
||||
|
||||
.contributor-link:hover {
|
||||
color: var(--color-highlight);
|
||||
background: rgba(245, 222, 179, 0.2);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 3px 8px rgba(245, 222, 179, 0.2);
|
||||
}
|
||||
|
||||
/* Translators Section */
|
||||
.translators-section {
|
||||
margin-bottom: 4rem;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.translators-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.translator-card {
|
||||
background: linear-gradient(145deg, var(--color-background-dark-light), var(--color-background-dark));
|
||||
border: 2px solid rgba(245, 222, 179, 0.2);
|
||||
border-radius: 20px;
|
||||
padding: 2rem;
|
||||
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.translator-card::before {
|
||||
content: '🌍';
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
font-size: 1.5rem;
|
||||
opacity: 0.3;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.translator-card:hover {
|
||||
transform: translateY(-6px) scale(1.02);
|
||||
box-shadow:
|
||||
0 15px 35px rgba(0, 0, 0, 0.3),
|
||||
0 0 25px rgba(245, 222, 179, 0.15);
|
||||
border-color: var(--color-highlight);
|
||||
}
|
||||
|
||||
.translator-card:hover::before {
|
||||
opacity: 1;
|
||||
transform: scale(1.2);
|
||||
}
|
||||
|
||||
.translator-avatar {
|
||||
position: relative;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
margin: 0 auto 1.5rem;
|
||||
}
|
||||
|
||||
.translator-avatar img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.translator-card:hover .translator-avatar img {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.completion-badge {
|
||||
position: absolute;
|
||||
bottom: -6px;
|
||||
right: -6px;
|
||||
background: linear-gradient(135deg, #10b981, #059669);
|
||||
color: white;
|
||||
border-radius: 15px;
|
||||
padding: 0.4rem 0.8rem;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 700;
|
||||
border: 3px solid var(--color-background-dark-light);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||
min-width: 45px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.completion-badge.incomplete {
|
||||
background: linear-gradient(135deg, #f59e0b, #d97706);
|
||||
}
|
||||
|
||||
.translator-info {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.translator-name {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 1rem;
|
||||
color: var(--color-highlight);
|
||||
font-family: var(--serif-font), serif;
|
||||
}
|
||||
|
||||
.translator-languages {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.75rem;
|
||||
justify-content: center;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.language-tag {
|
||||
background: linear-gradient(135deg, rgba(245, 222, 179, 0.2), rgba(245, 222, 179, 0.1));
|
||||
color: var(--color-highlight);
|
||||
padding: 0.4rem 0.8rem;
|
||||
border-radius: 20px;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
border: 1px solid rgba(245, 222, 179, 0.3);
|
||||
transition: all 0.3s ease;
|
||||
backdrop-filter: blur(5px);
|
||||
}
|
||||
|
||||
.language-tag:hover {
|
||||
background: var(--color-highlight);
|
||||
color: var(--color-background-dark);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(245, 222, 179, 0.3);
|
||||
}
|
||||
|
||||
.completion-bar {
|
||||
background: rgba(245, 222, 179, 0.2);
|
||||
height: 8px;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 1.5rem;
|
||||
overflow: hidden;
|
||||
border: 1px solid rgba(245, 222, 179, 0.3);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.completion-bar::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent);
|
||||
animation: shimmer 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.completion-fill {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, var(--color-highlight), rgba(245, 222, 179, 0.8), var(--color-highlight));
|
||||
border-radius: 10px;
|
||||
transition: width 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.completion-fill::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent);
|
||||
animation: progress-shine 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.translator-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
color: var(--color-text-white);
|
||||
text-decoration: none;
|
||||
font-size: 0.9rem;
|
||||
transition: all 0.3s ease;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 15px;
|
||||
background: rgba(245, 222, 179, 0.1);
|
||||
border: 1px solid rgba(245, 222, 179, 0.2);
|
||||
}
|
||||
|
||||
.translator-link:hover {
|
||||
color: var(--color-highlight);
|
||||
background: rgba(245, 222, 179, 0.2);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(245, 222, 179, 0.2);
|
||||
}
|
||||
|
||||
/* Projects Section */
|
||||
.projects-section {
|
||||
margin-bottom: 4rem;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.projects-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.project-card {
|
||||
background: linear-gradient(145deg, var(--color-background-dark-light), var(--color-background-dark));
|
||||
border: 2px solid rgba(245, 222, 179, 0.2);
|
||||
border-radius: 20px;
|
||||
overflow: hidden;
|
||||
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||
position: relative;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.project-card::before {
|
||||
content: '⚡';
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
font-size: 1.5rem;
|
||||
opacity: 0.3;
|
||||
transition: all 0.3s ease;
|
||||
z-index: 2;
|
||||
color: var(--color-highlight);
|
||||
}
|
||||
|
||||
.project-card:hover {
|
||||
transform: translateY(-6px) scale(1.02);
|
||||
box-shadow:
|
||||
0 15px 35px rgba(0, 0, 0, 0.3),
|
||||
0 0 25px rgba(245, 222, 179, 0.15);
|
||||
border-color: var(--color-highlight);
|
||||
}
|
||||
|
||||
.project-card:hover::before {
|
||||
opacity: 1;
|
||||
transform: scale(1.2);
|
||||
}
|
||||
|
||||
.project-header {
|
||||
background: linear-gradient(135deg, rgba(245, 222, 179, 0.15), rgba(245, 222, 179, 0.05));
|
||||
padding: 1.5rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 2px solid rgba(245, 222, 179, 0.2);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.project-category {
|
||||
background: linear-gradient(135deg, var(--color-highlight), #ffd700);
|
||||
color: var(--color-background-dark);
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 25px;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
box-shadow: 0 4px 12px rgba(245, 222, 179, 0.3);
|
||||
}
|
||||
|
||||
.project-license {
|
||||
color: var(--color-text-white);
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
opacity: 0.8;
|
||||
background: rgba(245, 222, 179, 0.1);
|
||||
padding: 0.3rem 0.8rem;
|
||||
border-radius: 15px;
|
||||
border: 1px solid rgba(245, 222, 179, 0.2);
|
||||
}
|
||||
|
||||
.project-content {
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.project-name {
|
||||
font-size: 1.3rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 1rem;
|
||||
color: var(--color-highlight);
|
||||
font-family: var(--serif-font), serif;
|
||||
}
|
||||
|
||||
.project-description {
|
||||
color: var(--color-text-white);
|
||||
line-height: 1.6;
|
||||
margin-bottom: 1.5rem;
|
||||
font-size: 0.95rem;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.project-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
color: var(--color-text-white);
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
font-size: 0.9rem;
|
||||
transition: all 0.3s ease;
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: 15px;
|
||||
background: linear-gradient(135deg, rgba(245, 222, 179, 0.2), rgba(245, 222, 179, 0.1));
|
||||
border: 1px solid rgba(245, 222, 179, 0.3);
|
||||
backdrop-filter: blur(5px);
|
||||
}
|
||||
|
||||
.project-link:hover {
|
||||
color: var(--color-background-dark);
|
||||
background: var(--color-highlight);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 18px rgba(245, 222, 179, 0.3);
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
/* Thank You Message */
|
||||
.thank-you-message {
|
||||
background: linear-gradient(135deg,
|
||||
rgba(245, 222, 179, 0.3) 0%,
|
||||
rgba(245, 222, 179, 0.1) 50%,
|
||||
rgba(255, 107, 107, 0.1) 100%);
|
||||
border: 3px solid rgba(245, 222, 179, 0.4);
|
||||
border-radius: 25px;
|
||||
padding: 3rem;
|
||||
text-align: center;
|
||||
margin-top: 3rem;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
backdrop-filter: blur(15px);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.thank-you-message::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background:
|
||||
radial-gradient(circle at 30% 30%, rgba(255, 107, 107, 0.1) 0%, transparent 50%),
|
||||
radial-gradient(circle at 70% 70%, rgba(245, 222, 179, 0.1) 0%, transparent 50%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.thank-you-content {
|
||||
max-width: 700px;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.thank-you-icon {
|
||||
font-size: 4rem;
|
||||
color: var(--color-highlight);
|
||||
margin-bottom: 1.5rem;
|
||||
animation: gentle-pulse 3s ease-in-out infinite;
|
||||
filter: drop-shadow(0 4px 8px rgba(245, 222, 179, 0.3));
|
||||
}
|
||||
|
||||
@keyframes gentle-pulse {
|
||||
0% { transform: scale(1); opacity: 0.8; }
|
||||
50% { transform: scale(1.05); opacity: 1; }
|
||||
100% { transform: scale(1); opacity: 0.8; }
|
||||
}
|
||||
|
||||
@keyframes gentle-glow {
|
||||
0% { filter: drop-shadow(0 2px 4px rgba(245, 222, 179, 0.3)); }
|
||||
50% { filter: drop-shadow(0 2px 8px rgba(245, 222, 179, 0.5)); }
|
||||
100% { filter: drop-shadow(0 2px 4px rgba(245, 222, 179, 0.3)); }
|
||||
}
|
||||
|
||||
@keyframes shimmer {
|
||||
0% { background-position: -300% 0; }
|
||||
100% { background-position: 300% 0; }
|
||||
}
|
||||
|
||||
@keyframes progress-shine {
|
||||
0% { transform: translateX(-100%); }
|
||||
100% { transform: translateX(100%); }
|
||||
}
|
||||
|
||||
.thank-you-message h4 {
|
||||
font-size: 2rem;
|
||||
font-weight: 700;
|
||||
color: var(--color-highlight);
|
||||
margin-bottom: 1.5rem;
|
||||
font-family: var(--serif-font), serif;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.thank-you-message p {
|
||||
color: var(--color-text-white);
|
||||
line-height: 1.8;
|
||||
font-size: 1.1rem;
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
/* Fireworks Container */
|
||||
.fireworks-container {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
/* Responsive Design */
|
||||
@media (max-width: 768px) {
|
||||
.contributors-grid,
|
||||
.translators-grid,
|
||||
.projects-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.acknowledgments-section {
|
||||
padding: 1.5rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.acknowledgments-title {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.project-header {
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.contributor-card,
|
||||
.translator-card,
|
||||
.project-card {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.thank-you-message {
|
||||
padding: 2rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.thank-you-icon {
|
||||
font-size: 3rem;
|
||||
}
|
||||
|
||||
.thank-you-message h4 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.thank-you-message p {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.acknowledgments-section {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.contributor-card,
|
||||
.translator-card,
|
||||
.project-card {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.contributors-grid {
|
||||
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.contributor-avatar,
|
||||
.translator-avatar {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.acknowledgments-title {
|
||||
font-size: 1.25rem;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
8
src/main/resources/static/js/fireworks.min.js
vendored
Normal file
8
src/main/resources/static/js/fireworks.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -9,8 +9,10 @@
|
||||
<link rel="shortcut icon" type="image/x-icon" th:href="@{/img/logo.svg}">
|
||||
<link rel="stylesheet" href="/css/main.css">
|
||||
<link rel="stylesheet" href="/css/lineicons.css">
|
||||
<link rel="stylesheet" href="/css/acknowledgments.css">
|
||||
<script src="/js/htmx.min.js"></script>
|
||||
<script src="/js/util.js"></script>
|
||||
<script src="/js/fireworks.min.js"></script>
|
||||
</head>
|
||||
<body class="settings-page">
|
||||
<div class="settings-container">
|
||||
@@ -32,10 +34,104 @@
|
||||
<span th:text="${buildTime}">N/A</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Acknowledgments Section -->
|
||||
<div class="acknowledgments-section">
|
||||
<h3 class="acknowledgments-title">
|
||||
<i class="lni lni-heart"></i>
|
||||
<span th:text="#{about.acknowledgments.title}">Acknowledgments</span>
|
||||
</h3>
|
||||
<p class="acknowledgments-subtitle" th:text="#{about.acknowledgments.subtitle}">
|
||||
Reitti wouldn't be possible without the amazing contributions from our community and the incredible open-source projects we build upon.
|
||||
</p>
|
||||
|
||||
<!-- Contributors Section -->
|
||||
<div class="contributors-section" th:if="${!contributors.isEmpty()}">
|
||||
<h4 class="section-title">
|
||||
<i class="lni lni-user-4"></i>
|
||||
<span th:text="#{about.contributors.title}">Contributors</span>
|
||||
</h4>
|
||||
<div class="contributors-grid">
|
||||
<div class="contributor-card" th:each="contributor : ${contributors}">
|
||||
<div class="contributor-avatar">
|
||||
<img th:src="${contributor.avatar}" th:alt="${contributor.name}" />
|
||||
<div class="contributor-badge">
|
||||
<i class="lni lni-github"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="contributor-info">
|
||||
<h5 class="contributor-name" th:text="${contributor.name}">Name</h5>
|
||||
<a th:href="'https://github.com/' + ${contributor.github}" class="contributor-link" target="_blank">
|
||||
<i class="lni lni-github"></i>
|
||||
<span th:text="${contributor.github}">GitHub</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Open Source Projects Section -->
|
||||
<div class="projects-section" th:if="${!projects.isEmpty()}">
|
||||
<h4 class="section-title">
|
||||
<i class="lni lni-code-1"></i>
|
||||
<span th:text="#{about.projects.title}">Open Source Projects</span>
|
||||
</h4>
|
||||
<div class="projects-grid">
|
||||
<div class="project-card" th:each="project : ${projects}">
|
||||
<div class="project-header">
|
||||
<div class="project-category" th:text="${project.category}">Category</div>
|
||||
<div class="project-license" th:text="${project.license}">License</div>
|
||||
</div>
|
||||
<div class="project-content">
|
||||
<h5 class="project-name" th:text="${project.name}">Project Name</h5>
|
||||
<p class="project-description" th:text="${project.description}">Description</p>
|
||||
<a th:href="${project.url}" class="project-link" target="_blank">
|
||||
<i class="lni lni-eye"></i>
|
||||
<span th:text="#{about.projects.visit}">Visit Project</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Thank You Message -->
|
||||
<div class="thank-you-message" onclick="startFireworks()">
|
||||
<div class="thank-you-content">
|
||||
<i class="lni lni-heart thank-you-icon"></i>
|
||||
<h4 th:text="#{about.thankyou.title}">Thank You!</h4>
|
||||
<p th:text="#{about.thankyou.message}">
|
||||
Every contribution, no matter how small, helps make Reitti better for everyone.
|
||||
We're grateful for your support and dedication to the open-source community.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Fireworks Container -->
|
||||
<div id="fireworks-container" class="fireworks-container"></div>
|
||||
|
||||
<script th:inline="javascript">
|
||||
window.userSettings = /*[[${userSettings}]]*/ {}
|
||||
|
||||
const container = document.getElementById('fireworks-container');
|
||||
let fireworks = new Fireworks.default(container, {
|
||||
particles: 100,
|
||||
explosion: 15,
|
||||
});
|
||||
let running = false;
|
||||
function startFireworks() {
|
||||
if (running) {
|
||||
fireworks.stop();
|
||||
running = false;
|
||||
} else {
|
||||
fireworks.start();
|
||||
running = true;
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user