add favicon
Gitea Actions Demo / build_and_push (push) Successful in 1m14s
Details
Gitea Actions Demo / build_and_push (push) Successful in 1m14s
Details
This commit is contained in:
parent
6f223e61d2
commit
72e1d4223d
|
|
@ -16,7 +16,9 @@
|
||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,300..600,0,0"
|
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,300..600,0,0"
|
||||||
/>
|
/>
|
||||||
|
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
||||||
<link rel="icon" href="/favicon.ico" />
|
<link rel="icon" href="/favicon.ico" />
|
||||||
|
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
||||||
|
|
||||||
<title>Cycle Rider Ala Strava for Russian/Belorussian</title>
|
<title>Cycle Rider Ala Strava for Russian/Belorussian</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||||
|
<!-- Background -->
|
||||||
|
<circle cx="32" cy="32" r="30" fill="#228BE6"/>
|
||||||
|
|
||||||
|
<!-- Rear wheel -->
|
||||||
|
<circle cx="16" cy="40" r="11" fill="none" stroke="white" stroke-width="3"/>
|
||||||
|
<!-- Front wheel -->
|
||||||
|
<circle cx="48" cy="40" r="11" fill="none" stroke="white" stroke-width="3"/>
|
||||||
|
|
||||||
|
<!-- Frame: chain stay (BB to rear hub) -->
|
||||||
|
<line x1="32" y1="40" x2="16" y2="40" stroke="white" stroke-width="2.5"/>
|
||||||
|
<!-- Frame: seat tube (BB to seat) -->
|
||||||
|
<line x1="32" y1="40" x2="26" y2="24" stroke="white" stroke-width="2.5"/>
|
||||||
|
<!-- Frame: top tube (seat to head tube) -->
|
||||||
|
<line x1="26" y1="24" x2="44" y2="24" stroke="white" stroke-width="2.5"/>
|
||||||
|
<!-- Frame: down tube (BB to head tube) -->
|
||||||
|
<line x1="32" y1="40" x2="44" y2="24" stroke="white" stroke-width="2.5"/>
|
||||||
|
<!-- Frame: seat stay (seat to rear hub) -->
|
||||||
|
<line x1="26" y1="24" x2="16" y2="40" stroke="white" stroke-width="2.5"/>
|
||||||
|
<!-- Frame: fork (head tube to front hub) -->
|
||||||
|
<line x1="44" y1="24" x2="48" y2="40" stroke="white" stroke-width="2.5"/>
|
||||||
|
|
||||||
|
<!-- Handlebar (drop bar shape) -->
|
||||||
|
<path d="M44 24 C47 22 49 24 47 27" fill="none" stroke="white" stroke-width="2.5" stroke-linecap="round"/>
|
||||||
|
|
||||||
|
<!-- Seat -->
|
||||||
|
<line x1="23" y1="23" x2="28" y2="23" stroke="white" stroke-width="3" stroke-linecap="round"/>
|
||||||
|
|
||||||
|
<!-- Crank + pedal -->
|
||||||
|
<line x1="32" y1="40" x2="34" y2="47" stroke="white" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<line x1="31" y1="48" x2="36" y2="48" stroke="white" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
|
||||||
|
<!-- Rider: rear leg (hip -> knee -> pedal) -->
|
||||||
|
<path d="M27 23 L31 33 L34 47" fill="none" stroke="white" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
|
||||||
|
<!-- Rider: torso (hips curving forward to shoulders) -->
|
||||||
|
<path d="M27 22 Q34 19 39 19" fill="none" stroke="white" stroke-width="4.5" stroke-linecap="round"/>
|
||||||
|
|
||||||
|
<!-- Rider: arm (shoulder to handlebar) -->
|
||||||
|
<path d="M39 19 L45 24" fill="none" stroke="white" stroke-width="3" stroke-linecap="round"/>
|
||||||
|
|
||||||
|
<!-- Rider: head (helmet - slightly elongated) -->
|
||||||
|
<ellipse cx="43" cy="15" rx="4" ry="3.5" fill="white"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.1 KiB |
|
|
@ -2,6 +2,11 @@
|
||||||
"name": "",
|
"name": "",
|
||||||
"short_name": "",
|
"short_name": "",
|
||||||
"icons": [
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "/favicon.svg",
|
||||||
|
"sizes": "any",
|
||||||
|
"type": "image/svg+xml"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"src": "/android-chrome-192x192.png",
|
"src": "/android-chrome-192x192.png",
|
||||||
"sizes": "192x192",
|
"sizes": "192x192",
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ export function renderTemplate(options: TemplateOptions): string {
|
||||||
<meta property="og:type" content="website" />
|
<meta property="og:type" content="website" />
|
||||||
<meta property="og:url" content="${meta.canonicalUrl}" />
|
<meta property="og:url" content="${meta.canonicalUrl}" />
|
||||||
${meta.ogImage ? `<meta property="og:image" content="${meta.ogImage}" />` : ""}
|
${meta.ogImage ? `<meta property="og:image" content="${meta.ogImage}" />` : ""}
|
||||||
<link rel="icon" href="/favicon.ico" />
|
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet" />
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet" />
|
||||||
${assetTags}
|
${assetTags}
|
||||||
${jsonLdScript}
|
${jsonLdScript}
|
||||||
|
|
|
||||||
|
|
@ -10,16 +10,6 @@
|
||||||
:hideFileList="true"
|
:hideFileList="true"
|
||||||
dropzone
|
dropzone
|
||||||
/>
|
/>
|
||||||
<div class="photo-upload" v-if="!inProgress">
|
|
||||||
<h2 class="photo-upload__title">Фото тренировки (опционально)</h2>
|
|
||||||
<VaFileUpload
|
|
||||||
v-model="photoFiles"
|
|
||||||
file-types="png,jpg,jpeg,webp,heic"
|
|
||||||
type="list"
|
|
||||||
color="#F4F6F8"
|
|
||||||
dropzone
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<VaInnerLoading loading :size="60"> </VaInnerLoading>
|
<VaInnerLoading loading :size="60"> </VaInnerLoading>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -37,7 +27,6 @@ const { init } = useToast();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const inProgress = ref(false);
|
const inProgress = ref(false);
|
||||||
let file: File | undefined = undefined;
|
let file: File | undefined = undefined;
|
||||||
const photoFiles = ref<File[]>([]);
|
|
||||||
|
|
||||||
type ErrorItem = {
|
type ErrorItem = {
|
||||||
code_string: string;
|
code_string: string;
|
||||||
|
|
@ -47,31 +36,6 @@ type Error = {
|
||||||
detail: ErrorItem;
|
detail: ErrorItem;
|
||||||
};
|
};
|
||||||
|
|
||||||
async function uploadPhotos(workoutId: string): Promise<boolean> {
|
|
||||||
const total = photoFiles.value.length;
|
|
||||||
if (total === 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
const results = await Promise.allSettled(
|
|
||||||
photoFiles.value.map((photo) => {
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append("file", photo);
|
|
||||||
return axiosAuth.post(`/api/v0/workouts/${workoutId}/photos`, formData);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
const failed = results.filter(
|
|
||||||
(r): r is PromiseRejectedResult => r.status === "rejected",
|
|
||||||
).length;
|
|
||||||
if (failed > 0) {
|
|
||||||
init({
|
|
||||||
message: `Часть фото не загружена (${failed} из ${total})`,
|
|
||||||
color: "error",
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function onFileChanged() {
|
function onFileChanged() {
|
||||||
if (file == undefined) {
|
if (file == undefined) {
|
||||||
init({
|
init({
|
||||||
|
|
@ -91,25 +55,13 @@ function onFileChanged() {
|
||||||
attachment_id: response.data.id,
|
attachment_id: response.data.id,
|
||||||
name: "Новая тренировка",
|
name: "Новая тренировка",
|
||||||
})
|
})
|
||||||
.then(async (response: AxiosResponse) => {
|
.then((response: AxiosResponse) => {
|
||||||
const workoutId = response.data.id;
|
const workoutId = response.data.id;
|
||||||
const hasPhotos = photoFiles.value.length > 0;
|
init({
|
||||||
if (hasPhotos) {
|
message: "Тренировка успешно загружена!",
|
||||||
const ok = await uploadPhotos(workoutId);
|
color: "success",
|
||||||
if (ok) {
|
});
|
||||||
init({
|
|
||||||
message: "Тренировка успешно загружена!",
|
|
||||||
color: "success",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
init({
|
|
||||||
message: "Тренировка успешно загружена!",
|
|
||||||
color: "success",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
inProgress.value = false;
|
inProgress.value = false;
|
||||||
photoFiles.value = [];
|
|
||||||
router.push({
|
router.push({
|
||||||
name: "workout_item",
|
name: "workout_item",
|
||||||
params: { id: workoutId },
|
params: { id: workoutId },
|
||||||
|
|
@ -117,7 +69,6 @@ function onFileChanged() {
|
||||||
})
|
})
|
||||||
.catch((error: AxiosError) => {
|
.catch((error: AxiosError) => {
|
||||||
inProgress.value = false;
|
inProgress.value = false;
|
||||||
photoFiles.value = [];
|
|
||||||
if (error.status == 400) {
|
if (error.status == 400) {
|
||||||
let err = <Error>error.response?.data;
|
let err = <Error>error.response?.data;
|
||||||
if (err.detail.code_string == "ObjectExists") {
|
if (err.detail.code_string == "ObjectExists") {
|
||||||
|
|
@ -136,7 +87,6 @@ function onFileChanged() {
|
||||||
})
|
})
|
||||||
.catch(function () {
|
.catch(function () {
|
||||||
inProgress.value = false;
|
inProgress.value = false;
|
||||||
photoFiles.value = [];
|
|
||||||
init({
|
init({
|
||||||
message: "Что-то пошло не так.",
|
message: "Что-то пошло не так.",
|
||||||
color: "error",
|
color: "error",
|
||||||
|
|
@ -144,12 +94,3 @@ function onFileChanged() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
|
||||||
.photo-upload {
|
|
||||||
margin-top: 16px;
|
|
||||||
}
|
|
||||||
.photo-upload__title {
|
|
||||||
font-size: 18px;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue