Fixed background, font size and output bot.js
This commit is contained in:
parent
8b964fc8ff
commit
c4b5ba6116
@ -86,7 +86,7 @@ app.post(
|
|||||||
// 8. Итоги
|
// 8. Итоги
|
||||||
let text = `🧼 <b>Расчёт мыла:</b> <i>${soapName}</i>\n\n`;
|
let text = `🧼 <b>Расчёт мыла:</b> <i>${soapName}</i>\n\n`;
|
||||||
|
|
||||||
text += `🔹 <b>Вес мыла:</b> ${weight} г\n`;
|
text += `🔹 <b>Вес мыла:</b> ${weight} г\n\n`;
|
||||||
// text += `🔹 <b>Цена за 1 кг основы:</b> ${basePrice} ₽/кг\n\n`;
|
// text += `🔹 <b>Цена за 1 кг основы:</b> ${basePrice} ₽/кг\n\n`;
|
||||||
|
|
||||||
// text += `🔹 <b>Отдушка:</b> ${aromaWeight} г по ${aromaPrice} ₽/фасовка\n`;
|
// text += `🔹 <b>Отдушка:</b> ${aromaWeight} г по ${aromaPrice} ₽/фасовка\n`;
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
@import url('https://fonts.googleapis.com/css2?family=Sofia+Sans+Condensed:ital,wght@0,100..900;1,100..900&display=swap');
|
@import url('https://fonts.googleapis.com/css2?family=Sofia+Sans+Condensed:wght@300;400;500;700&display=swap');
|
||||||
|
|
||||||
@import "tailwindcss";
|
@import "tailwindcss";
|
||||||
|
|
||||||
@ -7,12 +7,32 @@
|
|||||||
--foreground: #171717;
|
--foreground: #171717;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
html, body {
|
||||||
background: var(--background);
|
/* Убираем «джамп» при скрытии скроллбара — оставляем технически скролл, но скрываем его */
|
||||||
color: var(--foreground);
|
overflow-y: scroll;
|
||||||
font-family: "Sofia Sans Condensed", sans-serif;
|
font-family: "Sofia Sans Condensed", sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* WebKit (Chrome, Safari, Opera) */
|
||||||
|
html::-webkit-scrollbar,
|
||||||
|
body::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Firefox */
|
||||||
|
html {
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* IE/Edge */
|
||||||
|
html {
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/* Скрываем стрелочки у input[type=number] */
|
/* Скрываем стрелочки у input[type=number] */
|
||||||
input[type='number']::-webkit-outer-spin-button,
|
input[type='number']::-webkit-outer-spin-button,
|
||||||
input[type='number']::-webkit-inner-spin-button {
|
input[type='number']::-webkit-inner-spin-button {
|
||||||
|
|||||||
@ -25,7 +25,7 @@ export default function RootLayout({
|
|||||||
return (
|
return (
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<body
|
<body
|
||||||
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
className={`${geistSans.variable} ${geistMono.variable} antialiased bg-gray-800`}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@ -2,8 +2,8 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useState, useEffect, ChangeEvent, FormEvent } from 'react';
|
import { useState, useEffect, ChangeEvent, FormEvent } from 'react';
|
||||||
import { calculateTotal } from '@/lib/calc';
|
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
|
import { calculateTotal } from '@/lib/calc';
|
||||||
|
|
||||||
type InputNumberProps = {
|
type InputNumberProps = {
|
||||||
label: string;
|
label: string;
|
||||||
@ -12,7 +12,6 @@ type InputNumberProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const InputNumber = ({ label, value, onChange }: InputNumberProps) => {
|
const InputNumber = ({ label, value, onChange }: InputNumberProps) => {
|
||||||
// Генерируем id на основе текста лейбла (без пробелов)
|
|
||||||
const id = label.toLowerCase().replace(/\s+/g, '-');
|
const id = label.toLowerCase().replace(/\s+/g, '-');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -41,14 +40,18 @@ const InputNumber = ({ label, value, onChange }: InputNumberProps) => {
|
|||||||
className={`
|
className={`
|
||||||
absolute left-3
|
absolute left-3
|
||||||
-top-5
|
-top-5
|
||||||
text-gray-400 text-sm
|
text-gray-400
|
||||||
transition-all
|
transition-all
|
||||||
|
/* активное состояние: адаптивный размер шрифта */
|
||||||
|
text-xs sm:text-sm md:text-base lg:text-lg
|
||||||
|
/* когда поле пустое: слегка больше (помещается внутри) */
|
||||||
peer-placeholder-shown:top-2
|
peer-placeholder-shown:top-2
|
||||||
peer-placeholder-shown:text-base
|
|
||||||
peer-placeholder-shown:text-gray-500
|
peer-placeholder-shown:text-gray-500
|
||||||
|
peer-placeholder-shown:text-sm sm:peer-placeholder-shown:text-base md:peer-placeholder-shown:text-lg
|
||||||
|
/* при фокусе или если есть содержимое: сжатый текст */
|
||||||
peer-focus:-top-5
|
peer-focus:-top-5
|
||||||
peer-focus:text-gray-200
|
peer-focus:text-gray-200
|
||||||
peer-focus:text-sm
|
peer-focus:text-xs sm:peer-focus:text-sm md:peer-focus:text-base lg:peer-focus:text-lg
|
||||||
`}
|
`}
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
@ -75,7 +78,6 @@ export default function SoapCalculator() {
|
|||||||
const [photoFile, setPhotoFile] = useState<File | null>(null);
|
const [photoFile, setPhotoFile] = useState<File | null>(null);
|
||||||
const [chatId, setChatId] = useState<string | null>(null);
|
const [chatId, setChatId] = useState<string | null>(null);
|
||||||
|
|
||||||
// При монтировании достаём chat_id из URL
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const params = new URLSearchParams(window.location.search);
|
const params = new URLSearchParams(window.location.search);
|
||||||
const id = params.get('chat_id');
|
const id = params.get('chat_id');
|
||||||
@ -84,7 +86,6 @@ export default function SoapCalculator() {
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Конвертация строковых значений в числа
|
|
||||||
const toNum = (str: string) => {
|
const toNum = (str: string) => {
|
||||||
const n = parseFloat(str.replace(',', '.'));
|
const n = parseFloat(str.replace(',', '.'));
|
||||||
return isNaN(n) ? 0 : n;
|
return isNaN(n) ? 0 : n;
|
||||||
@ -102,7 +103,6 @@ export default function SoapCalculator() {
|
|||||||
const labelNum = toNum(labelValue);
|
const labelNum = toNum(labelValue);
|
||||||
const markupNum = toNum(markup);
|
const markupNum = toNum(markup);
|
||||||
|
|
||||||
// Считаем все базовые значения через calculateTotal
|
|
||||||
const result = calculateTotal({
|
const result = calculateTotal({
|
||||||
weight: weightNum,
|
weight: weightNum,
|
||||||
basePrice: basePriceNum,
|
basePrice: basePriceNum,
|
||||||
@ -202,22 +202,23 @@ export default function SoapCalculator() {
|
|||||||
rounded-lg shadow-lg
|
rounded-lg shadow-lg
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
|
{/* Центрированный адаптивный логотип */}
|
||||||
|
<div className="flex justify-center">
|
||||||
|
<Image
|
||||||
|
src="/logo.svg"
|
||||||
|
alt="Logo"
|
||||||
|
width={150}
|
||||||
|
height={50}
|
||||||
|
className="mx-auto w-32 md:w-48 lg:w-56 h-auto"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
{chatId === null && (
|
{chatId === null && (
|
||||||
<div className="bg-yellow-800 p-2 text-yellow-200 font-semibold rounded">
|
<div className="bg-yellow-800 p-2 text-yellow-200 font-semibold rounded">
|
||||||
❗ Не найден chat_id. Откройте калькулятор через Telegram-бота.
|
❗ Не найден chat_id. Откройте калькулятор через Telegram-бота.
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="flex justify-center">
|
|
||||||
<Image
|
|
||||||
src="/logo.svg"
|
|
||||||
alt="Logo"
|
|
||||||
width={250}
|
|
||||||
height={100}
|
|
||||||
className="mx-auto w-64 md:w-96 lg:w-112 h-auto"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Название мыла */}
|
{/* Название мыла */}
|
||||||
<div className="relative mt-6">
|
<div className="relative mt-6">
|
||||||
<input
|
<input
|
||||||
@ -244,14 +245,18 @@ export default function SoapCalculator() {
|
|||||||
className={`
|
className={`
|
||||||
absolute left-3
|
absolute left-3
|
||||||
-top-5
|
-top-5
|
||||||
text-gray-400 text-sm
|
text-gray-400
|
||||||
transition-all
|
transition-all
|
||||||
|
/* активное состояние: адаптивный размер шрифта */
|
||||||
|
text-xs sm:text-sm md:text-base lg:text-lg
|
||||||
|
/* когда поле пустое: немного крупнее, помещается внутри */
|
||||||
peer-placeholder-shown:top-2
|
peer-placeholder-shown:top-2
|
||||||
peer-placeholder-shown:text-base
|
|
||||||
peer-placeholder-shown:text-gray-500
|
peer-placeholder-shown:text-gray-500
|
||||||
|
peer-placeholder-shown:text-sm sm:peer-placeholder-shown:text-base md:peer-placeholder-shown:text-lg
|
||||||
|
/* при фокусе/заполненном поле: адаптивный размер */
|
||||||
peer-focus:-top-5
|
peer-focus:-top-5
|
||||||
peer-focus:text-gray-200
|
peer-focus:text-gray-200
|
||||||
peer-focus:text-sm
|
peer-focus:text-xs sm:peer-focus:text-sm md:peer-focus:text-base lg:peer-focus:text-lg
|
||||||
`}
|
`}
|
||||||
>
|
>
|
||||||
Название мыла
|
Название мыла
|
||||||
@ -348,7 +353,7 @@ export default function SoapCalculator() {
|
|||||||
<CostBlock title="Итого себестоимость" value={result.total} highlight />
|
<CostBlock title="Итого себестоимость" value={result.total} highlight />
|
||||||
|
|
||||||
{/* Блок «Наценка и цена 100 г» */}
|
{/* Блок «Наценка и цена 100 г» */}
|
||||||
<div className="grid grid-cols-1 gap-4">
|
<div className="grid grid-cols-2 gap-4">
|
||||||
<InputNumber label="Наценка, %" value={markup} onChange={setMarkup} />
|
<InputNumber label="Наценка, %" value={markup} onChange={setMarkup} />
|
||||||
</div>
|
</div>
|
||||||
<CostBlock title="Итоговая цена с наценкой" value={finalPrice} />
|
<CostBlock title="Итоговая цена с наценкой" value={finalPrice} />
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user