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"
|
||||
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="apple-touch-icon" href="/apple-touch-icon.png" />
|
||||
|
||||
<title>Cycle Rider Ala Strava for Russian/Belorussian</title>
|
||||
</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": "",
|
||||
"short_name": "",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/favicon.svg",
|
||||
"sizes": "any",
|
||||
"type": "image/svg+xml"
|
||||
},
|
||||
{
|
||||
"src": "/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ export function renderTemplate(options: TemplateOptions): string {
|
|||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="${meta.canonicalUrl}" />
|
||||
${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" />
|
||||
${assetTags}
|
||||
${jsonLdScript}
|
||||
|
|
|
|||
|
|
@ -10,16 +10,6 @@
|
|||
:hideFileList="true"
|
||||
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>
|
||||
<VaInnerLoading loading :size="60"> </VaInnerLoading>
|
||||
</div>
|
||||
|
|
@ -37,7 +27,6 @@ const { init } = useToast();
|
|||
const router = useRouter();
|
||||
const inProgress = ref(false);
|
||||
let file: File | undefined = undefined;
|
||||
const photoFiles = ref<File[]>([]);
|
||||
|
||||
type ErrorItem = {
|
||||
code_string: string;
|
||||
|
|
@ -47,31 +36,6 @@ type Error = {
|
|||
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() {
|
||||
if (file == undefined) {
|
||||
init({
|
||||
|
|
@ -91,25 +55,13 @@ function onFileChanged() {
|
|||
attachment_id: response.data.id,
|
||||
name: "Новая тренировка",
|
||||
})
|
||||
.then(async (response: AxiosResponse) => {
|
||||
.then((response: AxiosResponse) => {
|
||||
const workoutId = response.data.id;
|
||||
const hasPhotos = photoFiles.value.length > 0;
|
||||
if (hasPhotos) {
|
||||
const ok = await uploadPhotos(workoutId);
|
||||
if (ok) {
|
||||
init({
|
||||
message: "Тренировка успешно загружена!",
|
||||
color: "success",
|
||||
});
|
||||
}
|
||||
} else {
|
||||
init({
|
||||
message: "Тренировка успешно загружена!",
|
||||
color: "success",
|
||||
});
|
||||
}
|
||||
inProgress.value = false;
|
||||
photoFiles.value = [];
|
||||
router.push({
|
||||
name: "workout_item",
|
||||
params: { id: workoutId },
|
||||
|
|
@ -117,7 +69,6 @@ function onFileChanged() {
|
|||
})
|
||||
.catch((error: AxiosError) => {
|
||||
inProgress.value = false;
|
||||
photoFiles.value = [];
|
||||
if (error.status == 400) {
|
||||
let err = <Error>error.response?.data;
|
||||
if (err.detail.code_string == "ObjectExists") {
|
||||
|
|
@ -136,7 +87,6 @@ function onFileChanged() {
|
|||
})
|
||||
.catch(function () {
|
||||
inProgress.value = false;
|
||||
photoFiles.value = [];
|
||||
init({
|
||||
message: "Что-то пошло не так.",
|
||||
color: "error",
|
||||
|
|
@ -144,12 +94,3 @@ function onFileChanged() {
|
|||
});
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.photo-upload {
|
||||
margin-top: 16px;
|
||||
}
|
||||
.photo-upload__title {
|
||||
font-size: 18px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Reference in New Issue