Compare commits
111 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c0345aaa97 | |||
| f751a23e65 | |||
| 0756141fcc | |||
| 60c4327897 | |||
| ceb4c272c8 | |||
| 9332950817 | |||
| c4f0202ea2 | |||
| da7acee362 | |||
| 1f7d7a5f08 | |||
| ac94d11c26 | |||
| 46ab890306 | |||
| 29d9e6e697 | |||
| 4f98517e1c | |||
| e1e6c53af2 | |||
| 273fae5567 | |||
| a68d021683 | |||
| 2aa68fc251 | |||
| 0da343e3a0 | |||
| e05518d243 | |||
| 06afb4e637 | |||
| 9d074e416b | |||
| 57aaeae566 | |||
| ac56186cf7 | |||
| f6e295a3f5 | |||
| 09415adce2 | |||
| 3609f446cb | |||
| 145f0c6702 | |||
| 61947a5acc | |||
| 9d638839d6 | |||
| 39e2370fde | |||
| 1c25d760e2 | |||
| a869b20d2b | |||
| 4e44140183 | |||
| 8d36597e0e | |||
| cbca88ec9d | |||
| e4d89b5132 | |||
| 5feef83ae0 | |||
| 123fbb3fb4 | |||
| 2021e92467 | |||
| 26f4def6c3 | |||
| ace0cba558 | |||
| b669aba0dc | |||
| 3a20198e52 | |||
| c7e23817d6 | |||
| 8ab527e096 | |||
| baca55494c | |||
| 2ce47117e1 | |||
| 398d4cc342 | |||
| cbbfc629eb | |||
| a8d37525c3 | |||
| 08f15a687f | |||
| b3ff86ce8b | |||
| 17eeec3d26 | |||
| 702c2e01da | |||
| ff9885c5f8 | |||
| 021236498e | |||
| 28e159b8bd | |||
| 022a3ad303 | |||
| 71c9bcb05a | |||
| 6b8bccff1d | |||
| ea158a44b0 | |||
| c140ec8b21 | |||
| be581a8757 | |||
| 285babb9c9 | |||
| fa95157ab7 | |||
| e208f23363 | |||
| deab4d3df0 | |||
| 3fffc8d2df | |||
| ff41fe80c4 | |||
| 17a06a1ed0 | |||
| 3262b486cd | |||
| 1b5dc55743 | |||
| 9dfa7a1f51 | |||
| a76020874c | |||
| a75a69d522 | |||
| dcbb22232e | |||
| f4ffe76e1d | |||
| 186a18ad7c | |||
| 3a116091b1 | |||
| a68ff8d775 | |||
| 576ef6a113 | |||
| 5cd2b178d4 | |||
| 91713b08fd | |||
| 9c13712c86 | |||
| e6765237a0 | |||
| 885ea8ffa2 | |||
| b80aa1e4eb | |||
| bf6dea9f97 | |||
| 4f72f4240b | |||
| d0c2366767 | |||
| a9c21a6f1a | |||
| badf5ab847 | |||
| 776228dd10 | |||
| 7520e5c1f5 | |||
| f6e58a0858 | |||
| ac4fb708e5 | |||
| 7b466745d2 | |||
| 187d3f28c1 | |||
| 2cc76be5bc | |||
| 71fce139c4 | |||
| 93a42e2089 | |||
| e47551628a | |||
| 77b961a79a | |||
| c37a779ab6 | |||
| b97ea8c667 | |||
| 0b72328bd1 | |||
| 1a640f2411 | |||
| f7a36d9563 | |||
| df50c65b6e | |||
| 0f07e8291e | |||
| 1ec2f3f4df |
@@ -14,3 +14,7 @@ src/.vuepress/.cache
|
||||
src/.vuepress/.temp
|
||||
src/.vitepress/cache
|
||||
packages-list.json
|
||||
/.vale
|
||||
/.vscode
|
||||
/.vale.ini
|
||||
/VimpelcomCAG2.pem
|
||||
@@ -5,10 +5,12 @@ stages:
|
||||
|
||||
variables:
|
||||
DIST_DIR: "./src/.vitepress/dist"
|
||||
DMZ_DIST_DIR: "./dmz-dist"
|
||||
CONTAINER_REGISTRY: harbor.vimpelcom.ru
|
||||
PRODUCT_PROD: vega/beecloud
|
||||
IMAGE_NAME: docs
|
||||
PRODUCT_DMZ: vega/beecloud/dmz
|
||||
IMAGE_NAME: docs-portal
|
||||
|
||||
include:
|
||||
- ci/develop.yml
|
||||
- "ci/rules.yml"
|
||||
- ci/*.yml
|
||||
- "ci/deploy/*.inc.yml"
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
cafile=VimpelcomCAG2.pem
|
||||
@beeline:registry=https://nexus.vimpelcom.ru/repository/npm-all/
|
||||
registry=https://nexus.vimpelcom.ru/repository/npm-all/
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDdTCCAl2gAwIBAgIQQaIoxfL+KLhIxGpv9/PUMzANBgkqhkiG9w0BAQsFADBN
|
||||
MRIwEAYKCZImiZPyLGQBGRYCcnUxGTAXBgoJkiaJk/IsZAEZFgl2aW1wZWxjb20x
|
||||
HDAaBgNVBAMTE1ZpbXBlbGNvbSBSb290Q0EgRzIwHhcNMTgxMTIxMDkzMjE5WhcN
|
||||
MzgxMTIxMDk0MjE5WjBNMRIwEAYKCZImiZPyLGQBGRYCcnUxGTAXBgoJkiaJk/Is
|
||||
ZAEZFgl2aW1wZWxjb20xHDAaBgNVBAMTE1ZpbXBlbGNvbSBSb290Q0EgRzIwggEi
|
||||
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD7q+kJ4RNskizo7aNgVoAt9Z/p
|
||||
tcmjjcuH5iP/5MHLKN8eeWJWxwNm21tevwlIBGXWAvx43v4+xe77IELZdz3RErtA
|
||||
W1UYfdzI+c9eYyy9OORc5PgmcWDV2eWuVMFWFnkXbAX0evBM8FPzXie1n393vaT3
|
||||
BDmNuoiiuupq/uYY3z5iFVZBpLMZyBxrxYr5adq1oefbfMBeGJGT8N3sqIw1Jzt7
|
||||
TsUoYSgpgzSbMY7wbOY8yOcRb0NI1iWo3Rky5DBkyWBm4pvaIe2cXPq7gbXCSFRi
|
||||
ewP68+c2b4NTX091paEC542yb9KhKLBfTtcnZPbHAHOABtubhEwf9HfMsehlAgMB
|
||||
AAGjUTBPMAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTv
|
||||
4MjZ3yyuntT6y3fR60JeZm6wTjAQBgkrBgEEAYI3FQEEAwIBADANBgkqhkiG9w0B
|
||||
AQsFAAOCAQEApdVkNkRUMuu6p5hq32NdXkgHPTYKKdaxs+c2jEoB3giYrQFIfto+
|
||||
UVNPg3IE2iAlpxccRw0jyJ2neC/ai1Imgg6xCZ3a3RYFjoh5eaJWN/aSI8/pg1E8
|
||||
MDpzCCJGdo0Ei8zC2eDA8buSrbBtjDN8c//3X9/VhXkZzs3dL7jaIIxSR+EHXWH0
|
||||
3al6AavaN/X68qrRWHs2FBpw6qaecL8BPJiliaD3Rl1RyucTUibbUD6ryqeTgMrP
|
||||
aeaCPa0Ypb6pw7y0nLyJJPmsX9kgcgS0oEL6RsxhpjZ0eQZcRome/pV9BPUDJyLT
|
||||
z8mBO6VYVh9DcuqPmnBxgucMc6mjJiRIEg==
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGqTCCBZGgAwIBAgITcgAAAAI2SdIO0pgfxQAAAAAAAjANBgkqhkiG9w0BAQsF
|
||||
ADBNMRIwEAYKCZImiZPyLGQBGRYCcnUxGTAXBgoJkiaJk/IsZAEZFgl2aW1wZWxj
|
||||
b20xHDAaBgNVBAMTE1ZpbXBlbGNvbSBSb290Q0EgRzIwHhcNMTgxMTI2MTAzNzUw
|
||||
WhcNMjgxMTI2MTA0NzUwWjBmMRIwEAYKCZImiZPyLGQBGRYCcnUxGTAXBgoJkiaJ
|
||||
k/IsZAEZFgl2aW1wZWxjb20xEzARBgoJkiaJk/IsZAEZFgNiZWUxIDAeBgNVBAMT
|
||||
F1ZpbXBlbGNvbSBJbnRlcm5hbENBIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEA2uD2VDoEA25or20KxFS1fWZMIo1M61+WCwHE1kXZVJulbxOxMkEl
|
||||
1m8urNyvXkAbU9Gd+nZ6ZPSMkI9lx0ki9EPK5uaBxRY4FDACaT1sEjo+d/ZYMyBB
|
||||
P/s4VxIaISbqvD8/MH/h6N5e5eIgAnfqtyblEBKNUuJEDJAirIUb/VnjH7f8gvI/
|
||||
CqHa8KOSC/TE2ZqctlJRrm7mRJwwDHrL/VewC7LtwJD7bcWDHNc5+psJLmKc9R9R
|
||||
VREi5TfRKD8Mlr0syqmJxqzElfGOusUGSLJqpHS4LUlPrwXjoZ0ZMvWE5U3vftMX
|
||||
dHCCVmtB6R+O1iGaM6sK1jnliU8K8NssMwIDAQABo4IDZzCCA2MwEAYJKwYBBAGC
|
||||
NxUBBAMCAQAwHQYDVR0OBBYEFEhtK6bKwldIiW8e/DlSWntIC19xMBkGCSsGAQQB
|
||||
gjcUAgQMHgoAUwB1AGIAQwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/
|
||||
MB8GA1UdIwQYMBaAFO/gyNnfLK6e1PrLd9HrQl5mbrBOMIIBZwYDVR0fBIIBXjCC
|
||||
AVowggFWoIIBUqCCAU6GgcZsZGFwOi8vL0NOPVZpbXBlbGNvbSUyMFJvb3RDQSUy
|
||||
MEcyLENOPVZpbXBlbFJvb3RDQUcyLENOPUNEUCxDTj1QdWJsaWMlMjBLZXklMjBT
|
||||
ZXJ2aWNlcyxDTj1TZXJ2aWNlcyxDTj1Db25maWd1cmF0aW9uLERDPXZpbXBlbGNv
|
||||
bSxEQz1ydT9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0P2Jhc2U/b2JqZWN0Q2xh
|
||||
c3M9Y1JMRGlzdHJpYnV0aW9uUG9pbnSGRWh0dHA6Ly9wa2lpbnQuYmVlLnZpbXBl
|
||||
bGNvbS5ydS9DZXJ0RW5yb2xsL1ZpbXBlbGNvbSUyMFJvb3RDQSUyMEcyLmNybIY8
|
||||
aHR0cDovL3BraWV4dC5iZWVsaW5lLnJ1L3BraS9jZHAvVmltcGVsY29tJTIwUm9v
|
||||
dENBJTIwRzIuY3JsMIIBaQYIKwYBBQUHAQEEggFbMIIBVzCBtwYIKwYBBQUHMAKG
|
||||
gapsZGFwOi8vL0NOPVZpbXBlbGNvbSUyMFJvb3RDQSUyMEcyLENOPUFJQSxDTj1Q
|
||||
dWJsaWMlMjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2aWNlcyxDTj1Db25maWd1cmF0
|
||||
aW9uLERDPXZpbXBlbGNvbSxEQz1ydT9jQUNlcnRpZmljYXRlP2Jhc2U/b2JqZWN0
|
||||
Q2xhc3M9Y2VydGlmaWNhdGlvbkF1dGhvcml0eTBRBggrBgEFBQcwAoZFaHR0cDov
|
||||
L3BraWludC5iZWUudmltcGVsY29tLnJ1L0NlcnRFbnJvbGwvVmltcGVsY29tJTIw
|
||||
Um9vdENBJTIwRzIuY3J0MEgGCCsGAQUFBzAChjxodHRwOi8vcGtpZXh0LmJlZWxp
|
||||
bmUucnUvcGtpL2FpYS9WaW1wZWxjb20lMjBSb290Q0ElMjBHMi5jcnQwDQYJKoZI
|
||||
hvcNAQELBQADggEBAHMJHkHITBOqVf2nbsnWveBmZHEjYogxOxNLYezU5f6ySnJl
|
||||
ySDz62n7tueq5PFyAPWI4gtDN0K0zdZALCR9CmOT3vf65Wx7HWNU44jBD1slncMi
|
||||
rAVkaQW7UcMiB4FWTJMq6B9ozVel6KHkTp96wOGahwaAZgF9g3YtEgZXmrnYaMtw
|
||||
g5cjruQ/XAQopeu+47g13kbHTzH1eKaX4rqZI/YHbO5Sv4lX179LjT08qmTx2dc6
|
||||
SUyJloalYAK0Spgza8JhEnHPTmwRB6zcZ+PifgkTZVGbx7krsmUyegr53Nlj9hFd
|
||||
g5VD1UoDfvcTmkzvdKMVEFfKM7299m0d264YnuM=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,30 +1,4 @@
|
||||
develop:npm:
|
||||
image: harbor.vimpelcom.ru/dockerhub/library/node:lts
|
||||
stage: build
|
||||
cache:
|
||||
- key:
|
||||
files:
|
||||
- package.json
|
||||
paths:
|
||||
- node_modules/
|
||||
rules:
|
||||
- !reference [.build-npm-rules, rules]
|
||||
variables:
|
||||
PRODUCT: "$PRODUCT_PROD"
|
||||
script:
|
||||
- export PRODUCT_VERSION=$(node -p "require('./package.json').version")
|
||||
- echo PRODUCT_VERSION="$PRODUCT_VERSION" >> .env
|
||||
- echo PRODUCT="$PRODUCT_PROD" >> .env
|
||||
- npm install
|
||||
- npm run build
|
||||
artifacts:
|
||||
paths:
|
||||
- "$DIST_DIR"
|
||||
reports:
|
||||
dotenv: .env
|
||||
expire_in: 1h
|
||||
|
||||
develop-image:
|
||||
build-image:
|
||||
image: harbor.vimpelcom.ru/dockerhub/library/docker:20.10.11-dind
|
||||
stage: package
|
||||
rules:
|
||||
@@ -38,8 +12,11 @@ develop-image:
|
||||
- docker build --build-arg DIST_DIR=${DIST_DIR} -f ./build.Dockerfile -t ${CONTAINER_REGISTRY}/${PRODUCT}/${IMAGE_NAME}:$PRODUCT_VERSION -t ${CONTAINER_REGISTRY}/${PRODUCT}/${IMAGE_NAME}:latest .
|
||||
- docker push ${CONTAINER_REGISTRY}/${PRODUCT}/${IMAGE_NAME}:$PRODUCT_VERSION
|
||||
- docker push ${CONTAINER_REGISTRY}/${PRODUCT}/${IMAGE_NAME}:latest
|
||||
- docker build --build-arg DIST_DIR=${DMZ_DIST_DIR} --build-arg WROOT_DIR="/usr/share/nginx/html" -f ./build.Dockerfile -t ${CONTAINER_REGISTRY}/${PRODUCT_DMZ}/${IMAGE_NAME}:$PRODUCT_VERSION -t ${CONTAINER_REGISTRY}/${PRODUCT_DMZ}/${IMAGE_NAME}:latest .
|
||||
- docker push ${CONTAINER_REGISTRY}/${PRODUCT_DMZ}/${IMAGE_NAME}:$PRODUCT_VERSION
|
||||
- docker push ${CONTAINER_REGISTRY}/${PRODUCT_DMZ}/${IMAGE_NAME}:latest
|
||||
needs:
|
||||
- job: develop:npm
|
||||
- job: build:npm
|
||||
artifacts: true
|
||||
optional: true
|
||||
artifacts:
|
||||
@@ -0,0 +1,29 @@
|
||||
build:npm:
|
||||
image: harbor.vimpelcom.ru/dockerhub/library/node:lts
|
||||
stage: build
|
||||
cache:
|
||||
- key:
|
||||
files:
|
||||
- package.json
|
||||
paths:
|
||||
- node_modules/
|
||||
rules:
|
||||
- !reference [.build-npm-rules, rules]
|
||||
variables:
|
||||
PRODUCT: "$PRODUCT_PROD"
|
||||
script:
|
||||
- export PRODUCT_VERSION=$(node -p "require('./package.json').version")
|
||||
- echo PRODUCT_VERSION="$PRODUCT_VERSION" >> .env
|
||||
- echo PRODUCT="$PRODUCT_PROD" >> .env
|
||||
- npm install
|
||||
- npm run build
|
||||
- export VITE_NEW_VERSION="true"
|
||||
- echo "$DMZ_DIST_DIR"
|
||||
- ./node_modules/.bin/vitepress build src --outDir "$DMZ_DIST_DIR"
|
||||
artifacts:
|
||||
paths:
|
||||
- "$DIST_DIR"
|
||||
- "$DMZ_DIST_DIR"
|
||||
reports:
|
||||
dotenv: .env
|
||||
expire_in: 1h
|
||||
@@ -0,0 +1,39 @@
|
||||
deploy-test-stand:
|
||||
stage: deploy
|
||||
image: harbor.vimpelcom.ru/dockerhub/library/alpine:3.21.2
|
||||
variables:
|
||||
stand: cloud-stand.vega-dev.cloud.vimpelcom.ru
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH && $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
when: never
|
||||
- if: $CI_PIPELINE_SOURCE == "push"
|
||||
when: manual
|
||||
before_script:
|
||||
- |
|
||||
sed -i s%https://dl-cdn.alpinelinux.org/%http://rhrepo.vimpelcom.ru/ext/ya/mirrors/% /etc/apk/repositories && \
|
||||
apk --no-cache add tzdata ca-certificates curl openssh-client yq jq && \
|
||||
rm -rf /var/cache/apk/*
|
||||
- which ssh-agent || (apt-get update -y && apt-get install openssh-client -y)
|
||||
- eval $(ssh-agent -s)
|
||||
- mkdir -p ~/.ssh
|
||||
- echo -n "$TECH_SSH_KEY" | tr -d '\r' > ~/.ssh/id_rsa
|
||||
- chmod 700 ~/.ssh
|
||||
- chmod 600 ~/.ssh/id_rsa
|
||||
- >
|
||||
echo "stand: ${stand}"
|
||||
ssh-keyscan "${stand}" >> ~/.ssh/known_hosts
|
||||
- chmod 644 ~/.ssh/known_hosts
|
||||
script:
|
||||
- >
|
||||
echo -e "Connect to ${stand}..." &&
|
||||
scp -o StrictHostKeyChecking=no ci/deploy/deploy.sh "dorootless@${stand}:~/deploy.sh" &&
|
||||
ssh "dorootless@${stand}" "export CONTAINER_REGISTRY=$CONTAINER_REGISTRY &&
|
||||
export PRODUCT=$PRODUCT &&
|
||||
export PRODUCT_VERSION=$PRODUCT_VERSION &&
|
||||
export IMAGE_NAME=$IMAGE_NAME &&
|
||||
chmod 700 ~/deploy.sh &&
|
||||
~/deploy.sh ${IMAGE_NAME} &&
|
||||
rm -f ~/deploy.sh"
|
||||
needs:
|
||||
- job: build-image
|
||||
optional: true
|
||||
@@ -0,0 +1,73 @@
|
||||
# echo -e # ключ -e в комманде echo включает отображение "backslash escapes"; например \n - переход на следующую строку, \t -табуляция
|
||||
# echo -n # ключ -n в команде echo сигнализирует, что после вывода информации не нужно переходить на следующую строку.
|
||||
|
||||
# - > переносы строк удаляются
|
||||
# - | переносы строк не удаляются
|
||||
|
||||
# Git add
|
||||
# - git submodule add -b main https://gitlab-ci-token:${CI_JOB_TOKEN}@$CI_SERVER_URL/products/vega/infra
|
||||
# - git submodule sync --recursive
|
||||
# - git submodule update --init --recursive
|
||||
|
||||
# # Прокидываем name + email, чтобы gitlab не сыпал ошибки
|
||||
# - git config --global user.name "YourName"
|
||||
# - git config --global user.email "YourEmail"
|
||||
|
||||
# # Вызываем наш скрипт, который инкрементирует версию
|
||||
# - node bumpVersion.js
|
||||
|
||||
# # Добавляем и пушим наши изменения в ветку откуда стригерился pipeline
|
||||
# - git add ./package.json
|
||||
# - git commit -m "bump package.json version"
|
||||
# # Используем опцию gitlab -o ci.skip, для того, чтобы наш коммит не тригерил новый pipeline
|
||||
# - git push origin HEAD:$CI_COMMIT_REF_NAME -o ci.skip
|
||||
|
||||
.deploy-template:
|
||||
image: harbor.vimpelcom.ru/dockerhub/library/alpine:3.21.2
|
||||
before_script:
|
||||
- |
|
||||
sed -i s%https://dl-cdn.alpinelinux.org/%http://rhrepo.vimpelcom.ru/ext/ya/mirrors/% /etc/apk/repositories && \
|
||||
apk --no-cache add tzdata ca-certificates curl openssh-client yq jq && \
|
||||
rm -rf /var/cache/apk/*
|
||||
- which ssh-agent || (apt-get update -y && apt-get install openssh-client -y)
|
||||
- eval $(ssh-agent -s)
|
||||
- mkdir -p ~/.ssh
|
||||
- echo -n "$TECH_SSH_KEY" | tr -d '\r' > ~/.ssh/id_rsa
|
||||
- chmod 700 ~/.ssh
|
||||
- chmod 600 ~/.ssh/id_rsa
|
||||
# https://mikefarah.gitbook.io/yq/operators/traverse-read#nested-special-characters
|
||||
- STANDS=$(echo "$STANDS" | yq '."'"${CI_COMMIT_REF_NAME}"'".[]')
|
||||
- RED=$'\033[0;31m'
|
||||
- RESET=$'\033[0m'
|
||||
- >
|
||||
if [[ -z "$STANDS" ]]; then
|
||||
echo -e "${RED}STANDS for ${CI_COMMIT_REF_NAME:=CI_COMMIT_REF_NAME} is null${RESET}"
|
||||
exit 1
|
||||
fi
|
||||
- >
|
||||
for stand in $STANDS; do
|
||||
echo "stand: ${stand}"
|
||||
ssh-keyscan "${stand}" >> ~/.ssh/known_hosts
|
||||
done
|
||||
- chmod 644 ~/.ssh/known_hosts
|
||||
# Если получилось что-то пустое
|
||||
- >
|
||||
if [[ -z "$APPVERSION" ]]; then
|
||||
APPVERSION="0.0.1"
|
||||
fi
|
||||
script:
|
||||
- >
|
||||
for stand in $STANDS; do
|
||||
echo -e "Connect to ${stand}..." &&
|
||||
scp -o StrictHostKeyChecking=no ci/deploy/deploy.sh "dorootless@${stand}:~/deploy.sh" &&
|
||||
ssh "dorootless@${stand}" "export CONTAINER_REGISTRY=$CONTAINER_REGISTRY &&
|
||||
export PRODUCT=$PRODUCT &&
|
||||
export PRODUCT_VERSION=$PRODUCT_VERSION &&
|
||||
export IMAGE_NAME=$IMAGE_NAME &&
|
||||
chmod 700 ~/deploy.sh &&
|
||||
~/deploy.sh ${IMAGE_NAME} &&
|
||||
rm -f ~/deploy.sh"
|
||||
done
|
||||
needs:
|
||||
- job: build-image
|
||||
optional: true
|
||||
@@ -0,0 +1,56 @@
|
||||
#!/bin/bash
|
||||
|
||||
# CONTAINER_REGISTRY="harbor.vimpelcom.ru"
|
||||
# PRODUCT="vega/stage"
|
||||
# PRODUCT_VERSION="0.5.3"
|
||||
|
||||
if [[ $# -eq 0 ]] ; then
|
||||
echo "No arguments supplied"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$1" ]] ; then
|
||||
echo "No argument CONTAINER_NAME"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
GREEN=$'\033[0;32m'
|
||||
RED=$'\033[0;31m'
|
||||
BLUE=$'\033[0;36m'
|
||||
WHITE=$'\033[0;37m'
|
||||
RESET=$'\033[0m'
|
||||
|
||||
CONTAINER_NAME=${1}
|
||||
IMAGE_URL="$CONTAINER_REGISTRY/$PRODUCT/$IMAGE_NAME:$PRODUCT_VERSION"
|
||||
DOCKER_COMPOSE_EXEC="docker-compose"
|
||||
|
||||
echo -e "${GREEN}IMAGE_URL${RESET}: ${IMAGE_URL}"
|
||||
|
||||
if ! [ -x "$(command -v docker-compose)" ]; then
|
||||
DOCKER_COMPOSE_EXEC="docker compose"
|
||||
fi
|
||||
|
||||
# для -z необходимо указывать параметры в двойных ковычках
|
||||
if [ -z "$(docker ps -aq -f name=^${CONTAINER_NAME}$)" ]; then
|
||||
echo -e "${RED}${CONTAINER_NAME:-container} not running.${RESET}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
COMPOSE_FILE="$(docker inspect --format '{{index .Config.Labels "com.docker.compose.project.config_files"}}' $CONTAINER_NAME | tr , \\n | xargs grep -wH $IMAGE_NAME | cut -d: -sf1 | uniq)"
|
||||
COMPOSE_ALL_FILES="-f $COMPOSE_FILE"
|
||||
|
||||
cp $COMPOSE_FILE "$COMPOSE_FILE.orig"
|
||||
# sed -i '/image: .*'$IMAGE_NAME'/ s|:.*|: '"$IMAGE_URL"'|' $COMPOSE_FILE
|
||||
sed -r -i '/image: .*'$IMAGE_NAME'(:|@|$)/ s|:.*|: '"$IMAGE_URL"'|' $COMPOSE_FILE
|
||||
|
||||
if [ -e ~dorootless/docker-compose-svc.yaml ]; then
|
||||
COMPOSE_SVC_FILE=~dorootless/docker-compose-svc.yaml
|
||||
COMPOSE_ALL_FILES="-f $COMPOSE_SVC_FILE -f $COMPOSE_FILE"
|
||||
fi
|
||||
|
||||
$DOCKER_COMPOSE_EXEC $COMPOSE_ALL_FILES pull $CONTAINER_NAME
|
||||
$DOCKER_COMPOSE_EXEC $COMPOSE_ALL_FILES up -d
|
||||
|
||||
if [ "$(docker ps -a -q -f name=ingress)" ]; then
|
||||
$DOCKER_COMPOSE_EXEC $COMPOSE_ALL_FILES exec ingress angie -s reload
|
||||
fi
|
||||
@@ -2,7 +2,4 @@
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH && $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
when: never
|
||||
- if: $CI_PIPELINE_SOURCE == "push" && ($CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "feature/ci")
|
||||
exists:
|
||||
- .npmrc
|
||||
- ./*/.npmrc
|
||||
- if: $CI_PIPELINE_SOURCE == "push"
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
{
|
||||
"name": "docs",
|
||||
"version": "0.5.0",
|
||||
"version": "0.6.2",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "docs",
|
||||
"version": "0.5.0",
|
||||
"version": "0.6.2",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@beeline/design-tokens": "^1.31.0",
|
||||
"vue": "3.4.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -16,6 +17,7 @@
|
||||
"@types/node": "20.10.7",
|
||||
"@vitejs/plugin-vue": "4.3.4",
|
||||
"sass": "1.69.7",
|
||||
"typescript": "^5.8.3",
|
||||
"vitepress": "1.0.0-rc.40",
|
||||
"vitepress-plugin-tabs": "0.5.0"
|
||||
}
|
||||
@@ -244,6 +246,16 @@
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@beeline/design-tokens": {
|
||||
"version": "1.31.0",
|
||||
"resolved": "https://nexus.vimpelcom.ru/repository/npm-all/@beeline/design-tokens/-/design-tokens-1.31.0.tgz",
|
||||
"integrity": "sha512-sTyldwSkjvrpXuORcIfwjWD9Kmw5odEKB96UvCGv0uxYY5pIFsbnJodPE+DyuKh/eHg0aNsWl2DzEHii13kLqQ==",
|
||||
"hasInstallScript": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"ds-migrate": "migrator/migrator.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@docsearch/css": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://nexus.vimpelcom.ru/repository/npm-all/@docsearch/css/-/css-3.3.0.tgz",
|
||||
@@ -1768,6 +1780,20 @@
|
||||
"node": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.8.3",
|
||||
"resolved": "https://nexus.vimpelcom.ru/repository/npm-all/typescript/-/typescript-5.8.3.tgz",
|
||||
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
|
||||
"devOptional": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "5.26.5",
|
||||
"resolved": "https://nexus.vimpelcom.ru/repository/npm-all/undici-types/-/undici-types-5.26.5.tgz",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "docs",
|
||||
"version": "0.5.0",
|
||||
"description": "Vega docs portal",
|
||||
"version": "0.6.4",
|
||||
"description": "Beeline Cloud docs",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"dev": "vitepress dev src",
|
||||
@@ -15,14 +15,16 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@beeline/design-tokens": "^1.31.0",
|
||||
"vue": "3.4.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docsearch/css": "3.3.0",
|
||||
"@types/node": "20.10.7",
|
||||
"@vitejs/plugin-vue": "4.3.4",
|
||||
"sass": "1.69.7",
|
||||
"typescript": "^5.8.3",
|
||||
"vitepress": "1.0.0-rc.40",
|
||||
"vitepress-plugin-tabs": "0.5.0",
|
||||
"@vitejs/plugin-vue": "4.3.4"
|
||||
"vitepress-plugin-tabs": "0.5.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
#ps
|
||||
|
||||
# Configs
|
||||
$Env:CONTAINER_REGISTRY = "harbor.vimpelcom.ru"
|
||||
$Env:PRODUCT = "vega/cloud"
|
||||
$Env:IMAGE_NAME = "docs"
|
||||
$Env:PRODUCT_VERSION = "0.6.2" # node -p "require('./package.json').version"
|
||||
$Env:PKG_NAME = "vega-portal" # node -p "require('./package.json').name"
|
||||
|
||||
# VITE VARS
|
||||
|
||||
Remove-Item -Recurse -Force dist
|
||||
|
||||
# Write-Output "Version: " node -p "require('./package.json').version"
|
||||
git pull
|
||||
Write-Output " Компиляция:" $env:PKG_NAME'@'$env:PRODUCT_VERSION
|
||||
npm install
|
||||
npm run build
|
||||
|
||||
docker build -f ./build.Dockerfile -t $env:CONTAINER_REGISTRY/$env:PRODUCT/$env:IMAGE_NAME':'$env:PRODUCT_VERSION .
|
||||
docker image list | FINDSTR "$env:PRODUCT/$env:IMAGE_NAME"
|
||||
docker push $env:CONTAINER_REGISTRY/$env:PRODUCT/$env:IMAGE_NAME':'$env:PRODUCT_VERSION
|
||||
@@ -42,9 +42,10 @@ console.log({ base: typeof new_version !== 'undefined' ? '/' : '/docs/' })
|
||||
|
||||
// https://vitepress.dev/reference/site-config
|
||||
export default defineConfig({
|
||||
title: "BeeCloud Docs",
|
||||
description: "Документация публичного облака",
|
||||
head: [['link', { rel: 'icon', href: '/favicon.svg' }]],
|
||||
srcDir: ".",
|
||||
title: "cloud",
|
||||
description: "Документация Beeline Cloud",
|
||||
head: [['link', { rel: 'icon', type: 'image/png', sizes: '32x32', href: '/bee-favicon.png' }]],
|
||||
base: typeof new_version !== 'undefined' ? '/' : '/docs/',
|
||||
markdown: {
|
||||
config(md) {
|
||||
@@ -63,7 +64,11 @@ export default defineConfig({
|
||||
}
|
||||
},
|
||||
themeConfig: {
|
||||
logo: '/favicon.svg',
|
||||
logo: {
|
||||
light: '/logo-light-theme.svg',
|
||||
dark: '/logo-dark-theme.svg',
|
||||
alt: 'cloud',
|
||||
},
|
||||
search: {
|
||||
provider: 'local',
|
||||
options: {
|
||||
@@ -75,7 +80,7 @@ export default defineConfig({
|
||||
buttonAriaLabel: 'Поиск'
|
||||
},
|
||||
modal: {
|
||||
noResultsText: 'Нет результатов для',
|
||||
noResultsText: 'Не удалось загрузить данные',
|
||||
resetButtonTitle: 'Сбросить',
|
||||
displayDetails: 'Показать расширенный список',
|
||||
footer: {
|
||||
@@ -90,412 +95,182 @@ export default defineConfig({
|
||||
}
|
||||
},
|
||||
// https://vitepress.dev/reference/default-theme-config
|
||||
nav: [
|
||||
{
|
||||
text: 'Документация',
|
||||
link: '/guide/',
|
||||
},
|
||||
// nav: [
|
||||
// {
|
||||
// text: 'Wiki-DF',
|
||||
// link: '/wikidf/',
|
||||
// text: 'Документация',
|
||||
// link: '/guide/',
|
||||
// },
|
||||
// {
|
||||
// text: 'API',
|
||||
// link: '',
|
||||
// },
|
||||
// {
|
||||
// text: 'Terraform',
|
||||
// // link: '/terraform/',
|
||||
// link: '',
|
||||
// },
|
||||
|
||||
{
|
||||
text: 'Terraform',
|
||||
link: '/terraform/',
|
||||
},
|
||||
{
|
||||
text: 'Консоль управления',
|
||||
link: 'https://console.cloud.dfcloud.ru'
|
||||
}
|
||||
],
|
||||
|
||||
// socialLinks: [
|
||||
// { icon: { svg: gitlab }, link: 'https://git.vimpelcom.ru/common/vega/docs' }
|
||||
// ],
|
||||
|
||||
// editLink: {
|
||||
// pattern: 'https://git.vimpelcom.ru/-/ide/project/common/vega/docs/edit/develop/-/src/:path',
|
||||
// text: 'Отредактируйте эту страницу на GitLab'
|
||||
// },
|
||||
|
||||
docFooter: {
|
||||
next: 'Вперед',
|
||||
prev: 'Назад'
|
||||
},
|
||||
|
||||
lastUpdated: {
|
||||
text: 'Обновлена',
|
||||
formatOptions: {
|
||||
dateStyle: 'long',
|
||||
}
|
||||
},
|
||||
|
||||
outline: {
|
||||
label: 'Содержание'
|
||||
},
|
||||
sidebar: {
|
||||
'/guide/': [
|
||||
'/platform/': [
|
||||
{
|
||||
text: 'Облачные вычисления',
|
||||
text: 'Платформа Beeline Cloud', link: '/platform/index.md',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'Обзор сервиса', link: '/guide/compute/compute-overview.md' },
|
||||
{ text: 'Быстрый старт', link: '/guide/compute/compute-getting-started.md' },
|
||||
{ text: 'Виртуальные серверы', link: '/guide/compute/compute-instructions/compute-servers-create.md' },
|
||||
{ text: 'Управление виртуальными серверами', link: '/guide/compute/compute-instructions/compute-servers-manage.md' },
|
||||
{ text: 'Диски', link: '/guide/compute/compute-instructions/compute-disks.md' },
|
||||
{ text: 'Группы размещения', link: '/guide/compute/compute-instructions/compute-affinity.md' },
|
||||
{ text: 'IP-адрес', link: '/guide/compute/compute-instructions/compute-ip.md' },
|
||||
{ text: 'Квоты и лимиты', link: '/guide/compute/compute-limits.md' },
|
||||
{ text: 'Уровень обслуживания', link: '/guide/compute/compute-ola.md' },
|
||||
{text: 'Обзор', link: '/platform/about.md'},
|
||||
{text: 'Техническая поддержка', link: '/platform/support/support-overview.md'},
|
||||
],
|
||||
},
|
||||
],
|
||||
'/start/': [
|
||||
{
|
||||
text: 'Начало работы в Beeline Cloud', link: '/start/index.md',
|
||||
},
|
||||
{text: 'Начать работу', link: '/start/getting-started.md'},
|
||||
{text: 'Бесплатный период', link: '/start/trial.md'},
|
||||
{text: 'Платное использование', link: '/start/organization.md'},
|
||||
],
|
||||
'/ai/': [
|
||||
{ text: 'AI платформа', link: '/ai/index.md' },
|
||||
{ text: 'Обзор сервиса', link: '/ai/ai-overview-platform.md' },
|
||||
{ text: 'Быстрый старт', link: '/ai/ai-getting-started.md' },
|
||||
{ text: 'Управление сервисом', link: '/ai/ai-setting.md' },
|
||||
{ text: 'Чат с LLM', link: '/ai/ai-chat-llm.md' },
|
||||
{ text: 'Концепции', link: '/ai/ai-glossary.md' },
|
||||
],
|
||||
'/vdc/': [
|
||||
{
|
||||
text: 'Виртуальные дата-центры на VMware', link: '/vdc/index.md',
|
||||
},
|
||||
{
|
||||
text: 'Обзор сервиса', link: '/vdc/vdc-overview.md',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'Техническое описание', link: '/vdc/vdc-tech.md' },
|
||||
{ text: 'Квоты и лимиты', link: '/vdc/vdc-quatos.md' },
|
||||
]
|
||||
},
|
||||
{
|
||||
text: 'Объектное хранилище',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'Обзор сервиса', link: '/guide/storage/storage-overview.md' },
|
||||
{
|
||||
text: 'Подключение к хранилищу',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'WinSCP', link: '/guide/storage/storage-instructions/s3-connect/winscp.md' },
|
||||
{ text: 'S3cmd', link: '/guide/storage/storage-instructions/s3-connect/s3cmd.md' },
|
||||
]
|
||||
},
|
||||
{ text: 'Управление хранилищем', link: '/guide/storage/storage-instructions/storage-s3.md' },
|
||||
{ text: 'Квоты и лимиты', link: '/guide/storage/storage-limits.md' },
|
||||
{ text: 'Уровень обслуживания', link: '/guide/storage/storage-ola.md' },
|
||||
]
|
||||
},
|
||||
{
|
||||
text: 'DNS',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'Обзор сервиса', link: '/guide/dns/dns-overview.md' },
|
||||
{ text: 'Ресурсные записи', link: '/guide/dns/dns-instructions/dns-create.md' },
|
||||
{ text: 'Квоты и лимиты', link: '/guide/dns/dns-limits.md' },
|
||||
]
|
||||
},
|
||||
{
|
||||
text: 'Аккаунт',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'Проекты', link: '/guide/admin/projects.md' },
|
||||
{ text: 'Ролевая модель', link: '/guide/admin/roles.md' },
|
||||
{ text: 'Квоты и лимиты', link: '/guide/admin/limits.md' },
|
||||
{ text: 'Регионы', link: '/guide/admin/availability-matrix.md' },
|
||||
{ text: 'SSH ключи', link: '/guide/admin/ssh.md' },
|
||||
{ text: 'Участники проекта', link: '/guide/admin/users.md' },
|
||||
]
|
||||
},
|
||||
{
|
||||
text: 'Wiki DF',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{
|
||||
text: 'Cертификаты и лицензии beeline cloud',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'Лицензии', link: '/guide/wikidf/01-lic-sert/lic.md' },
|
||||
{ text: 'Cертификаты', link: '/guide/wikidf/01-lic-sert/sert.md' },
|
||||
]
|
||||
},
|
||||
{ text: 'База знаний beeline cloud', link: '/guide/wikidf/02-kb/02-kb-overview.md' },
|
||||
{
|
||||
text: 'Инфраструктурные сервисы',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'Инфраструктурные сервисы - Обзор', link: '/guide/wikidf/03-iaas/03-0-iaas-overview.md' },
|
||||
{
|
||||
text: 'BeeCloud Stack',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'BeeCloud Stack - Обзор сервиса', link: '/guide/wikidf/03-iaas/03-1-stack/03-1-0-stack-overview.md' },
|
||||
{ text: '1. Архитектура сервиса', link: '/guide/wikidf/03-iaas/03-1-stack/03-1-1.md' },
|
||||
{ text: '2. Роли и авторизация', link: '/guide/wikidf/03-iaas/03-1-stack/03-1-2.md' },
|
||||
{
|
||||
text: '3. Инструкция',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{
|
||||
text: 'Вычисления',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'A. Создание ВМ', link: '/guide/wikidf/03-iaas/03-1-stack/03-1-3/03-1-3-1/03-1-3-1-a.md' },
|
||||
{ text: 'B. Старт, стоп и рестарт ВМ', link: '/guide/wikidf/03-iaas/03-1-stack/03-1-3/03-1-3-1/03-1-3-1-b.md' },
|
||||
{ text: 'C. Модификация ВМ', link: '/guide/wikidf/03-iaas/03-1-stack/03-1-3/03-1-3-1/03-1-3-1-c.md' },
|
||||
{ text: 'D. Создание, удаление и откат к снимку ВМ', link: '/guide/wikidf/03-iaas/03-1-stack/03-1-3/03-1-3-1/03-1-3-1-d.md' },
|
||||
{ text: 'E. Доступ к консоли ВМ', link: '/guide/wikidf/03-iaas/03-1-stack/03-1-3/03-1-3-1/03-1-3-1-e.md' },
|
||||
{ text: 'F. Использование носителя для восстановления ВМ', link: '/guide/wikidf/03-iaas/03-1-stack/03-1-3/03-1-3-1/03-1-3-1-f.md' },
|
||||
{ text: 'G. Удаление ВМ', link: '/guide/wikidf/03-iaas/03-1-stack/03-1-3/03-1-3-1/03-1-3-1-g.md' },
|
||||
{ text: 'H. Cдувание ОЗУ гостевой ОС ВМ', link: '/guide/wikidf/03-iaas/03-1-stack/03-1-3/03-1-3-1/03-1-3-1-h.md' },
|
||||
{ text: 'I. Просмотр истории ВМ', link: '/guide/wikidf/03-iaas/03-1-stack/03-1-3/03-1-3-1/03-1-3-1-i.md' },
|
||||
]
|
||||
},
|
||||
{
|
||||
text: 'Программно-определяемый маршрутизатор (Edge)',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'Edge - Обзор', link: '/guide/wikidf/03-iaas/03-1-stack/03-1-3/03-1-3-2/03-1-3-2-0-overview.md' },
|
||||
{ text: 'A. Создание роутера', link: '/guide/wikidf/03-iaas/03-1-stack/03-1-3/03-1-3-2/03-1-3-2-a.md' },
|
||||
{ text: 'B. Удаление роутера', link: '/guide/wikidf/03-iaas/03-1-stack/03-1-3/03-1-3-2/03-1-3-2-b.md' },
|
||||
{ text: 'C. Старт, стоп и рестарт роутера', link: '/guide/wikidf/03-iaas/03-1-stack/03-1-3/03-1-3-2/03-1-3-2-c.md' },
|
||||
{ text: 'D. Добавление правил фаервола', link: '/guide/wikidf/03-iaas/03-1-stack/03-1-3/03-1-3-2/03-1-3-2-d.md' },
|
||||
{ text: 'E. Удаление правил фаервола', link: '/guide/wikidf/03-iaas/03-1-stack/03-1-3/03-1-3-2/03-1-3-2-e.md' },
|
||||
{ text: 'F. Добавление правил NAT', link: '/guide/wikidf/03-iaas/03-1-stack/03-1-3/03-1-3-2/03-1-3-2-f.md' },
|
||||
{ text: 'G. Добавление виртуального сетевого порта', link: '/guide/wikidf/03-iaas/03-1-stack/03-1-3/03-1-3-2/03-1-3-2-g.md' },
|
||||
{ text: 'H. Получение отчета о работе маршрутизатора', link: '/guide/wikidf/03-iaas/03-1-stack/03-1-3/03-1-3-2/03-1-3-2-h.md' },
|
||||
]
|
||||
},
|
||||
{
|
||||
text: 'Сети',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'Edge - Обзор', link: '/guide/wikidf/03-iaas/03-1-stack/03-1-3/03-1-3-2/03-1-3-2-0-overview.md' },
|
||||
{ text: 'A. Создание роутера', link: '/guide/wikidf/03-iaas/03-1-stack/03-1-3/03-1-3-2/03-1-3-2-a.md' },
|
||||
{ text: 'B. Удаление роутера', link: '/guide/wikidf/03-iaas/03-1-stack/03-1-3/03-1-3-2/03-1-3-2-b.md' },
|
||||
{ text: 'C. Старт, стоп и рестарт роутера', link: '/guide/wikidf/03-iaas/03-1-stack/03-1-3/03-1-3-2/03-1-3-2-c.md' },
|
||||
{ text: 'D. Добавление правил фаервола', link: '/guide/wikidf/03-iaas/03-1-stack/03-1-3/03-1-3-2/03-1-3-2-d.md' },
|
||||
{ text: 'E. Удаление правил фаервола', link: '/guide/wikidf/03-iaas/03-1-stack/03-1-3/03-1-3-2/03-1-3-2-e.md' },
|
||||
{ text: 'F. Добавление правил NAT', link: '/guide/wikidf/03-iaas/03-1-stack/03-1-3/03-1-3-2/03-1-3-2-f.md' },
|
||||
{ text: 'G. Добавление виртуального сетевого порта', link: '/guide/wikidf/03-iaas/03-1-stack/03-1-3/03-1-3-2/03-1-3-2-g.md' },
|
||||
{ text: 'H. Получение отчета о работе маршрутизатора', link: '/guide/wikidf/03-iaas/03-1-stack/03-1-3/03-1-3-2/03-1-3-2-h.md' },
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
text: 'Cloud Compute',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'Cloud Compute - Назначение сервиса', link: '/guide/wikidf/03-iaas/03-2-cloud-compute/03-2-0-cc-overview.md' },
|
||||
{
|
||||
text: '1. Описание сервиса',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: '01. Состав сервиса', link: '/guide/wikidf/03-iaas/03-2-cloud-compute/03-2-1/03-2-1-1.md' },
|
||||
{
|
||||
text: '02. Техническое описание сервиса',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'Техническое описание сервиса', link: '/guide/wikidf/03-iaas/03-2-cloud-compute/03-2-1/03-2-1-2/03-2-1-2-0-overview.md' },
|
||||
{ text: 'A. Cloud Compute Metrocluster', link: '/guide/wikidf/03-iaas/03-2-cloud-compute/03-2-1/03-2-1-2/03-2-1-2-1.md' },
|
||||
]
|
||||
},
|
||||
{ text: '03. Основные функциональные возможности', link: '/guide/wikidf/03-iaas/03-2-cloud-compute/03-2-1/03-2-1-3.md' },
|
||||
{ text: '04. Дополнительные возможности', link: '/guide/wikidf/03-iaas/03-2-cloud-compute/03-2-1/03-2-1-4.md' },
|
||||
{ text: '05. Основные опции', link: '/guide/wikidf/03-iaas/03-2-cloud-compute/03-2-1/03-2-1-5.md' },
|
||||
{ text: '06. Хранение данных сервиса', link: '/guide/wikidf/03-iaas/03-2-cloud-compute/03-2-1/03-2-1-6.md' },
|
||||
{ text: '07. Регионы доступности сервиса', link: '/guide/wikidf/03-iaas/03-2-cloud-compute/03-2-1/03-2-1-7.md' },
|
||||
{ text: '08. Подключение Terraform к VCD', link: '/guide/wikidf/03-iaas/03-2-cloud-compute/03-2-1/03-2-1-8.md' },
|
||||
]
|
||||
},
|
||||
{ text: '2. Соответствие сервиса требованиям и стандартам безопасности сервиса', link: '/guide/wikidf/03-iaas/03-2-cloud-compute/03-2-2.md' },
|
||||
{ text: '3. Порядок подключения и зоны ответственности', link: '/guide/wikidf/03-iaas/03-2-cloud-compute/03-2-3.md' },
|
||||
{ text: '4. Тарификация и модели оплаты', link: '/guide/wikidf/03-iaas/03-2-cloud-compute/03-2-4.md' },
|
||||
{
|
||||
text: '5. Инструкция по настройке Distributed Firewall (DFW)',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'Инструкция по настройке DFW', link: '/guide/wikidf/03-iaas/03-2-cloud-compute/03-2-5/03-2-5-0-overview.md' },
|
||||
{ text: 'A. Добавление DFW в DCG', link: '/guide/wikidf/03-iaas/03-2-cloud-compute/03-2-5/03-2-5-1.md' },
|
||||
{ text: 'B. Дополнительные настройки', link: '/guide/wikidf/03-iaas/03-2-cloud-compute/03-2-5/03-2-5-2.md' },
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
text: 'Аварийное восстановление (Disaster Recovery)',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'Аварийное восстановление (Disaster Recovery) - Назначение сервиса', link: '/guide/wikidf/03-iaas/03-3-recovery/03-3-0-overview.md' },
|
||||
{ text: 'DRaaS', link: '/guide/wikidf/03-iaas/03-3-recovery/03-3-1.md' },
|
||||
{ text: 'Репликация ВМ', link: '/guide/wikidf/03-iaas/03-3-recovery/03-3-2.md' },
|
||||
]
|
||||
},
|
||||
{
|
||||
text: 'Миграция виртуальных машин',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'Миграция виртуальных машин - Назначение сервиса', link: '/guide/wikidf/03-iaas/03-4-migration/03-4-0-overview.md' },
|
||||
{ text: '1. Состав сервиса', link: '/guide/wikidf/03-iaas/03-4-migration/03-4-1.md' },
|
||||
{ text: '2. Порядок предоставления сервиса. Зоны ответственности', link: '/guide/wikidf/03-iaas/03-4-migration/03-4-2.md' },
|
||||
{ text: '3. Тарификация сервиса', link: '/guide/wikidf/03-iaas/03-4-migration/03-4-3.md' },
|
||||
]
|
||||
},
|
||||
{
|
||||
text: 'Резервное копирование',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'Назначение сервиса', link: '/guide/wikidf/03-iaas/03-5-backup/03-5-0-overview.md' },
|
||||
{ text: 'ПО Veeam в аренду', link: '/guide/wikidf/03-iaas/03-5-backup/03-5-1.md' },
|
||||
{
|
||||
text: 'Резервное копирование Veeam',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'Резервное копирование Veeam - Обзор', link: '/guide/wikidf/03-iaas/03-5-backup/03-5-2/03-5-2-0-overview.md' },
|
||||
{
|
||||
text: '1. Резервное копирование виртуальных машин (ВМ) с администрированием (Managed Cloud Backup)',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'Managed Cloud Backup - Обзор', link: '/guide/wikidf/03-iaas/03-5-backup/03-5-2/03-5-2-1/03-5-2-1-0-overview.md' },
|
||||
{ text: '01. Описание сервиса', link: '/guide/wikidf/03-iaas/03-5-backup/03-5-2/03-5-2-1/03-5-2-1-1.md' },
|
||||
]
|
||||
},
|
||||
{
|
||||
text: '2. Резервное копирование ВМ (Cloud Backup)',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'Cloud Backup - Обзор', link: '/guide/wikidf/03-iaas/03-5-backup/03-5-2/03-5-2-2/03-5-2-2-0-overview.md' },
|
||||
{ text: '01. Описание сервиса', link: '/guide/wikidf/03-iaas/03-5-backup/03-5-2/03-5-2-2/03-5-2-2-1.md' },
|
||||
{ text: '02. Инструкция', link: '/guide/wikidf/03-iaas/03-5-backup/03-5-2/03-5-2-2/03-5-2-2-2.md' },
|
||||
]
|
||||
},
|
||||
{
|
||||
text: '3. Резервное копирование в облако на базе Veeam Cloud Connect (Veeam Cloud Connect Backup)',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'Veeam Cloud Connect Backup - Обзор', link: '/guide/wikidf/03-iaas/03-5-backup/03-5-2/03-5-2-3/03-5-2-3-0-overview.md' },
|
||||
{ text: '01. Состав сервиса', link: '/guide/wikidf/03-iaas/03-5-backup/03-5-2/03-5-2-3/03-5-2-3-1.md' },
|
||||
{ text: '02. Порядок подключения и зоны ответственности', link: '/guide/wikidf/03-iaas/03-5-backup/03-5-2/03-5-2-3/03-5-2-3-2.md' },
|
||||
{ text: '03. Тарификация и порядок оплаты', link: '/guide/wikidf/03-iaas/03-5-backup/03-5-2/03-5-2-3/03-5-2-3-3.md' },
|
||||
]
|
||||
},
|
||||
{
|
||||
text: '4. Резервное копирование в облако на базе Veeam агента (Veeam Agent BackUp)',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'Veeam Cloud Connect Backup - Обзор', link: '/guide/wikidf/03-iaas/03-5-backup/03-5-2/03-5-2-4/03-5-2-4-0-overview.md' },
|
||||
{ text: '01. Описание сервиса', link: '/guide/wikidf/03-iaas/03-5-backup/03-5-2/03-5-2-4/03-5-2-4-1.md' },
|
||||
{ text: '02. Инструкция',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: '1. Описание портала', link: '/guide/wikidf/03-iaas/03-5-backup/03-5-2/03-5-2-4/03-5-2-4-2/03-5-2-4-2-1.md' },
|
||||
{ text: '2. Установка агента резервного копирования', link: '/guide/wikidf/03-iaas/03-5-backup/03-5-2/03-5-2-4/03-5-2-4-2/03-5-2-4-2-2.md' },
|
||||
{ text: '3. Настройка политики резервного копирования', link: '/guide/wikidf/03-iaas/03-5-backup/03-5-2/03-5-2-4/03-5-2-4-2/03-5-2-4-2-3.md' },
|
||||
{ text: '4. Восстановление из резервных копий', link: '/guide/wikidf/03-iaas/03-5-backup/03-5-2/03-5-2-4/03-5-2-4-2/03-5-2-4-2-4.md' },
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
text: 'Резервное копирование Киберпротект',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'О сервисе', link: '/guide/wikidf/03-iaas/03-5-backup/03-5-3/03-5-3-0-overview.md' },
|
||||
{
|
||||
text: 'Инструкция по работе с сервисом',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: '1. Начало работы с сервисом', link: '/guide/wikidf/03-iaas/03-5-backup/03-5-3/03-5-3-1/03-5-3-1-1.md' },
|
||||
{ text: '2. Резервное копирование агентами', link: '/guide/wikidf/03-iaas/03-5-backup/03-5-3/03-5-3-1/03-5-3-1-2.md' },
|
||||
{ text: '3. Установка и настройка агентов', link: '/guide/wikidf/03-iaas/03-5-backup/03-5-3/03-5-3-1/03-5-3-1-3.md' },
|
||||
{ text: '4. Представления консоли резервного копирования', link: '/guide/wikidf/03-iaas/03-5-backup/03-5-3/03-5-3-1/03-5-3-1-4.md' },
|
||||
{ text: '5. Резервное копирование приложений Microsoft', link: '/guide/wikidf/03-iaas/03-5-backup/03-5-3/03-5-3-1/03-5-3-1-5.md' },
|
||||
{ text: '6. Восстановление: памятка', link: '/guide/wikidf/03-iaas/03-5-backup/03-5-3/03-5-3-1/03-5-3-1-6.md' },
|
||||
{ text: '7. Другие способы восстановления', link: '/guide/wikidf/03-iaas/03-5-backup/03-5-3/03-5-3-1/03-5-3-1-7.md' },
|
||||
{ text: '8. Восстановление из ISO-образа', link: '/guide/wikidf/03-iaas/03-5-backup/03-5-3/03-5-3-1/03-5-3-1-8.md' },
|
||||
{ text: '9. Кроссплатформенная миграция на базе Киберпротект Облачный Бэкап', link: '/guide/wikidf/03-iaas/03-5-backup/03-5-3/03-5-3-1/03-5-3-1-9.md' },
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
text: 'Быстрый старт', link: '/vdc/vdc-getting-started.md'
|
||||
},
|
||||
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
],
|
||||
'/terraform/': [
|
||||
{
|
||||
text: 'Terraform',
|
||||
items: [
|
||||
{
|
||||
text: 'BeeCloud провайдер', link: '/terraform/providers/beecloud/index.md',
|
||||
{ text: 'Виртуальные дата-центры', link: '/vdc/vdc-how-to/vdc-index.md',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{
|
||||
text: 'Облачные вычисления',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{
|
||||
text: 'Источники данных',
|
||||
items: [
|
||||
{ text: 'beecloud_affinity_groups', link: '/terraform/providers/beecloud/compute/data-sources/beecloud_affinity_groups.md' },
|
||||
{ text: 'beecloud_flavors', link: '/terraform/providers/beecloud/compute/data-sources/beecloud_flavors.md' },
|
||||
{ text: 'beecloud_images', link: '/terraform/providers/beecloud/compute/data-sources/beecloud_images.md' },
|
||||
{ text: 'beecloud_regions', link: '/terraform/providers/beecloud/compute/data-sources/beecloud_regions.md' },
|
||||
{ text: 'beecloud_server', link: '/terraform/providers/beecloud/compute/data-sources/beecloud_server.md' },
|
||||
{ text: 'beecloud_servers', link: '/terraform/providers/beecloud/compute/data-sources/beecloud_servers.md' },
|
||||
{ text: 'beecloud_volume', link: '/terraform/providers/beecloud/compute/data-sources/beecloud_volume.md' },
|
||||
{ text: 'beecloud_volumes', link: '/terraform/providers/beecloud/compute/data-sources/beecloud_volumes.md' },
|
||||
{ text: 'Создание дата-центра', link: '/vdc/vdc-how-to/vdc-create.md' },
|
||||
{ text: 'Вход в дата-центр', link: '/vdc/vdc-how-to/vdc-enter.md' },
|
||||
{ text: 'Управление дата-центром', link: '/vdc/vdc-how-to/vdc-manage.md'},
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Ресурсы',
|
||||
items: [
|
||||
{ text: 'beecloud_address_ip', link: '/terraform/providers/beecloud/compute/resources/beecloud_address_ip.md' },
|
||||
{ text: 'beecloud_affinity_group', link: '/terraform/providers/beecloud/compute/resources/beecloud_affinity_group.md' },
|
||||
{ text: 'beecloud_server', link: '/terraform/providers/beecloud/compute/resources/beecloud_server.md' },
|
||||
{ text: 'beecloud_volume_bind', link: '/terraform/providers/beecloud/compute/resources/beecloud_volume_bind.md' },
|
||||
{ text: 'beecloud_volume', link: '/terraform/providers/beecloud/compute/resources/beecloud_volume.md' },
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
text: 'DNS',
|
||||
{ text: 'Виртуальные машины', link: '/vdc/vdc-how-to/vm/vm-index.md',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{
|
||||
text: 'Источники данных',
|
||||
items: [
|
||||
{ text: 'beecloud_dns_records', link: '/terraform/providers/beecloud/dns/data-sources/beecloud_dns_records.md' },
|
||||
{ text: 'beecloud_dns_zones', link: '/terraform/providers/beecloud/dns/data-sources/beecloud_dns_zones.md' },
|
||||
{text: 'Создание ВМ', link: '/vdc/vdc-how-to/vm/create-vm.md'},
|
||||
{text: 'Создание vApp', link: '/vdc/vdc-how-to/vm/create-vapp.md'},
|
||||
{text: 'Клонирование ВМ', link: '/vdc/vdc-how-to/vm/clone-vm.md'},
|
||||
{text: 'Изменение конфигурации ВМ', link: '/vdc/vdc-how-to/vm/edit-vm.md'},
|
||||
{text: 'Удаление ВМ', link: '/vdc/vdc-how-to/vm/delete-vm.md'},
|
||||
{text: 'Группы размещения', link: '/vdc/vdc-how-to/vm/create-affinity-rules.md'},
|
||||
{ text: 'Снимки ВМ', link: '/vdc/vdc-how-to/vm/create-snapshot.md'},
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Ресурсы',
|
||||
items: [
|
||||
{ text: 'beecloud_dns_record', link: '/terraform/providers/beecloud/dns/resources/beecloud_dns_record.md' },
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
text: 'Null провайдер', link: '/terraform/providers/null/index.md',
|
||||
{ text: 'Сети', link: '/vdc/vdc-how-to/networks/networks-index.md',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{
|
||||
text: 'Источники данных',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'null_resource', link: '/terraform/providers/null/resources/null_resource.md' },
|
||||
{text: 'Настройка доступа к ВМ из интернета', link: '/vdc/vdc-how-to/networks/allow-external-connections-to-vm.md'},
|
||||
{text: 'Подключение ВМ в vApp к сети', link: '/vdc/vdc-how-to/networks/connect-vapp-to-network.md'},
|
||||
{text: 'Подключение ВМ к интернету', link: '/vdc/vdc-how-to/networks/connect-vm-to-network.md'},
|
||||
{text: 'Создание сети в организации и подключение к Edge Gateway', link: '/vdc/vdc-how-to/networks/create-network.md'},
|
||||
{text: 'Подключение сети к Edge Gateway', link: '/vdc/vdc-how-to/networks/isolated-to-routed.md'},
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Ресурсы',
|
||||
{ text: 'Пользователи и роли', link: '/vdc/vdc-how-to/users/users-index.md',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'null_data_source', link: '/terraform/providers/null/data-sources/null_data_source.md' },
|
||||
]
|
||||
{text: 'Ролевая модель', link: '/vdc/vdc-how-to/users/roles.md'},
|
||||
{text: 'Создание пользователя', link: '/vdc/vdc-how-to/users/add-user.md'},
|
||||
{text: 'Изменение пароля пользователя', link: '/vdc/vdc-how-to/users/change-users-password.md'},
|
||||
{text: 'Настройка квот', link: '/vdc/vdc-how-to/users/quotas.md'},
|
||||
],
|
||||
},
|
||||
]
|
||||
},
|
||||
{ text: 'Вопросы и ответы', link: '/terraform/faq.md' },
|
||||
{ text: 'Двухфакторная аутентификация', link: '/vdc/vdc-how-to/vdc-2fa.md',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{text: 'Подключение 2FA', link: '/vdc/vdc-how-to/vdc-2fa-start.md'},
|
||||
{text: 'Управление 2FA', link: '/vdc/vdc-how-to/vdc-2fa-manage.md'},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
// { text: 'Тарификация', link: '/vdc/vdc-tarif.md' },
|
||||
'/compute/': [
|
||||
{
|
||||
text: 'Виртуальные машины', link: '/compute/index.md',
|
||||
},
|
||||
{ text: 'Обзор сервиса', link: '/compute/compute-overview.md' },
|
||||
{text: 'Быстрый старт', link: '/compute/compute-getting-started.md'},
|
||||
{ text: 'Виртуальные машины', link: '/compute/compute-how-to/compute-index.md',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'Создание ВМ', link: '/compute/compute-how-to/compute-servers-create.md' },
|
||||
{ text: 'Подключение к ВМ', link: '/compute/compute-how-to/compute-connect-index.md',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'Подключение по SSH к ВМ по внешнему IP-адресу', link: '/compute/compute-how-to/compute-connect-public.md'},
|
||||
{ text: 'Подключение по SSH к ВМ по внутреннему IP-адресу', link: '/compute/compute-how-to/compute-connect-inside.md' },
|
||||
]
|
||||
},
|
||||
{ text: 'Управление ВМ', link: '/compute/compute-how-to/compute-servers-manage.md' },
|
||||
],
|
||||
},
|
||||
{ text: 'Диски', link: '/compute/compute-how-to/compute-disks.md' },
|
||||
{ text: 'IP-адреса', link: '/compute/compute-how-to/compute-ip.md' },
|
||||
{ text: 'Группы размещения', link: '/compute/compute-how-to/compute-affinity.md' },
|
||||
{ text: 'Сети', link: '/compute/compute-how-to/compute-network/compute-network-index.md',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'Настройка site-to-site VPN с помощью VyOS', link: '/compute/compute-how-to/compute-network/compute-vpn-vyos.md' },
|
||||
{ text: 'Подключение ВМ закрытого контура к интернету', link: '/compute/compute-how-to/compute-network/compute-network-inside.md' },
|
||||
],
|
||||
},
|
||||
],
|
||||
'/admin/': [
|
||||
{
|
||||
text: 'Администрирование', link: '/admin/index.md',
|
||||
},
|
||||
{text: 'Управление ключевыми парами', link: '/admin/ssh.md'},
|
||||
],
|
||||
'/billing/': [
|
||||
{ text: 'Биллинг', link: '/billing/about.md',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'Аналитика потребления', link: '/billing/usage-analytics.md' },
|
||||
],
|
||||
},
|
||||
],
|
||||
'/concepts/': [
|
||||
{text: 'Виртуальные дата-центры', link: '/concepts/datacenters.md'},
|
||||
{text: 'DNS', link: '/concepts/dns.md'},
|
||||
{text: 'Edge Gateway', link: '/concepts/edge-gateway.md'},
|
||||
{text: 'NAT', link: '/concepts/nat.md'},
|
||||
{text: 'Типы сетей в vDC', link: '/concepts/network-types.md'},
|
||||
{text: 'Ролевая модель', link: '/concepts/roles.md'},
|
||||
{text: 'vApp', link: '/concepts/vApp.md'},
|
||||
],
|
||||
'/monitoring/': [
|
||||
{
|
||||
text: 'Мониторинг', link: '/monitoring/about.md',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
@@ -106,7 +106,7 @@ export default function(parameters: IParameters) {
|
||||
// window._paq elsewhere when needed, including closure scopes.
|
||||
const _paq = window._paq;
|
||||
// If user requests consent checking, do this before we actually track.
|
||||
// Note: this doesn't work at the moment because the user has no way to set
|
||||
// tip: this doesn't work at the moment because the user has no way to set
|
||||
// whether consent was given. Oops.
|
||||
if (requireConsent) {
|
||||
_paq.push(['requireConsent']);
|
||||
|
||||
@@ -26,6 +26,12 @@ export const overrideComponents = () => (
|
||||
new URL('./theme/components/CustomContent.vue', import.meta.url)
|
||||
)
|
||||
},
|
||||
{
|
||||
find: /^.*\/VPHome\.vue$/,
|
||||
replacement: fileURLToPath(
|
||||
new URL('./theme/components/CustomHome.vue', import.meta.url)
|
||||
)
|
||||
},
|
||||
{
|
||||
find: /^.*\/VPDocFooter\.vue$/,
|
||||
replacement: fileURLToPath(
|
||||
@@ -41,7 +47,7 @@ export const overrideComponents = () => (
|
||||
{
|
||||
find: /^.*\/VPFeature\.vue$/,
|
||||
replacement: fileURLToPath(
|
||||
new URL('./theme/components/CustomFeature.vue', import.meta.url)
|
||||
new URL('./theme/components/CustomHomeFeature.vue', import.meta.url)
|
||||
)
|
||||
},
|
||||
{
|
||||
@@ -62,6 +68,12 @@ export const overrideComponents = () => (
|
||||
new URL('./theme/components/CustomNavBarSearchButton.vue', import.meta.url)
|
||||
)
|
||||
},
|
||||
{
|
||||
find: /^.*\/VPHomeHero\.vue$/,
|
||||
replacement: fileURLToPath(
|
||||
new URL('./theme/components/CustomHomeHero.vue', import.meta.url)
|
||||
)
|
||||
},
|
||||
{
|
||||
find: /^.*\/VPLocalSearchBox\.vue$/,
|
||||
replacement: fileURLToPath(
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<div :class="[$style.CustomFeatureImage, classes]">
|
||||
<CustomIcon :icon="icon" size="large" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Icons } from '@beeline/design-tokens/js/iconfont/icons';
|
||||
import { computed, useCssModule } from 'vue';
|
||||
import CustomIcon from './CustomIcon.vue';
|
||||
|
||||
const { size = 'medium' } = defineProps<{
|
||||
icon: Icons,
|
||||
size?: 'medium' | 'small'
|
||||
}>()
|
||||
|
||||
const style = useCssModule()
|
||||
const classes = computed(() => ({
|
||||
[style.CustomAvatar]: true,
|
||||
[style.CustomAvatarSmall]: size === 'small'
|
||||
}))
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
@use '@beeline/design-tokens/scss/tokens/components/avatar';
|
||||
@use "@beeline/design-tokens/scss/tokens/themes";
|
||||
|
||||
.CustomAvatar {
|
||||
border-radius: avatar.$avatar-squircle-border-radius;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
height: avatar.$avatar-medium-height;
|
||||
width: avatar.$avatar-medium-width;
|
||||
letter-spacing: avatar.$avatar-medium-text-font-letter-spacing;
|
||||
line-height: avatar.$avatar-medium-text-font-line-height;
|
||||
font-size: avatar.$avatar-medium-text-font-size;
|
||||
background-color: themes.$color-status-neutral-background;
|
||||
|
||||
&Small {
|
||||
height: avatar.$avatar-small-height;
|
||||
width: avatar.$avatar-small-width;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -5,7 +5,7 @@ import { EXTERNAL_URL_RE } from 'vitepress/dist/client/shared'
|
||||
|
||||
interface Props {
|
||||
tag?: string
|
||||
size?: 'medium' | 'big'
|
||||
size?: 'medium' | 'big' | 'small'
|
||||
theme?: 'brand' | 'alt' | 'sponsor'
|
||||
text: string
|
||||
href?: string
|
||||
@@ -51,6 +51,15 @@ const component = computed(() => {
|
||||
transition: color 0.1s, border-color 0.1s, background-color 0.1s;
|
||||
}
|
||||
|
||||
.VPButton.small {
|
||||
border-radius: 12px;
|
||||
padding: 0 16px;
|
||||
line-height: 20px;
|
||||
height: 40px;
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.VPButton.medium {
|
||||
border-radius: 12px;
|
||||
padding: 0 20px;
|
||||
|
||||
@@ -11,49 +11,82 @@ const { hasSidebar } = useSidebar()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="VPContent CustomContent"
|
||||
id="VPContent"
|
||||
:class="{
|
||||
<div class="VPContent CustomContent" id="VPContent" :class="{
|
||||
'has-sidebar': hasSidebar,
|
||||
'is-home': frontmatter.layout === 'home'
|
||||
}"
|
||||
>
|
||||
<slot name="not-found" v-if="page.isNotFound"><NotFound /></slot>
|
||||
}">
|
||||
<slot name="not-found" v-if="page.isNotFound">
|
||||
<NotFound />
|
||||
</slot>
|
||||
|
||||
<VPPage v-else-if="frontmatter.layout === 'page'">
|
||||
<template #page-top><slot name="page-top" /></template>
|
||||
<template #page-bottom><slot name="page-bottom" /></template>
|
||||
<template #page-top>
|
||||
<slot name="page-top" />
|
||||
</template>
|
||||
<template #page-bottom>
|
||||
<slot name="page-bottom" />
|
||||
</template>
|
||||
</VPPage>
|
||||
|
||||
<VPHome v-else-if="frontmatter.layout === 'home'">
|
||||
<template #home-hero-before><slot name="home-hero-before" /></template>
|
||||
<template #home-hero-info><slot name="home-hero-info" /></template>
|
||||
<template #home-hero-image><slot name="home-hero-image" /></template>
|
||||
<template #home-hero-after><slot name="home-hero-after" /></template>
|
||||
<template #home-features-before><slot name="home-features-before" /></template>
|
||||
<template #home-features-after><slot name="home-features-after" /></template>
|
||||
<template #home-hero-before>
|
||||
<slot name="home-hero-before" />
|
||||
</template>
|
||||
<template #home-hero-info>
|
||||
<slot name="home-hero-info" />
|
||||
</template>
|
||||
<template #home-hero-image>
|
||||
<slot name="home-hero-image" />
|
||||
</template>
|
||||
<template #home-hero-after>
|
||||
<slot name="home-hero-after" />
|
||||
</template>
|
||||
<template #home-features-before>
|
||||
<slot name="home-features-before" />
|
||||
</template>
|
||||
<template #home-features-after>
|
||||
<slot name="home-features-after" />
|
||||
</template>
|
||||
</VPHome>
|
||||
|
||||
<component
|
||||
v-else-if="frontmatter.layout && frontmatter.layout !== 'doc'"
|
||||
:is="frontmatter.layout"
|
||||
/>
|
||||
<component v-else-if="frontmatter.layout && frontmatter.layout !== 'doc'" :is="frontmatter.layout" />
|
||||
|
||||
<CustomDoc v-else>
|
||||
<template #doc-top><slot name="doc-top" /></template>
|
||||
<template #doc-bottom><slot name="doc-bottom" /></template>
|
||||
<template #doc-top>
|
||||
<slot name="doc-top" />
|
||||
</template>
|
||||
<template #doc-bottom>
|
||||
<slot name="doc-bottom" />
|
||||
</template>
|
||||
|
||||
<template #doc-footer-before><slot name="doc-footer-before" /></template>
|
||||
<template #doc-before><slot name="doc-before" /></template>
|
||||
<template #doc-after><slot name="doc-after" /></template>
|
||||
<template #doc-footer-before>
|
||||
<slot name="doc-footer-before" />
|
||||
</template>
|
||||
<template #doc-before>
|
||||
<slot name="doc-before" />
|
||||
</template>
|
||||
<template #doc-after>
|
||||
<slot name="doc-after" />
|
||||
</template>
|
||||
|
||||
<template #aside-top><slot name="aside-top" /></template>
|
||||
<template #aside-outline-before><slot name="aside-outline-before" /></template>
|
||||
<template #aside-outline-after><slot name="aside-outline-after" /></template>
|
||||
<template #aside-ads-before><slot name="aside-ads-before" /></template>
|
||||
<template #aside-ads-after><slot name="aside-ads-after" /></template>
|
||||
<template #aside-bottom><slot name="aside-bottom" /></template>
|
||||
<template #aside-top>
|
||||
<slot name="aside-top" />
|
||||
</template>
|
||||
<template #aside-outline-before>
|
||||
<slot name="aside-outline-before" />
|
||||
</template>
|
||||
<template #aside-outline-after>
|
||||
<slot name="aside-outline-after" />
|
||||
</template>
|
||||
<template #aside-ads-before>
|
||||
<slot name="aside-ads-before" />
|
||||
</template>
|
||||
<template #aside-ads-after>
|
||||
<slot name="aside-ads-after" />
|
||||
</template>
|
||||
<template #aside-bottom>
|
||||
<slot name="aside-bottom" />
|
||||
</template>
|
||||
</CustomDoc>
|
||||
</div>
|
||||
</template>
|
||||
@@ -82,7 +115,7 @@ const { hasSidebar } = useSidebar()
|
||||
|
||||
.VPContent.has-sidebar {
|
||||
margin: var(--vp-layout-top-height, 0px) 0 0;
|
||||
padding-left: var(--vp-sidebar-width);
|
||||
padding-left: 320px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,11 +5,13 @@ import { useData } from 'vitepress/dist/client/theme-default/composables/data'
|
||||
import { useSidebar } from 'vitepress/dist/client/theme-default/composables/sidebar'
|
||||
import VPDocAside from 'vitepress/dist/client/theme-default/components/VPDocAside.vue'
|
||||
import VPDocFooter from 'vitepress/dist/client/theme-default/components/VPDocFooter.vue'
|
||||
import SectionLinkList from './SectionLinkList/SectionLinkList.vue'
|
||||
|
||||
const { theme } = useData()
|
||||
|
||||
const route = useRoute()
|
||||
const { hasSidebar, hasAside, leftAside } = useSidebar()
|
||||
const { frontmatter } = useData()
|
||||
|
||||
const pageName = computed(() =>
|
||||
route.path.replace(/[./]+/g, '_').replace(/_html$/, '')
|
||||
@@ -17,10 +19,7 @@ const pageName = computed(() =>
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="VPDoc CustomDoc"
|
||||
:class="{ 'has-sidebar': hasSidebar, 'has-aside': hasAside }"
|
||||
>
|
||||
<div class="VPDoc CustomDoc" :class="{ 'has-sidebar': hasSidebar, 'has-aside': hasAside }">
|
||||
<slot name="doc-top" />
|
||||
<div class="container">
|
||||
<div v-if="hasAside" class="aside" :class="{'left-aside': leftAside}">
|
||||
@@ -28,12 +27,24 @@ const pageName = computed(() =>
|
||||
<div class="aside-container">
|
||||
<div class="aside-content">
|
||||
<VPDocAside>
|
||||
<template #aside-top><slot name="aside-top" /></template>
|
||||
<template #aside-bottom><slot name="aside-bottom" /></template>
|
||||
<template #aside-outline-before><slot name="aside-outline-before" /></template>
|
||||
<template #aside-outline-after><slot name="aside-outline-after" /></template>
|
||||
<template #aside-ads-before><slot name="aside-ads-before" /></template>
|
||||
<template #aside-ads-after><slot name="aside-ads-after" /></template>
|
||||
<template #aside-top>
|
||||
<slot name="aside-top" />
|
||||
</template>
|
||||
<template #aside-bottom>
|
||||
<slot name="aside-bottom" />
|
||||
</template>
|
||||
<template #aside-outline-before>
|
||||
<slot name="aside-outline-before" />
|
||||
</template>
|
||||
<template #aside-outline-after>
|
||||
<slot name="aside-outline-after" />
|
||||
</template>
|
||||
<template #aside-ads-before>
|
||||
<slot name="aside-ads-before" />
|
||||
</template>
|
||||
<template #aside-ads-after>
|
||||
<slot name="aside-ads-after" />
|
||||
</template>
|
||||
</VPDocAside>
|
||||
</div>
|
||||
</div>
|
||||
@@ -43,16 +54,16 @@ const pageName = computed(() =>
|
||||
<div class="content-container">
|
||||
<slot name="doc-before" />
|
||||
<main class="main">
|
||||
<Content
|
||||
class="vp-doc"
|
||||
:class="[
|
||||
<Content class="vp-doc" :class="[
|
||||
pageName,
|
||||
theme.externalLinkIcon && 'external-link-icon-enabled'
|
||||
]"
|
||||
/>
|
||||
]" />
|
||||
<SectionLinkList v-if="frontmatter.section_links" :links="frontmatter.section_links" />
|
||||
</main>
|
||||
<VPDocFooter>
|
||||
<template #doc-footer-before><slot name="doc-footer-before" /></template>
|
||||
<template #doc-footer-before>
|
||||
<slot name="doc-footer-before" />
|
||||
</template>
|
||||
</VPDocFooter>
|
||||
<slot name="doc-after" />
|
||||
</div>
|
||||
@@ -62,58 +73,70 @@ const pageName = computed(() =>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
<style scoped lang="scss">
|
||||
@use 'src/assets/scss/app/helpers/media';
|
||||
|
||||
.VPDoc {
|
||||
padding: 32px 24px 96px;
|
||||
width: 100%;
|
||||
|
||||
@include media.media_min(960px) {
|
||||
padding: 48px 32px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.VPDoc {
|
||||
@include media.media_max(768px) {
|
||||
padding: 48px 32px 128px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
.VPDoc {
|
||||
padding: 48px 32px 0;
|
||||
.VPDoc:not(.has-sidebar) .container {
|
||||
@include media.media_min(1440px) {
|
||||
max-width: 1104px;
|
||||
}
|
||||
|
||||
.VPDoc:not(.has-sidebar) .container {
|
||||
display: flex;
|
||||
@include media.media_max(960px) {
|
||||
padding: 0 32px 128px;display: flex;
|
||||
justify-content: center;
|
||||
max-width: 992px;
|
||||
}
|
||||
}
|
||||
|
||||
.VPDoc:not(.has-sidebar) .content {
|
||||
@include media.media_min(1440px) {
|
||||
max-width: 784px;
|
||||
}
|
||||
|
||||
@include media.media_max(960px) {
|
||||
max-width: 752px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1280px) {
|
||||
.VPDoc .container {
|
||||
@include media.media_min(1280px) {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.VPDoc .aside {
|
||||
@include media.media_min(1280px) {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1440px) {
|
||||
.VPDoc:not(.has-sidebar) .content {
|
||||
max-width: 784px;
|
||||
}
|
||||
|
||||
.VPDoc:not(.has-sidebar) .container {
|
||||
max-width: 1104px;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
|
||||
@include media.media_min(1280px) {
|
||||
order: 1;
|
||||
margin: 0;
|
||||
min-width: 640px;
|
||||
}
|
||||
|
||||
@include media.media_max(960px) {
|
||||
padding: 0 32px 128px;
|
||||
}
|
||||
}
|
||||
|
||||
.aside {
|
||||
@@ -169,20 +192,6 @@ const pageName = computed(() =>
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
.content {
|
||||
padding: 0 32px 128px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1280px) {
|
||||
.content {
|
||||
order: 1;
|
||||
margin: 0;
|
||||
min-width: 640px;
|
||||
}
|
||||
}
|
||||
|
||||
.content-container {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import type { DefaultTheme } from 'vitepress/theme'
|
||||
import VPImage from 'vitepress/dist/client/theme-default/components/VPImage.vue'
|
||||
import VPLink from 'vitepress/dist/client/theme-default/components/VPLink.vue'
|
||||
import VPIconArrowRight from 'vitepress/dist/client/theme-default/components/icons/VPIconArrowRight.vue'
|
||||
|
||||
defineProps<{
|
||||
icon?: DefaultTheme.FeatureIcon
|
||||
title: string
|
||||
details?: string
|
||||
link?: string
|
||||
linkText?: string
|
||||
rel?: string
|
||||
target?: string
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VPLink
|
||||
class="VPFeature CustomFeature"
|
||||
:href="link"
|
||||
:rel="rel"
|
||||
:target="target"
|
||||
:no-icon="true"
|
||||
:tag="link ? 'a' : 'div'"
|
||||
>
|
||||
<article class="box">
|
||||
<div v-if="typeof icon === 'object' && icon.wrap" class="icon">
|
||||
<VPImage
|
||||
:image="icon"
|
||||
:alt="icon.alt"
|
||||
:height="icon.height || 48"
|
||||
:width="icon.width || 48"
|
||||
/>
|
||||
</div>
|
||||
<VPImage
|
||||
v-else-if="typeof icon === 'object'"
|
||||
:image="icon"
|
||||
:alt="icon.alt"
|
||||
:height="icon.height || 48"
|
||||
:width="icon.width || 48"
|
||||
/>
|
||||
<div v-else-if="icon" class="icon" v-html="icon"></div>
|
||||
<h2 class="title" v-html="title"></h2>
|
||||
<p v-if="details" class="details" v-html="details"></p>
|
||||
|
||||
<div v-if="linkText" class="link-text">
|
||||
<p class="link-text-value">
|
||||
{{ linkText }} <VPIconArrowRight class="link-text-icon" />
|
||||
</p>
|
||||
</div>
|
||||
</article>
|
||||
</VPLink>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.VPFeature {
|
||||
display: block;
|
||||
border: 1px solid var(--vp-c-bg-soft);
|
||||
border-radius: 12px;
|
||||
height: 100%;
|
||||
background-color: var(--vp-c-bg-soft);
|
||||
transition: border-color 0.25s, background-color 0.25s;
|
||||
}
|
||||
|
||||
.VPFeature.link:hover {
|
||||
border-color: var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
.box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 24px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.box > :deep(.VPImage) {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 6px;
|
||||
background-color: var(--vp-c-default-soft);
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
font-size: 24px;
|
||||
transition: background-color 0.25s;
|
||||
}
|
||||
|
||||
.title {
|
||||
line-height: 24px;
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-active);
|
||||
}
|
||||
|
||||
.details {
|
||||
flex-grow: 1;
|
||||
padding-top: 8px;
|
||||
line-height: 24px;
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-inactive);
|
||||
}
|
||||
|
||||
.link-text {
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
.link-text-value {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
.link-text-icon {
|
||||
display: inline-block;
|
||||
margin-left: 6px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
fill: currentColor;
|
||||
}
|
||||
</style>
|
||||
@@ -1,8 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { type Ref, inject } from 'vue'
|
||||
import { type Ref, inject, ref } from 'vue'
|
||||
import type { DefaultTheme } from 'vitepress/theme'
|
||||
import CustomButton from './CustomButton.vue'
|
||||
import VPImage from 'vitepress/dist/client/theme-default/components/VPImage.vue'
|
||||
import HomeHeroSearchButton from './HomeHeroSearchButton.vue'
|
||||
import VPLocalSearchBox from 'vitepress/dist/client/theme-default/components/VPLocalSearchBox.vue'
|
||||
|
||||
export interface HeroAction {
|
||||
theme?: 'brand' | 'alt'
|
||||
@@ -14,11 +16,14 @@ defineProps<{
|
||||
name?: string
|
||||
text?: string
|
||||
tagline?: string
|
||||
search?: boolean
|
||||
image?: DefaultTheme.ThemeableImage
|
||||
actions?: HeroAction[]
|
||||
}>()
|
||||
|
||||
const heroImageSlotExists = inject('hero-image-slot-exists') as Ref<boolean>
|
||||
|
||||
const showSearch = ref(false)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -27,21 +32,20 @@ const heroImageSlotExists = inject('hero-image-slot-exists') as Ref<boolean>
|
||||
<div class="main">
|
||||
<slot name="home-hero-info">
|
||||
<h1 v-if="name" class="name">
|
||||
<span v-html="name" class="clip"></span>
|
||||
{{ name }}
|
||||
</h1>
|
||||
<p v-if="text" v-html="text" class="text"></p>
|
||||
<p v-if="tagline" v-html="tagline" class="tagline"></p>
|
||||
</slot>
|
||||
|
||||
<div v-if="search" class="VPHeroSearchWrapper">
|
||||
<VPLocalSearchBox v-if="showSearch" @close="showSearch = false" />
|
||||
<HomeHeroSearchButton @click="showSearch = true" />
|
||||
</div>
|
||||
|
||||
<div v-if="actions" class="actions">
|
||||
<div v-for="action in actions" :key="action.link" class="action">
|
||||
<CustomButton
|
||||
tag="a"
|
||||
size="medium"
|
||||
:theme="action.theme"
|
||||
:text="action.text"
|
||||
:href="action.link"
|
||||
/>
|
||||
<CustomButton tag="a" size="medium" :theme="action.theme" :text="action.text" :href="action.link" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -59,20 +63,26 @@ const heroImageSlotExists = inject('hero-image-slot-exists') as Ref<boolean>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use "@beeline/design-tokens/scss/tokens/themes";
|
||||
@use "@beeline/design-tokens/scss/tokens/globals/sizes";
|
||||
@use "@beeline/design-tokens/scss/mixin";
|
||||
|
||||
$topSpacing: 40px;
|
||||
|
||||
.VPHero {
|
||||
margin-top: calc((var(--vp-nav-height) + var(--vp-layout-top-height, 0px)) * -1);
|
||||
padding: calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 48px) 24px 48px;
|
||||
padding: calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + $topSpacing) 24px 48px;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.VPHero {
|
||||
padding: calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 80px) 48px 64px;
|
||||
padding: calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + $topSpacing) 48px 64px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
.VPHero {
|
||||
padding: calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 80px) 64px 64px;
|
||||
padding: calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + $topSpacing) 64px 64px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +90,7 @@ const heroImageSlotExists = inject('hero-image-slot-exists') as Ref<boolean>
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0 auto;
|
||||
max-width: 1152px;
|
||||
max-width: 1080px;
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
@@ -95,18 +105,14 @@ const heroImageSlotExists = inject('hero-image-slot-exists') as Ref<boolean>
|
||||
order: 2;
|
||||
flex-grow: 1;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
background-color: themes.$color-background-secondary;
|
||||
padding: 98px 92px;
|
||||
border-radius: sizes.$size-border-radius-x6;
|
||||
|
||||
.VPHero.has-image .container {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
.VPHero.has-image .container {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
.main {
|
||||
order: 1;
|
||||
@@ -120,11 +126,7 @@ const heroImageSlotExists = inject('hero-image-slot-exists') as Ref<boolean>
|
||||
|
||||
.name,
|
||||
.text {
|
||||
max-width: 392px;
|
||||
letter-spacing: -0.4px;
|
||||
line-height: 40px;
|
||||
font-size: 32px;
|
||||
font-weight: 700;
|
||||
@include mixin.h1;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
@@ -134,7 +136,10 @@ const heroImageSlotExists = inject('hero-image-slot-exists') as Ref<boolean>
|
||||
}
|
||||
|
||||
.name {
|
||||
color: var(--vp-home-hero-name-color);
|
||||
color: themes.$color-text-active;
|
||||
padding-bottom: 40px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.clip {
|
||||
@@ -144,22 +149,7 @@ const heroImageSlotExists = inject('hero-image-slot-exists') as Ref<boolean>
|
||||
-webkit-text-fill-color: var(--vp-home-hero-name-color);
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.name,
|
||||
.text {
|
||||
max-width: 576px;
|
||||
line-height: 56px;
|
||||
font-size: 48px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
.name,
|
||||
.text {
|
||||
line-height: 64px;
|
||||
font-size: 56px;
|
||||
}
|
||||
|
||||
.VPHero.has-image .name,
|
||||
.VPHero.has-image .text {
|
||||
margin: 0;
|
||||
@@ -168,7 +158,6 @@ const heroImageSlotExists = inject('hero-image-slot-exists') as Ref<boolean>
|
||||
|
||||
.tagline {
|
||||
padding-top: 8px;
|
||||
max-width: 392px;
|
||||
line-height: 28px;
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
@@ -183,7 +172,6 @@ const heroImageSlotExists = inject('hero-image-slot-exists') as Ref<boolean>
|
||||
@media (min-width: 640px) {
|
||||
.tagline {
|
||||
padding-top: 12px;
|
||||
max-width: 576px;
|
||||
line-height: 32px;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
<script setup lang="ts">
|
||||
import VPHomeHero from 'vitepress/dist/client/theme-default/components/VPHomeHero.vue'
|
||||
import CustomHomeFeatures from './CustomHomeFeatures.vue';
|
||||
import CustomHomeServices from './CustomHomeServices.vue';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="VPHome CustomHome">
|
||||
<slot name="home-hero-before" />
|
||||
<VPHomeHero>
|
||||
<template #home-hero-info>
|
||||
<slot name="home-hero-info" />
|
||||
</template>
|
||||
<template #home-hero-image>
|
||||
<slot name="home-hero-image" />
|
||||
</template>
|
||||
</VPHomeHero>
|
||||
<slot name="home-hero-after" />
|
||||
|
||||
<slot name="home-features-before" />
|
||||
<CustomHomeFeatures />
|
||||
<slot name="home-features-after" />
|
||||
|
||||
<CustomHomeServices />
|
||||
|
||||
<Content />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.VPHome {
|
||||
padding-bottom: 96px;
|
||||
}
|
||||
|
||||
.VPHome :deep(.VPHomeSponsors) {
|
||||
margin-top: 112px;
|
||||
margin-bottom: -128px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,129 @@
|
||||
<script setup lang="ts">
|
||||
import VPLink from 'vitepress/dist/client/theme-default/components/VPLink.vue'
|
||||
import { computed, useCssModule } from 'vue';
|
||||
import { NAVBAR_HEIGHT } from '../constants'
|
||||
import { Icons } from '@beeline/design-tokens/js/iconfont/icons'
|
||||
import CustomAvatar from './CustomAvatar.vue';
|
||||
|
||||
const { disabled, scrollTo, link, items } = defineProps<{
|
||||
icon: string
|
||||
title: string
|
||||
link?: string
|
||||
scrollTo?: string
|
||||
disabled?: boolean
|
||||
items?: ItemFeature[]
|
||||
}>()
|
||||
|
||||
type ItemFeature = {
|
||||
title: string
|
||||
link?: string
|
||||
}
|
||||
|
||||
const style = useCssModule()
|
||||
const classes = computed(() => ({
|
||||
[style.CustomFeature]: true,
|
||||
[style.CustomFeatureDisabled]: disabled || !link && !scrollTo,
|
||||
}))
|
||||
|
||||
const handleClick = (event: Event) => {
|
||||
if (scrollTo) {
|
||||
const targetElTop = document.querySelector(scrollTo)?.getBoundingClientRect().top
|
||||
|
||||
if (targetElTop) {
|
||||
event.stopPropagation()
|
||||
window.scrollTo({ behavior: 'smooth', top: targetElTop + window.scrollY - NAVBAR_HEIGHT - 32 })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Component :is="!disabled && link ? VPLink : 'article'"
|
||||
:class="classes" @click="handleClick">
|
||||
<CustomAvatar :class="$style.CustomFeatureIcon" :icon="icon as Icons" />
|
||||
|
||||
<div :class="$style.CustomFeatureContent">
|
||||
<Component :is="!disabled && link ? VPLink : 'article'" v-bind="{ ...(!disabled && link && { href: link }) }">
|
||||
<p :class="$style.CustomFeatureTitle" :href="`/docs${link}`">
|
||||
{{ title }}
|
||||
</p>
|
||||
</Component>
|
||||
<div :class="$style.CustomFeatureContainer">
|
||||
<div v-for="(item, i) in items" :key="i">
|
||||
<Component
|
||||
:is="!disabled && item.link ? VPLink : 'article'"
|
||||
v-bind="{ ...(!disabled && item.link && { href: item.link }) }"
|
||||
:class="{ [style.CustomFeatureDisabled]: disabled || !item.link }"
|
||||
>
|
||||
<p :class="$style.CustomFeatureSubtitle">{{ item.title }}</p>
|
||||
</Component>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Component>
|
||||
</template>
|
||||
|
||||
<style lang="scss" module>
|
||||
@use "@beeline/design-tokens/scss/tokens/globals/sizes";
|
||||
@use "@beeline/design-tokens/scss/tokens/themes";
|
||||
@use "@beeline/design-tokens/scss/mixin";
|
||||
|
||||
.CustomFeature {
|
||||
$el: &;
|
||||
border-radius: sizes.$size-border-radius-x6;
|
||||
border: 1px solid themes.$color-border;
|
||||
max-width: 344px;
|
||||
padding: sizes.$size-spacing-x8 sizes.$size-spacing-x6;
|
||||
|
||||
&WithScroll {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&Icon {
|
||||
#{$el}Disabled & {
|
||||
color: themes.$color-text-disabled;
|
||||
}
|
||||
}
|
||||
|
||||
&Content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-top: sizes.$size-spacing-x4;
|
||||
gap: sizes.$size-spacing-x6;
|
||||
}
|
||||
|
||||
&Title {
|
||||
@include mixin.h4;
|
||||
color: themes.$color-text-active;
|
||||
|
||||
&:hover {
|
||||
color: themes.$color-text-link;
|
||||
}
|
||||
|
||||
#{$el}Disabled & {
|
||||
color: themes.$color-text-disabled;
|
||||
}
|
||||
}
|
||||
|
||||
&Subtitle {
|
||||
@include mixin.caption;
|
||||
|
||||
&:hover {
|
||||
color: themes.$color-text-link;
|
||||
}
|
||||
|
||||
#{$el}Disabled & {
|
||||
color: themes.$color-text-disabled;
|
||||
}
|
||||
|
||||
#{$el}WithScroll & {
|
||||
color: themes.$color-text-active;
|
||||
}
|
||||
}
|
||||
|
||||
&Container {
|
||||
display: flex;
|
||||
gap: sizes.$size-spacing-x4;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,26 @@
|
||||
<script setup lang="ts">
|
||||
import { useData } from 'vitepress'
|
||||
import CustomHomeFeature from './CustomHomeFeature.vue'
|
||||
|
||||
const { frontmatter } = useData()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="Array.isArray(frontmatter.features)" :class="$style.HomeFeatures">
|
||||
<CustomHomeFeature v-for="feature in frontmatter.features" :key="feature.title" :title="feature.title"
|
||||
:icon="feature.icon" :link="feature.link" :scrollTo="feature.scroll_to" :disabled="feature.disabled" :items="feature.items" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" module>
|
||||
@use "@beeline/design-tokens/scss/tokens/globals/sizes";
|
||||
|
||||
.HomeFeatures {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: sizes.$size-spacing-x8 sizes.$size-spacing-x6;
|
||||
max-width: 1080px;
|
||||
margin: 0 auto;
|
||||
margin-bottom: 80px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,18 @@
|
||||
<script setup lang="ts">
|
||||
import { useData } from 'vitepress/dist/client/theme-default/composables/data'
|
||||
import VPHero from 'vitepress/dist/client/theme-default/components/VPHero.vue'
|
||||
|
||||
const { frontmatter: fm } = useData()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VPHero v-if="fm.hero" class="CustomHomeHero" :name="fm.hero.name" :text="fm.hero.text" :tagline="fm.hero.tagline"
|
||||
:search="fm.hero.search" :image="fm.hero.image" :actions="fm.hero.actions">
|
||||
<template #home-hero-info>
|
||||
<slot name="home-hero-info" />
|
||||
</template>
|
||||
<template #home-hero-image>
|
||||
<slot name="home-hero-image" />
|
||||
</template>
|
||||
</VPHero>
|
||||
</template>
|
||||
@@ -0,0 +1,109 @@
|
||||
<template>
|
||||
<div :class="$style.CustomHomeServiceCard">
|
||||
<h3 :class="$style.CustomHomeServiceCardTitle">{{ title }}</h3>
|
||||
|
||||
<div :class="$style.CustomHomeServiceCardLinks">
|
||||
<Component v-for="article in articles" :is="!article.disabled && article.link ? VPLink : 'div'"
|
||||
v-bind="{ ...(!article.disabled && article.link && { href: article.link }) }"
|
||||
:class="[$style.CustomHomeServiceCardLink, { [$style.CustomHomeServiceCardLinkDisabled]: article.disabled || !article.link }]">
|
||||
<div :class="$style.CustomHomeServiceCardLinkTitle">
|
||||
<div :class="[$style.CustomHomeServiceCardLinkTitleIcon, { [$style.CustomHomeServiceCardLinkTitleIconActive] : article.link && article.icon === 'magic' }]">
|
||||
<CustomIcon :icon="(article.icon || 'cloud') as Icons" />
|
||||
</div>
|
||||
<div :class="[$style.CustomHomeServiceCardLinkTitleText, { [$style.CustomHomeServiceCardLinkTitleTextActive]: article.link }]">
|
||||
{{ article.title }}
|
||||
</div>
|
||||
</div>
|
||||
<div :class="$style.CustomHomeServiceCardLinkDescription">
|
||||
{{ article.description }}
|
||||
</div>
|
||||
</Component>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import VPLink from 'vitepress/dist/client/theme-default/components/VPLink.vue'
|
||||
import CustomIcon from './CustomIcon.vue'
|
||||
import { Icons } from '@beeline/design-tokens/js/iconfont/icons'
|
||||
|
||||
export type ServiceArticle = {
|
||||
title: string
|
||||
description: string
|
||||
icon: string
|
||||
link?: string
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
defineProps<{
|
||||
title: string
|
||||
articles: ServiceArticle[]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
@use "@beeline/design-tokens/scss/tokens/globals/sizes";
|
||||
@use "@beeline/design-tokens/scss/tokens/themes";
|
||||
@use "@beeline/design-tokens/scss/mixin";
|
||||
|
||||
.CustomHomeServiceCard {
|
||||
background-color: themes.$color-background-secondary;
|
||||
border-radius: sizes.$size-border-radius-x6;
|
||||
padding: sizes.$size-spacing-x8 sizes.$size-spacing-x6;
|
||||
|
||||
&Title {
|
||||
@include mixin.h4();
|
||||
color: themes.$color-text-active;
|
||||
margin-bottom: sizes.$size-spacing-x6;
|
||||
}
|
||||
|
||||
&Links {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: sizes.$size-spacing-x6;
|
||||
}
|
||||
|
||||
&Link {
|
||||
$iconRightSpacing: 8px;
|
||||
$iconSize: 20px;
|
||||
$el: &;
|
||||
|
||||
color: themes.$color-text-active !important;
|
||||
|
||||
&Disabled {
|
||||
color: themes.$color-text-disabled !important;
|
||||
}
|
||||
|
||||
&Title {
|
||||
margin-bottom: sizes.$size-spacing-x1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&Icon {
|
||||
width: $iconSize;
|
||||
height: $iconSize;
|
||||
margin-right: $iconRightSpacing;
|
||||
|
||||
&Active {
|
||||
color: themes.$color-text-link;
|
||||
}
|
||||
}
|
||||
|
||||
&Text {
|
||||
@include mixin.subtitle2;
|
||||
|
||||
&Active:hover {
|
||||
color: themes.$color-text-link;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&Description {
|
||||
padding-left: calc($iconSize + $iconRightSpacing);
|
||||
color: themes.$color-text-inactive;
|
||||
@include mixin.caption;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<div :class="$style.CustomHomeServices">
|
||||
<h2 id="home-services-section-title" :class="$style.CustomHomeServicesTitle">Документация по сервисам</h2>
|
||||
|
||||
<div v-if="Array.isArray(frontmatter.services)" :class="$style.CustomHomeServicesList">
|
||||
<CustomHomeServiceCard v-for="service in frontmatter.services" :key="service.title" :title="service.title"
|
||||
:articles="service.articles" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useData } from 'vitepress';
|
||||
import CustomHomeServiceCard from './CustomHomeServiceCard.vue';
|
||||
|
||||
const { frontmatter } = useData()
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
@use "@beeline/design-tokens/scss/tokens/globals/sizes";
|
||||
@use "@beeline/design-tokens/scss/tokens/themes";
|
||||
@use "@beeline/design-tokens/scss/mixin";
|
||||
|
||||
.CustomHomeServices {
|
||||
max-width: 1080px;
|
||||
margin: 0 auto;
|
||||
|
||||
&Title {
|
||||
@include mixin.h2;
|
||||
text-align: center;
|
||||
margin-bottom: 40px;
|
||||
color: themes.$color-text-active;
|
||||
}
|
||||
|
||||
&List {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: sizes.$size-spacing-x6;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,36 @@
|
||||
<template>
|
||||
<i :class="['beeline-icons', `beeline-icons-${icon}`, classes]"></i>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Icons } from '@beeline/design-tokens/js/iconfont/icons';
|
||||
import { computed, useCssModule } from 'vue';
|
||||
|
||||
const { size = 'medium' } = defineProps<{
|
||||
icon: Icons,
|
||||
size?: 'large' | 'medium' | 'small'
|
||||
}>()
|
||||
|
||||
const style = useCssModule()
|
||||
const classes = computed(() => ({
|
||||
[style.CustomIcon]: true,
|
||||
[style.CustomIconLarge]: size === 'large',
|
||||
[style.CustomIconSmall]: size === 'small'
|
||||
}))
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
@use "@beeline/design-tokens/scss/tokens/components/icon";
|
||||
|
||||
.CustomIcon {
|
||||
font-size: icon.$icon-medium-size !important;
|
||||
|
||||
&Large {
|
||||
font-size: icon.$icon-large-size !important;
|
||||
}
|
||||
|
||||
&Small {
|
||||
font-size: icon.$icon-small-size !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
useSessionStorage
|
||||
} from '@vueuse/core'
|
||||
import { useFocusTrap } from '@vueuse/integrations/useFocusTrap'
|
||||
import Mark from 'mark.js/src/vanilla.js'
|
||||
import Mark from 'mark.js/dist/mark'
|
||||
import MiniSearch, { type SearchResult } from 'minisearch'
|
||||
import { dataSymbol, inBrowser, useRouter } from 'vitepress'
|
||||
import {
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
nextTick,
|
||||
onBeforeUnmount,
|
||||
onMounted,
|
||||
Raw,
|
||||
ref,
|
||||
shallowRef,
|
||||
watch,
|
||||
@@ -132,6 +133,7 @@ watchEffect(() => {
|
||||
const results: Ref<(SearchResult & Result)[]> = shallowRef([])
|
||||
|
||||
const enableNoResults = ref(false)
|
||||
const loadig = ref(true)
|
||||
|
||||
watch(filterText, () => {
|
||||
enableNoResults.value = false
|
||||
@@ -160,11 +162,7 @@ debouncedWatch(
|
||||
if (!index) return
|
||||
|
||||
// Search
|
||||
results.value = index
|
||||
.search(filterTextValue)
|
||||
.slice(0, 16) as (SearchResult & Result)[]
|
||||
enableNoResults.value = true
|
||||
|
||||
retrySearch(index, filterTextValue)
|
||||
// Highlighting
|
||||
const mods = showDetailedListValue
|
||||
? await Promise.all(results.value.map((r) => fetchExcerpt(r.id)))
|
||||
@@ -268,6 +266,16 @@ function focusSearchInput(select = true) {
|
||||
select && searchInput.value?.select()
|
||||
}
|
||||
|
||||
const retrySearch = (index: Raw<MiniSearch<Result>>, filter: string) => {
|
||||
if (!index) return
|
||||
|
||||
results.value = index
|
||||
.search(filter)
|
||||
.slice(0, 16) as (SearchResult & Result)[]
|
||||
|
||||
enableNoResults.value = true
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
focusSearchInput()
|
||||
})
|
||||
@@ -481,33 +489,6 @@ function formMarkRegex(terms: Set<string>) {
|
||||
class="search-input"
|
||||
/>
|
||||
<div class="search-actions">
|
||||
<button
|
||||
v-if="!disableDetailedView"
|
||||
class="toggle-layout-button"
|
||||
type="button"
|
||||
:class="{ 'detailed-list': showDetailedList }"
|
||||
:title="$t('modal.displayDetails')"
|
||||
@click="
|
||||
selectedIndex > -1 && (showDetailedList = !showDetailedList)
|
||||
"
|
||||
>
|
||||
<svg
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 24 24"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M3 14h7v7H3zM3 3h7v7H3zm11 1h7m-7 5h7m-7 6h7m-7 5h7"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="clear-button"
|
||||
type="reset"
|
||||
@@ -535,6 +516,7 @@ function formMarkRegex(terms: Set<string>) {
|
||||
</form>
|
||||
|
||||
<ul
|
||||
v-if="!!results.length"
|
||||
ref="resultsEl"
|
||||
:id="results?.length ? 'localsearch-list' : undefined"
|
||||
:role="results?.length ? 'listbox' : undefined"
|
||||
@@ -561,29 +543,21 @@ function formMarkRegex(terms: Set<string>) {
|
||||
>
|
||||
<div>
|
||||
<div class="titles">
|
||||
<span class="title-icon">#</span>
|
||||
<span
|
||||
v-for="(t, index) in p.titles"
|
||||
:key="index"
|
||||
class="title"
|
||||
>
|
||||
<span class="text" v-html="t" />
|
||||
<svg width="18" height="18" viewBox="0 0 24 24">
|
||||
<path
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="m9 18l6-6l-6-6"
|
||||
/>
|
||||
</svg>
|
||||
<span class="text"> > </span>
|
||||
</span>
|
||||
<span class="title main">
|
||||
<span class="text" v-html="p.title" />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<span v-html="p.title" />
|
||||
|
||||
<div v-if="showDetailedList" class="excerpt-wrapper">
|
||||
<div v-if="p.text" class="excerpt" inert>
|
||||
<div class="vp-doc" v-html="p.text" />
|
||||
@@ -594,65 +568,21 @@ function formMarkRegex(terms: Set<string>) {
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li
|
||||
v-if="filterText && !results.length && enableNoResults"
|
||||
</ul>
|
||||
<ul
|
||||
v-else-if="filterText && !results.length && enableNoResults"
|
||||
class="no-results"
|
||||
>
|
||||
{{ $t('modal.noResultsText') }} "<strong>{{ filterText }}</strong
|
||||
>"
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="search-keyboard-shortcuts">
|
||||
<span>
|
||||
<kbd :aria-label="$t('modal.footer.navigateUpKeyAriaLabel')">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24">
|
||||
<path
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 19V5m-7 7l7-7l7 7"
|
||||
/>
|
||||
</svg>
|
||||
</kbd>
|
||||
<kbd :aria-label="$t('modal.footer.navigateDownKeyAriaLabel')">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24">
|
||||
<path
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 5v14m7-7l-7 7l-7-7"
|
||||
/>
|
||||
</svg>
|
||||
</kbd>
|
||||
{{ $t('modal.footer.navigateText') }}
|
||||
</span>
|
||||
<span>
|
||||
<kbd :aria-label="$t('modal.footer.selectKeyAriaLabel')">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24">
|
||||
<g
|
||||
fill="none"
|
||||
stroke="currentcolor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
<p class="no-results-text">
|
||||
{{ $t('modal.noResultsText') }}
|
||||
</p>
|
||||
<button
|
||||
class="no-results-button"
|
||||
@click="retrySearch(searchIndex, filterText)"
|
||||
>
|
||||
<path d="m9 10l-5 5l5 5" />
|
||||
<path d="M20 4v7a4 4 0 0 1-4 4H4" />
|
||||
</g>
|
||||
</svg>
|
||||
</kbd>
|
||||
{{ $t('modal.footer.selectText') }}
|
||||
</span>
|
||||
<span>
|
||||
<kbd :aria-label="$t('modal.footer.closeKeyAriaLabel')">esc</kbd>
|
||||
{{ $t('modal.footer.closeText') }}
|
||||
</span>
|
||||
</div>
|
||||
Попробовать еще раз
|
||||
</button>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</Teleport>
|
||||
@@ -675,16 +605,13 @@ function formMarkRegex(terms: Set<string>) {
|
||||
|
||||
.shell {
|
||||
position: relative;
|
||||
padding: 12px;
|
||||
padding: 24px;
|
||||
margin: 64px auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
background: var(--vp-local-search-bg);
|
||||
width: min(100vw - 60px, 900px);
|
||||
height: min-content;
|
||||
max-height: min(100vh - 128px, 900px);
|
||||
border-radius: 6px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
@@ -698,7 +625,7 @@ function formMarkRegex(terms: Set<string>) {
|
||||
}
|
||||
|
||||
.search-bar {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border: 1px solid rgb(32, 33, 35);
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -712,10 +639,6 @@ function formMarkRegex(terms: Set<string>) {
|
||||
}
|
||||
}
|
||||
|
||||
.search-bar:focus-within {
|
||||
border-color: var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
margin: 8px;
|
||||
}
|
||||
@@ -802,27 +725,31 @@ function formMarkRegex(terms: Set<string>) {
|
||||
}
|
||||
|
||||
.results {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
overscroll-behavior: contain;
|
||||
box-shadow: var(--vp-c-shadow-3);
|
||||
border-radius: 12px;
|
||||
border: 1px solid rgba(25, 28, 52, 0.18);
|
||||
padding: 8px 0;
|
||||
max-height: min(100vh - 214px, 900px);
|
||||
|
||||
li:hover {
|
||||
background-color: rgba(25, 28, 52, 0.08);
|
||||
}
|
||||
}
|
||||
|
||||
.result {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
border-radius: 12px;
|
||||
transition: none;
|
||||
line-height: 1rem;
|
||||
border: solid 2px var(--vp-local-search-result-border);
|
||||
outline: none;
|
||||
height: 66px;
|
||||
}
|
||||
|
||||
.result > div {
|
||||
margin: 12px;
|
||||
margin: 12px 16px;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -840,6 +767,13 @@ function formMarkRegex(terms: Set<string>) {
|
||||
position: relative;
|
||||
z-index: 1001;
|
||||
padding: 2px 0;
|
||||
font-size: 13px !important;
|
||||
line-height: 16px !important;
|
||||
}
|
||||
|
||||
:deep(mark) {
|
||||
background-color: transparent;
|
||||
color: none;
|
||||
}
|
||||
|
||||
.title {
|
||||
@@ -852,21 +786,10 @@ function formMarkRegex(terms: Set<string>) {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.title-icon {
|
||||
opacity: 0.5;
|
||||
font-weight: 500;
|
||||
color: var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
.title svg {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.result.selected {
|
||||
--vp-local-search-result-bg: var(--vp-local-search-result-selected-bg);
|
||||
border-color: var(--vp-local-search-result-selected-border);
|
||||
}
|
||||
|
||||
.excerpt-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
@@ -892,10 +815,7 @@ function formMarkRegex(terms: Set<string>) {
|
||||
|
||||
.titles :deep(mark),
|
||||
.excerpt :deep(mark) {
|
||||
background-color: var(--vp-local-search-highlight-bg);
|
||||
color: var(--vp-local-search-highlight-text);
|
||||
border-radius: 2px;
|
||||
padding: 0 2px;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.excerpt :deep(.vp-code-group) .tabs {
|
||||
@@ -932,12 +852,42 @@ function formMarkRegex(terms: Set<string>) {
|
||||
}
|
||||
|
||||
.no-results {
|
||||
font-size: 0.9rem;
|
||||
text-align: center;
|
||||
padding: 12px;
|
||||
padding: 28px 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
align-items: center;
|
||||
z-index: 100;
|
||||
box-shadow: 0 0 10 0 rgba(0, 0, 0, 0.16);
|
||||
border-radius: 12px;
|
||||
border: 1px solid rgba(25, 28, 52, 0.18);
|
||||
background-color: rgb(255, 255, 255);
|
||||
}
|
||||
|
||||
.no-results-text {
|
||||
font-weight: 700;
|
||||
font-size: 17px;
|
||||
line-height: 22px;
|
||||
letter-spacing: 0.2px;
|
||||
}
|
||||
|
||||
.no-results-button {
|
||||
border-radius: 12px;
|
||||
border: 1px solid rgba(25, 28, 52, 0.18);
|
||||
padding: 13px 20px;
|
||||
font-weight: 500;
|
||||
font-size: 17px;
|
||||
line-height: 22px;
|
||||
letter-spacing: 0.2px;
|
||||
}
|
||||
|
||||
svg {
|
||||
flex: none;
|
||||
}
|
||||
|
||||
.text {
|
||||
font-size: 13px !important;
|
||||
line-height: 16px !important;
|
||||
color: rgba(25, 28, 52, 0.48);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -12,6 +12,7 @@ import VPNavBarSearch from 'vitepress/dist/client/theme-default/components/VPNav
|
||||
import VPNavBarSocialLinks from 'vitepress/dist/client/theme-default/components/VPNavBarSocialLinks.vue'
|
||||
import CustomNavBarTitle from './CustomNavBarTitle.vue'
|
||||
import VPNavBarTranslations from 'vitepress/dist/client/theme-default/components/VPNavBarTranslations.vue'
|
||||
import CustomButton from './CustomButton.vue'
|
||||
|
||||
defineProps<{
|
||||
isScreenOpen: boolean
|
||||
@@ -27,6 +28,7 @@ const { hasLocalNav } = useLocalNav()
|
||||
const { frontmatter } = useData()
|
||||
|
||||
const classes = ref<Record<string, boolean>>({})
|
||||
const loginUrl = import.meta.env.VITE_LOGIN_URL
|
||||
|
||||
watchPostEffect(() => {
|
||||
classes.value = {
|
||||
@@ -43,22 +45,21 @@ watchPostEffect(() => {
|
||||
<div class="container">
|
||||
<div class="title">
|
||||
<CustomNavBarTitle>
|
||||
<template #nav-bar-title-before><slot name="nav-bar-title-before" /></template>
|
||||
<template #nav-bar-title-after><slot name="nav-bar-title-after" /></template>
|
||||
<template #nav-bar-title-before>
|
||||
<slot name="nav-bar-title-before" />
|
||||
</template>
|
||||
<template #nav-bar-title-after>
|
||||
<slot name="nav-bar-title-after" />
|
||||
</template>
|
||||
</CustomNavBarTitle>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div class="content-body">
|
||||
<slot name="nav-bar-content-before" />
|
||||
<VPNavBarSearch class="search" />
|
||||
<VPNavBarMenu class="menu" />
|
||||
<VPNavBarTranslations class="translations" />
|
||||
<VPNavBarAppearance class="appearance" />
|
||||
<VPNavBarSocialLinks class="social-links" />
|
||||
<VPNavBarExtra class="extra" />
|
||||
<slot name="nav-bar-content-after" />
|
||||
<VPNavBarHamburger class="hamburger" :active="isScreenOpen" @click="$emit('toggle-screen')" />
|
||||
<VPNavBarSearch class="search" />
|
||||
<!-- <CustomButton text="Войти" size="small" :href="loginUrl" /> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -105,7 +106,7 @@ watchPostEffect(() => {
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.wrapper {
|
||||
padding: 0 32px;
|
||||
padding: 0 24px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,7 +175,7 @@ watchPostEffect(() => {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
padding-right: 32px;
|
||||
padding-left: var(--vp-sidebar-width);
|
||||
padding-left: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,7 +188,7 @@ watchPostEffect(() => {
|
||||
|
||||
.content-body {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: var(--vp-nav-height);
|
||||
transition: background-color 0.5s;
|
||||
@@ -221,6 +222,10 @@ watchPostEffect(() => {
|
||||
height: 24px;
|
||||
background-color: var(--vp-c-divider);
|
||||
content: "";
|
||||
font-weight: 500;
|
||||
font-size: 15px;
|
||||
line-height: 20px;
|
||||
letter-spacing: 0.2px;
|
||||
}
|
||||
|
||||
.menu + .appearance::before,
|
||||
@@ -251,4 +256,9 @@ watchPostEffect(() => {
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.search {
|
||||
justify-content: flex-end;
|
||||
margin-right: 24px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3,12 +3,16 @@ import type { DefaultTheme } from 'vitepress/theme'
|
||||
import { useData } from 'vitepress/dist/client/theme-default/composables/data'
|
||||
import { isActive } from 'vitepress/dist/client/shared'
|
||||
import VPLink from 'vitepress/dist/client/theme-default/components/VPLink.vue'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
defineProps<{
|
||||
item: DefaultTheme.NavItemWithLink
|
||||
}>()
|
||||
|
||||
const { page } = useData()
|
||||
const textRef = ref<HTMLElement | null>(null)
|
||||
|
||||
const wrapperWidth = computed(() => textRef.value?.offsetWidth)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -20,22 +24,32 @@ const { page } = useData()
|
||||
page.relativePath,
|
||||
item.activeMatch || item.link,
|
||||
!!item.activeMatch
|
||||
)
|
||||
),
|
||||
disabled: !isActive(
|
||||
page.relativePath,
|
||||
item.activeMatch || item.link,
|
||||
!!item.activeMatch
|
||||
) && !item.link ? 'disabled' : '',
|
||||
}"
|
||||
:href="item.link"
|
||||
:target="item.target"
|
||||
:rel="item.rel"
|
||||
tabindex="0"
|
||||
>
|
||||
<span v-html="item.text"></span>
|
||||
<span
|
||||
ref="textRef"
|
||||
v-html="item.text"
|
||||
/>
|
||||
</VPLink>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
<style lang="scss" scoped>
|
||||
@use '@beeline/design-tokens/scss/tokens/globals/colors';
|
||||
|
||||
.VPNavBarMenuLink {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 12px;
|
||||
padding: 0 24px;
|
||||
line-height: var(--vp-nav-height);
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
@@ -45,9 +59,32 @@ const { page } = useData()
|
||||
|
||||
.VPNavBarMenuLink.active {
|
||||
color: var(--color-text-active);
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
content: '';
|
||||
height: 4px;
|
||||
display: none;
|
||||
width: calc(v-bind(wrapperWidth) * 1px);
|
||||
border-top-left-radius: 12px;
|
||||
border-top-right-radius: 12px;
|
||||
background-color: colors.$color-background-brand;
|
||||
}
|
||||
|
||||
.VPNavBarMenuLink:hover {
|
||||
&.active {
|
||||
&::after {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.disabled {
|
||||
opacity: 0.45;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.VPNavBarMenuLink:hover:not(.disabled) {
|
||||
color: var(--color-text-active);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -14,8 +14,6 @@ const $t = createSearchTranslate(defaultTranslations)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button type="button" class="DocSearch DocSearch-Button CustomDocSearch-Button" :aria-label="$t('button.buttonAriaLabel')">
|
||||
<span class="DocSearch-Button-Container">
|
||||
<svg
|
||||
class="DocSearch-Search-Icon"
|
||||
width="20"
|
||||
@@ -32,13 +30,6 @@ const $t = createSearchTranslate(defaultTranslations)
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
<span class="DocSearch-Button-Placeholder">{{ $t('button.buttonText') }}</span>
|
||||
</span>
|
||||
<span class="DocSearch-Button-Keys">
|
||||
<kbd class="DocSearch-Button-Key"></kbd>
|
||||
<kbd class="DocSearch-Button-Key">K</kbd>
|
||||
</span>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
@@ -65,156 +56,13 @@ const $t = createSearchTranslate(defaultTranslations)
|
||||
--docsearch-hit-shadow: none;
|
||||
}
|
||||
|
||||
.DocSearch-Button {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 12px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 48px;
|
||||
height: 55px;
|
||||
background: transparent;
|
||||
transition: border-color 0.25s;
|
||||
}
|
||||
|
||||
.DocSearch-Button:hover {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.DocSearch-Button:focus {
|
||||
outline: 1px dotted;
|
||||
outline: 5px auto -webkit-focus-ring-color;
|
||||
}
|
||||
|
||||
.DocSearch-Button:focus:not(:focus-visible) {
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.DocSearch-Button {
|
||||
justify-content: flex-start;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 12px;
|
||||
padding: 0 10px 0 12px;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
background-color: var(--vp-c-bg-alt);
|
||||
}
|
||||
|
||||
.DocSearch-Button:hover {
|
||||
border-color: var(--vp-c-brand-1);
|
||||
background: var(--vp-c-bg-alt);
|
||||
}
|
||||
}
|
||||
|
||||
.DocSearch-Button .DocSearch-Button-Container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.DocSearch-Button .DocSearch-Search-Icon {
|
||||
.DocSearch-Search-Icon {
|
||||
position: relative;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
color: var(--vp-c-text-1);
|
||||
fill: currentColor;
|
||||
transition: color 0.5s;
|
||||
}
|
||||
|
||||
.DocSearch-Button:hover .DocSearch-Search-Icon {
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.DocSearch-Button .DocSearch-Search-Icon {
|
||||
top: 1px;
|
||||
margin-right: 8px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
}
|
||||
|
||||
.DocSearch-Button .DocSearch-Button-Placeholder {
|
||||
display: none;
|
||||
margin-top: 2px;
|
||||
padding: 0 16px 0 0;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--vp-c-text-2);
|
||||
transition: color 0.5s;
|
||||
}
|
||||
|
||||
.DocSearch-Button:hover .DocSearch-Button-Placeholder {
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.DocSearch-Button .DocSearch-Button-Placeholder {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.DocSearch-Button .DocSearch-Button-Keys {
|
||||
/*rtl:ignore*/
|
||||
direction: ltr;
|
||||
display: none;
|
||||
min-width: auto;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.DocSearch-Button .DocSearch-Button-Keys {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.DocSearch-Button .DocSearch-Button-Key {
|
||||
display: block;
|
||||
margin: 2px 0 0 0;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
/*rtl:begin:ignore*/
|
||||
border-right: none;
|
||||
border-radius: 4px 0 0 4px;
|
||||
padding-left: 6px;
|
||||
/*rtl:end:ignore*/
|
||||
min-width: 0;
|
||||
width: auto;
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
font-family: var(--vp-font-family-base);
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
transition: color 0.5s, border-color 0.5s;
|
||||
}
|
||||
|
||||
.DocSearch-Button .DocSearch-Button-Key + .DocSearch-Button-Key {
|
||||
/*rtl:begin:ignore*/
|
||||
border-right: 1px solid var(--vp-c-divider);
|
||||
border-left: none;
|
||||
border-radius: 0 4px 4px 0;
|
||||
padding-left: 2px;
|
||||
padding-right: 6px;
|
||||
/*rtl:end:ignore*/
|
||||
}
|
||||
|
||||
.DocSearch-Button .DocSearch-Button-Key:first-child {
|
||||
font-size: 0 !important;
|
||||
}
|
||||
|
||||
.DocSearch-Button .DocSearch-Button-Key:first-child:after {
|
||||
content: 'Ctrl';
|
||||
font-size: 12px;
|
||||
letter-spacing: normal;
|
||||
color: var(--docsearch-muted-color);
|
||||
}
|
||||
|
||||
.mac .DocSearch-Button .DocSearch-Button-Key:first-child:after {
|
||||
content: '\2318';
|
||||
}
|
||||
|
||||
.DocSearch-Button .DocSearch-Button-Key:first-child > * {
|
||||
display: none;
|
||||
margin: 8px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -38,10 +38,10 @@ const target = computed(() =>
|
||||
:target="target"
|
||||
>
|
||||
<slot name="nav-bar-title-before" />
|
||||
<VPImage v-if="theme.logo" class="logo" :image="theme.logo" />
|
||||
<template v-if="theme.siteTitle">{{ theme.siteTitle }}</template>
|
||||
<template v-else-if="theme.siteTitle === undefined">{{ site.title }}</template>
|
||||
<slot name="nav-bar-title-after" />
|
||||
<VPImage v-if="theme.logo" class="logo" :image="theme.logo" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
@@ -53,10 +53,13 @@ const target = computed(() =>
|
||||
border-bottom: 1px solid transparent;
|
||||
width: 100%;
|
||||
height: var(--vp-nav-height);
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
font-size: 25px;
|
||||
font-weight: 500;
|
||||
line-height: 28px;
|
||||
color: var(--color-text-inactive);
|
||||
transition: opacity 0.25s;
|
||||
gap: 20px;
|
||||
margin-right: 24px;
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
@@ -72,7 +75,6 @@ const target = computed(() =>
|
||||
}
|
||||
|
||||
:deep(.logo) {
|
||||
margin-right: 8px;
|
||||
height: var(--vp-nav-logo-height);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -60,9 +60,8 @@ watch(
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: var(--vp-z-index-sidebar);
|
||||
padding: 32px 32px 96px 32px;
|
||||
width: 256px;
|
||||
max-width: 320px;
|
||||
padding: 0px 0px 96px 0px;
|
||||
width: 320px;
|
||||
background-color: var(--vp-sidebar-bg-color);
|
||||
opacity: 0;
|
||||
box-shadow: var(--vp-c-shadow-3);
|
||||
@@ -88,8 +87,6 @@ watch(
|
||||
@media (min-width: 960px) {
|
||||
.VPSidebar {
|
||||
padding-top: var(--vp-nav-height);
|
||||
// width: var(--vp-sidebar-width);
|
||||
// max-width: 100%;
|
||||
background-color: var(--vp-sidebar-bg-color);
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
@@ -98,13 +95,6 @@ watch(
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1440px) {
|
||||
.VPSidebar {
|
||||
// padding-left: max(32px, calc((100% - (var(--vp-layout-max-width) - 64px)) / 2));
|
||||
// width: calc((100% - (var(--vp-layout-max-width) - 64px)) / 2 + var(--vp-sidebar-width) - 32px);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
.curtain {
|
||||
position: sticky;
|
||||
@@ -121,17 +111,14 @@ watch(
|
||||
|
||||
.nav {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.group + .group {
|
||||
border-top: 1px solid var(--vp-c-divider);
|
||||
padding-top: 10px;
|
||||
padding-top: 24px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
.group {
|
||||
padding-top: 10px;
|
||||
width: calc(var(--vp-sidebar-width) - 64px);
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
<script lang="ts" setup>
|
||||
import type { ButtonTranslations } from 'vitepress/types/local-search'
|
||||
import { createSearchTranslate } from 'vitepress/dist/client/theme-default/support/translation'
|
||||
|
||||
const defaultTranslations: { button: ButtonTranslations } = {
|
||||
button: {
|
||||
buttonText: 'Поиск',
|
||||
buttonAriaLabel: 'Поиск'
|
||||
}
|
||||
}
|
||||
|
||||
const $t = createSearchTranslate(defaultTranslations)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button type="button" :class="$style.HomeHeroSearchButton" :aria-label="$t('button.buttonAriaLabel')">
|
||||
<span :class="$style.HomeHeroSearchButtonContainer">
|
||||
<img :class="$style.HomeHeroSearchButtonIcon" src="/icons/search.svg" alt="Поиск">
|
||||
<span :class="$style.HomeHeroSearchButtonPlaceholder">{{ $t('button.buttonText') }}</span>
|
||||
</span>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<style lang="scss" module>
|
||||
@use "@beeline/design-tokens/scss/tokens/themes";
|
||||
@use "@beeline/design-tokens/scss/tokens/globals/sizes";
|
||||
@use "@beeline/design-tokens/scss/mixin";
|
||||
@use "@beeline/design-tokens/scss/tokens/components/search";
|
||||
|
||||
.HomeHeroSearchButton {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
border-radius: search.$search-border-radius;
|
||||
height: search.$search-medium-height;
|
||||
background: search.$search-background-color;
|
||||
|
||||
&Container {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
&Icon {
|
||||
margin: 0 search.$search-category-icon-spacing;
|
||||
color: themes.$color-text-inactive;
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
&Placeholder {
|
||||
@include mixin.body2;
|
||||
color: themes.$color-text-disabled;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,9 @@
|
||||
export type SectionLinkListItem = {
|
||||
title: string,
|
||||
link: string,
|
||||
description?: string
|
||||
}
|
||||
|
||||
export type SectionLinkListProps = {
|
||||
links: SectionLinkListItem[]
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<template>
|
||||
<div :class="$style.SectionLinkList">
|
||||
<div v-for="link in links" :key="link.title" :class="$style.SectionLinkListItem">
|
||||
<div :class="$style.SectionLinkListLink">
|
||||
<VPLink :href="link.link">{{ link.title }}</VPLink>
|
||||
</div>
|
||||
<div :class="$style.SectionLinkListDescription">
|
||||
{{ link.description }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import VPLink from 'vitepress/dist/client/theme-default/components/VPLink.vue';
|
||||
import { SectionLinkListProps } from './SectionLinkList.types'
|
||||
|
||||
defineProps<SectionLinkListProps>()
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
@use "@beeline/design-tokens/scss/tokens/themes";
|
||||
@use "@beeline/design-tokens/scss/tokens/globals/sizes";
|
||||
@use "@beeline/design-tokens/scss/mixin";
|
||||
|
||||
.SectionLinkList {
|
||||
$el: &;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: sizes.$size-spacing-x6 sizes.$size-spacing-x6;
|
||||
margin-top: sizes.$size-spacing-x10;
|
||||
|
||||
&Item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: sizes.$size-spacing-x2;
|
||||
// max-width: 315px;
|
||||
}
|
||||
|
||||
&Link {
|
||||
|
||||
a,
|
||||
a:hover,
|
||||
a:visited,
|
||||
a:active {
|
||||
color: themes.$color-text-link;
|
||||
text-decoration: none;
|
||||
@include mixin.subtitle3;
|
||||
}
|
||||
}
|
||||
|
||||
&Description {
|
||||
color: themes.$color-text-inactive;
|
||||
@include mixin.body3;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1 @@
|
||||
export const NAVBAR_HEIGHT = 64
|
||||
@@ -0,0 +1,27 @@
|
||||
@use "@beeline/design-tokens/scss/tokens/themes";
|
||||
@use "@beeline/design-tokens/scss/tokens/globals/sizes";
|
||||
|
||||
.SectionLinkList {
|
||||
$el: &;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: sizes.$size-spacing-x6 sizes.$size-spacing-x6;
|
||||
margin-top: sizes.$size-spacing-x10;
|
||||
|
||||
&__Item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: sizes.$size-spacing-x2;
|
||||
max-width: 315px;
|
||||
}
|
||||
|
||||
&__Link {
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
&__Description {
|
||||
color: themes.$color-text-inactive;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
@use "vp-doc.scss";
|
||||
@use "vp-custom-block.scss";
|
||||
@use "vp-doc-aside.scss";
|
||||
@use "vp-sidebar.scss";
|
||||
@use "vp-doc";
|
||||
@use "vp-custom-block";
|
||||
@use "vp-doc-aside";
|
||||
@use "vp-sidebar";
|
||||
@use "SectionLinkList";
|
||||
@@ -1,10 +1,52 @@
|
||||
@use '@beeline/design-tokens/scss/tokens/components/navigationDrawer';
|
||||
@use "@beeline/design-tokens/scss/tokens/globals/colors";
|
||||
|
||||
.VPDocAside {
|
||||
.outline-link {
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
font-size: 17px;
|
||||
line-height: 22px;
|
||||
letter-spacing: 0.2px;
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
white-space: unset;
|
||||
color: colors.$color-text-grey-inactive;
|
||||
}
|
||||
|
||||
.outline-link.active {
|
||||
font-weight: 500 !important;
|
||||
color: colors.$color-text-black-active;
|
||||
}
|
||||
|
||||
.outline-title {
|
||||
font-size: 17px;
|
||||
font-weight: 500;
|
||||
line-height: 22px;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding-left: 0px !important;
|
||||
border-left: 0px !important;
|
||||
|
||||
nav {
|
||||
border-left: 1px solid var(--vp-c-divider) !important;
|
||||
|
||||
.outline-link {
|
||||
padding-left: 20px !important;
|
||||
|
||||
&.active {
|
||||
padding-left: 16px !important;
|
||||
position: relative !important;
|
||||
left: -1px !important;
|
||||
border-left: navigationDrawer.$navigation-drawer-item-indicator-width solid
|
||||
navigationDrawer.$navigation-drawer-item-activated-indicator-color !important;
|
||||
|
||||
border-top-right-radius: navigationDrawer.$navigation-drawer-item-indicator-border-radius-topright !important;
|
||||
border-bottom-right-radius: navigationDrawer.$navigation-drawer-item-indicator-border-radius-bottomright !important;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
@use "@beeline/design-tokens/scss/tokens/globals/colors";
|
||||
@use "@beeline/design-tokens/scss/tokens/themes";
|
||||
|
||||
@mixin font_style($fontSize, $fontWeight, $lineHeight, $letterSpacing) {
|
||||
font-size: $fontSize;
|
||||
font-weight: $fontWeight;
|
||||
@@ -66,7 +69,7 @@
|
||||
}
|
||||
|
||||
li + li {
|
||||
margin-top: 50px;
|
||||
margin-top: 34px;
|
||||
}
|
||||
|
||||
ul li {
|
||||
@@ -75,16 +78,6 @@
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
ol li:nth-last-of-type(n+2)::after {
|
||||
content: '';
|
||||
border-left: 1px solid rgb(201, 197, 197);
|
||||
position: absolute;
|
||||
line-height: 100%;
|
||||
left: -30px;
|
||||
top: 43px;
|
||||
bottom: -30px;
|
||||
}
|
||||
|
||||
ol li::before {
|
||||
content: counter(list);
|
||||
counter-increment: list;
|
||||
@@ -94,8 +87,8 @@
|
||||
left: -48px;
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
background-color: #7e00ed;
|
||||
color: #fff;
|
||||
background-color: colors.$color-background-brand;
|
||||
color: themes.$color-text-active;
|
||||
text-align: center;
|
||||
line-height: 25px;
|
||||
font-size: 16px;
|
||||
@@ -115,6 +108,10 @@
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ol li:last-child, ul li:last-child {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
ol li p {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,116 @@
|
||||
@use '@beeline/design-tokens/scss/tokens/components/navigationDrawer';
|
||||
@use '@beeline/design-tokens/scss/tokens/themes/theme-variables' as theme;
|
||||
@use 'src/assets/scss/app/helpers/media';
|
||||
|
||||
.VPSidebar {
|
||||
&Item {
|
||||
--vp-sidebar-bg-color: var(--vp-c-bg);
|
||||
}
|
||||
|
||||
.VPSidebar .VPSidebarItem .item {
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
.VPSidebar .VPSidebarItem .link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.indicator {
|
||||
border-top-right-radius: navigationDrawer.$navigation-drawer-item-indicator-border-radius-topright !important;
|
||||
border-bottom-right-radius: navigationDrawer.$navigation-drawer-item-indicator-border-radius-bottomright !important;
|
||||
position: absolute !important;
|
||||
left: 0 !important;
|
||||
}
|
||||
|
||||
.VPSidebarItem.is-active > .item .link > .text {
|
||||
color: theme.$color-text-active !important;
|
||||
font-weight: 500 !important;
|
||||
line-height: 20px !important;
|
||||
}
|
||||
|
||||
.VPSidebarItem {
|
||||
.item {
|
||||
padding: 12px 32px !important;
|
||||
border-top-right-radius: 12px !important;
|
||||
border-bottom-right-radius: 12px !important;
|
||||
color: theme.$color-text-inactive;
|
||||
|
||||
&:hover {
|
||||
background-color: navigationDrawer.$navigation-drawer-item-hover-background-color !important;
|
||||
color: theme.$color-text-inactive;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-active > .item > .indicator {
|
||||
border-left: navigationDrawer.$navigation-drawer-item-indicator-width solid
|
||||
navigationDrawer.$navigation-drawer-item-activated-indicator-color !important;
|
||||
}
|
||||
}
|
||||
|
||||
.VPSidebarItem.collapsible {
|
||||
.items {
|
||||
margin-left: 16px;
|
||||
|
||||
.item {
|
||||
padding: 12px 16px 12px 56px !important;
|
||||
border-top-left-radius: 12px !important;
|
||||
border-bottom-left-radius: 12px !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-active,
|
||||
&.has-active {
|
||||
> .item {
|
||||
.indicator {
|
||||
display: block !important;
|
||||
border-left: navigationDrawer.$navigation-drawer-item-indicator-width solid
|
||||
navigationDrawer.$navigation-drawer-item-activated-indicator-color !important;
|
||||
}
|
||||
|
||||
.text {
|
||||
font-size: 15px;
|
||||
color: theme.$color-text-active !important;
|
||||
font-weight: 500 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.items .VPSidebarItem.is-active > .item {
|
||||
background-color: navigationDrawer.$navigation-drawer-item-hover-background-color !important;
|
||||
|
||||
.text {
|
||||
color: theme.$color-text-active !important;
|
||||
font-weight: 500 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.VPSidebarItem.collapsible .items .item .indicator {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.text {
|
||||
padding: 0px !important;
|
||||
font-weight: 400 !important;
|
||||
font-size: 15px !important;
|
||||
line-height: 18px !important;
|
||||
letter-spacing: 0.2px !important;
|
||||
|
||||
transition-property: all;
|
||||
transition-duration: 150ms;
|
||||
transition-timing-function: ease-in-out;
|
||||
color: theme.$color-text-inactive !important;
|
||||
}
|
||||
|
||||
.VPSidebarItem .items {
|
||||
border-left: 0px !important;
|
||||
}
|
||||
|
||||
.VPSidebarItem {
|
||||
padding-bottom: 0px !important;
|
||||
}
|
||||
|
||||
.VPLocalNav.has-sidebar {
|
||||
@include media.max(sm) {
|
||||
padding-left: 0px;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
@use '@beeline/design-tokens/scss/tokens/themes/dark';
|
||||
@use '@beeline/design-tokens/scss/tokens/themes';
|
||||
|
||||
:root {
|
||||
--color-text-active: rgba(9, 11, 22, 0.94);
|
||||
--color-text-inactive: rgba(25, 28, 52, 0.7);
|
||||
@@ -7,9 +10,13 @@
|
||||
--color-button-contained-background-color: #fdd835;
|
||||
--color-button-contained-hover-background-color: #fdc435;
|
||||
--color-button-contained-text-color: rgba(9, 11, 22, 0.94);
|
||||
|
||||
@include themes.theme();
|
||||
}
|
||||
|
||||
.dark {
|
||||
--color-text-active: rgba(255, 255, 255, 0.87);
|
||||
--color-text-inactive: rgba(255, 255, 255, 0.6);
|
||||
|
||||
@include themes.theme(dark.$theme);
|
||||
}
|
||||
@@ -1,3 +1,8 @@
|
||||
@use "@beeline/design-tokens/scss/iconfont/iconfont" with (
|
||||
$font-path-iconfont: '/fonts/iconfont'
|
||||
);
|
||||
@use "@beeline/design-tokens/scss/iconfont/icons";
|
||||
|
||||
$font-path-beeline-sans: '/fonts/beeline-sans' !default;
|
||||
|
||||
@mixin beeline-sans-font($type, $weight, $style: normal) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@use "fonts.scss";
|
||||
@use "design-system.scss";
|
||||
@use "vars.scss";
|
||||
@use "fonts";
|
||||
@use "design-system";
|
||||
@use "vars";
|
||||
@use "components";
|
||||
@@ -203,3 +203,6 @@
|
||||
--docsearch-primary-color: var(--vp-c-brand-1) !important;
|
||||
}
|
||||
|
||||
:root {
|
||||
--vp-sidebar-width: 320px;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
section_links:
|
||||
- title: Управление ключевыми парами
|
||||
link: /admin/ssh.md
|
||||
description: Добавление SSH-ключей для подключения к виртуальным машинам
|
||||
---
|
||||
|
||||
# Администрирование
|
||||
|
||||
При [регистрации пользователя](../start/getting-started.md#1-регистрация-в-beeline-cloud) в Beeline Cloud создается аккаунт и проект в Beeline Cloud.
|
||||
|
||||
С помощью аккаунта можно управлять профилем пользователя - добавлять SSH-ключи, чтобы подключаться к виртуальным машинам без ввода пароля.
|
||||
|
||||
В проекте можно создавать ресурсы, добавлять пользователей в проект и управлять доступом к ресурсам.
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
| Название квоты | Количество |
|
||||
|---------------------|------------|
|
||||
| Количество виртуальных серверов | 3 штуки|
|
||||
| Количество виртуальных ВМов | 3 штуки|
|
||||
| ЦПУ | 200 |
|
||||
| ОЗУ | 200 Гбайт |
|
||||
| Хранилище NVME | 5000 Гбайт |
|
||||
@@ -11,7 +11,7 @@
|
||||
- сетевые диски;
|
||||
- IP-адреса.
|
||||
|
||||
Аппаратные ресурсы (серверы, сети, диски) размещены в центрах обработки данных (ЦОД). Каждый дата-центр разделен на модули. Модули оснащены независимыми системами электропитания и охлаждения.
|
||||
Аппаратные ресурсы (ВМы, сети, диски) размещены в центрах обработки данных (ЦОД). Каждый дата-центр разделен на модули. Модули оснащены независимыми системами электропитания и охлаждения.
|
||||
|
||||
При получении доступа в публичное облако текущий пользователь становится менеджера проектов. Менеджер проектов может создавать новые проекты, в которых он получает роль владельца проекта. Владелец проекта может добавлять пользователей в проект, назначая им роли.
|
||||
|
||||
@@ -7,28 +7,28 @@
|
||||
В проекте предусмотрен базовый набор ролей:
|
||||
|
||||
- **Владелец продукта** — управление пользователями проекта, просмотр ресурсов.
|
||||
- **DevOps-инженер** — управление инфраструктурой, стандартное администрирование ОС UNIX по протоколу ssh и права управления виртуальными серверами и дисками в консоли управления.
|
||||
- **DevOps-инженер** — управление инфраструктурой, стандартное администрирование ОС UNIX по протоколу ssh и права управления виртуальными ВМами и дисками в консоли управления.
|
||||
|
||||
## Матрица ролей
|
||||
|
||||
| Действие | Владелец проекта | DevOps-инженер |
|
||||
|---|---|---|
|
||||
| Обзор проекта<br> (квоты и количество использованных ресурсов)| ✅ | ✅ |
|
||||
| Серверы: обзор | ✅ | ✅ |
|
||||
| Серверы: мониторинг | ✅ | ✅ |
|
||||
| Серверы: создать сервер |✘ | ✅ |
|
||||
| Серверы: подключить диск | ✘ | ✅ |
|
||||
| Серверы: отключить диск | ✘ | ✅ |
|
||||
| Серверы: добавить диск | ✘ | ✅ |
|
||||
| Серверы: теги | ✘ |✅ |
|
||||
| Серверы: масштабирование сервера | ✘ | ✅ |
|
||||
| Серверы: выключить сервер | ✘ | ✅ |
|
||||
| Серверы: включить сервер | ✘ | ✅ |
|
||||
| Серверы: перезагрузить сервер | ✘ | ✅ |
|
||||
| Серверы: принудительно перезагрузить сервер | ✘ | ✅ |
|
||||
| Серверы: удалить сервер | ✘ | ✅ |
|
||||
| Серверы: группы размещения | ✘ | ✅ |
|
||||
| Серверы: IP-адреса | ✘ | ✅ |
|
||||
| ВМы: обзор | ✅ | ✅ |
|
||||
| ВМы: мониторинг | ✅ | ✅ |
|
||||
| ВМы: создать ВМ |✘ | ✅ |
|
||||
| ВМы: подключить диск | ✘ | ✅ |
|
||||
| ВМы: отключить диск | ✘ | ✅ |
|
||||
| ВМы: добавить диск | ✘ | ✅ |
|
||||
| ВМы: теги | ✘ |✅ |
|
||||
| ВМы: масштабирование ВМа | ✘ | ✅ |
|
||||
| ВМы: выключить ВМ | ✘ | ✅ |
|
||||
| ВМы: включить ВМ | ✘ | ✅ |
|
||||
| ВМы: перезагрузить ВМ | ✘ | ✅ |
|
||||
| ВМы: принудительно перезагрузить ВМ | ✘ | ✅ |
|
||||
| ВМы: удалить ВМ | ✘ | ✅ |
|
||||
| ВМы: группы размещения | ✘ | ✅ |
|
||||
| ВМы: IP-адреса | ✘ | ✅ |
|
||||
| Диски: просмотр дисков | ✅ | ✅ |
|
||||
| Диски: добавление дискового пространства | ✘ | ✅ |
|
||||
| Диски: удалить диск| ✘ | ✅ |
|
||||
@@ -0,0 +1,56 @@
|
||||
# Управление ключевыми парами
|
||||
|
||||
SSH-ключи используются для подключения к виртуальной машине по SSH. SSH-ключ позволит подключаться к виртуальному серверу без ввода пароля.
|
||||
|
||||
SSH-ключ состоит из публичного и приватного ключей: публичный ключ хранится в профиле пользователя в публичном облаке, приватный — хранится у пользователя.
|
||||
|
||||
::: warning Важно
|
||||
SSH-ключ добавляется на этапе [создания виртуальной машины](../compute/compute-how-to/compute-servers-create.md#создать-виртуальную-машину). Подключиться к существующим виртуальным машинам по SSH-ключу не получится.
|
||||
:::
|
||||
|
||||
## Добавить SSH-ключ
|
||||
|
||||
1. Войдите в [личный кабинет](https://lk.cloud.beeline.ru/).
|
||||
2. Перейдите в профиль пользователя в правом верхнем углу.
|
||||
3. Перейдите в раздел **SSH-ключи**.
|
||||
4. Нажмите **Добавить ключ**.
|
||||
5. Укажите название ключа.
|
||||
6. Откройте терминал и сгенерируйте ключевую пару. Можно использовать команду:
|
||||
|
||||
```sh
|
||||
ssh-keygen -t ed25519 -C “login” -Z aes256-gcm@openssh.com
|
||||
```
|
||||
7. Результатом выполнения команды будет сгенерированная ключевая пара. По умолчанию ключи сохраняются в каталоге `~/.ssh` для ОС Linux или `C:\users\имя_пользователя\.ssh\` для ОС Windows.
|
||||
8. Перейдите в каталог с ключевой парой и скопируйте публичную часть ключа. Пример публичной части ключа:
|
||||
|
||||
```
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5ABFLIFyapYheN7OZNhTaNqEHefjmU5mtzK********+gRPCz user@Desktop
|
||||
```
|
||||
9. Перейдите в консоль управления и вставьте скопированную публичную часть ключа в поле **SSH-ключ**.
|
||||
10. Нажмите **Сохранить**.
|
||||
|
||||
## Посмотреть SSH-ключи
|
||||
|
||||
1. Войдите в [личный кабинет](https://lk.cloud.beeline.ru/).
|
||||
2. Перейдите в профиль пользователя в правом верхнем углу.
|
||||
3. Перейдите в раздел **SSH-ключи**.
|
||||
4. В таблице показаны SSH-ключи пользователя.
|
||||
|
||||
## Изменить название SSH-ключа
|
||||
|
||||
1. Войдите в [личный кабинет](https://lk.cloud.beeline.ru/).
|
||||
2. Перейдите в профиль пользователя в правом верхнем углу.
|
||||
3. Перейдите в раздел **SSH-ключи**.
|
||||
4. Выберите нужный ключ.
|
||||
5. Нажмите на … и выберите **Редактировать**.
|
||||
6. Измените имя ключа.
|
||||
7. Нажмите **Сохранить**.
|
||||
|
||||
## Удалить SSH-ключ
|
||||
|
||||
1. Войдите в [личный кабинет](https://lk.cloud.beeline.ru/).
|
||||
2. Перейдите в профиль пользователя в правом верхнем углу.
|
||||
3. Перейдите в раздел **SSH-ключи**.
|
||||
4. Выберите нужный ключ.
|
||||
5. Нажмите на … и выберите **Удалить**.
|
||||
6. Нажмите **Удалить**, чтобы подтвердить удаление ключа.
|
||||
@@ -0,0 +1,178 @@
|
||||
# Чат с LLM
|
||||
|
||||
**Чат с LLM** - это интерфейс для общения с LLM-моделями. Подходит для знакомства и тестирования моделей.
|
||||
|
||||
Исходя из возможностей сервиса Чат с LLM пользовательский путь от авторизации к диалогу выглядит следующим образом:
|
||||
|
||||
1. Переход в чат с LLM.
|
||||
2. Выбор LLM.
|
||||
3. Выбор базы знаний.
|
||||
4. Настройка системного промпта.
|
||||
5. Диалог с LLM.
|
||||
|
||||
## Доступные модели
|
||||
|
||||
Чат с LLM поддерживает модели:.
|
||||
|
||||
| Модель | Контекст | Параметры | Reasoning | Инструменты | Картинки |
|
||||
|:-------|:-------|:-------|:-------|:-------|:-------|
|
||||
| Deepseek-chat | 131k | 671B | ✅ | ✅ | ❌ |
|
||||
| Gemma 3 | 128k | 27B | ❌ | ❌ | ✅ |
|
||||
| Qwen 3 | 131k | 32B | ✅ |✅ | ❌|
|
||||
|
||||
::: details Описание моделей
|
||||
|
||||
- **DeepSeek Chat**
|
||||
|
||||
DeepSeek V3 — это мощная гибридная модель с 671 млрд. параметров, специально оптимизированная для кодогенерации и работы поисковых агентов. Модель поддерживает контекст до 128 тыс. токенов и позволяет гибко управлять режимом рассуждений через параметр "reasoning_enabled". Она демонстрирует производительность уровня DeepSeek-R1, но работает быстрее, идеально подходя для программирования, исследований и агентных workflow.
|
||||
|
||||
- **Gemma 3**
|
||||
|
||||
Основная особенность этой модели в том, что она поддерживает картинки. Вы можете использовать ее как OCR: модель распознает рукописный текст на русском языке. Кроме этого, модель распознает и классифицирует объекты на фотографиях; может распознавать и переводить надписи.
|
||||
|
||||
- **Qwen 3 32B**
|
||||
|
||||
Основная модель, с которой рекомендуется начинать эксперименты. Поддерживает нативный вызов инструментов.
|
||||
|
||||
Режимы работы:
|
||||
|
||||
- с рассуждениями (включен по умолчанию).
|
||||
- без рассуждений (нужно передать в запросе /no_think).
|
||||
|
||||
:::
|
||||
|
||||
## Авторизация в чате с LLM
|
||||
|
||||
Доступ к чату с LLM-моделями предоставляется по уникальной ссылке, которая формируется после [создания тенанта](ai-setting.md#создать-тенант).
|
||||
|
||||
1. В левом меню откройте раздел **Тенанты**.
|
||||
2. Нажмите на имя тенанта.
|
||||
3. Из поля **Url приложения** скопируйте ссылку на чат с LLM.
|
||||
4. Вставьте ссылку в браузер. Откроется чат с LLM.
|
||||
|
||||

|
||||
|
||||
::: details Интерфейс чата с LLM
|
||||
|
||||
- **Чат**
|
||||
|
||||
Раздел включает функции:
|
||||
|
||||
- диалог с моделью в режиме вопрос-ответ;
|
||||
- выбор LLM;
|
||||
- выбор базы знаний.
|
||||
|
||||
- **Базы знаний**
|
||||
|
||||
Раздел предназначен для подготовки базы знаний, на основе которой модель будет генерировать ответы.
|
||||
|
||||
- **Системные промпты**
|
||||
|
||||
Раздел предназначен для создания системных промптов. Системный промпт представляет из себя набор инструкций, на которые опирается модель при подготовке ответа на запрос пользователя.
|
||||
|
||||
:::
|
||||
|
||||
## Начать диалог с моделью
|
||||
|
||||
1. [Авторизоваться в чате с LLM](#авторизация-в-чате-с-llm).
|
||||
2. В левом меню выберите раздел **Чаты**.
|
||||
3. Выберите из списка модель. Если в списке отсутствует нужная [модель](#доступные-модели), то [добавьте модель](ai-setting.md#добавить-модель) в тенант.
|
||||
|
||||
::: tip Информация
|
||||
|
||||
Эксперименты рекомендуется с модели **Qwen 3 32B**, которая имеет больший контекст и поддерживает нативный вызов инструментов.
|
||||
|
||||
Модель **Qwen 3 32B** может работать:
|
||||
- [с рассуждениями](ai-glossary.md#рассуждения) - этот режим включен по умолчанию;
|
||||
- без рассуждений - в этом случае нужно передать в запросе `/no_think`.
|
||||
|
||||
:::
|
||||
4. (опционально) Выберите базу знаний, на основе которой модель составит ответ. Если список баз данных пуст, то [создайте](#создать-базу-знаний) базу знаний.
|
||||
5. (опциоанльно) Выберите системный промпт. По умолчанию в чате задан системный промпт. Если необходим промпт под определенную задачу, то [измените](#редактировать-системный-промпт) системный промпт.
|
||||
6. Введите запрос к модели. Дождитесь ответа.
|
||||
|
||||
## Использовать базу знаний
|
||||
|
||||
Если необходимо, чтобы модель генерировала ответы не на базе своего раннего обучения, а обращалась, например, к актуальной нормативной базе или актуальным тарифам, то необходимо указать [базу знаний](ai-glossary.md#база-знаний-rag), с которой чат должен расширить свой контекст.
|
||||
|
||||
Для этого необходимо выбрать базу знаний и продолжить диалог.
|
||||
|
||||

|
||||
|
||||
Если база знаний отсутствует в списке, то [создайте](#создать-базу-знаний) базу знаний и добавьте документы.
|
||||
|
||||
### Создать базу знаний
|
||||
|
||||
1. [Авторизоваться в чате с LLM](#авторизация-в-чате-с-llm).
|
||||
2. В левом меню выберите раздел **Базы знаний**.
|
||||
3. Нажмите кнопку **Создать базу знаний**.
|
||||
4. Заполните параметры базы знаний:
|
||||
- **Имя**: введите имя базы знаний, имя будет отображаться при выборе базы знаний в чате.
|
||||
- **Описание**: введите описание базы знаний.
|
||||
5. Нажмите кнопку **Создать**.
|
||||
|
||||
База знаний будет создана, но в ней пока нет информации для генерации ответов модели. Добавьте документы в базу знаний.
|
||||
|
||||
### Добавить документ в базу знаний
|
||||
|
||||
1. [Авторизоваться в чате с LLM](#авторизация-в-чате-с-llm).
|
||||
2. В левом меню выберите раздел **Базы знаний**.
|
||||
3. В списке нажмите на нужную базу знаний.
|
||||
4. Нажмите кнопку **Добавить документ**.
|
||||
5. Загрузите файлы в базу знаний.
|
||||
6. Нажмите **Добавить**.
|
||||
|
||||
## Редактировать системный промпт
|
||||
|
||||
По умолчанию задан простой "размытый" [промпт](ai-glossary.md#промпт), который указывает, что ответы модели должны быть полезными. Но такой чат не всегда сможет предоставить пользователю ответ, который его устроит.
|
||||
|
||||
В чате с LLM доступен редактор системных промптов. Возможны способы редактирования системных промптов:
|
||||
|
||||
- редактирование системного промпта в текущей сессии диалога с моделью;
|
||||
- создание системного промпта в библиотеке системных промптов для дальнейшего использования.
|
||||
|
||||
### Редактирование системного промпта в текущей сессии
|
||||
|
||||
1. [Начните](#начать-диалог-с-моделью) диалог с моделью.
|
||||
2. Системный промпт отображается над строкой для ввода текста в чате.
|
||||
3. Нажмите на значок карандаша справа от системного промпта.
|
||||
4. В появившемся окне справа введите содержимое промпта.
|
||||
5. Нажмите кнопку **Сохранить**.
|
||||
6. Содержимое системного промпта обновится.
|
||||
|
||||
Редактируемый системный промпт доступен для всех моделей и сохраняется только в рамках текущей сессии.
|
||||
|
||||
### Создать системный промпт
|
||||
|
||||
1. [Авторизоваться в чате с LLM](#авторизация-в-чате-с-llm).
|
||||
2. В левом меню выберите раздел **Системные промпты**.
|
||||
3. Нажмите кнопку **Создать системный промпт**.
|
||||
4. Заполните параметры промпта:
|
||||
- **Название**: введите название системного промпта.
|
||||
- **Содержание**: введите содержание промпта.
|
||||
5. Нажмите **Создать**.
|
||||
|
||||
Системный промпт добавлен в библиотеку системных промптов. Посмотреть список промптов можно в левом меню в разделе **Системные промпты**.
|
||||
|
||||
## Сменить тенант
|
||||
|
||||
В чате с LLM-моделями есть возможность работать сразу с несколькими [тенантами](ai-setting.md#создать-тенант).
|
||||
|
||||
Для смены текущего тенанта необходимо:
|
||||
|
||||
1. В верхнем меню нажмите на вкладку **Тенант**.
|
||||
2. Выберите из списка тенант.
|
||||
|
||||
К тенанта привязаны сущности:
|
||||
|
||||
- модели;
|
||||
- базы знаний;
|
||||
- системные промпты.
|
||||
|
||||
Для каждого тенанта эти сущности будут отличаться.
|
||||
|
||||
## Очистить контекст диалога
|
||||
|
||||
При длительном диалоге модель накапливает [контекст](ai-glossary.md#контекст) и может начать генерировать неточные ответы ("галлюцинации"). Для предотвращения "галлюцинации" рекомендуется периодически очищать контекст диалога.
|
||||
|
||||
Для очистки контекста диалога нажмите на значок корзины в правом верхнем углу окна чата.
|
||||
@@ -0,0 +1,51 @@
|
||||
# Быстрый старт с AI платформа
|
||||
|
||||
Данная инструкция рассматривает начальную настройку сервиса **AI платформа** и отправку первого запроса к LLM-модели.
|
||||
|
||||
## Перед началом работы
|
||||
|
||||
- [Зарегистрируйтесь](../start/getting-started.md#1-регистрация-в-beeline-cloud) в личном кабинете Beeline Cloud.
|
||||
|
||||
## 1. Создать тенант
|
||||
|
||||
1. В верхнем меню нажмите на пункт **Сервисы**.
|
||||
2. Выберите **Сервис AI платфома**.
|
||||
3. В левом меню откройте раздел **Тенанты**.
|
||||
4. Нажмите кнопку **Создать тенант**.
|
||||
5. Введите имя тенанта.
|
||||
6. Нажмите **Создать тенант**.
|
||||
|
||||
## 2. Добавить модель
|
||||
|
||||
1. В левом меню откройте раздел **Модель**.
|
||||
2. Нажмите кнопку **Добавить модель**.
|
||||
3. В поле **Тенант** выберите созданный тенант.
|
||||
4. В поле **Модель** выберите из списка подходящую **LLM-модель**.
|
||||
5. Установите лимит использования токенов в час.
|
||||
6. Нажмите **Добавить модель**.
|
||||
|
||||
## 3. Перейти в чат с LLM
|
||||
|
||||
Протестировать модели в интерфейсе можно в чате с LLM. Доступ к чату с LLM-моделями предоставляется по уникальной ссылке, которая формируется после создания тенанта.
|
||||
|
||||
1. В левом меню откройте раздел **Тенанты**.
|
||||
2. Нажмите на имя тенанта.
|
||||
3. Из поля **Url приложения** скопируйте ссылку на чат с LLM.
|
||||
4. Вставьте ссылку в браузер.
|
||||
|
||||
## 4. Создать системный промпт
|
||||
|
||||
1. В чате с LLM в левом меню откройте раздел **Системные промпты**.
|
||||
2. Нажмите кнопку **Создать системный промпт**.
|
||||
3. Заполните параметры промпта:
|
||||
- **Название**: введите название систменого промпта;
|
||||
- **Содержание**: введите содержание промпта.
|
||||
4. Нажмите **Создать**.
|
||||
|
||||
## 5. Начать диалог с моделью
|
||||
|
||||
1. В чате с LLM-моделями в левом меню перейдите в раздел **Чат**.
|
||||
2. Выберите из списка модель.
|
||||
3. Выберите из списка системный промпт.
|
||||
4. Откроется чат. В текстовом поле внизу введите запрос к LLM-модели.
|
||||
5. Дождитесь ответа модели.
|
||||
@@ -0,0 +1,26 @@
|
||||
# Концепции
|
||||
|
||||
## База знаний (RAG)
|
||||
|
||||
RAG — это подход, при котором ответ LLM формируется с использованием дополнительного источника актуальных данных.
|
||||
|
||||
## Контекст
|
||||
|
||||
Контекст — это ограниченное по размеру окно, в которое должен уместиться запрос к LLM. У каждой модели контекст строго ограничен и указан в документации к ней.
|
||||
|
||||
## Рассуждения
|
||||
|
||||
Reasoning (рассуждение или логическое мышление) у LLM — это способность модели не просто воспроизводить выученные паттерны текста, а последовательно и логически выводить новую информацию из уже известных ей данных.
|
||||
|
||||
|
||||
## Промпт
|
||||
|
||||
Промпт — это текстовый запрос, который вы отправляете модели, и который задает контекст и направление для ответа. LLM анализирует промпт и генерирует ответ, который является логическим продолжением текста. Чем понятнее и конкретнее сформулирован промпт, тем качественнее будет ответ.
|
||||
|
||||
Системные промпты — специальные инструкции, которые задают общие рамки поведения модели на протяжении всего диалога. Системный промпт устанавливается в начале общения и сообщает модели, какую роль она должна играть, какие ограничения соблюдать и какой стиль общения использовать.
|
||||
|
||||
В сервисе **AI-платформа** системный промпт доступен для редактирования, чтобы пользователи могли максимально настраивать поведение моделей.
|
||||
|
||||
## Токен
|
||||
|
||||
LLM представляет текст не в виде слов или букв, а в виде токенов. Токен — это несколько букв (часть слова), которые часто встречаются рядом в обучающей выборке. Текст запроса, который вы отправляете в LLM, сначала нарезается на токены, и только потом обрабатывается моделью.
|
||||
@@ -0,0 +1,11 @@
|
||||
# Обзор сервиса
|
||||
|
||||
Сервис **AI платфома** предоставляет доступ к большим языковым моделям (Large Language Models, LLM). LLM-модели готовы к использованию и избавляют пользователя от необходимости самостоятельного развертывания и изучения связанных технологий.
|
||||
|
||||
## Возможности сервиса
|
||||
|
||||
- Интерфейс для взаимодействия с моделями в формате чат-бота.
|
||||
- Предоставляет различные [модели](ai-chat-llm.md#доступные-модели).
|
||||
- Использование баз знаний (RAG).
|
||||
- Редактирование системного промпта.
|
||||
- Диалог с моделью.
|
||||
@@ -0,0 +1,56 @@
|
||||
# Управление сервисом
|
||||
|
||||
В разделе рассмотрены компоненты сервиса **AI платформа** и приведены пошаговые инструкции по их созданию и управлению компонентами.
|
||||
|
||||
## Создать тенант
|
||||
|
||||
**Тенант** представляет собой изолированный логический контейнер ресурсов сервиса (модели, базы знаний) для работы в рамках проекта. Создается в личном кабинете Beeline Cloud.
|
||||
|
||||
1. Войдите в [личный кабинет](https://lk.cloud.beeline.ru/).
|
||||
2. В верхнем меню нажмите на раздел **Сервисы**.
|
||||
3. Выберите **Сервис AI платформа**.
|
||||
4. В левом меню откройте раздел **Тенанты**.
|
||||
5. Нажмите кнопку **Создать тенант**.
|
||||
6. Введите имя тенанта.
|
||||
7. Нажмите **Создать тенант**.
|
||||
|
||||
## Добавить модель
|
||||
|
||||
1. Войдите в [личный кабинет](https://lk.cloud.beeline.ru/).
|
||||
2. В верхнем меню нажмите на раздел **Сервисы**.
|
||||
3. Выберите **Сервис AI платформа**.
|
||||
4. В левом меню откройте раздел **Модели**.
|
||||
5. Нажмите кнопку **Добавить модель**.
|
||||
6. Заполните параметры модели:
|
||||
- **Тенант**: выберите тенант, в котором будет использоваться модель.
|
||||
- **Модель**: выберите из списка подходящую LLM-модель.
|
||||
- **Токены**: введите лимит использования токенов в час.
|
||||
7. Нажмите кнопку **Добавить модель**.
|
||||
|
||||
## Добавить базу знаний
|
||||
|
||||
1. Войдите в [личный кабинет](https://lk.cloud.beeline.ru/).
|
||||
2. В верхнем меню нажмите на раздел **Сервисы**.
|
||||
3. Выберите **Сервис AI платформа**.
|
||||
4. В левом меню откройте раздел **База знаний**.
|
||||
5. Нажмите кнопку **Создать базу знаний**.
|
||||
6. Заполните параметры базы знаний:
|
||||
- **Тенант**: выберите из списка тенант.
|
||||
- **Имя**: введите имя базы знаний.
|
||||
- **Описание**: введите описание базы знаний.
|
||||
7. Нажмите **Создать базу знаний**.
|
||||
|
||||
[Наполнение базы знаний](ai-chat-llm.md#добавить-документ-в-базу-знаний) документами, на основании которых будет генерироваться ответ модели, выполняется в чате с LLM.
|
||||
|
||||
## Удалить тенант, модель, базу знаний
|
||||
|
||||
1. Войдите в [личный кабинет](https://lk.cloud.beeline.ru/).
|
||||
2. В верхнем меню нажмите на раздел **Сервисы**.
|
||||
3. Выберите **Сервис AI платформа**.
|
||||
4. Откройте раздел c нужным компонентом сервиса:
|
||||
- **Тенанты**,
|
||||
- **Модели**,
|
||||
- **Базы знаний**.
|
||||
5. В таблице найдите строку с нужным компонентом сервиса.
|
||||
6. Нажмите … и выберите **Удалить**.
|
||||
7. В открывшемся окне подтвердите операцию, нажав **Удалить**.
|
||||
|
After Width: | Height: | Size: 126 KiB |
|
After Width: | Height: | Size: 105 KiB |
|
After Width: | Height: | Size: 141 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 122 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 194 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 105 KiB |
|
After Width: | Height: | Size: 238 KiB |
|
After Width: | Height: | Size: 58 KiB |
@@ -0,0 +1,21 @@
|
||||
---
|
||||
section_links:
|
||||
- title: Обзор сервиса
|
||||
link: /ai/ai-overview-platform.md
|
||||
description: Обзор сервиса, решаемые задачи
|
||||
- title: Быстрый старт
|
||||
link: /ai/ai-getting-started.md
|
||||
description: Создание виртуальной машины в дата-центре
|
||||
- title: Настройка сервиса
|
||||
link: /ai/ai-setting.md
|
||||
description: Создание тенанта, добавление моделей и базы знаний
|
||||
- title: Чат с LLM
|
||||
link: /ai/ai-chat-llm.md
|
||||
description: Интерфейс для взаимодействия с LLM-моделями в формате чат-бота
|
||||
- title: Концепции
|
||||
link: /ai/ai-glossary.md
|
||||
description: Основные понятия, используемые в сервисе
|
||||
|
||||
---
|
||||
|
||||
# AI платформа
|
||||