diff --git a/.forgejo/workflows/make-image.yml b/.forgejo/workflows/make-image.yml new file mode 100644 index 0000000..9296fa4 --- /dev/null +++ b/.forgejo/workflows/make-image.yml @@ -0,0 +1,40 @@ +on: + push: + tags: + - 'v[0-9]+*' + workflow_dispatch: + +env: + IMAGE_NAME: mtv2-frontend + +jobs: + build-and-push: + name: Make image + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Forgejo + uses: docker/login-action@v3 + with: + registry: repo.nqws.ru + username: ${{ secrets.MAINTAINER_USERNAME }} + password: ${{ secrets.MAINTAINER_TOKEN }} + + - name: Extract version from tag + id: extract_version + run: | + VERSION=${GITHUB_REF#refs/tags/} + echo "VERSION=${VERSION}" >> $GITHUB_ENV + + - name: Make image + run: | + docker buildx build --platform linux/amd64 \ + --tag repo.nqws.ru/${{ github.repository }}:latest \ + --tag repo.nqws.ru/${{ github.repository }}:${{ env.VERSION }} \ + --push . \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 6ff35c8..7737ca2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,17 @@ +FROM node:24.10-alpine3.22 AS builder + +WORKDIR /app + +COPY package*.json ./ +RUN npm ci --prefer-offline --no-audit + +COPY . . + +RUN npm run build + FROM nginx:alpine -COPY dist/ /usr/share/nginx/html + +COPY --from=builder /app/dist/ /usr/share/nginx/html/ COPY nginx.conf /etc/nginx/nginx.conf diff --git a/src/App.vue b/src/App.vue index d6e1430..ec2a28a 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,23 +1,40 @@ diff --git a/src/components/ChartBlock.vue b/src/components/ChartBlock.vue index c70f039..96a5243 100644 --- a/src/components/ChartBlock.vue +++ b/src/components/ChartBlock.vue @@ -137,11 +137,9 @@ const chartOptions = { watch( () => props.chartsData, (newData) => { - // Сброс состояния showPlaceholder.value = false placeholderMessage.value = '' - // Случай 1: null или undefined if (newData === null || newData === undefined) { showPlaceholder.value = true placeholderMessage.value = 'No prices found' @@ -149,7 +147,6 @@ watch( return } - // Случай 2: явная ошибка в объекте if (typeof newData === 'object' && newData.error) { showPlaceholder.value = true placeholderMessage.value = newData.error @@ -157,13 +154,11 @@ watch( return } - // Случай 3: нормальный объект — пробуем преобразовать let datasets = [] if (newData.origins && Array.isArray(newData.origins)) { datasets = transformToChartJSSeries(newData) } - // 🔥 Ключевое изменение: проверяем, есть ли хоть один датасет if (datasets.length === 0) { showPlaceholder.value = true placeholderMessage.value = 'No prices found' diff --git a/src/components/CopyToClipboard.vue b/src/components/CopyToClipboard.vue new file mode 100644 index 0000000..0100e5f --- /dev/null +++ b/src/components/CopyToClipboard.vue @@ -0,0 +1,48 @@ + + + + + diff --git a/src/components/Footer/Footer.vue b/src/components/Footer/Footer.vue new file mode 100644 index 0000000..9fdc12e --- /dev/null +++ b/src/components/Footer/Footer.vue @@ -0,0 +1,12 @@ + + + + + diff --git a/src/main.js b/src/main.js index aa2ca8c..753d4a0 100644 --- a/src/main.js +++ b/src/main.js @@ -7,7 +7,10 @@ import App from './App.vue' import router from './router' const app = createApp(App) -export const BASE_URL = 'http://localhost:9090/api/v2' +export const BASE_URL = 'https://api.nqws.ru/api/v2' +// export const BASE_URL = 'http://localhost:9090/api/v2' + +export const BASE_MANDARAKE_LINK = 'https://order.mandarake.co.jp/order/listPage/list?soldOut=1&keyword=' app.use(createPinia()) app.use(router) diff --git a/src/styles/styles.css b/src/styles/styles.css index b8994a0..5c4660b 100644 --- a/src/styles/styles.css +++ b/src/styles/styles.css @@ -2,6 +2,10 @@ margin-top: 10px; } +.mb-10 { + margin-bottom: 10px; +} + .mb-20 { margin-bottom: 30px; } @@ -53,6 +57,10 @@ text-align: center; } +.text-muted { + opacity: 0.6; +} + .sticky-search-container { position: sticky; top: 0; @@ -100,3 +108,15 @@ :deep(.mobile-full-width) { width: 100%; } + +.default-color{ + color: #18a058; +} + +.underline { + text-decoration: underline; +} + +.link-like-text { + cursor: pointer; +} diff --git a/src/views/AddMerchView.vue b/src/views/AddMerchView.vue index eb12ff6..a1af5f8 100644 --- a/src/views/AddMerchView.vue +++ b/src/views/AddMerchView.vue @@ -2,11 +2,10 @@ import router from '@/router/index.js' import { computed, ref } from 'vue' import { useMerchApi } from '@/api/merch.js' +import { BASE_MANDARAKE_LINK } from '@/main.js' const { addMerch } = useMerchApi() -const mandarakeLink = 'https://order.mandarake.co.jp/order/listPage/list?soldOut=1&keyword=' - const name = ref('') // surugaya block @@ -17,7 +16,7 @@ const checkAutoComplete = ref(true) const customLink = ref('') const mandarakeAutocomplete = computed(() => { - return `${mandarakeLink}${name.value}` + return `${BASE_MANDARAKE_LINK}${name.value}` }) const mandarakeResultLink = computed({ diff --git a/src/views/DetailsView.vue b/src/views/DetailsView.vue index 587d625..1c54897 100644 --- a/src/views/DetailsView.vue +++ b/src/views/DetailsView.vue @@ -6,6 +6,7 @@ import PeriodSelector from '@/components/PeriodSelector.vue' import ChartBlock from '@/components/ChartBlock.vue' import { useChartsApi } from '@/api/charts.js' import EditLink from '@/views/DetailsView/EditLink.vue' +import CopyToClipboard from '@/components/CopyToClipboard.vue' const { getMerchDetails, deleteMerch } = useMerchApi() const { getDistinctPrices } = useChartsApi() @@ -17,6 +18,11 @@ const props = defineProps({ }, }) +const editing = ref({ + surugaya: false, + mandarake: false, +}) + const merchDetails = ref(null) const loading = ref(true) const error = ref(null) @@ -76,11 +82,15 @@ const fetchPrices = async (days = 7) => { } } +function handleLinkUpdate(origin, newLink) { + merchDetails.value[`origin_${origin}`].link = newLink + editing.value[origin] = false +} + function handleSelectDays(days) { fetchPrices(days) } - onMounted(() => { fetchMerch() fetchPrices(7) @@ -102,20 +112,71 @@ onMounted(() => { - Surugaya + + + Surugaya + +
+ + +
+ + :model-value="merchDetails.origin_surugaya?.link || ''" + @update:model-value="handleLinkUpdate('surugaya', $event)" + @cancel-edit="editing.surugaya = false" + /> + + + + Mandarake + +
+ + +
- Mandarake - + :model-value="merchDetails.origin_mandarake?.link || ''" + @update:model-value="handleLinkUpdate('mandarake', $event)" + @cancel-edit="editing.mandarake = false" + />
Not found
diff --git a/src/views/DetailsView/EditLink.vue b/src/views/DetailsView/EditLink.vue index 81a2376..d855a40 100644 --- a/src/views/DetailsView/EditLink.vue +++ b/src/views/DetailsView/EditLink.vue @@ -1,33 +1,26 @@