Binary files /dev/null and b/public/images/dashboard.png differ @@ -0,0 +1,47 @@ +const observedRequests = [ + '/api/auth/providers', + '/api/auth/csrf', + '/api/auth/callback/credentials', + '/api/auth/session', +] + +const failedRequests = [] + +self.addEventListener('install', (event) => { + event.waitUntil(() => self.skipWaiting()()) +}) + +self.addEventListener('activate', (event) => { + event.waitUntil(self.clients.claim()) +}) + +function sendMessageToClients(data) { + clients.matchAll().then((clients) => { + clients.forEach((client) => { + client.postMessage(data) + }) + }) +} + +self.addEventListener('fetch', (event) => { + event.respondWith( + (async () => { + try { + const response = await fetch(event.request) + + if ( + response.status >= 400 && + observedRequests.some((url) => event.request.url.includes(url)) + ) { + sendMessageToClients({ + url: event.request.url, + reason: await response.text(), + status: response.status, + }) + } + + return response + } catch (error) {} + })() + ) +}) \ No newline at end of file @@ -131,11 +131,11 @@ export const UniqInput: FC = ({ }, }, fieldset: { - borderRadius: '15px', + borderRadius: '15px', border: theme === 'light' - ? '2px solidrgb(242, 242, 242)' - : '2px solid #303035', + ? '2px solid #E1E1E1' + : '2px solid rgb(66, 66, 72) !important', }, '& ::placeholder': { fontSize: '16px', @@ -0,0 +1,160 @@ +.tag { + display: flex; + align-items: center; + justify-content: center; + background-color: white; + border-radius: 100px; + // padding-right: 20px; + width: 40px; + height: 40px; + box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.1); + transition: width 0.3s ease-in-out; + + &__icon { + color: var(--air-color); + } + + &:hover { + width: 60%; + padding: 12px; + // height: unset; + + .tag__icon { + animation: fadein 0.6s ease-in-out; + } + + .tag__text { + opacity: 1; + position: static; + animation: fadein 0.6s ease-in-out; + display: block; + } + } + + &__text { + position: absolute; + color: var(--air-color); + font-weight: 500; + padding-left: 10px; + font-size: 14px; + opacity: 0; + display: none; + min-width: max-content !important; + } +} + +.card { + background-color: var(--new-ui-main-color); + border-radius: 15px; + position: relative; + min-height: 235px; + max-height: 235px; + user-select: none !important; + + cursor: pointer; + box-sizing: border-box; + overflow: hidden; + height: 100%; + + padding: 20px; + + @media (max-width: 420px) { + width: 92vw; + } + + &__tags { + position: absolute; + top: 20px; + right: 20px; + width: calc(100% - 40px); + display: flex; + justify-content: flex-end; + gap: 8px; + } + + &__content { + display: flex; + flex-direction: column; + justify-content: space-between; + height: calc(100% - 160px); + } + + &__image { + width: 40px; + height: 40px; + object-fit: cover; + border-radius: 100%; + margin-bottom: 20px; + } + + .description { + margin-bottom: 40px; + .title { + font-weight: 600; + font-size: 20px; + margin-bottom: 8px; + } + + .text { + color: var(--new-ui-gray-color); + font-weight: 400; + font-size: 15px; + line-height: 24px; + } + } +} + +@keyframes fadein { + 0% { + opacity: 0; + } + 50% { + opacity: 0; + } + 100% { + opacity: 1; + } +} + +.blocked { + display: flex; + align-items: center; + justify-content: center; + background-color: #c32528; + // padding-right: 20px; + padding: 8px 15px; + gap: 5px; + // border-radius: 15px 15px 0px 0px; + position: absolute; + width: 100%; + left: 0; + bottom: 0; + + &__text { + color: white; + font-size: 13px; + font-weight: 600; + } +} + +.locked { + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.7); + border-radius: 15px; + padding-right: 20px; + z-index: 1; + + span { + color: white; + padding-top: 10px; + font-weight: 500; + } +} @@ -5,9 +5,9 @@ background-color: white; border-radius: 100px; // padding-right: 20px; - width: 50px; - height: 50px; - box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.1); + width: 40px; + height: 40px; + box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.1); transition: width 0.3s ease-in-out; &__icon { @@ -47,7 +47,9 @@ background-color: var(--new-ui-main-color); border-radius: 15px; position: relative; - min-height: 280px; + min-height: 310px; + max-height: 310px; + user-select: none !important; cursor: pointer; box-sizing: border-box; @@ -65,7 +67,7 @@ width: calc(100% - 40px); display: flex; justify-content: flex-end; - gap: 8px; + gap: 8px; } &__content { @@ -77,13 +79,14 @@ &__image { width: 100%; - height: 160px; + height: 145px; object-fit: cover; } .description { padding: 20px; padding-top: 15px; + margin-bottom: 40px; .title { font-weight: 600; @@ -94,6 +97,7 @@ .text { color: var(--new-ui-gray-color); font-weight: 400; + line-height: 24px; font-size: 15px; } } @@ -117,12 +121,16 @@ justify-content: center; background-color: #c32528; // padding-right: 20px; - padding: 12px 15px; + padding: 8px 15px; + position: absolute; + width: 100%; + left: 0; + bottom: 0; gap: 5px; &__text { color: white; - font-size: 14px; + font-size: 13px; font-weight: 600; } } @@ -5,13 +5,13 @@ import Link from 'next/link' import LockSvg from '#/assets/svg/lock.svg?react' import BlockedSvg from '#/assets/svg/blocked.svg?react' -import styles from './card.module.scss' +import styles from './card-chat.module.scss' import { useThemeAndDevice } from '#/shared/lib/hooks' import { c } from '#/shared/lib/helpers' import { IShortModel } from '#/entities/model-entity' import { SvgIcon } from '#/shared/ui/svg' -export interface ModelCardProps extends IShortModel { +export interface ChatModelCardProps extends IShortModel { accessed_models: string[] | null } @@ -23,7 +23,7 @@ export function ChatModelCard({ accessed_models, blocked, tags, -}: ModelCardProps) { +}: ChatModelCardProps) { const link = useMemo(() => { return accessed_models && !accessed_models.includes(slug) ? '/account?scope=subscribe' @@ -34,12 +34,12 @@ export function ChatModelCard({ return ( -
= NextPage
& { @@ -35,6 +38,35 @@ export interface AppPropsWithLayout extends AppProps { function App({ Component, pageProps: { session, ...pageProps } }: AppPropsWithLayout) { const getLayout = Component.getLayout ?? ((page) => page) + const callback = useCallback((event: any) => { + Sentry.captureMessage(`error in response + - ${event.data.url} - + ${event.data.status} - ${event.data.reason}`) + + console.log('Ответ от Service Worker:', event.data) + }, []) + + function registerSw() { + navigator.serviceWorker.register('sw.js').then((registration) => { + registration.onupdatefound = () => { + const newWorker = registration.installing! + + newWorker.onstatechange = () => { + if (newWorker.state === 'installed') { + if (navigator.serviceWorker.controller) { + registration.unregister().then(() => { + window.location.reload() + }) + } + } + } + } + }) + navigator.serviceWorker.addEventListener('message', callback) + } + + useEffect(registerSw, []) + return ( <>