Шаблоны HTML виджетов: Мы предлагаем широкий спектр готовых шаблонов, которые помогут пригодиться в Mini-App
В этой статье мы рассмотрим, как в Puzzle можно интегрировать NocoDB с вашими мини-приложениями для вывода списка рефералов, приглашенных пользователями. Мы используем JavaScript для создания простого интерфейса, который позволяет пользователям вводить идентификатор (ID) и получать соответствующий список рефералов.
В этом примере мы создадим простую линейную диаграмму с помощью технологии HTML5 Canvas. Это позволяет нам визуализировать данные, используя простые графические элементы. Реализовано в конструкторе Puzzle
В данном кейсе мы рассмотрим, как реализовать виджет PIN-кода в мини-приложении, используя сервис Puzzlebot.
Этот виджет позволяет пользователям вводить PIN-код для доступа к определенным функциям приложения, что повышает уровень защиты информации и делает взаимодействие с вашим ботом более безопасным.
Результат • Список рефералов в красивом формате • С аватарками • С юзернеймами • С кликабельными ссылками на профиль «Такой код легко вставить в любой сайт или лендинг. Всё работает сразу и не требует фреймворков.»
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Замените на свои токены и все заработает!
"}},{"type":"link","cover":false,"hidden":false,"anchor":"","data":{"link":{"type":"link","data":{"url":"https://api.vc.ru/v2.8/redirect?to=https%3A%2F%2Ft.me%2FPuzzleHTML&postId=2097026","title":"Puzzle Html • Шаблоны","description":"@PuzzleHtmlBot: Мы предлагаем широкий спектр готовых шаблонов, которые помогут пригодиться в Mini-App","image":{"type":"image","data":{"uuid":"0c5ec522-6456-5837-a7a9-efa6a12645d2","width":180,"height":180,"size":4016,"type":"png","color":"26a5e4","hash":"","external_service":[]}},"v":1,"hostname":"t.me"}}}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Если возникнут вопросы пишите в предложку канала.
"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Готовый код!"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"\n\n\n \nПОДПИШИСЬ!
"}}],"summaryContent":null,"isExistSummaryContent":false,"warningFromEditor":null,"warningFromEditorTitle":null,"counters":{"comments":0,"favorites":0,"reposts":0,"views":529,"hits":221,"reads":null,"online":0},"dateFavorite":0,"hitsCount":221,"isCommentsEnabled":true,"isLikesEnabled":true,"isRemovedByUserRequest":false,"isFavorited":false,"isPinned":false,"repostId":null,"repostData":null,"subscribedToTreads":false,"isEditorial":false,"isAudioAvailable":false,"audioUrl":null,"isAudioAvailableToGenerate":false,"commentEditor":{"enabled":true,"who":null,"text":"","until":null,"reason":null,"type":"everybody"},"isBlur":false,"isPublished":true,"isDisabledAd":false,"withheld":[],"ogTitle":null,"ogDescription":"Обновлённый виджет рефералов, улучшенный интерфейс, отображение аватарок, кликабельные ссылки на профиль, поддержка фильтрации по статусу.","url":"https://vc.ru/telegram/2097026-obnovlennyj-vidzhet-referalov-22-marta","author":{"id":755936,"name":"Hacker Verifure","nickname":null,"description":"Шаблоны HTML виджетов: Мы предлагаем широкий спектр готовых шаблонов, которые помогут пригодиться в Mini-App","uri":"","avatar":{"type":"image","data":{"uuid":"f536a51a-90ad-53e6-9996-52506cd70148","width":828,"height":828,"size":59583,"type":"jpg","color":"e7d4c5","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAkGBwgHBgkIBwgKCgkLDRYPDQwMDRsUFRAWIB0iIiAdHx8kKDQsJCYxJx8fLT0tMTU3Ojo6Iys/RD84QzQ5Ojf/2wBDAQoKCg0MDRoPDxo3JR8lNzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzf/wAARCAAKAAoDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIFB//EACYQAAECBAMJAAAAAAAAAAAAAAECAwAEESEFBjESExUiMkFRYXH/xAAUAQEAAAAAAAAAAAAAAAAAAAAF/8QAHREAAQQCAwAAAAAAAAAAAAAAAQACBBEDMVFhof/aAAwDAQACEQMRAD8AotzRmcTCEzZC0sgol20jmNb1tXT55hjO3NiPR7QZHSnj2KKoNre60v1LjQCw0TUtIJOpKRCEebT322we9IyTBvGwB1EDjfq//9k="}},"cover":{"cover":{"type":"image","data":{"uuid":"03bffb95-befa-548d-9188-a0dff1180e28","width":800,"height":800,"size":44565,"type":"jpg","color":"32a9f6","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAQDAwQDAwQEAwQFBAQFBgoHBgYGBg0JCggKDw0QEA8NDw4RExgUERIXEg4PFRwVFxkZGxsbEBQdHx0aHxgaGxr/2wBDAQQFBQYFBgwHBwwaEQ8RGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhr/wAARCAAKAAoDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAABgAD/8QAIhABAAEDAwQDAAAAAAAAAAAAAQIAAxIFE1EEETGRQVKh/8QAFQEBAQAAAAAAAAAAAAAAAAAABwj/xAAcEQEAAQQDAAAAAAAAAAAAAAABAgADBREhcaH/2gAMAwEAAhEDEQA/AF17X4FvpdgtXBlhed1jKPzl2RH6/tZT12MZyI3BBQR80HyeX3Vk8vunyGMtwXau/KneeQnIAA13zX//2Q=="}},"cover_y":50},"achievements":[{"title":"Год на vc.ru","code":"registration_1_year","description":"Первый год с vc.ru. Получена 24 июля 2025.","previewUuid":"0d11c244-49de-50e7-894e-b9b27945d42b","formats":{"glb":"https://static.vc.ru/achievements/fish.glb","usdz":"https://static.vc.ru/achievements/fish.usdz"},"viewData":{"contentColor":"#C67AA3","textMaxWidth":0.634765625,"textX":0.5888671875,"textY":0.54296875,"logoX":0.5859375,"logoY":0.6669921875,"logoXNoText":0.6044921875,"logoYNoText":0.5439453125},"id":4680765,"userId":755936,"count":0,"shareImage":"https://api.vc.ru/achievements/share/4680765"},{"title":"3 года на vc.ru","code":"registration_3_years","description":"Провёл 3 года вместе с vc.ru. Получена 23 июля 2025.","previewUuid":"d9d72ac5-bcb5-55e0-8c72-b99251e5cdd9","formats":{"glb":"https://static.vc.ru/achievements/shark.glb","usdz":"https://static.vc.ru/achievements/shark.usdz"},"viewData":{"contentColor":"#8E6F09","textMaxWidth":0.66796875,"textX":0.5205078125,"textY":0.341796875,"logoX":0.5205078125,"logoY":0.4609375,"logoXNoText":0.5,"logoYNoText":0.3662109375},"id":1056678,"userId":755936,"count":0,"shareImage":"https://api.vc.ru/achievements/share/1056678"}],"lastModificationDate":1764976772,"isSubscribed":false,"isSubscribedToNewPosts":false,"isMuted":false,"isAvailableForMessenger":true,"badgeId":null,"isDonationsEnabled":false,"isPlusGiftEnabled":true,"isUnverifiedBlogForCompanyWithoutPro":true,"isRemovedByUserRequest":false,"isFrozen":false,"isDisabledAd":false,"isPlus":false,"isVerified":false,"isPro":false,"yandexMetricaId":null,"badge":null,"isOnline":false,"tgChannelShortname":null,"isUnsubscribable":true,"type":1,"subtype":"personal_blog"},"subsite":{"id":3680492,"name":"Телеграм","description":"Все о мессенджере Телеграм: новые фичи, каналы, новости, Павел Дуров, TON","uri":"/telegram","avatar":{"type":"image","data":{"uuid":"a6bd3ea3-1a25-5402-8c27-d063a43ad500","width":500,"height":500,"size":6665,"type":"jpg","color":"28a7e8","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCAAKAAoDASEAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAABgME/8QAIRAAAQIGAgMAAAAAAAAAAAAAAQMEAAIFERIxBiETFEH/xAAVAQEBAAAAAAAAAAAAAAAAAAAEB//EABkRAAIDAQAAAAAAAAAAAAAAAAIDAAERYf/aAAwDAQACEQMRAD8AZcWpFGqLJ24fVgJKt2yi3ryjGY4g2F5tkn4AeoNBQ21FOS5hsMSHKrM7I69C1qAgLbLd5yTVA8uo0AdQmoSf/9k="}},"cover":{"type":"image","data":{"uuid":"ebe1c612-381b-52c8-897c-ac8a8002770f","width":1920,"height":1080,"size":636123,"type":"jpg","color":"def2f4","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCAAKAAoDASEAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAwEI/8QAHxAAAQMEAwEAAAAAAAAAAAAAAQACERIiQVEhMTKS/8QAFwEAAwEAAAAAAAAAAAAAAAAAAAEDBP/EABURAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIRAxEAPwDSQjeNKtIgXD5V2EVToNx8jKRrnUjk9bQUf//Z"}},"lastModificationDate":1721721308,"isSubscribed":false,"isSubscribedToNewPosts":false,"isMuted":false,"isAvailableForMessenger":false,"isDisabledAd":false,"nickname":"telegram","isUnsubscribable":true,"badge":null,"badgeId":null,"isDonationsEnabled":false,"isOnline":false,"isPlus":false,"isUnverifiedBlogForCompanyWithoutPro":false,"isVerified":false,"isRemovedByUserRequest":false,"isFrozen":false,"isPro":false,"type":2,"subtype":"community"},"reactions":{"counters":[{"id":1,"count":2}],"reactionId":0},"isNews":false,"source":null,"clusters":[],"donations":{"amount":0,"isDonated":false},"commentsSeenCount":null}},{"type":"entry","data":{"id":1880232,"customUri":null,"subsiteId":755936,"title":"Интеграция с NocoDB для вывода списка рефералов по USER_ID. Реализовано на PuzzleBot","date":1742656165,"dateModified":1742670198,"blocks":[{"type":"media","cover":true,"hidden":false,"anchor":"","data":{"items":[{"title":"СПИСОК РЕФЕРАЛОВ","image":{"type":"image","data":{"uuid":"292f9435-a522-51c7-82dc-ea3c6da5816e","width":3312,"height":1860,"size":151801,"type":"jpg","color":"49b0f4","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCAAKAAoDASEAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAgQFCP/EACQQAAEEAQEJAQAAAAAAAAAAAAECAwQRAAYFEiEkMWGBk8LR/8QAFAEBAAAAAAAAAAAAAAAAAAAABP/EAB0RAQABBAMBAAAAAAAAAAAAAAEDAAIEUREhsZH/2gAMAwEAAhEDEQA/ANcN7PhyIbzDsZG64CgkCjRFcD1HjIqdC6eQkIDUykihc10/WMx86aASzjvYPtEmw4pkbj4p5SaJkxKQBKfA7OHAM2ZZ5uR7D+4gjs1RWS/df//Z"}}}]}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"В этой статье мы рассмотрим, как в Puzzle можно интегрировать NocoDB с вашими мини-приложениями для вывода списка рефералов, приглашенных пользователями. Мы используем JavaScript для создания простого интерфейса, который позволяет пользователям вводить идентификатор (ID) и получать соответствующий список рефералов.
"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Основные элементы кода"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"const token = 'заIT43zdIy2vXNEXmLV*********';\nconst tableUrl = 'https://nocodb.puzzlebot.top/api/v2/tables/m0o0ba8********/records';","lang":""}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Что такое token и tableUrl?"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"- token: это токен аутентификации, который используется при обращении к API NocoDB. Он позволяет вашему приложению делать запросы к вашему табличному хранилищу.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"- tableUrl: это URL-адрес API, который ссылается на таблицу в NocoDB, содержащую записи рефералов.
"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Функция searchUsers"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"async function searchUsers() {\n const userId = document.getElementById('userIdInput').value.trim();\n const resultsContainer = document.getElementById('results');\n const loadingIndicator = document.getElementById('loading');\n\n if (!userId) {\n showError('Рефералы не найдены');\n return;\n }\n ...\n}","lang":""}},{"type":"quote","cover":false,"hidden":false,"anchor":"","data":{"text":"Эта функция выполняется по нажатию кнопки \"Поиск\" после ввода ID пользователя. Она берет значение userId из текстового поля и проверяет, что оно не пустое. Если это не так, отображается сообщение об ошибке.","subline1":"@verifure"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"- loadingIndicator: элемент, который показывает состояние загрузки во время выполнения запроса. - resultsContainer: область, куда будут выводиться найденные рефералы.
"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Формирование и отправка запроса"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"const params = new URLSearchParams({\n where: USER_ID_TEXT,eq,${userId},\n fields: 'username'\n});\n\nconst response = await fetch(${tableUrl}?${params}, {\n headers: {\n 'xc-token': token,\n 'Content-Type': 'application/json'\n }\n});","lang":""}},{"type":"quote","cover":false,"hidden":false,"anchor":"","data":{"text":"Здесь мы формируем параметры запроса, чтобы найти записи, соответствующие введенному ID пользователя. Мы используем метод fetch для отправки HTTP-запроса к API NocoDB.","subline1":"@verifure"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"- where: здесь мы указываем условие для фильтрации записей по идентификатору пользователя. - fields: вы можете указать, какие поля таблицы вы хотите получить. В нашем случае мы хотим получить только поле username.
"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Обработка ответа"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"if (!response.ok) throw new Error(HTTP error! status: ${response.status});\n\nconst data = await response.json();\n\nif (data.list.length === 0) {\n showError('Рефералы не найдены');\n return;\n}","lang":""}},{"type":"quote","cover":false,"hidden":false,"anchor":"","data":{"text":"После отправки запроса мы проверяем, успешно ли он выполнен, и извлекаем данные в формате JSON. Если рефералы не найдены, выводится сообщение об ошибке.","subline1":"@verifure"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Отображение результатов"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"data.list.forEach(user => {\n const div = document.createElement('div');\n div.className = 'user-container';\n div.textContent = user.username;\n resultsContainer.appendChild(div);\n});","lang":""}},{"type":"quote","cover":false,"hidden":false,"anchor":"","data":{"text":"Если данные были успешно получены, мы проходим по каждому пользователю из ответа и создаем новый элемент div, который добавляется в контейнер результатов.","subline1":""}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Функция showError"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"function showError(message) {\n const resultsContainer = document.getElementById('results');\n resultsContainer.innerHTML =Таким образом, с помощью этого небольшого скрипта вы можете интегрировать ваше веб-приложение с NocoDB, позволяя пользователям вводить идентификаторы и получать список их приглашенных рефералов. Это простое решение можно адаптировать под ваши конкретные нужды и расширить для дополнительных задач.
"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Код"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"\n\n\n \n \nМой канал
"}},{"type":"link","cover":false,"hidden":false,"anchor":"","data":{"link":{"type":"link","data":{"url":"https://api.vc.ru/v2.8/redirect?to=https%3A%2F%2Ft.me%2FPuzzleHTML&postId=1880232","title":"Puzzle Html • Шаблоны","description":"@PuzzleHtmlBot: Мы предлагаем широкий спектр готовых шаблонов, которые помогут пригодиться в Mini-App","image":{"type":"image","data":{"uuid":"0c5ec522-6456-5837-a7a9-efa6a12645d2","width":180,"height":180,"size":4016,"type":"png","color":"26a5e4","hash":"","external_service":[]}},"v":1,"hostname":"t.me"}}}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Мой ТГ
"}},{"type":"link","cover":false,"hidden":false,"anchor":"","data":{"link":{"type":"link","data":{"url":"https://api.vc.ru/v2.8/redirect?to=https%3A%2F%2Ft.me%2FVerifure&postId=1880232","title":"Hacker Verifure","description":"The service of the best bots Verifure","image":{"type":"image","data":{"uuid":"0c5ec522-6456-5837-a7a9-efa6a12645d2","width":180,"height":180,"size":4016,"type":"png","color":"26a5e4","hash":"","external_service":[]}},"v":1,"hostname":"t.me"}}}}],"summaryContent":null,"isExistSummaryContent":false,"warningFromEditor":null,"warningFromEditorTitle":null,"counters":{"comments":6,"favorites":0,"reposts":0,"views":761,"hits":542,"reads":null,"online":0},"dateFavorite":0,"hitsCount":542,"isCommentsEnabled":true,"isLikesEnabled":true,"isRemovedByUserRequest":false,"isFavorited":false,"isPinned":false,"repostId":null,"repostData":null,"subscribedToTreads":false,"isEditorial":false,"isAudioAvailable":false,"audioUrl":null,"isAudioAvailableToGenerate":false,"commentEditor":{"enabled":true,"who":null,"text":"","until":null,"reason":null,"type":"everybody"},"isBlur":false,"isPublished":true,"isDisabledAd":false,"withheld":[],"ogTitle":null,"ogDescription":null,"url":"https://vc.ru/telegram/1880232-integraciya-s-nocodb-dlya-vyvoda-spiska-referalov-po-user-id-realizovano-na-puzzlebot","author":{"id":755936,"name":"Hacker Verifure","nickname":null,"description":"Шаблоны HTML виджетов: Мы предлагаем широкий спектр готовых шаблонов, которые помогут пригодиться в Mini-App","uri":"","avatar":{"type":"image","data":{"uuid":"f536a51a-90ad-53e6-9996-52506cd70148","width":828,"height":828,"size":59583,"type":"jpg","color":"e7d4c5","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAkGBwgHBgkIBwgKCgkLDRYPDQwMDRsUFRAWIB0iIiAdHx8kKDQsJCYxJx8fLT0tMTU3Ojo6Iys/RD84QzQ5Ojf/2wBDAQoKCg0MDRoPDxo3JR8lNzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzf/wAARCAAKAAoDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIFB//EACYQAAECBAMJAAAAAAAAAAAAAAECAwAEESEFBjESExUiMkFRYXH/xAAUAQEAAAAAAAAAAAAAAAAAAAAF/8QAHREAAQQCAwAAAAAAAAAAAAAAAQACBBEDMVFhof/aAAwDAQACEQMRAD8AotzRmcTCEzZC0sgol20jmNb1tXT55hjO3NiPR7QZHSnj2KKoNre60v1LjQCw0TUtIJOpKRCEebT322we9IyTBvGwB1EDjfq//9k="}},"cover":{"cover":{"type":"image","data":{"uuid":"03bffb95-befa-548d-9188-a0dff1180e28","width":800,"height":800,"size":44565,"type":"jpg","color":"32a9f6","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAQDAwQDAwQEAwQFBAQFBgoHBgYGBg0JCggKDw0QEA8NDw4RExgUERIXEg4PFRwVFxkZGxsbEBQdHx0aHxgaGxr/2wBDAQQFBQYFBgwHBwwaEQ8RGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhr/wAARCAAKAAoDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAABgAD/8QAIhABAAEDAwQDAAAAAAAAAAAAAQIAAxIFE1EEETGRQVKh/8QAFQEBAQAAAAAAAAAAAAAAAAAABwj/xAAcEQEAAQQDAAAAAAAAAAAAAAABAgADBREhcaH/2gAMAwEAAhEDEQA/AF17X4FvpdgtXBlhed1jKPzl2RH6/tZT12MZyI3BBQR80HyeX3Vk8vunyGMtwXau/KneeQnIAA13zX//2Q=="}},"cover_y":50},"achievements":[{"title":"Год на vc.ru","code":"registration_1_year","description":"Первый год с vc.ru. Получена 24 июля 2025.","previewUuid":"0d11c244-49de-50e7-894e-b9b27945d42b","formats":{"glb":"https://static.vc.ru/achievements/fish.glb","usdz":"https://static.vc.ru/achievements/fish.usdz"},"viewData":{"contentColor":"#C67AA3","textMaxWidth":0.634765625,"textX":0.5888671875,"textY":0.54296875,"logoX":0.5859375,"logoY":0.6669921875,"logoXNoText":0.6044921875,"logoYNoText":0.5439453125},"id":4680765,"userId":755936,"count":0,"shareImage":"https://api.vc.ru/achievements/share/4680765"},{"title":"3 года на vc.ru","code":"registration_3_years","description":"Провёл 3 года вместе с vc.ru. Получена 23 июля 2025.","previewUuid":"d9d72ac5-bcb5-55e0-8c72-b99251e5cdd9","formats":{"glb":"https://static.vc.ru/achievements/shark.glb","usdz":"https://static.vc.ru/achievements/shark.usdz"},"viewData":{"contentColor":"#8E6F09","textMaxWidth":0.66796875,"textX":0.5205078125,"textY":0.341796875,"logoX":0.5205078125,"logoY":0.4609375,"logoXNoText":0.5,"logoYNoText":0.3662109375},"id":1056678,"userId":755936,"count":0,"shareImage":"https://api.vc.ru/achievements/share/1056678"}],"lastModificationDate":1764976772,"isSubscribed":false,"isSubscribedToNewPosts":false,"isMuted":false,"isAvailableForMessenger":true,"badgeId":null,"isDonationsEnabled":false,"isPlusGiftEnabled":true,"isUnverifiedBlogForCompanyWithoutPro":true,"isRemovedByUserRequest":false,"isFrozen":false,"isDisabledAd":false,"isPlus":false,"isVerified":false,"isPro":false,"yandexMetricaId":null,"badge":null,"isOnline":false,"tgChannelShortname":null,"isUnsubscribable":true,"type":1,"subtype":"personal_blog"},"subsite":{"id":3680492,"name":"Телеграм","description":"Все о мессенджере Телеграм: новые фичи, каналы, новости, Павел Дуров, TON","uri":"/telegram","avatar":{"type":"image","data":{"uuid":"a6bd3ea3-1a25-5402-8c27-d063a43ad500","width":500,"height":500,"size":6665,"type":"jpg","color":"28a7e8","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCAAKAAoDASEAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAABgME/8QAIRAAAQIGAgMAAAAAAAAAAAAAAQMEAAIFERIxBiETFEH/xAAVAQEBAAAAAAAAAAAAAAAAAAAEB//EABkRAAIDAQAAAAAAAAAAAAAAAAIDAAERYf/aAAwDAQACEQMRAD8AZcWpFGqLJ24fVgJKt2yi3ryjGY4g2F5tkn4AeoNBQ21FOS5hsMSHKrM7I69C1qAgLbLd5yTVA8uo0AdQmoSf/9k="}},"cover":{"type":"image","data":{"uuid":"ebe1c612-381b-52c8-897c-ac8a8002770f","width":1920,"height":1080,"size":636123,"type":"jpg","color":"def2f4","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCAAKAAoDASEAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAwEI/8QAHxAAAQMEAwEAAAAAAAAAAAAAAQACERIiQVEhMTKS/8QAFwEAAwEAAAAAAAAAAAAAAAAAAAEDBP/EABURAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIRAxEAPwDSQjeNKtIgXD5V2EVToNx8jKRrnUjk9bQUf//Z"}},"lastModificationDate":1721721308,"isSubscribed":false,"isSubscribedToNewPosts":false,"isMuted":false,"isAvailableForMessenger":false,"isDisabledAd":false,"nickname":"telegram","isUnsubscribable":true,"badge":null,"badgeId":null,"isDonationsEnabled":false,"isOnline":false,"isPlus":false,"isUnverifiedBlogForCompanyWithoutPro":false,"isVerified":false,"isRemovedByUserRequest":false,"isFrozen":false,"isPro":false,"type":2,"subtype":"community"},"reactions":{"counters":[{"id":1,"count":3},{"id":2,"count":1}],"reactionId":0},"isNews":false,"source":null,"clusters":[],"donations":{"amount":0,"isDonated":false},"commentsSeenCount":null}},{"type":"entry","data":{"id":1869998,"customUri":null,"subsiteId":755936,"title":"Создание линейной диаграммы с использованием HTML5 Canvas на примере конструктора Puzzle","date":1742227632,"dateModified":1742228381,"blocks":[{"type":"media","cover":true,"hidden":false,"anchor":"","data":{"items":[{"title":"","image":{"type":"image","data":{"uuid":"c7bb8d87-1da8-59f6-a26b-2d28de41fca4","width":1656,"height":930,"size":46117,"type":"jpg","color":"34a7f3","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAAKAAoDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAf/xAAhEAAABAUFAAAAAAAAAAAAAAAAAQQVAgVUk9EDIVVhkv/EABQBAQAAAAAAAAAAAAAAAAAAAAX/xAAbEQAABwEAAAAAAAAAAAAAAAAAAQIUU4HwA//aAAwDAQACEQMRAD8AtTHLDLaX6BdnCDFLePTeRInBbWKLsWQcFtYouxZDDNch6wK95xlqH//Z"}}}]}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"В этом примере мы создадим простую линейную диаграмму с помощью технологии HTML5 Canvas. Это позволяет нам визуализировать данные, используя простые графические элементы. Реализовано в конструкторе Puzzle
"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Структура кода"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"1. HTML-структура"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Начнем с основной структуры HTML-документа:
"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"\n\n\n \n \nЗдесь мы создаем элемент <canvas> внутри контейнера с идентификатором chartContainer. Это будет область, где мы будем рисовать нашу диаграмму.
"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"2. Стилизация"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Внутри тега <style> мы задаем стили для страницы и нашего контейнера:
"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"body {\n font-family: Arial, sans-serif;\n display: flex;\n justify-content: center;\n align-items: center;\n height: 100vh;\n background-color: #f0f0f0;\n}\n#chartContainer {\n width: 380px;\n max-width: 600px;\n background: white;\n border-radius: 10px;\n padding: 20px;\n}\ncanvas {\n width: 380px;\n height: 200px;\n}","lang":""}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Мы используем flexbox для центрирования контейнера на странице и задаем некоторые стили для осей и фона.
"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"3. Обработка данных и рисование графика"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Теперь перейдем к JavaScript-коду, который будет обрабатывать данные и рисовать саму диаграмму:
"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"const dataPoints = [10, 20, 15, 25, 30, 20, 35]; // Пример данных\n\nconst canvas = document.getElementById('lineChart');\nconst ctx = canvas.getContext('2d');","lang":""}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Здесь мы определяем массив dataPoints, который содержит наши данные для диаграммы. Затем получаем контекст рисования ctx для элемента canvas.
"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"4. Установка размеров и расчеты"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"canvas.width = canvas.clientWidth;\ncanvas.height = canvas.clientHeight;\n\nconst maxDataPoint = Math.max(...dataPoints);\nconst chartHeight = canvas.height - 40; // Отступы\nconst chartWidth = canvas.width - 40;\nconst stepX = chartWidth / (dataPoints.length - 1);\nconst stepY = chartHeight / maxDataPoint;","lang":""}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Мы устанавливаем размеры canvas и вычисляем максимальное значение данных, а также ширину и высоту диаграммы, огражденные отступами.
"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"5. Рисование сетки и осей"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"ctx.strokeStyle = '#e0e0e0';\nctx.lineWidth = 1;\n// Рисуем линии сетки\nfor (let i = 0; i <= maxDataPoint; i += 5) {\n const y = chartHeight + 30 - (i * stepY);\n ctx.beginPath();\n ctx.moveTo(10, y);\n ctx.lineTo(chartWidth + 10, y);\n ctx.stroke();\n ctx.fillStyle = '#333';\n ctx.fillText(i, 5, y + 5); // Подписи по оси Y\n}","lang":""}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Мы рисуем горизонтальные линии сетки и добавляем подписи по оси Y.
"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"// Рисуем оси\nctx.beginPath();\nctx.moveTo(10, 30);\nctx.lineTo(10, chartHeight + 30);\nctx.lineTo(chartWidth + 10, chartHeight + 30);\nctx.strokeStyle = '#ccc';\nctx.stroke();","lang":""}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Затем мы рисуем оси X и Y для графика.
"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"6. Рисование линии диаграммы и точек"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"ctx.beginPath();\ndataPoints.forEach((point, index) => {\n const x = index * stepX + 10;\n const y = chartHeight + 30 - (point * stepY);\n ctx.lineTo(x, y);\n});\nctx.strokeStyle = '#007AFF'; // Цвет линии\nctx.lineWidth = 2;\nctx.stroke();","lang":""}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Здесь мы создаем линию, которая соединяет все точки данных, а также рисуем точки на линии:
"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Итог и сам код"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Этот код создаёт простую, но функциональную линейную диаграмму с использованием HTML5 и JavaScript, демонстрируя основные принципы работы с <canvas>. Документ выглядит стильно благодаря CSS, а логика построения графика достаточно проста для понимания, что делает его отличным примером для начинающих веб-разработчиков.
"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"\n\n\n \n \nВ данном кейсе мы рассмотрим, как реализовать виджет PIN-кода в мини-приложении, используя сервис Puzzlebot.
Этот виджет позволяет пользователям вводить PIN-код для доступа к определенным функциям приложения, что повышает уровень защиты информации и делает взаимодействие с вашим ботом более безопасным.
Использование PIN-кода в мини-приложении может быть полезно в следующих сценариях: - Защита пользовательских данных. PIN-код обеспечит дополнительный уровень безопасности, позволяя пользователям контролировать доступ к своим данным. - Ограничение доступа к специализированным функциям вашего бота. Например, вы можете создать контент, доступный только тем пользователям, которые ввели правильный PIN-код. - Повышение уровня информированности о безопасности и конфиденциальности. Наличие PIN-кода помогает пользователю осознать важность безопасности данных.
"}},{"type":"header","cover":false,"hidden":false,"anchor":"-A4y5e682sk","data":{"style":"h2","text":"Давайте разберем код HTML, CSS и JavaScript, который реализует виджет для ввода PIN-кода."}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Я объясню, какие главные атрибуты используются, и укажу, что отвечает за проверку ввода PIN-кода.
"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"\n\n\n \n \nПроверка ввода PIN-кода осуществляется в JavaScript:
"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"const pinInput = document.getElementById('pin');\nconst circles = [\n document.getElementById('circle1'),\n document.getElementById('circle2'),\n document.getElementById('circle3'),\n document.getElementById('circle4')\n];\nconst continueBtn = document.getElementById('continueBtn');\nconst continueLink = document.getElementById('continueLink');\nconst correctPin = '{{pin}}'; // Задайте правильный PIN-код здесь\n\npinInput.addEventListener('input', () => {\n const value = pinInput.value;\n for (let i = 0; i < circles.length; i++) {\n circles[i].textContent = i < value.length ? '●' : '';\n }\n\n if (value.length === 4) {\n if (value === correctPin) {\n continueBtn.disabled = false;\n continueLink.click(); // Автоматический переход\n } else {\n alert('Неверный PIN-код. Попробуйте еще раз.');\n pinInput.value = '';\n circles.forEach(circle => circle.textContent = '');\n }\n }\n});","lang":""}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["pinInput.addEventListener('input', ...): Добавляет обработчик события, который срабатывает при вводе данных в поле.","const value = pinInput.value;: Получает текущее значение, введенное пользователем.","circles[i].textContent = i < value.length ? '●' : '';: Обновляет отображение кругов в зависимости от введенных символов.","if (value.length === 4): Проверяет, введены ли все 4 символа.","if (value === correctPin): Сравнивает введенный PIN-код с правильным значением.","continueBtn.disabled = false;: Если PIN-код правильный, происходит автоматическое перенаправление пользователя к следующей странице.","alert('Неверный PIN-код. Попробуйте еще раз.');: Если PIN-код неверный, выводится сообщение об ошибке в попапе."],"type":"UL"}},{"type":"media","cover":false,"hidden":false,"anchor":"","data":{"items":[{"title":"alert('Неверный PIN-код. Попробуйте еще раз.');","image":{"type":"image","data":{"uuid":"555c5e41-cfb3-544b-8f5d-8a93600fddb4","width":1656,"height":930,"size":45866,"type":"jpg","color":"797a7b","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCAAKAAoDASEAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAABgQF/8QAJBAAAQMDAgcBAAAAAAAAAAAAAgEDBAAGEQUzEiExMkFRclL/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/EABURAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIRAxEAPwBPb9tWlM03TZE28GoTrjSE+wuMgvrtXxz60AnCATnwaPjAXCQS/SZXC0FjOyHylZ728f0tEr//2Q=="}}}]}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Таким образом, код создает интерактивный виджет для ввода PIN-кода с визуальной обратной связью и проверкой правильности ввода
"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Код виджета:"}},{"type":"code","cover":false,"hidden":false,"anchor":"-A4y5e682sk","data":{"text":"\n\n\n \n \n