Compare commits
113 Commits
f904f91a9c
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
| fc5ad996c0 | |||
| 59de951edd | |||
| 99c3efe678 | |||
| e0f89df21c | |||
| ffd821dbd6 | |||
| b821af9747 | |||
| 4f9f2cd854 | |||
| 495162ff43 | |||
| c16f4f773a | |||
| 3fff4b7b20 | |||
| 4265e84764 | |||
| 9080e1193d | |||
| 3b90549202 | |||
| 05af7f19f5 | |||
| 0462ed1ef5 | |||
| 32dabcff9c | |||
| 82eca6ee1a | |||
| 7a335f9415 | |||
| 5595bc7371 | |||
| a4c4084f9b | |||
| 44a2a437df | |||
| 74b5b615ac | |||
| 282df2bc91 | |||
| 0ce198aa5e | |||
| b051b2778f | |||
| 22d30a2469 | |||
| 43a3d75f43 | |||
| 24a5abb1f1 | |||
| f41b14349c | |||
| 501d562025 | |||
| 6d7d63a891 | |||
| 820e0b5216 | |||
| 61949e7149 | |||
| e9657a4003 | |||
| 38b6e9fca6 | |||
| 35cd174c8b | |||
| 5aee0eccb2 | |||
| 9a5dfdb2ed | |||
| 794ad2913f | |||
| 6c509a6b54 | |||
| fb816fca11 | |||
| 82064af0db | |||
| 5b13ec8d8d | |||
| 288cde5dcf | |||
| d18c29f391 | |||
| 1a77d471ad | |||
| d270d9435b | |||
| 104d62bc13 | |||
| 86ca32bc01 | |||
| 793e980c93 | |||
| a987a83280 | |||
| da4dea7f5d | |||
| c9082a9f58 | |||
| e81dd69f19 | |||
| b94f5f44cb | |||
| 0dbe26fd4e | |||
| b3d2f56797 | |||
| 4c60e2d773 | |||
| ef3766bc2a | |||
| 3d21d078cf | |||
| 184abb25b4 | |||
| 55e8f13e32 | |||
| 2a5b894a1b | |||
| 092bbec6ac | |||
| 5a0e77ebb8 | |||
| cdf3323d77 | |||
| 2a3193a3fa | |||
| 8c4a9cc85f | |||
| faf5c56219 | |||
| e403413965 | |||
| 9d04076921 | |||
| 8306543828 | |||
| de91f8129e | |||
| f38ae2c288 | |||
| 9aa61dce27 | |||
| 395eb3de47 | |||
| a98e1ac5b0 | |||
| 0ebf8e1c65 | |||
| 23b2c6f534 | |||
| c8d2415e50 | |||
| 82dfd7fa56 | |||
| 051835b9bd | |||
| 282b365287 | |||
| 3b4ff71b9a | |||
| dc6d048645 | |||
| ee468fe4fe | |||
| 8f0e912d9e | |||
| b5dcda83a9 | |||
| 457eee4ffa | |||
| 7e025fb449 | |||
| 8c0bff8082 | |||
| 2a3e908c44 | |||
| 6599d8bf21 | |||
| 194b3ad3c2 | |||
| 488eee1a25 | |||
| f5514b8fb5 | |||
| e7c8322c63 | |||
| 663347889b | |||
| 97d505dcc7 | |||
| c09928a2b2 | |||
| 047f662736 | |||
| 3808086529 | |||
| 7424bc43b0 | |||
| a8097c95d4 | |||
| 4c81862bb4 | |||
| 3682f25282 | |||
| 57e3d6b3e5 | |||
| b220798978 | |||
| dca3ca67ad | |||
| 494195c532 | |||
| 2ad8f9793b | |||
| 7d774440a9 | |||
| b54fdb987e |
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 TailAdmin
|
||||
Copyright (c) 2026 Pregnant guide
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -1 +1,206 @@
|
||||
xamluoccampuchia
|
||||
# Ultimate History Map
|
||||
|
||||
> Explore history through maps, timelines, and connected knowledge.
|
||||
|
||||
## Overview
|
||||
|
||||
**Ultimate History Map** is an interactive history platform designed to make historical knowledge easier to explore, understand, and connect through maps, timelines, and structured wiki content.
|
||||
|
||||
The project helps users learn history in a more visual and intuitive way. Instead of reading isolated articles or looking at static maps, users can explore historical information directly on a map, move through time, and connect people, places, countries, wars, and events within the same experience.
|
||||
|
||||
Ultimate History Map is built around one core idea: history should not only be read — it should be seen, explored, and understood in context.
|
||||
|
||||
## Why Ultimate History Map?
|
||||
|
||||
History is one of the most important subjects for understanding the world, but it is often difficult to approach.
|
||||
|
||||
Many historical resources already exist, but they are usually separated across books, articles, maps, timelines, videos, and databases. This makes it hard for learners to understand how historical events relate to real places, time periods, people, countries, and surrounding events.
|
||||
|
||||
Some historical map platforms allow users to view countries across time, but they often focus mainly on borders. That is useful, but not enough for learning history deeply. History is not only about borders. It is also about people, wars, cities, cultures, migrations, political changes, ideas, and the connections between them.
|
||||
|
||||
Ultimate History Map aims to solve these problems by bringing historical maps, wiki-style information, timelines, and structured historical data into one connected platform.
|
||||
|
||||
## The Solution
|
||||
|
||||
Ultimate History Map provides a central place where users can explore historical information visually.
|
||||
|
||||
The platform allows users to:
|
||||
|
||||
* view historical maps by time period,
|
||||
* explore countries, people, wars, places, and events on the map,
|
||||
* search for historical information quickly,
|
||||
* read wiki-style content connected directly to map objects,
|
||||
* move from a wiki article back to the related location or event on the map,
|
||||
* understand historical context through surrounding events and related entities,
|
||||
* and access data that can be contributed, reviewed, and improved over time.
|
||||
|
||||
The goal is not only to display historical data, but to make that data easier to understand.
|
||||
|
||||
## Core Experience
|
||||
|
||||
The main user experience is centered around the map.
|
||||
|
||||
A user can choose a point in time and see what the world looked like at that moment. Countries, territories, places, events, people, and conflicts can appear based on the selected time period.
|
||||
|
||||
When the user selects something on the map, the platform shows related wiki content. When the user reads a wiki page and follows related links, the map can automatically focus on the relevant place, entity, or event.
|
||||
|
||||
This creates a two-way connection between map and knowledge:
|
||||
|
||||
* the map helps users discover historical information,
|
||||
* and the wiki helps users understand what they are seeing on the map.
|
||||
|
||||
For example, a user may search for a historical figure such as Quang Trung, view related places and events on the map, read connected wiki content, and continue exploring surrounding events from the same historical context.
|
||||
|
||||
## User Roles
|
||||
|
||||
Ultimate History Map is designed for multiple types of users.
|
||||
|
||||
### Learners and Explorers
|
||||
|
||||
General users who want to learn history in a more visual and accessible way. They can search, explore, read, and understand historical events through the map and wiki system.
|
||||
|
||||
### Teachers, Researchers, and Historians
|
||||
|
||||
Users with historical knowledge who can create or manage historical content, contribute map data, and help improve the quality of the platform.
|
||||
|
||||
### Contributors
|
||||
|
||||
Community members who can help add new information, improve existing content, and participate in building a larger historical knowledge base.
|
||||
|
||||
### Historians and Reviewers
|
||||
|
||||
Trusted reviewers who help verify submitted content before it becomes official data on the platform.
|
||||
|
||||
### Admins
|
||||
|
||||
Platform managers who handle users, roles, projects, submissions, and overall system moderation.
|
||||
|
||||
## Key Features
|
||||
|
||||
Ultimate History Map already includes the core features required for a functional historical map platform.
|
||||
|
||||
### Interactive Historical Map
|
||||
|
||||
The map can display default map layers, custom drawings, icons, and historical layers based on time and location.
|
||||
|
||||
### Time and Area Filtering
|
||||
|
||||
Map data and related information can be filtered by selected time and map bounds, allowing users to explore only the content relevant to a specific period and area.
|
||||
|
||||
### Wiki System
|
||||
|
||||
Historical content can be written, viewed, and connected to map objects. This allows the platform to work not only as a map, but also as a structured historical knowledge base.
|
||||
|
||||
### Visual Editor
|
||||
|
||||
The editor allows contributors to add and manage historical information directly on the map. This makes data creation more intuitive than editing raw coordinates or disconnected documents.
|
||||
|
||||
### Version Control
|
||||
|
||||
Historical data can be versioned, allowing changes to be tracked and managed over time.
|
||||
|
||||
### Team and Project Management
|
||||
|
||||
The platform supports project-based management, including contributors, team workflows, and progress tracking.
|
||||
|
||||
### Review and Approval Workflow
|
||||
|
||||
Submitted data can be reviewed before becoming official, helping maintain quality and reliability.
|
||||
|
||||
### Role-based Management
|
||||
|
||||
The system supports different roles such as admin and historian, allowing responsibilities to be separated clearly.
|
||||
|
||||
## What Makes It Different?
|
||||
|
||||
Ultimate History Map is not just a historical map and not just a wiki.
|
||||
|
||||
Most historical maps focus mainly on showing borders at different points in time. Ultimate History Map aims to go further by connecting multiple types of historical data in one place.
|
||||
|
||||
It can represent:
|
||||
|
||||
* countries and territories,
|
||||
* people,
|
||||
* places,
|
||||
* wars,
|
||||
* battles,
|
||||
* historical events,
|
||||
* routes,
|
||||
* and related wiki knowledge.
|
||||
|
||||
Another important difference is the interaction between the map and wiki content. Instead of using external wiki links that are disconnected from the map, Ultimate History Map is designed so that map objects and wiki content can reference each other directly.
|
||||
|
||||
This makes the learning experience more connected. Users can move from a map object to an explanation, then from that explanation to another related object on the map.
|
||||
|
||||
The platform is also designed with future event replay features in mind, especially battle replay and event replay. These features aim to help users understand historical processes as sequences, not just static descriptions.
|
||||
|
||||
## Example Use Cases
|
||||
|
||||
Ultimate History Map can be used in many learning and research scenarios.
|
||||
|
||||
For example, users can:
|
||||
|
||||
* learn about a historical figure such as Quang Trung,
|
||||
* see what was happening around the world in the year 1900,
|
||||
* observe country borders during a specific period,
|
||||
* select a war and understand how it progressed,
|
||||
* explore related places, people, and events from a wiki page,
|
||||
* follow a historical route such as migration, attack, or expansion,
|
||||
* or compare different historical periods through the map.
|
||||
|
||||
These use cases are designed to make history easier to understand for both casual learners and serious researchers.
|
||||
|
||||
## Current Status
|
||||
|
||||
Ultimate History Map has completed its basic core platform and is already usable.
|
||||
|
||||
The current system includes:
|
||||
|
||||
* interactive map visualization,
|
||||
* default map layers,
|
||||
* custom drawings and icons,
|
||||
* time-based and area-based filtering,
|
||||
* wiki functionality,
|
||||
* editor tools,
|
||||
* version control,
|
||||
* team control,
|
||||
* content submission and approval,
|
||||
* admin management features,
|
||||
* and role-based workflows for admins and historians.
|
||||
|
||||
Advanced learning and replay features are still under development, but the foundation of the platform is already in place.
|
||||
|
||||
## Future Extensions
|
||||
|
||||
Ultimate History Map is designed to grow beyond a map viewer.
|
||||
|
||||
Planned and possible future extensions include:
|
||||
|
||||
* multilingual support,
|
||||
* structured history courses,
|
||||
* exams and quizzes,
|
||||
* video-based learning content,
|
||||
* battle replay,
|
||||
* event replay,
|
||||
* improved community contribution workflows,
|
||||
* and AI agents that can help users ask questions, understand context, and interact with the map more easily.
|
||||
|
||||
These extensions aim to turn the platform into a broader historical learning ecosystem.
|
||||
|
||||
## Technology
|
||||
|
||||
The README focuses mainly on the product idea and user value, but the platform is supported by a modern web and geospatial stack.
|
||||
|
||||
* **Go** is used for the backend because of its performance, simplicity, and reliability for building scalable services.
|
||||
* **Next.js** is used for the frontend because it provides a modern web experience and supports SEO-friendly pages.
|
||||
* **PostgreSQL** and **PostGIS** are used for structured data, geospatial storage, and efficient map-based queries.
|
||||
|
||||
The technology is chosen to support long-term scalability, reliable data management, and interactive map-based experiences.
|
||||
|
||||
## Mission
|
||||
|
||||
Ultimate History Map is built with the goal of creating community value.
|
||||
|
||||
History should not only exist as disconnected text, static maps, or scattered documents. It should be connected through time, place, people, events, and context.
|
||||
|
||||
Ultimate History Map aims to make history more visual, accessible, trustworthy, and meaningful for everyone.
|
||||
|
||||
@@ -0,0 +1,254 @@
|
||||
# FrontEndUser Technical README
|
||||
|
||||
## Scope
|
||||
|
||||
Tài liệu này mô tả phần **FrontEndUser** như một runtime web độc lập: biên dịch bằng Next.js, triển khai bằng Docker, phụ thuộc vào API backend để xử lý dữ liệu lịch sử, xác thực, media và proxy bản đồ. Nội dung ở đây không mô tả giá trị sản phẩm; nó mô tả ràng buộc hệ thống, quyết định kỹ thuật, điểm kiểm soát vận hành và số đo hiện có trong repository.
|
||||
|
||||
## Baseline Thực Nghiệm
|
||||
|
||||
Các số liệu dưới đây được đo trực tiếp tại working tree hiện tại.
|
||||
|
||||
```text
|
||||
package name fe_admin_history_web
|
||||
package version 2.2.3
|
||||
runtime image node:24-alpine
|
||||
production server port 3000
|
||||
docker-compose host port 3014
|
||||
dependencies 34
|
||||
devDependencies 12
|
||||
TypeScript/TSX files in src 232
|
||||
Next app route files 20
|
||||
TypeScript/TSX files in uhm 140
|
||||
src size 3.4M
|
||||
public size 43M
|
||||
node_modules size 759M
|
||||
.next size 941M
|
||||
.next/standalone size 58M
|
||||
.next/static size 5.3M
|
||||
```
|
||||
|
||||
Diễn giải vận hành:
|
||||
|
||||
* Kích thước `node_modules` và `.next` không được dùng làm runtime artifact. Runtime Docker chỉ cần standalone server, static assets và `public`.
|
||||
* `.next/standalone` đang ở mức 58M, thấp hơn rất nhiều so với full build directory 941M. Đây là lý do bắt buộc giữ `output: "standalone"` trong `next.config.ts`.
|
||||
* 140/232 file TS/TSX nằm trong `src/uhm`; rủi ro thay đổi tập trung ở module bản đồ, editor, wiki, replay và geospatial client logic.
|
||||
* `npm ls --depth=0` hiện báo một package extraneous: `@emnapi/runtime@1.9.1`. Đây không phải lỗi build mặc định, nhưng là tín hiệu cần dọn dependency tree trước khi khóa môi trường CI nghiêm ngặt.
|
||||
|
||||
## Runtime Boundary
|
||||
|
||||
FrontEndUser không sở hữu dữ liệu lõi. Nó là boundary hiển thị và tương tác.
|
||||
|
||||
Các trách nhiệm nằm trong frontend:
|
||||
|
||||
* render route bằng Next.js App Router;
|
||||
* giữ state tương tác của bản đồ/editor/wiki;
|
||||
* gọi API backend qua Axios/fetch;
|
||||
* xử lý token phía client khi backend trả token trong payload;
|
||||
* gửi cookie theo `withCredentials: true`;
|
||||
* rewrite request Goong qua backend proxy;
|
||||
* render MapLibre layer/source sau khi nhận manifest/style đã sanitize từ backend.
|
||||
|
||||
Các trách nhiệm không được đặt vào frontend:
|
||||
|
||||
* giữ Goong API key thật;
|
||||
* quyết định quyền truy cập dữ liệu;
|
||||
* xử lý refresh token như một nguồn tin cậy;
|
||||
* proxy trực tiếp tới upstream map provider từ browser;
|
||||
* query geospatial nặng;
|
||||
* normalize dữ liệu lịch sử ở quy mô database.
|
||||
|
||||
## Stack
|
||||
|
||||
Stack chính theo `package.json` và lockfile hiện tại:
|
||||
|
||||
```text
|
||||
Next.js 16.x
|
||||
React 19.x
|
||||
TypeScript 5.9.x
|
||||
Tailwind CSS 4.x
|
||||
MapLibre GL 5.x
|
||||
Axios 1.x
|
||||
Redux Toolkit 2.x
|
||||
Zustand 5.x
|
||||
```
|
||||
|
||||
Các dependency nặng đã được tách chunk trong `next.config.ts`:
|
||||
|
||||
* `maplibre-gl` -> chunk `maplibre`
|
||||
* `react-quill-new`, `quill`, `quill-blot-formatter` -> chunk `quill`
|
||||
* `apexcharts`, `react-apexcharts` -> chunk `charts`
|
||||
* `@fullcalendar/*` -> chunk `calendar`
|
||||
|
||||
Ràng buộc ở đây là rõ: bản đồ, rich text editor, chart và calendar không được kéo vào cùng một client bundle mặc định nếu route không cần chúng.
|
||||
|
||||
## Configuration Contract
|
||||
|
||||
Frontend đọc cấu hình từ environment tại thời điểm build.
|
||||
|
||||
```bash
|
||||
NEXT_PUBLIC_API_URL_ROOT="https://api.uhm.io.vn"
|
||||
NEXT_PUBLIC_URL_MEDIA="https://cdn.uhm.io.vn/history-app/"
|
||||
NEXT_PUBLIC_HOME_URL="http://localhost:3000"
|
||||
|
||||
BACKGROUND_MAP_API_KEY=
|
||||
SEARCH_MAP_API_KEY=
|
||||
```
|
||||
|
||||
Biến đang được code client đọc trực tiếp:
|
||||
|
||||
* `NEXT_PUBLIC_API_URL_ROOT`
|
||||
* `NEXT_PUBLIC_URL_MEDIA`
|
||||
* `NEXT_PUBLIC_HOME_URL`
|
||||
|
||||
Quy tắc triển khai: mọi biến `NEXT_PUBLIC_*` phải đúng trước `npm run build` hoặc trước `docker build`. Đổi biến ở runtime container không đảm bảo đổi behavior phía browser vì Next.js đã inline các giá trị public vào client bundle.
|
||||
|
||||
## Backend Dependency Contract
|
||||
|
||||
`NEXT_PUBLIC_API_URL_ROOT` là contract trung tâm. Từ biến này, frontend tạo các endpoint:
|
||||
|
||||
```text
|
||||
<API_ROOT>/users/current
|
||||
<API_ROOT>/auth/signin
|
||||
<API_ROOT>/auth/refresh
|
||||
<API_ROOT>/projects
|
||||
<API_ROOT>/submissions
|
||||
<API_ROOT>/geometries
|
||||
<API_ROOT>/entities
|
||||
<API_ROOT>/wikis
|
||||
<API_ROOT>/battle-replays
|
||||
```
|
||||
|
||||
Map proxy contract:
|
||||
|
||||
```text
|
||||
<API_ROOT>/map/proxy/tiles.goong.io/...
|
||||
<API_ROOT>/api/proxy/rsapi.goong.io/...
|
||||
```
|
||||
|
||||
Backend phải thỏa các điều kiện sau:
|
||||
|
||||
* CORS cho phép frontend origin production.
|
||||
* Cookie policy tương thích cross-origin nếu deploy khác domain.
|
||||
* `/auth/refresh` hoạt động với cookie httpOnly hoặc trả access token mới theo payload mà frontend hiểu.
|
||||
* Proxy Goong không trả JSON chứa `api_key`.
|
||||
* Proxy Goong giữ shape đủ tương thích để frontend tiếp tục rewrite nested resource URLs.
|
||||
|
||||
## Map Constraint
|
||||
|
||||
MapLibre không được gọi trực tiếp Goong bằng URL chứa key. Flow hiện tại:
|
||||
|
||||
1. Frontend gọi style/source/font/tile qua backend proxy.
|
||||
2. Backend gọi upstream Goong bằng server-side key.
|
||||
3. Backend sanitize URL lồng bên trong response.
|
||||
4. Frontend rewrite URL sạch qua `buildGoongProxyUrl`.
|
||||
5. MapLibre chỉ thấy proxy URL.
|
||||
|
||||
Constraint quan trọng: backend không nên rewrite sẵn mọi nested URL thành `/proxy/...` nếu frontend vẫn gọi `buildGoongProxyUrl`; làm vậy có rủi ro double-proxy. Contract hiện tại yêu cầu backend trả upstream URL sạch hoặc relative URL, không trả URL đã chứa key.
|
||||
|
||||
## Auth Constraint
|
||||
|
||||
Axios instance dùng `withCredentials: true` và request interceptor gắn Bearer token nếu có token trong client storage. Response interceptor xử lý hai loại hết hạn token:
|
||||
|
||||
* HTTP `401`;
|
||||
* response `200` nhưng body có `status: false` và message cho thấy token hết hạn/không hợp lệ.
|
||||
|
||||
Khi refresh thất bại với `401` hoặc `404`, frontend xóa token local và redirect về `/signin`.
|
||||
|
||||
Ràng buộc vận hành:
|
||||
|
||||
* backend không được trả message hết hạn token mơ hồ nếu muốn frontend tự refresh;
|
||||
* refresh endpoint không được tạo vòng lặp interceptor;
|
||||
* cookie refresh phải có domain, path, SameSite và Secure tương thích domain deploy.
|
||||
|
||||
## Build And Deployment
|
||||
|
||||
Development:
|
||||
|
||||
```bash
|
||||
npm ci
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Dev server khác port:
|
||||
|
||||
```bash
|
||||
npm run dev -- --port 3005
|
||||
```
|
||||
|
||||
Quality gates cục bộ:
|
||||
|
||||
```bash
|
||||
npm run lint
|
||||
npm run build
|
||||
```
|
||||
|
||||
Production bằng Docker Compose:
|
||||
|
||||
```bash
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
Port mapping:
|
||||
|
||||
```text
|
||||
host:3014 -> container:3000
|
||||
```
|
||||
|
||||
Dockerfile hiện có ba lớp logic:
|
||||
|
||||
1. `deps`: cài dependency bằng `npm ci`.
|
||||
2. `builder`: build Next.js standalone bằng `npm run build`.
|
||||
3. `runner`: chạy `node server.js` từ `.next/standalone`.
|
||||
|
||||
Do `Dockerfile` copy `.env` vào build stage, file `.env` production phải được kiểm soát trước khi build image. Không dùng `.env.local` như nguồn cấu hình production trừ khi Dockerfile được đổi có chủ đích.
|
||||
|
||||
## Operational Checks
|
||||
|
||||
Sau khi deploy, kiểm tra theo thứ tự phụ thuộc:
|
||||
|
||||
1. `GET /` trả HTML và load client bundle không lỗi.
|
||||
2. Browser không request trực tiếp `tiles.goong.io` hoặc `rsapi.goong.io`.
|
||||
3. Map request đi qua `<API_ROOT>/map/proxy/...`.
|
||||
4. Place search/reverse geocode request đi qua `<API_ROOT>/api/proxy/...`.
|
||||
5. `/auth/signin` ghi được cookie hoặc trả token mà client lưu được.
|
||||
6. `/auth/refresh` trả token mới khi access token hết hạn.
|
||||
7. `/users/current` hoạt động sau refresh.
|
||||
8. `/wiki/[slug]`, `/editor`, `/user/projects` không crash khi reload trực tiếp.
|
||||
9. Media URL dưới `NEXT_PUBLIC_URL_MEDIA` trả được ảnh/video cần render.
|
||||
|
||||
## Failure Modes
|
||||
|
||||
Các lỗi có xác suất cao nhất khi triển khai:
|
||||
|
||||
* Build image bằng sai `NEXT_PUBLIC_API_URL_ROOT`: frontend deploy thành công nhưng mọi API call trỏ sai host.
|
||||
* Backend CORS đúng cho API thường nhưng sai cho credentialed request: sign in được một phần, refresh/session hỏng.
|
||||
* Goong proxy trả URL còn `api_key`: lộ key qua DevTools và cache layer.
|
||||
* Goong proxy rewrite nested URL quá sớm: MapLibre nhận URL double-proxy và tile/font hỏng.
|
||||
* Thêm dependency bản đồ/editor/chart vào shared component: tăng client bundle của route không liên quan.
|
||||
* Deploy sau khi `npm install` tạo dependency tree khác lockfile: `npm ci` trong Docker/CI có thể fail hoặc build khác local.
|
||||
|
||||
## Change Control
|
||||
|
||||
Các thay đổi cần được xem như thay đổi kiến trúc, không phải chỉnh UI đơn thuần:
|
||||
|
||||
* đổi `NEXT_PUBLIC_API_URL_ROOT` semantics;
|
||||
* đổi đường dẫn `/map/proxy` hoặc `/api/proxy`;
|
||||
* đổi cơ chế refresh token;
|
||||
* đưa Goong key xuống browser;
|
||||
* bỏ `output: "standalone"`;
|
||||
* thay MapLibre style loading từ incremental source/layer sang `map.setStyle(goongStyleJson)` trực tiếp;
|
||||
* đưa `maplibre-gl`, Quill, chart hoặc calendar vào layout dùng chung.
|
||||
|
||||
## Measurement Commands
|
||||
|
||||
Dùng các lệnh này để cập nhật baseline khi cần:
|
||||
|
||||
```bash
|
||||
du -sh .next node_modules public src
|
||||
du -sh .next/standalone .next/static
|
||||
find src -type f \( -name '*.ts' -o -name '*.tsx' \) | wc -l
|
||||
find src/app -type f \( -name 'page.tsx' -o -name 'layout.tsx' \) | wc -l
|
||||
find src/uhm -type f \( -name '*.ts' -o -name '*.tsx' \) | wc -l
|
||||
node -e "const p=require('./package.json'); console.log(Object.keys(p.dependencies||{}).length, Object.keys(p.devDependencies||{}).length)"
|
||||
npm ls --depth=0
|
||||
```
|
||||
@@ -0,0 +1,32 @@
|
||||
# Third-party notices
|
||||
|
||||
This project includes portions of TailAdmin.
|
||||
|
||||
TailAdmin
|
||||
Copyright (c) 2023 TailAdmin
|
||||
Licensed under the MIT License.
|
||||
Website: https://tailadmin.com
|
||||
|
||||
## TailAdmin MIT License
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 TailAdmin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -66,5 +66,6 @@ export const API = {
|
||||
},
|
||||
Chatbot:{
|
||||
CHAT: `${API_URL_ROOT}/chatbot/chat`,
|
||||
HISTORY: `${API_URL_ROOT}/chatbot/history`,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,248 +0,0 @@
|
||||
# Commit Snapshot (`commits.snapshot_json`) - Chuẩn Hiện Tại (FrontEndUser / UHM)
|
||||
|
||||
Tài liệu này mô tả **snapshot_json** mà `FrontEndUser` (module UHM editor) tạo ra khi bấm **Commit** trong `/editor/[id]`, và gửi lên endpoint `POST /projects/{id}/commits`.
|
||||
|
||||
Nguồn tham chiếu trong code (FrontEndUser):
|
||||
|
||||
- Types:
|
||||
- `src/uhm/types/sections.ts` (`EditorSnapshot`, `EntityWikiLinkSnapshot`)
|
||||
- `src/uhm/types/geo.ts` (`FeatureCollection`, `GeometrySnapshot`, `GeometryEntitySnapshot`)
|
||||
- `src/uhm/types/entities.ts` (`EntitySnapshot`)
|
||||
- `src/uhm/types/wiki.ts` (`WikiSnapshot`)
|
||||
- Build/normalize snapshot:
|
||||
- `src/uhm/lib/editor/snapshot/editorSnapshot.ts` (`buildEditorSnapshot`, `normalizeEditorSnapshot`)
|
||||
|
||||
## 1) Root Shape
|
||||
|
||||
FE hiện tại không dùng `schema_version`. `snapshot_json` là một object có các phần sau:
|
||||
|
||||
```ts
|
||||
export type EditorSnapshot = {
|
||||
editor_feature_collection?: FeatureCollection;
|
||||
entities?: EntitySnapshot[];
|
||||
geometries?: GeometrySnapshot[];
|
||||
geometry_entity?: GeometryEntitySnapshot[];
|
||||
wikis?: WikiSnapshot[];
|
||||
entity_wiki?: EntityWikiLinkSnapshot[];
|
||||
};
|
||||
```
|
||||
|
||||
Lưu ý:
|
||||
|
||||
- FE có thể **đọc** cả `entity_wiki` và legacy alias `entity_wikis` khi load snapshot (normalize), nhưng khi commit FE ghi `entity_wiki`.
|
||||
- `editor_feature_collection` là nguồn để render editor/map. Các join table (`geometry_entity`, `entity_wiki`) là nguồn quan hệ.
|
||||
|
||||
## 2) Types (TypeScript) - Đúng Theo FE Hiện Tại
|
||||
|
||||
### 2.1 GeoJSON (editor_feature_collection)
|
||||
|
||||
```ts
|
||||
export type Geometry =
|
||||
| { type: "Point"; coordinates: [number, number] }
|
||||
| { type: "MultiPoint"; coordinates: [number, number][] }
|
||||
| { type: "LineString"; coordinates: [number, number][] }
|
||||
| { type: "MultiLineString"; coordinates: [number, number][][] }
|
||||
| { type: "Polygon"; coordinates: [number, number][][] }
|
||||
| { type: "MultiPolygon"; coordinates: [number, number][][][] };
|
||||
|
||||
export type FeatureId = string | number;
|
||||
|
||||
export type FeatureProperties = {
|
||||
id: FeatureId;
|
||||
type?: string | null;
|
||||
geometry_preset?: string | null;
|
||||
time_start?: number | null;
|
||||
time_end?: number | null;
|
||||
binding?: string[];
|
||||
|
||||
// UI-only / legacy fields (FE sẽ strip khi persist snapshot):
|
||||
entity_id?: string | null;
|
||||
entity_ids?: string[];
|
||||
entity_name?: string | null;
|
||||
entity_names?: string[];
|
||||
entity_type_id?: string | null;
|
||||
};
|
||||
|
||||
export type Feature = {
|
||||
type: "Feature";
|
||||
properties: FeatureProperties;
|
||||
geometry: Geometry;
|
||||
};
|
||||
|
||||
export type FeatureCollection = {
|
||||
type: "FeatureCollection";
|
||||
features: Feature[];
|
||||
};
|
||||
```
|
||||
|
||||
### 2.2 Snapshot rows
|
||||
|
||||
```ts
|
||||
export type SnapshotSource = "inline" | "ref";
|
||||
|
||||
export type EntitySnapshotOperation = "create" | "update" | "delete" | "reference";
|
||||
export type GeometrySnapshotOperation = "create" | "update" | "delete" | "reference";
|
||||
export type WikiSnapshotOperation = "create" | "update" | "delete" | "reference";
|
||||
|
||||
export type EntitySnapshot = {
|
||||
id: string;
|
||||
source: SnapshotSource;
|
||||
operation?: EntitySnapshotOperation;
|
||||
name?: string;
|
||||
slug?: string | null;
|
||||
description?: string | null;
|
||||
status?: number | null;
|
||||
base_updated_at?: string;
|
||||
base_hash?: string;
|
||||
};
|
||||
|
||||
export type GeometrySnapshot = {
|
||||
id: string;
|
||||
source: SnapshotSource;
|
||||
operation?: GeometrySnapshotOperation;
|
||||
type?: string | null;
|
||||
draw_geometry?: Geometry;
|
||||
geometry?: Geometry; // legacy
|
||||
binding?: string[];
|
||||
time_start?: number | null;
|
||||
time_end?: number | null;
|
||||
bbox?: {
|
||||
min_lng: number;
|
||||
min_lat: number;
|
||||
max_lng: number;
|
||||
max_lat: number;
|
||||
} | null;
|
||||
base_updated_at?: string;
|
||||
base_hash?: string;
|
||||
};
|
||||
|
||||
// FE stores wiki doc as a string (commonly HTML; in some flows it may be a JSON-stringified editor payload).
|
||||
export type WikiDoc = string | null;
|
||||
|
||||
export type WikiSnapshot = {
|
||||
id: string;
|
||||
source: SnapshotSource;
|
||||
operation?: WikiSnapshotOperation;
|
||||
title: string;
|
||||
slug?: string | null;
|
||||
doc: WikiDoc;
|
||||
updated_at?: string;
|
||||
};
|
||||
```
|
||||
|
||||
### 2.3 Join tables
|
||||
|
||||
```ts
|
||||
export type GeometryEntitySnapshot = {
|
||||
geometry_id: string;
|
||||
entity_id: string;
|
||||
base_links_hash?: string;
|
||||
};
|
||||
|
||||
export type EntityWikiLinkSnapshot = {
|
||||
entity_id: string;
|
||||
wiki_id: string;
|
||||
operation?: "reference" | "binding" | "delete";
|
||||
};
|
||||
```
|
||||
|
||||
## 3) Quy Ước FE Khi Build Snapshot (buildEditorSnapshot)
|
||||
|
||||
### 3.1 Feature.properties entity fields bị strip
|
||||
|
||||
Khi persist snapshot, FE chủ động xoá các field denormalize trên feature properties:
|
||||
`entity_id`, `entity_ids`, `entity_name`, `entity_names`, `entity_type_id`.
|
||||
|
||||
Quan hệ geometry ↔ entity chỉ nằm ở `geometry_entity[]`.
|
||||
|
||||
### 3.2 entities[]
|
||||
|
||||
FE cố gắng đảm bảo mọi entity có `name` không rỗng (fallback sang `id`) và có `source`.
|
||||
|
||||
`operation` được dùng như "delta" trong commit:
|
||||
|
||||
- `"create"|"update"|"delete"`: thay đổi record entity
|
||||
- `"reference"`: đưa entity vào context snapshot (pin/link) nhưng commit không sửa record entity
|
||||
|
||||
### 3.3 geometries[]
|
||||
|
||||
FE sinh 1 `GeometrySnapshot` cho mỗi feature đang tồn tại trong `editor_feature_collection.features[]`:
|
||||
|
||||
- `id = String(feature.properties.id)`
|
||||
- `source:"inline"`
|
||||
- `draw_geometry = feature.geometry`
|
||||
- `binding`, `time_start`, `time_end`, `bbox` (nếu tính được)
|
||||
- `type`: FE hiện gửi **string code** (geo_type smallint) dưới dạng string
|
||||
- `operation`:
|
||||
- `"create"` nếu geometry mới
|
||||
- `"update"` nếu geometry thay đổi
|
||||
- `undefined` nếu geometry không đổi
|
||||
|
||||
Nếu feature bị xoá khỏi draft, FE thêm 1 row:
|
||||
|
||||
```json
|
||||
{ "id": "…", "source": "ref", "operation": "delete" }
|
||||
```
|
||||
|
||||
### 3.4 geometry_entity[]
|
||||
|
||||
`geometry_entity` là danh sách quan hệ many-to-many geometry ↔ entity. Mỗi row là một cặp:
|
||||
|
||||
```ts
|
||||
{ geometry_id: string; entity_id: string }
|
||||
```
|
||||
|
||||
### 3.5 wikis[]
|
||||
|
||||
- Wiki `source:"ref"` (được add từ search): FE set `operation:"reference"` và `doc:null`.
|
||||
- Wiki `source:"inline"` (được tạo/sửa trong editor):
|
||||
- nếu UI set explicit `create|update|delete` thì giữ nguyên
|
||||
- nếu không có operation:
|
||||
- wiki mới: FE coi là `"create"`
|
||||
- wiki cũ không đổi: FE gán `"reference"`
|
||||
- wiki cũ có đổi nội dung: FE gán `"update"`
|
||||
|
||||
### 3.6 entity_wiki[]
|
||||
|
||||
Type trong FE cho UI state cho phép `"binding"` và `"delete"`.
|
||||
|
||||
Khi build snapshot để commit, FE map link “đang bật” về `"reference"` để tương thích với backend (một số backend chỉ chấp nhận `"reference"|"delete"`).
|
||||
|
||||
## 4) Ví Dụ snapshot_json (rút gọn)
|
||||
|
||||
```json
|
||||
{
|
||||
"editor_feature_collection": {
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": { "id": "019e…", "type": "country", "time_start": 1000, "time_end": 1500 },
|
||||
"geometry": { "type": "Polygon", "coordinates": [[[100, 10], [101, 10], [101, 11], [100, 10]]] }
|
||||
}
|
||||
]
|
||||
},
|
||||
"entities": [
|
||||
{ "id": "019e…", "source": "inline", "operation": "reference", "name": "ent1", "description": null, "status": 1 }
|
||||
],
|
||||
"geometries": [
|
||||
{ "id": "019e…", "source": "inline", "operation": "update", "type": "9", "draw_geometry": { "type": "Polygon", "coordinates": [] }, "binding": [], "time_start": 1000, "time_end": 1500, "bbox": null }
|
||||
],
|
||||
"geometry_entity": [
|
||||
{ "geometry_id": "019e…", "entity_id": "019e…" }
|
||||
],
|
||||
"wikis": [
|
||||
{ "id": "019e…", "source": "ref", "operation": "reference", "title": "Existing wiki", "doc": null, "updated_at": "2026-05-08T00:00:00.000Z" }
|
||||
],
|
||||
"entity_wiki": [
|
||||
{ "entity_id": "019e…", "wiki_id": "019e…", "operation": "reference" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 5) Compat Notes (khi load snapshot cũ)
|
||||
|
||||
FE normalize khi load snapshot:
|
||||
|
||||
- Nếu thấy `entity_wikis` (plural) sẽ đọc như `entity_wiki`.
|
||||
- Nếu join link có `operation:"reference"` thì FE coi như link active (UI biểu diễn như “binding”).
|
||||
@@ -27,11 +27,43 @@ const nextConfig: NextConfig = {
|
||||
],
|
||||
},
|
||||
output: 'standalone',
|
||||
webpack(config) {
|
||||
webpack(config, { isServer }) {
|
||||
config.module.rules.push({
|
||||
test: /\.svg$/,
|
||||
use: ["@svgr/webpack"],
|
||||
});
|
||||
|
||||
if (!isServer) {
|
||||
// Split heavy third-party vendor libraries into their own dedicated chunks
|
||||
config.optimization.splitChunks.cacheGroups = {
|
||||
...config.optimization.splitChunks.cacheGroups,
|
||||
maplibre: {
|
||||
test: /[\\/]node_modules[\\/]maplibre-gl[\\/]/,
|
||||
name: "maplibre",
|
||||
chunks: "all",
|
||||
priority: 40,
|
||||
},
|
||||
quill: {
|
||||
test: /[\\/]node_modules[\\/](react-quill-new|quill|quill-blot-formatter)[\\/]/,
|
||||
name: "quill",
|
||||
chunks: "all",
|
||||
priority: 35,
|
||||
},
|
||||
charts: {
|
||||
test: /[\\/]node_modules[\\/](apexcharts|react-apexcharts)[\\/]/,
|
||||
name: "charts",
|
||||
chunks: "all",
|
||||
priority: 30,
|
||||
},
|
||||
calendar: {
|
||||
test: /[\\/]node_modules[\\/]@fullcalendar[\\/]/,
|
||||
name: "calendar",
|
||||
chunks: "all",
|
||||
priority: 25,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return config;
|
||||
},
|
||||
|
||||
|
||||
@@ -20,9 +20,6 @@
|
||||
"@reduxjs/toolkit": "^2.11.2",
|
||||
"@tailwindcss/forms": "^0.5.10",
|
||||
"@tailwindcss/postcss": "^4.1.17",
|
||||
"@tiptap/extension-link": "^2.26.1",
|
||||
"@tiptap/react": "^2.26.1",
|
||||
"@tiptap/starter-kit": "^2.26.1",
|
||||
"apexcharts": "^4.7.0",
|
||||
"autoprefixer": "^10.4.22",
|
||||
"axios": "^1.14.0",
|
||||
@@ -44,7 +41,8 @@
|
||||
"swiper": "^11.2.10",
|
||||
"tailwind-merge": "^2.6.0",
|
||||
"uuid": "^13.0.0",
|
||||
"yet-another-react-lightbox": "^3.30.1"
|
||||
"yet-another-react-lightbox": "^3.30.1",
|
||||
"zustand": "^5.0.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3.3.1",
|
||||
@@ -70,4 +68,4 @@
|
||||
"react-dom": "^16.8.0 || ^17 || ^18 || ^19"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M26.5002 14.9998C27.8808 14.9998 29 13.8806 29 12.5C29 11.1194 27.8807 10.0002 26.5001 10.0002C25.1194 10.0002 24 11.1195 24 12.5002V14.9998H26.5002ZM19.5 14.9998C20.8807 14.9998 22 13.8805 22 12.4998V5.50018C22 4.11947 20.8807 3.00018 19.5 3.00018C18.1193 3.00018 17 4.11947 17 5.50018V12.4998C17 13.8805 18.1193 14.9998 19.5 14.9998Z" fill="#2EB67D"/>
|
||||
<path d="M5.49979 17.0002C4.11919 17.0002 3 18.1194 3 19.5C3 20.8806 4.1193 21.9998 5.49989 21.9998C6.8806 21.9998 8 20.8805 8 19.4998V17.0002H5.49979ZM12.5 17.0002C11.1193 17.0002 10 18.1195 10 19.5002V26.4998C10 27.8805 11.1193 28.9998 12.5 28.9998C13.8807 28.9998 15 27.8805 15 26.4998V19.5002C15 18.1195 13.8807 17.0002 12.5 17.0002Z" fill="#E01E5A"/>
|
||||
<path d="M17.0002 26.5002C17.0002 27.8808 18.1194 29 19.5 29C20.8806 29 21.9998 27.8807 21.9998 26.5001C21.9998 25.1194 20.8805 24 19.4998 24L17.0002 24L17.0002 26.5002ZM17.0002 19.5C17.0002 20.8807 18.1195 22 19.5002 22L26.4998 22C27.8805 22 28.9998 20.8807 28.9998 19.5C28.9998 18.1193 27.8805 17 26.4998 17L19.5002 17C18.1195 17 17.0002 18.1193 17.0002 19.5Z" fill="#ECB22E"/>
|
||||
<path d="M14.9998 5.49979C14.9998 4.11919 13.8806 3 12.5 3C11.1194 3 10.0002 4.1193 10.0002 5.49989C10.0002 6.88061 11.1195 8 12.5002 8L14.9998 8L14.9998 5.49979ZM14.9998 12.5C14.9998 11.1193 13.8805 10 12.4998 10L5.50024 10C4.11953 10 3.00024 11.1193 3.00024 12.5C3.00024 13.8807 4.11953 15 5.50024 15L12.4998 15C13.8805 15 14.9998 13.8807 14.9998 12.5Z" fill="#36C5F0"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -1,10 +0,0 @@
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="16" cy="16" r="14" fill="url(#paint0_linear_1589_37170)"/>
|
||||
<path d="M21.2137 20.2816L21.8356 16.3301H17.9452V13.767C17.9452 12.6857 18.4877 11.6311 20.2302 11.6311H22V8.26699C22 8.26699 20.3945 8 18.8603 8C15.6548 8 13.5617 9.89294 13.5617 13.3184V16.3301H10V20.2816H13.5617V29.8345C14.2767 29.944 15.0082 30 15.7534 30C16.4986 30 17.2302 29.944 17.9452 29.8345V20.2816H21.2137Z" fill="white"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_1589_37170" x1="16" y1="2" x2="16" y2="29.917" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#18ACFE"/>
|
||||
<stop offset="1" stop-color="#0163E0"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 725 B |
@@ -1,5 +0,0 @@
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M19.3851 10.9171C20.4654 9.0306 19.8243 6.61829 17.9532 5.5291C16.0821 4.4399 13.6896 5.08628 12.6093 6.97282L4.53087 21.0806C3.45059 22.9671 4.09168 25.3794 5.96277 26.4686C7.83387 27.5578 10.2264 26.9114 11.3067 25.0249L19.3851 10.9171Z" fill="#F8BB2D"/>
|
||||
<path d="M11.8263 23.0546C11.8263 25.2336 10.0743 27 7.91313 27C5.75197 27 4 25.2336 4 23.0546C4 20.8756 5.75197 19.1091 7.91313 19.1091C10.0743 19.1091 11.8263 20.8756 11.8263 23.0546Z" fill="#3BA757"/>
|
||||
<path d="M12.621 10.9171C11.5407 9.0306 12.1818 6.61829 14.0529 5.5291C15.924 4.4399 18.3165 5.08628 19.3968 6.97282L27.4752 21.0806C28.5555 22.9671 27.9144 25.3794 26.0433 26.4686C24.1722 27.5578 21.7797 26.9114 20.6994 25.0249L12.621 10.9171Z" fill="#4689F2"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 836 B |
@@ -1,26 +0,0 @@
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="2" y="2" width="28" height="28" rx="6" fill="url(#paint0_radial_1589_37182)"/>
|
||||
<rect x="2" y="2" width="28" height="28" rx="6" fill="url(#paint1_radial_1589_37182)"/>
|
||||
<rect x="2" y="2" width="28" height="28" rx="6" fill="url(#paint2_radial_1589_37182)"/>
|
||||
<path d="M23 10.5C23 11.3284 22.3284 12 21.5 12C20.6716 12 20 11.3284 20 10.5C20 9.67157 20.6716 9 21.5 9C22.3284 9 23 9.67157 23 10.5Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M16 21C18.7614 21 21 18.7614 21 16C21 13.2386 18.7614 11 16 11C13.2386 11 11 13.2386 11 16C11 18.7614 13.2386 21 16 21ZM16 19C17.6569 19 19 17.6569 19 16C19 14.3431 17.6569 13 16 13C14.3431 13 13 14.3431 13 16C13 17.6569 14.3431 19 16 19Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M6 15.6C6 12.2397 6 10.5595 6.65396 9.27606C7.2292 8.14708 8.14708 7.2292 9.27606 6.65396C10.5595 6 12.2397 6 15.6 6H16.4C19.7603 6 21.4405 6 22.7239 6.65396C23.8529 7.2292 24.7708 8.14708 25.346 9.27606C26 10.5595 26 12.2397 26 15.6V16.4C26 19.7603 26 21.4405 25.346 22.7239C24.7708 23.8529 23.8529 24.7708 22.7239 25.346C21.4405 26 19.7603 26 16.4 26H15.6C12.2397 26 10.5595 26 9.27606 25.346C8.14708 24.7708 7.2292 23.8529 6.65396 22.7239C6 21.4405 6 19.7603 6 16.4V15.6ZM15.6 8H16.4C18.1132 8 19.2777 8.00156 20.1779 8.0751C21.0548 8.14674 21.5032 8.27659 21.816 8.43597C22.5686 8.81947 23.1805 9.43139 23.564 10.184C23.7234 10.4968 23.8533 10.9452 23.9249 11.8221C23.9984 12.7223 24 13.8868 24 15.6V16.4C24 18.1132 23.9984 19.2777 23.9249 20.1779C23.8533 21.0548 23.7234 21.5032 23.564 21.816C23.1805 22.5686 22.5686 23.1805 21.816 23.564C21.5032 23.7234 21.0548 23.8533 20.1779 23.9249C19.2777 23.9984 18.1132 24 16.4 24H15.6C13.8868 24 12.7223 23.9984 11.8221 23.9249C10.9452 23.8533 10.4968 23.7234 10.184 23.564C9.43139 23.1805 8.81947 22.5686 8.43597 21.816C8.27659 21.5032 8.14674 21.0548 8.0751 20.1779C8.00156 19.2777 8 18.1132 8 16.4V15.6C8 13.8868 8.00156 12.7223 8.0751 11.8221C8.14674 10.9452 8.27659 10.4968 8.43597 10.184C8.81947 9.43139 9.43139 8.81947 10.184 8.43597C10.4968 8.27659 10.9452 8.14674 11.8221 8.0751C12.7223 8.00156 13.8868 8 15.6 8Z" fill="white"/>
|
||||
<defs>
|
||||
<radialGradient id="paint0_radial_1589_37182" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(12 23) rotate(-55.3758) scale(25.5196)">
|
||||
<stop stop-color="#B13589"/>
|
||||
<stop offset="0.79309" stop-color="#C62F94"/>
|
||||
<stop offset="1" stop-color="#8A3AC8"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="paint1_radial_1589_37182" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(11 31) rotate(-65.1363) scale(22.5942)">
|
||||
<stop stop-color="#E0E8B7"/>
|
||||
<stop offset="0.444662" stop-color="#FB8A2E"/>
|
||||
<stop offset="0.71474" stop-color="#E2425C"/>
|
||||
<stop offset="1" stop-color="#E2425C" stop-opacity="0"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="paint2_radial_1589_37182" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(0.500002 3) rotate(-8.1301) scale(38.8909 8.31836)">
|
||||
<stop offset="0.156701" stop-color="#406ADC"/>
|
||||
<stop offset="0.467799" stop-color="#6A45BE"/>
|
||||
<stop offset="1" stop-color="#6A45BE" stop-opacity="0"/>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 3.2 KiB |
@@ -1,6 +0,0 @@
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M30.0014 16.3109C30.0014 15.1598 29.9061 14.3198 29.6998 13.4487H16.2871V18.6442H24.1601C24.0014 19.9354 23.1442 21.8798 21.2394 23.1864L21.2127 23.3604L25.4536 26.58L25.7474 26.6087C28.4458 24.1665 30.0014 20.5731 30.0014 16.3109Z" fill="#4285F4"/>
|
||||
<path d="M16.2863 30C20.1434 30 23.3814 28.7555 25.7466 26.6089L21.2386 23.1865C20.0323 24.011 18.4132 24.5866 16.2863 24.5866C12.5086 24.5866 9.30225 22.1444 8.15929 18.7688L7.99176 18.7827L3.58208 22.1272L3.52441 22.2843C5.87359 26.8577 10.699 30 16.2863 30Z" fill="#34A853"/>
|
||||
<path d="M8.16013 18.7688C7.85855 17.8977 7.68401 16.9643 7.68401 15.9999C7.68401 15.0354 7.85855 14.1021 8.14426 13.231L8.13627 13.0455L3.67132 9.64734L3.52524 9.71544C2.55703 11.6132 2.00146 13.7444 2.00146 15.9999C2.00146 18.2555 2.55703 20.3865 3.52524 22.2843L8.16013 18.7688Z" fill="#FBBC05"/>
|
||||
<path d="M16.2864 7.4133C18.9689 7.4133 20.7784 8.54885 21.8102 9.4978L25.8419 5.64C23.3658 3.38445 20.1435 2 16.2864 2C10.699 2 5.8736 5.1422 3.52441 9.71549L8.14345 13.2311C9.30229 9.85555 12.5086 7.4133 16.2864 7.4133Z" fill="#EB4335"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.2 KiB |
@@ -1,4 +0,0 @@
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2.24451 9.94111C2.37304 7.96233 3.96395 6.41157 5.94447 6.31345C8.81239 6.17136 12.9115 6 16 6C19.0885 6 23.1876 6.17136 26.0555 6.31345C28.0361 6.41157 29.627 7.96233 29.7555 9.94111C29.8786 11.8369 30 14.1697 30 16C30 17.8303 29.8786 20.1631 29.7555 22.0589C29.627 24.0377 28.0361 25.5884 26.0555 25.6866C23.1876 25.8286 19.0885 26 16 26C12.9115 26 8.81239 25.8286 5.94447 25.6866C3.96395 25.5884 2.37304 24.0377 2.24451 22.0589C2.12136 20.1631 2 17.8303 2 16C2 14.1697 2.12136 11.8369 2.24451 9.94111Z" fill="#FC0D1B"/>
|
||||
<path d="M13 12V20L21 16L13 12Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 684 B |
@@ -1,4 +0,0 @@
|
||||
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M37.5 20C37.5 29.66 29.6687 37.5 20 37.5C10.3312 37.5 2.5 29.66 2.5 20C2.5 10.3312 10.3312 2.49999 20 2.49999C29.6687 2.49999 37.5 10.3312 37.5 20Z" fill="#283544"/>
|
||||
<path d="M28.2026 15.5717C28.1071 15.6274 25.8338 16.8031 25.8338 19.4098C25.941 22.3826 28.7026 23.4252 28.75 23.4252C28.7026 23.4809 28.3331 24.8454 27.2383 26.2757C26.3696 27.5078 25.4053 28.75 23.941 28.75C22.5481 28.75 22.0481 27.9288 20.441 27.9288C18.715 27.9288 18.2267 28.75 16.9052 28.75C15.441 28.75 14.4052 27.4412 13.4891 26.2207C12.2989 24.6232 11.2872 22.1164 11.2515 19.7093C11.2274 18.4338 11.4899 17.18 12.156 16.1151C13.0962 14.6283 14.7748 13.619 16.6079 13.5858C18.0124 13.5416 19.2624 14.4843 20.1195 14.4843C20.941 14.4843 22.4767 13.5858 24.2143 13.5858C24.9643 13.5865 26.9643 13.797 28.2026 15.5717ZM20.0008 13.3311C19.7508 12.1663 20.441 11.0015 21.0838 10.2585C21.9053 9.3599 23.2026 8.75 24.3214 8.75C24.3928 9.91481 23.9402 11.0572 23.1312 11.8892C22.4053 12.7878 21.1553 13.4642 20.0008 13.3311Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -1,7 +0,0 @@
|
||||
<svg width="41" height="40" viewBox="0 0 41 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="0.5" width="40" height="40" rx="20" fill="#1B4BF1"/>
|
||||
<path opacity="0.5" d="M28.9266 15.7265C29.1963 13.9679 28.9266 12.7956 27.9826 11.7134C26.9487 10.496 25.0607 10 22.6333 10H15.6657C15.1713 10 14.7667 10.3607 14.6768 10.8567L11.7549 29.3437C11.7099 29.7044 11.9797 30.02 12.3393 30.02H16.6547L16.34 31.9138C16.2951 32.2295 16.5198 32.5 16.8794 32.5H20.5205C20.9701 32.5 21.3297 32.1844 21.3746 31.7786L22.1388 26.999C22.1838 26.5932 22.5883 26.2776 22.9929 26.2776H23.5323C27.0386 26.2776 29.8256 24.8347 30.6348 20.6864C30.9494 18.9729 30.8146 17.485 29.9155 16.493C29.6458 16.1774 29.3311 15.9519 28.9266 15.7265" fill="white"/>
|
||||
<path d="M28.9266 15.7265C29.1963 13.9679 28.9266 12.7956 27.9826 11.7134C26.9487 10.496 25.0607 10 22.6333 10H15.6657C15.1713 10 14.7667 10.3607 14.6768 10.8567L11.7549 29.3437C11.7099 29.7044 11.9797 30.02 12.3393 30.02H16.6547L17.6886 23.3467C17.7785 22.8507 18.183 22.49 18.6775 22.49H20.7453C24.791 22.49 27.9376 20.8667 28.8367 16.0872C28.8816 15.997 28.8816 15.8617 28.9266 15.7265Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M30.1209 16.096C30.1192 16.105 30.1161 16.121 30.1115 16.1467C30.1057 16.1785 30.0932 16.2474 30.0743 16.3214C30.0669 16.3504 30.0572 16.3854 30.0445 16.425C29.5373 19.0088 28.3926 20.8874 26.6974 22.0981C25.0064 23.3058 22.9195 23.74 20.7452 23.74H18.8924L17.7258 31.27H12.3392C11.1964 31.27 10.3804 30.2642 10.5144 29.1891L10.5169 29.1688L13.4442 10.6476L13.4467 10.6338C13.6357 9.59143 14.519 8.75 15.6656 8.75H22.6332C25.1361 8.75 27.5194 9.24302 28.9298 10.8979C29.516 11.5715 29.9235 12.3133 30.1267 13.1814C30.3266 14.0353 30.3118 14.9394 30.162 15.916L30.146 16.0204L30.1209 16.096ZM27.9825 11.7134C26.9486 10.496 25.0606 10 22.6332 10H15.6656C15.1712 10 14.7666 10.3607 14.6767 10.8567L11.7548 29.3437C11.7099 29.7044 11.9796 30.02 12.3392 30.02H16.6546L17.6885 23.3467C17.7784 22.8507 18.1829 22.49 18.6774 22.49H20.7452C24.7909 22.49 27.9375 20.8667 28.8366 16.0872C28.8609 16.0384 28.8721 15.9763 28.8843 15.9082C28.8947 15.8505 28.9059 15.7885 28.9265 15.7265C29.1962 13.9679 28.9265 12.7956 27.9825 11.7134Z" fill="#1B4BF1"/>
|
||||
<path d="M18.9023 15.7715C18.9472 15.4559 19.3518 15.0501 19.7564 15.0501H25.2405C25.8698 15.0501 26.4992 15.0952 27.0386 15.1854C27.5331 15.2755 28.4321 15.501 28.8816 15.7715C29.1513 14.013 28.8816 12.8407 27.9376 11.7585C26.9487 10.496 25.0607 10 22.6333 10H15.6657C15.1713 10 14.7667 10.3607 14.6768 10.8567L11.7549 29.3437C11.7099 29.7044 11.9797 30.02 12.3393 30.02H16.6547L18.9023 15.7715V15.7715Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.6 KiB |
@@ -1,5 +0,0 @@
|
||||
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="20" cy="20" r="20" fill="#E31937"/>
|
||||
<path d="M20.0005 31.4285L22.9444 14.8726C25.7502 14.8726 26.6353 15.1803 26.7632 16.4362C26.7632 16.4362 28.6456 15.7343 29.5948 14.3089C25.8901 12.5923 22.1678 12.5148 22.1678 12.5148L19.9957 15.1604L20.0006 15.16L17.8285 12.5144C17.8285 12.5144 14.106 12.5919 10.4019 14.3086C11.3504 15.734 13.2334 16.4358 13.2334 16.4358C13.362 15.1799 14.2459 14.8722 17.033 14.8702L20.0005 31.4285Z" fill="white"/>
|
||||
<path d="M19.9996 11.7508C22.9943 11.7279 26.422 12.2141 29.9311 13.7434C30.4001 12.8993 30.5207 12.5262 30.5207 12.5262C26.6847 11.0086 23.0925 10.4893 19.9992 10.4762C16.906 10.4893 13.3139 11.0087 9.47852 12.5262C9.47852 12.5262 9.64962 12.9858 10.0677 13.7434C13.576 12.2141 17.0045 11.7279 19.9993 11.7508H19.9996Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 892 B |
@@ -1,6 +0,0 @@
|
||||
<svg width="41" height="40" viewBox="0 0 41 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M20.5 2.5C10.8477 2.5 3 10.3477 3 20C3 29.6523 10.8477 37.5 20.5 37.5C30.1523 37.5 38 29.6523 38 20C38 10.3477 30.1523 2.5 20.5 2.5Z" fill="#F9981B"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M26.5124 22.5475C26.461 22.4738 26.4093 22.4016 26.3578 22.3298C25.9392 21.7463 25.5402 21.1902 25.5402 20.0754V15.9195C25.5402 15.775 25.541 15.6315 25.5418 15.4891C25.551 13.8957 25.5593 12.4417 24.4101 11.3294C23.4246 10.3467 21.7876 10 20.5357 10C18.0872 10 15.3558 10.947 14.783 14.0851C14.7223 14.4184 14.9558 14.5929 15.1675 14.642L17.6607 14.9218C17.8941 14.9095 18.0627 14.6715 18.1079 14.4318C18.3217 13.3505 19.195 12.831 20.1762 12.831C20.7054 12.831 21.3063 13.0316 21.6196 13.5238C21.9425 14.0146 21.9374 14.6699 21.9328 15.2558C21.9323 15.3241 21.9317 15.3914 21.9317 15.4574V15.8058C21.7004 15.8326 21.458 15.858 21.2083 15.8842C19.8486 16.0267 18.2732 16.1919 17.0932 16.7283C15.4823 17.4517 14.3511 18.9238 14.3511 21.0876C14.3511 23.8606 16.0344 25.2469 18.2016 25.2469C20.0305 25.2469 21.0314 24.7993 22.4423 23.3077C22.5128 23.4136 22.5762 23.5113 22.6358 23.6033C22.9724 24.1222 23.1921 24.4609 23.9171 25.0864C24.1085 25.1923 24.3618 25.1883 24.5314 25.0289C25.0451 24.5552 25.9779 23.7146 26.5039 23.2576C26.714 23.0786 26.6767 22.7894 26.5124 22.5475ZM21.4505 21.3491C21.0421 22.1015 20.3916 22.5619 19.6689 22.5619C18.6834 22.5619 18.1047 21.7816 18.1047 20.6272C18.1047 18.3547 20.0714 17.9423 21.9312 17.9423C21.9312 18.0782 21.9325 18.2149 21.9337 18.352C21.9428 19.3807 21.9521 20.4299 21.4505 21.3491Z" fill="white"/>
|
||||
<path d="M29.5873 27.0823C27.1246 28.9867 23.5531 30 20.4773 30C16.1681 30 12.2866 28.3307 9.34948 25.5515C9.11909 25.333 9.32473 25.0346 9.60151 25.2042C12.7708 27.1371 16.6894 28.3006 20.7367 28.3006C23.4672 28.3006 26.4682 27.7073 29.2295 26.479C29.646 26.2944 29.9951 26.7674 29.5873 27.0823Z" fill="white"/>
|
||||
<path d="M27.7363 25.7559C28.5293 25.6555 30.2974 25.4334 30.6122 25.8556C30.9273 26.2775 30.2654 28.0124 29.967 28.7943L29.9649 28.8C29.8751 29.0358 30.0681 29.1299 30.2715 28.9512C31.5931 27.7933 31.9346 25.366 31.6638 25.0143C31.3951 24.6674 29.0847 24.367 27.6747 25.4049C27.458 25.5659 27.4951 25.7852 27.7363 25.7559Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.3 KiB |
@@ -1,4 +0,0 @@
|
||||
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="20" cy="20" r="17.5" fill="#1ED760"/>
|
||||
<path d="M27.9554 27.0287C27.6564 27.5031 27.0186 27.6359 26.5203 27.3513C22.5937 25.0742 17.6705 24.5618 11.8503 25.8142C11.2922 25.9281 10.7341 25.6055 10.6145 25.0742C10.4949 24.5428 10.8338 24.0115 11.3919 23.8976C17.7502 22.5124 23.2116 23.1007 27.5966 25.6624C28.095 25.9471 28.2544 26.5543 27.9554 27.0287ZM29.9885 22.7022C29.6098 23.2904 28.8125 23.4612 28.1946 23.1196C23.7099 20.482 16.8732 19.7229 11.5712 21.26C10.8736 21.4497 10.1561 21.0892 9.95674 20.444C9.75742 19.7798 10.1361 19.0967 10.8338 18.9069C16.8931 17.1611 24.4274 17.9961 29.5899 21.0133C30.1679 21.3549 30.3672 22.1139 29.9885 22.7022ZM30.1679 18.1859C24.7862 15.1497 15.9164 14.865 10.774 16.3452C9.95674 16.5919 9.07973 16.1554 8.82061 15.3584C8.5615 14.5804 9.03987 13.7455 9.85708 13.4988C15.757 11.7909 25.5636 12.1325 31.7425 15.6241C32.48 16.0416 32.7192 16.9524 32.2807 17.6545C31.8621 18.3756 30.9054 18.6223 30.1679 18.1859Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -1,4 +0,0 @@
|
||||
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M20 2.5C10.3477 2.5 2.5 10.3477 2.5 20C2.5 29.6523 10.3477 37.5 20 37.5C29.6523 37.5 37.5 29.6523 37.5 20C37.5 10.3477 29.6523 2.5 20 2.5Z" fill="#FF5A5F"/>
|
||||
<path d="M20.0002 24.6084C18.8528 23.1652 18.1779 21.9001 17.953 20.8178C17.728 19.9383 17.818 19.2393 18.2004 18.7206C18.6054 18.1118 19.2128 17.8186 20.0002 17.8186C20.7875 17.8186 21.3949 18.1118 21.7999 18.7206C22.1823 19.2393 22.2723 19.9383 22.0473 20.8178C21.7999 21.9227 21.125 23.1855 20.0002 24.6084ZM26.2812 27.9458C24.369 28.7801 22.477 27.4497 20.8573 25.6457C23.5366 22.2835 24.0315 19.6677 22.882 17.9742C22.2071 17.0046 21.2397 16.531 20.0002 16.531C17.503 16.531 16.1285 18.6507 16.6684 21.1109C16.9834 22.4413 17.8158 23.9544 19.143 25.6457C18.1475 26.7515 16.8414 28.0059 15.2736 28.1487C13.0015 28.487 11.222 26.2771 12.0319 23.9973L17.7933 12.0413C18.285 11.1425 18.8919 10.3726 19.9979 10.3726C20.8078 10.3726 21.4377 10.8462 21.7076 11.2295L27.9639 23.9973C28.5769 25.54 27.7996 27.2886 26.2812 27.9458ZM29.1832 23.5463L23.8268 12.3796C22.8145 10.305 22.0946 9.0625 20.0002 9.0625C17.9305 9.0625 17.0509 10.5057 16.151 12.3796L10.8171 23.5463C9.66976 26.7055 12.0319 29.4792 14.8912 29.4792C15.0712 29.4792 15.2499 29.4566 15.4311 29.4566C16.9159 29.2762 18.4479 28.3291 20.0002 26.6356C21.5524 28.3269 23.0844 29.2762 24.5692 29.4566C24.7505 29.4566 24.9291 29.4792 25.1091 29.4792C27.9684 29.4814 30.3306 26.7055 29.1832 23.5463Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -1,5 +0,0 @@
|
||||
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M20 2.5C10.3477 2.5 2.5 10.3477 2.5 20C2.5 29.6523 10.3477 37.5 20 37.5C29.6523 37.5 37.5 29.6523 37.5 20C37.5 10.3477 29.6523 2.5 20 2.5Z" fill="#87E64B"/>
|
||||
<path d="M20.4865 30C20.9801 30 21.3803 29.5998 21.3803 29.1062C21.3803 28.6126 20.9801 28.2125 20.4865 28.2125C19.9929 28.2125 19.5928 28.6126 19.5928 29.1062C19.5928 29.5998 19.9929 30 20.4865 30Z" fill="white"/>
|
||||
<path d="M25.6233 23.0134L20.5833 23.5539C20.4895 23.5633 20.4427 23.4477 20.5177 23.3883L25.4483 19.5482C25.767 19.2857 25.9732 18.8795 25.8857 18.4421C25.7982 17.7734 25.2452 17.336 24.5453 17.4235L19.1866 18.2077C19.0928 18.2202 19.0428 18.1015 19.1178 18.0421L24.4297 13.9864C25.4764 13.1709 25.5639 11.5711 24.6046 10.6399C23.7329 9.76817 22.3331 9.79629 21.4613 10.6681L12.903 19.3763C12.5843 19.7263 12.4374 20.1919 12.5249 20.6855C12.6718 21.4729 13.4561 21.9947 14.2435 21.851L18.8585 20.9105C18.9585 20.8886 19.0116 21.023 18.9272 21.0792L13.8091 24.3569C13.1686 24.7631 12.878 25.4912 13.0811 26.2192C13.2842 27.1785 14.2466 27.7315 15.1777 27.5003L22.8299 25.6162C22.9174 25.5943 22.9798 25.6943 22.9236 25.763L21.73 27.2378C21.4113 27.644 21.9331 28.1971 22.3705 27.8784L26.3013 24.6475C27.0012 24.0664 26.5356 22.929 25.6326 23.0165L25.6233 23.0134Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.3 KiB |
@@ -1,6 +0,0 @@
|
||||
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="20" cy="20" r="17.5" fill="#FF8C00"/>
|
||||
<path d="M27.4363 25.1256C27.408 24.8784 27.2659 24.3115 26.8965 24.1659H26.897C26.712 24.0931 26.5558 24.151 26.4852 24.2821C26.3713 24.486 26.4565 24.8784 26.6697 25.2278C26.8824 25.5768 27.0814 25.7513 27.2235 25.7513C27.3656 25.7513 27.4932 25.5768 27.4363 25.1256Z" fill="white"/>
|
||||
<path d="M25.4485 26.1147C25.2213 25.9113 24.9657 25.8096 24.7384 25.8096C24.5398 25.8096 24.3836 25.8819 24.2839 26.013C24.0288 26.3326 24.1422 26.9148 24.5398 27.2638C24.7102 27.4239 24.9657 27.5111 25.2071 27.5111C25.4485 27.5111 25.6613 27.4094 25.7892 27.2494C26.0165 26.9293 25.8885 26.4931 25.4485 26.1147Z" fill="white"/>
|
||||
<path d="M10 20.0061C10 25.5328 14.3728 30.0125 19.7687 30.0128C21.203 30.0128 22.6227 29.7365 24.7102 29.7216C26.5704 29.7216 28.615 30.3907 30.8583 32.4272C31.0856 32.6306 31.3835 32.3688 31.1849 32.1216C28.984 29.2565 26.9393 28.7185 24.8947 28.2529C22.3959 27.6856 21.1178 26.2603 20.2233 24.6749C20.0529 24.3549 19.9677 24.4132 19.9532 24.8205C19.9371 25.4198 19.98 26.0192 20.0812 26.6097H19.7833C16.2191 26.6097 13.3223 23.6424 13.3223 19.9917C13.3223 16.3409 16.2191 13.3737 19.7828 13.3737C23.347 13.3737 26.2438 16.3409 26.2438 19.9917C26.2438 20.2534 26.2292 20.5152 26.201 20.7624C25.7182 20.6752 24.7954 20.6607 24.1422 20.719C23.9008 20.748 23.9291 20.8641 24.114 20.8935C26.2438 21.3004 27.7063 22.6534 28.047 25.1112C28.0612 25.1695 28.1322 25.1839 28.1609 25.1405C29.0268 23.6424 29.5378 21.8822 29.5378 20.0061C29.5378 14.4798 25.1643 10 19.7687 10C14.3735 10 10 14.4794 10 20.0061Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.6 KiB |
@@ -1,4 +0,0 @@
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M16 30C23.732 30 30 23.732 30 16C30 8.26801 23.732 2 16 2C8.26801 2 2 8.26801 2 16C2 23.732 8.26801 30 16 30Z" fill="#2BDE73"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.357 13.4527L17.3808 9.20142C17.9525 8.40047 18.6904 8 19.5953 8C20.3334 8 20.972 8.25407 21.512 8.76237C22.0516 9.27068 22.3213 9.8791 22.3213 10.5876C22.3213 11.1114 22.1788 11.5736 21.8929 11.9741L19.1665 15.821L22.5 19.9222C22.8334 20.3303 23 20.808 23 21.3547C23 22.0788 22.7384 22.7004 22.2144 23.2203C21.6906 23.7403 21.0553 24 20.3096 24C19.492 24 18.8691 23.7423 18.4404 23.2261L14.357 18.2817V21.0082C14.357 21.7862 14.2182 22.3906 13.9403 22.8219C13.4324 23.6072 12.6943 24 11.7262 24C10.8452 24 10.1624 23.7112 9.67848 23.1337C9.22604 22.6022 9 21.8973 9 21.0198V10.9111C9 10.0793 9.22983 9.39412 9.69041 8.85495C10.1745 8.2851 10.841 8 11.6903 8C12.4999 8 13.1744 8.2851 13.7141 8.85495C14.0157 9.17056 14.2061 9.4902 14.2855 9.8137C14.3332 10.0141 14.357 10.3874 14.357 10.9343V13.4527Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 227 KiB |
|
Before Width: | Height: | Size: 346 KiB |
|
Before Width: | Height: | Size: 162 KiB |
|
Before Width: | Height: | Size: 262 KiB |
|
Before Width: | Height: | Size: 189 KiB |
|
Before Width: | Height: | Size: 312 KiB |
|
Before Width: | Height: | Size: 869 KiB |
|
Before Width: | Height: | Size: 704 KiB |
|
Before Width: | Height: | Size: 453 KiB |
|
Before Width: | Height: | Size: 849 KiB |
@@ -1,15 +0,0 @@
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_1788_4304)">
|
||||
<path d="M16 32C24.8366 32 32 24.8366 32 16C32 7.16344 24.8366 0 16 0C7.16344 0 0 7.16344 0 16C0 24.8366 7.16344 32 16 32Z" fill="#F0F0F0"/>
|
||||
<path d="M15.3037 16H31.9993C31.9993 14.5559 31.8068 13.1569 31.4481 11.826H15.3037V16Z" fill="#D80027"/>
|
||||
<path d="M15.3037 7.65135H29.651C28.6715 6.0531 27.4192 4.64042 25.9591 3.47742H15.3037V7.65135Z" fill="#D80027"/>
|
||||
<path d="M15.9995 32C19.7651 32 23.2262 30.6985 25.9593 28.5217H6.03979C8.77292 30.6985 12.234 32 15.9995 32Z" fill="#D80027"/>
|
||||
<path d="M2.34797 24.3465H29.6512C30.4375 23.0635 31.0473 21.661 31.4484 20.1726H0.550781C0.951844 21.661 1.56166 23.0635 2.34797 24.3465Z" fill="#D80027"/>
|
||||
<path d="M7.4115 2.49863H8.86956L7.51331 3.48394L8.03137 5.07825L6.67519 4.09294L5.319 5.07825L5.7665 3.70094C4.57237 4.69562 3.52575 5.861 2.66325 7.1595H3.13044L2.26712 7.78669C2.13262 8.01106 2.00362 8.239 1.88 8.47031L2.29225 9.73913L1.52313 9.18031C1.33194 9.58537 1.15706 9.99956 0.999875 10.4224L1.45406 11.8204H3.13044L1.77419 12.8057L2.29225 14.4L0.936063 13.4147L0.123687 14.0049C0.042375 14.6586 0 15.3243 0 16H16C16 7.1635 16 6.12175 16 0C12.8393 0 9.89281 0.916875 7.4115 2.49863ZM8.03137 14.4L6.67519 13.4147L5.319 14.4L5.83706 12.8057L4.48081 11.8204H6.15719L6.67519 10.2261L7.19319 11.8204H8.86956L7.51331 12.8057L8.03137 14.4ZM7.51331 8.14481L8.03137 9.73913L6.67519 8.75381L5.319 9.73913L5.83706 8.14481L4.48081 7.1595H6.15719L6.67519 5.56519L7.19319 7.1595H8.86956L7.51331 8.14481ZM13.7705 14.4L12.4143 13.4147L11.0581 14.4L11.5762 12.8057L10.2199 11.8204H11.8963L12.4143 10.2261L12.9323 11.8204H14.6087L13.2524 12.8057L13.7705 14.4ZM13.2524 8.14481L13.7705 9.73913L12.4143 8.75381L11.0581 9.73913L11.5762 8.14481L10.2199 7.1595H11.8963L12.4143 5.56519L12.9323 7.1595H14.6087L13.2524 8.14481ZM13.2524 3.48394L13.7705 5.07825L12.4143 4.09294L11.0581 5.07825L11.5762 3.48394L10.2199 2.49863H11.8963L12.4143 0.904312L12.9323 2.49863H14.6087L13.2524 3.48394Z" fill="#0052B4"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_1788_4304">
|
||||
<rect width="32" height="32" rx="16" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.1 KiB |
@@ -1,12 +0,0 @@
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_1788_4322)">
|
||||
<path d="M16 32C24.8366 32 32 24.8366 32 16C32 7.16344 24.8366 0 16 0C7.16344 0 0 7.16344 0 16C0 24.8366 7.16344 32 16 32Z" fill="#F0F0F0"/>
|
||||
<path d="M32 15.9999C32 9.12049 27.658 3.2558 21.5652 0.995117V31.0048C27.658 28.7441 32 22.8794 32 15.9999Z" fill="#D80027"/>
|
||||
<path d="M0.000488281 16.001C0.000488281 22.8805 4.34255 28.7452 10.4353 31.0058V0.996216C4.34255 3.2569 0.000488281 9.12159 0.000488281 16.001Z" fill="#0052B4"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_1788_4322">
|
||||
<rect width="32" height="32" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 680 B |
@@ -1,17 +0,0 @@
|
||||
<svg width="21" height="21" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_1589_35166)">
|
||||
<path d="M10.875 20.5C16.3978 20.5 20.875 16.0228 20.875 10.5C20.875 4.97715 16.3978 0.5 10.875 0.5C5.35215 0.5 0.875 4.97715 0.875 10.5C0.875 16.0228 5.35215 20.5 10.875 20.5Z" fill="#F0F0F0"/>
|
||||
<path d="M0.875 10.5C0.875 4.97719 5.35219 0.5 10.875 0.5C16.3978 0.5 20.875 4.97719 20.875 10.5" fill="#D80027"/>
|
||||
<path d="M6.96163 5.71751C6.96163 4.26056 7.98558 3.04345 9.35292 2.74481C9.14276 2.69896 8.92475 2.67407 8.70073 2.67407C7.01983 2.67407 5.65726 4.03665 5.65726 5.71755C5.65726 7.39845 7.01983 8.76103 8.70073 8.76103C8.92468 8.76103 9.14272 8.73614 9.35292 8.69025C7.98558 8.39161 6.96163 7.1745 6.96163 5.71751Z" fill="#F0F0F0"/>
|
||||
<path d="M10.8747 2.89172L11.0905 3.55598H11.789L11.2239 3.96657L11.4398 4.63083L10.8747 4.22032L10.3096 4.63083L10.5255 3.96657L9.96039 3.55598H10.6588L10.8747 2.89172Z" fill="#F0F0F0"/>
|
||||
<path d="M9.18043 4.19556L9.39625 4.85985H10.0947L9.52964 5.2704L9.7455 5.93466L9.18043 5.52415L8.61527 5.93466L8.83117 5.2704L8.26605 4.85985H8.96453L9.18043 4.19556Z" fill="#F0F0F0"/>
|
||||
<path d="M12.5691 4.19556L12.785 4.85985H13.4835L12.9184 5.2704L13.1343 5.93466L12.5691 5.52415L12.0041 5.93466L12.2199 5.2704L11.6548 4.85985H12.3533L12.5691 4.19556Z" fill="#F0F0F0"/>
|
||||
<path d="M11.9171 6.15283L12.133 6.81713H12.8314L12.2663 7.22768L12.4822 7.89193L11.9171 7.48143L11.352 7.89193L11.5679 7.22768L11.0028 6.81713H11.7012L11.9171 6.15283Z" fill="#F0F0F0"/>
|
||||
<path d="M9.83243 6.15283L10.0482 6.81713H10.7468L10.1816 7.22768L10.3975 7.89193L9.83243 7.48143L9.26731 7.89193L9.48317 7.22768L8.91809 6.81713H9.61657L9.83243 6.15283Z" fill="#F0F0F0"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_1589_35166">
|
||||
<rect x="0.875" y="0.5" width="20" height="20" rx="10" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.8 KiB |
@@ -1,23 +0,0 @@
|
||||
<svg width="21" height="21" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_1589_35168)">
|
||||
<path d="M10.875 20.5C16.3978 20.5 20.875 16.0228 20.875 10.5C20.875 4.97715 16.3978 0.5 10.875 0.5C5.35215 0.5 0.875 4.97715 0.875 10.5C0.875 16.0228 5.35215 20.5 10.875 20.5Z" fill="#F0F0F0"/>
|
||||
<path d="M2.94224 4.41089C2.15673 5.43288 1.56443 6.61081 1.21954 7.89046H6.42181L2.94224 4.41089Z" fill="#0052B4"/>
|
||||
<path d="M20.5309 7.89054C20.186 6.61093 19.5936 5.433 18.8082 4.41101L15.3287 7.89054H20.5309Z" fill="#0052B4"/>
|
||||
<path d="M1.21954 13.1085C1.56447 14.3881 2.15677 15.5661 2.94224 16.588L6.42169 13.1085H1.21954Z" fill="#0052B4"/>
|
||||
<path d="M16.9629 2.56649C15.9409 1.78098 14.763 1.18867 13.4834 0.84375V6.04598L16.9629 2.56649Z" fill="#0052B4"/>
|
||||
<path d="M4.78662 18.4314C5.80861 19.2169 6.98655 19.8092 8.26616 20.1541V14.9519L4.78662 18.4314Z" fill="#0052B4"/>
|
||||
<path d="M8.26611 0.84375C6.9865 1.18867 5.80857 1.78098 4.78662 2.56644L8.26611 6.04593V0.84375Z" fill="#0052B4"/>
|
||||
<path d="M13.4834 20.1541C14.763 19.8092 15.9409 19.2169 16.9629 18.4314L13.4834 14.9519V20.1541Z" fill="#0052B4"/>
|
||||
<path d="M15.3287 13.1085L18.8082 16.588C19.5936 15.5661 20.186 14.3881 20.5309 13.1085H15.3287Z" fill="#0052B4"/>
|
||||
<path d="M20.7904 9.19566H12.1794H12.1794V0.584648C11.7524 0.529063 11.3171 0.5 10.875 0.5C10.4329 0.5 9.99762 0.529063 9.57066 0.584648V9.19559V9.19563H0.959648C0.904063 9.62262 0.875 10.0579 0.875 10.5C0.875 10.9421 0.904063 11.3774 0.959648 11.8043H9.57059H9.57063V20.4154C9.99762 20.4709 10.4329 20.5 10.875 20.5C11.3171 20.5 11.7524 20.471 12.1793 20.4154V11.8044V11.8044H20.7904C20.8459 11.3774 20.875 10.9421 20.875 10.5C20.875 10.0579 20.8459 9.62262 20.7904 9.19566Z" fill="#D80027"/>
|
||||
<path d="M13.4837 13.1094L17.946 17.5718C18.1513 17.3666 18.3471 17.1521 18.5339 16.9298L14.7135 13.1094H13.4837V13.1094Z" fill="#D80027"/>
|
||||
<path d="M8.26628 13.1094H8.2662L3.80389 17.5717C4.00905 17.7769 4.22354 17.9727 4.44589 18.1595L8.26628 14.339V13.1094Z" fill="#D80027"/>
|
||||
<path d="M8.26616 7.89093V7.89085L3.80382 3.42847C3.59858 3.63362 3.4028 3.84812 3.216 4.07046L7.03643 7.89089H8.26616V7.89093Z" fill="#D80027"/>
|
||||
<path d="M13.4837 7.89187L17.9461 3.42945C17.7409 3.22421 17.5264 3.02843 17.3041 2.84167L13.4837 6.6621V7.89187V7.89187Z" fill="#D80027"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_1589_35168">
|
||||
<rect x="0.875" y="0.5" width="20" height="20" rx="10" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.4 KiB |
@@ -1,12 +0,0 @@
|
||||
<svg width="21" height="21" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_1589_35170)">
|
||||
<path d="M10.875 20.5C16.3978 20.5 20.875 16.0228 20.875 10.5C20.875 4.97715 16.3978 0.5 10.875 0.5C5.35215 0.5 0.875 4.97715 0.875 10.5C0.875 16.0228 5.35215 20.5 10.875 20.5Z" fill="#F0F0F0"/>
|
||||
<path d="M10.875 20.4993C15.1746 20.4993 18.84 17.7856 20.253 13.9775H1.49695C2.90988 17.7856 6.57531 20.4993 10.875 20.4993Z" fill="black"/>
|
||||
<path d="M10.875 0.50061C6.57531 0.50061 2.90988 3.21436 1.49695 7.02237H20.253C18.84 3.21436 15.1746 0.50061 10.875 0.50061Z" fill="#D80027"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_1589_35170">
|
||||
<rect x="0.875" y="0.5" width="20" height="20" rx="10" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 758 B |
@@ -1,11 +0,0 @@
|
||||
<svg width="21" height="21" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_1589_35172)">
|
||||
<path d="M10.875 20.5C16.3978 20.5 20.875 16.0228 20.875 10.5C20.875 4.97715 16.3978 0.5 10.875 0.5C5.35215 0.5 0.875 4.97715 0.875 10.5C0.875 16.0228 5.35215 20.5 10.875 20.5Z" fill="#F0F0F0"/>
|
||||
<path d="M20.7905 9.19564H8.70125H8.70122V0.737671C7.77708 0.942593 6.90094 1.27474 6.0925 1.71587V9.19556V9.1956H0.959771C0.904106 9.62259 0.875122 10.0579 0.875122 10.5C0.875122 10.942 0.904106 11.3774 0.959771 11.8043H6.09247H6.0925V19.284C6.90094 19.7251 7.77708 20.0574 8.70122 20.2622V11.8044V11.8044H20.7905C20.8461 11.3774 20.8751 10.942 20.8751 10.5C20.8751 10.0579 20.8461 9.62259 20.7905 9.19564Z" fill="#0052B4"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_1589_35172">
|
||||
<rect x="0.875" y="0.5" width="20" height="20" rx="10" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 898 B |
@@ -1,12 +0,0 @@
|
||||
<svg width="21" height="21" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_1589_35174)">
|
||||
<path d="M14.353 1.12211C13.2697 0.720161 12.0979 0.500122 10.8747 0.500122C9.65153 0.500122 8.47981 0.720161 7.39649 1.12211L6.52692 10.5001L7.39649 19.8781C8.47981 20.2801 9.65153 20.5001 10.8747 20.5001C12.0979 20.5001 13.2697 20.2801 14.353 19.8781L15.2225 10.5001L14.353 1.12211Z" fill="#FFDA44"/>
|
||||
<path d="M20.8749 10.4994C20.8749 6.19982 18.1612 2.53435 14.3531 1.12146V19.8775C18.1612 18.4645 20.8749 14.7991 20.8749 10.4994Z" fill="#D80027"/>
|
||||
<path d="M0.874664 10.5C0.874664 14.7997 3.58841 18.4651 7.39642 19.8781V1.12207C3.58841 2.53496 0.874664 6.20043 0.874664 10.5Z" fill="black"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_1589_35174">
|
||||
<rect x="0.875" y="0.5" width="20" height="20" rx="10" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 874 B |
@@ -1,11 +0,0 @@
|
||||
<svg width="21" height="21" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_1589_35176)">
|
||||
<path d="M10.875 20.5C16.3978 20.5 20.875 16.0228 20.875 10.5C20.875 4.97715 16.3978 0.5 10.875 0.5C5.35215 0.5 0.875 4.97715 0.875 10.5C0.875 16.0228 5.35215 20.5 10.875 20.5Z" fill="#496E2D"/>
|
||||
<path d="M8.70105 14.8479C11.1023 14.8479 13.0489 12.9013 13.0489 10.5C13.0489 8.09881 11.1023 6.15222 8.70105 6.15222C6.29982 6.15222 4.35324 8.09881 4.35324 10.5C4.35324 12.9013 6.29982 14.8479 8.70105 14.8479Z" fill="#D80027"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_1589_35176">
|
||||
<rect x="0.875" y="0.5" width="20" height="20" rx="10" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 703 B |
|
After Width: | Height: | Size: 448 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 692 B |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 430 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 119 KiB |
@@ -1,4 +0,0 @@
|
||||
<svg width="80" height="80" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5.61127 24.8528C5.93259 19.9058 9.90987 16.0289 14.8612 15.7836C22.031 15.4284 32.2787 15 40 15C47.7213 15 57.969 15.4284 65.1388 15.7836C70.0901 16.0289 74.0674 19.9058 74.3887 24.8528C74.6966 29.5923 75 35.4241 75 40C75 44.5759 74.6966 50.4077 74.3887 55.1472C74.0674 60.0942 70.0901 63.9711 65.1388 64.2164C57.969 64.5716 47.7213 65 40 65C32.2787 65 22.031 64.5716 14.8612 64.2164C9.90987 63.9711 5.93259 60.0942 5.61127 55.1472C5.30341 50.4077 5 44.5759 5 40C5 35.4241 5.30341 29.5923 5.61127 24.8528Z" fill="#FC0D1B"/>
|
||||
<path d="M32.5 30V50L52.5 40L32.5 30Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 691 B |
@@ -0,0 +1,284 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import html
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
import unicodedata
|
||||
from html.parser import HTMLParser
|
||||
from pathlib import Path
|
||||
from urllib.parse import unquote, urlparse
|
||||
|
||||
import requests
|
||||
|
||||
|
||||
API_URL = "https://vi.wikipedia.org/w/api.php"
|
||||
DEFAULT_OUTPUT_DIR = Path(__file__).resolve().parents[1] / "tmp" / "wiki"
|
||||
USER_AGENT = "UltimateHistoryMapWikiImporter/1.0"
|
||||
|
||||
ALLOWED_TAGS = {
|
||||
"p",
|
||||
"blockquote",
|
||||
"h2",
|
||||
"h3",
|
||||
"h4",
|
||||
"h5",
|
||||
"h6",
|
||||
"ul",
|
||||
"ol",
|
||||
"li",
|
||||
"b",
|
||||
"strong",
|
||||
"i",
|
||||
"em",
|
||||
"code",
|
||||
"pre",
|
||||
"a",
|
||||
"br",
|
||||
}
|
||||
|
||||
SKIP_TAGS = {
|
||||
"audio",
|
||||
"canvas",
|
||||
"figure",
|
||||
"form",
|
||||
"iframe",
|
||||
"img",
|
||||
"input",
|
||||
"map",
|
||||
"math",
|
||||
"meta",
|
||||
"noscript",
|
||||
"picture",
|
||||
"script",
|
||||
"style",
|
||||
"svg",
|
||||
"table",
|
||||
"video",
|
||||
}
|
||||
|
||||
SKIP_CLASS_PARTS = (
|
||||
"ambox",
|
||||
"authority-control",
|
||||
"catlinks",
|
||||
"error",
|
||||
"hatnote",
|
||||
"metadata",
|
||||
"mw-editsection",
|
||||
"mw-empty-elt",
|
||||
"navbox",
|
||||
"navigation-not-searchable",
|
||||
"noprint",
|
||||
"reference",
|
||||
"reflist",
|
||||
"shortdescription",
|
||||
"sidebar",
|
||||
"toc",
|
||||
"vertical-navbox",
|
||||
)
|
||||
|
||||
VOID_TAGS = {"br"}
|
||||
|
||||
|
||||
class WikiHtmlSanitizer(HTMLParser):
|
||||
def __init__(self) -> None:
|
||||
super().__init__(convert_charrefs=False)
|
||||
self.parts: list[str] = []
|
||||
self.open_tags: list[str] = []
|
||||
self.skip_depth = 0
|
||||
|
||||
def handle_starttag(self, tag: str, attrs: list[tuple[str, str | None]]) -> None:
|
||||
tag = tag.lower()
|
||||
if self.skip_depth:
|
||||
self.skip_depth += 1
|
||||
return
|
||||
|
||||
attr_map = {name.lower(): value or "" for name, value in attrs}
|
||||
if tag in SKIP_TAGS or self._has_skipped_class(attr_map.get("class", "")):
|
||||
self.skip_depth = 1
|
||||
return
|
||||
|
||||
if tag not in ALLOWED_TAGS:
|
||||
return
|
||||
|
||||
if tag == "a":
|
||||
self.parts.append('<a href="__missing__">')
|
||||
elif tag == "br":
|
||||
self.parts.append("<br>")
|
||||
return
|
||||
else:
|
||||
self.parts.append(f"<{tag}>")
|
||||
self.open_tags.append(tag)
|
||||
|
||||
def handle_startendtag(self, tag: str, attrs: list[tuple[str, str | None]]) -> None:
|
||||
tag = tag.lower()
|
||||
if self.skip_depth:
|
||||
return
|
||||
attr_map = {name.lower(): value or "" for name, value in attrs}
|
||||
if tag in SKIP_TAGS or self._has_skipped_class(attr_map.get("class", "")):
|
||||
return
|
||||
if tag == "br":
|
||||
self.parts.append("<br>")
|
||||
|
||||
def handle_endtag(self, tag: str) -> None:
|
||||
tag = tag.lower()
|
||||
if self.skip_depth:
|
||||
self.skip_depth -= 1
|
||||
return
|
||||
if tag not in ALLOWED_TAGS or tag in VOID_TAGS:
|
||||
return
|
||||
|
||||
for index in range(len(self.open_tags) - 1, -1, -1):
|
||||
if self.open_tags[index] == tag:
|
||||
while len(self.open_tags) > index:
|
||||
closing_tag = self.open_tags.pop()
|
||||
self.parts.append(f"</{closing_tag}>")
|
||||
return
|
||||
|
||||
def handle_data(self, data: str) -> None:
|
||||
if self.skip_depth:
|
||||
return
|
||||
if not data:
|
||||
return
|
||||
self.parts.append(html.escape(data, quote=False))
|
||||
|
||||
def handle_entityref(self, name: str) -> None:
|
||||
if self.skip_depth:
|
||||
return
|
||||
self.parts.append(f"&{name};")
|
||||
|
||||
def handle_charref(self, name: str) -> None:
|
||||
if self.skip_depth:
|
||||
return
|
||||
self.parts.append(f"&#{name};")
|
||||
|
||||
def get_html(self) -> str:
|
||||
while self.open_tags:
|
||||
self.parts.append(f"</{self.open_tags.pop()}>")
|
||||
return "".join(self.parts)
|
||||
|
||||
@staticmethod
|
||||
def _has_skipped_class(class_value: str) -> bool:
|
||||
classes = class_value.lower().split()
|
||||
return any(any(part in cls for part in SKIP_CLASS_PARTS) for cls in classes)
|
||||
|
||||
|
||||
def title_from_source(source: str) -> str:
|
||||
parsed = urlparse(source)
|
||||
if parsed.scheme and parsed.netloc:
|
||||
if "/wiki/" in parsed.path:
|
||||
return unquote(parsed.path.rsplit("/wiki/", 1)[1]).replace("_", " ")
|
||||
raise ValueError(f"Unsupported Wikipedia URL: {source}")
|
||||
return source.replace("_", " ").strip()
|
||||
|
||||
|
||||
def slugify_title(title: str) -> str:
|
||||
text = unicodedata.normalize("NFD", title.strip().lower())
|
||||
text = "".join(ch for ch in text if unicodedata.category(ch) != "Mn")
|
||||
text = text.replace("đ", "d")
|
||||
text = re.sub(r"[^a-z0-9]+", "-", text)
|
||||
return text.strip("-") or "wiki"
|
||||
|
||||
|
||||
def fetch_wikipedia_html(title: str) -> tuple[str, str]:
|
||||
response = requests.get(
|
||||
API_URL,
|
||||
params={
|
||||
"action": "parse",
|
||||
"page": title,
|
||||
"prop": "text",
|
||||
"format": "json",
|
||||
"formatversion": "2",
|
||||
"redirects": "1",
|
||||
"disableeditsection": "1",
|
||||
},
|
||||
headers={"User-Agent": USER_AGENT},
|
||||
timeout=30,
|
||||
)
|
||||
response.raise_for_status()
|
||||
payload = response.json()
|
||||
if "error" in payload:
|
||||
raise RuntimeError(json.dumps(payload["error"], ensure_ascii=False))
|
||||
parsed = payload.get("parse") or {}
|
||||
fetched_title = str(parsed.get("title") or title).strip()
|
||||
article_html = str(parsed.get("text") or "")
|
||||
if not article_html.strip():
|
||||
raise RuntimeError(f"No article HTML returned for title: {title}")
|
||||
return fetched_title, article_html
|
||||
|
||||
|
||||
def sanitize_wikipedia_html(article_html: str) -> str:
|
||||
parser = WikiHtmlSanitizer()
|
||||
parser.feed(article_html)
|
||||
parser.close()
|
||||
content = html.unescape(parser.get_html())
|
||||
content = normalize_fragment(content)
|
||||
return content
|
||||
|
||||
|
||||
def normalize_fragment(content: str) -> str:
|
||||
content = re.sub(r"\r\n?", "\n", content)
|
||||
content = re.sub(r"[ \t\f\v]+", " ", content)
|
||||
content = re.sub(r"\s*\n\s*", "\n", content)
|
||||
content = re.sub(r">\s+<", "><", content)
|
||||
content = re.sub(r"<(p|li|h[2-6]|blockquote)>\s*</\1>", "", content)
|
||||
content = re.sub(r"<(ul|ol)>\s*</\1>", "", content)
|
||||
content = re.sub(r"(</(?:p|h[2-6]|ul|ol|li|blockquote|pre)>)", r"\1\n", content)
|
||||
content = re.sub(r"\n{2,}", "\n", content)
|
||||
return content.strip()
|
||||
|
||||
|
||||
def put_first_paragraph_in_blockquote(content: str) -> str:
|
||||
match = re.search(r"<p>(.*?)</p>", content, flags=re.S)
|
||||
if not match:
|
||||
return content
|
||||
|
||||
quote_inner = match.group(1).strip()
|
||||
before = content[: match.start()].strip()
|
||||
after = content[match.end() :].strip()
|
||||
parts = []
|
||||
if quote_inner:
|
||||
parts.append(f"<blockquote>{quote_inner}</blockquote>")
|
||||
if before:
|
||||
parts.append(before)
|
||||
if after:
|
||||
parts.append(after)
|
||||
return "\n".join(parts).strip()
|
||||
|
||||
|
||||
def write_article(source: str, output_dir: Path, output_name: str | None = None) -> Path:
|
||||
title = title_from_source(source)
|
||||
fetched_title, article_html = fetch_wikipedia_html(title)
|
||||
content = sanitize_wikipedia_html(article_html)
|
||||
content = put_first_paragraph_in_blockquote(content)
|
||||
|
||||
filename = output_name or f"{slugify_title(fetched_title)}.html"
|
||||
if not filename.endswith(".html"):
|
||||
filename = f"{filename}.html"
|
||||
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
output_path = output_dir / filename
|
||||
output_path.write_text(content + "\n", encoding="utf-8")
|
||||
return output_path
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description="Fetch a Vietnamese Wikipedia article into UHM wiki HTML format.")
|
||||
parser.add_argument("source", help="Vietnamese Wikipedia URL or page title.")
|
||||
parser.add_argument("--output-dir", type=Path, default=DEFAULT_OUTPUT_DIR)
|
||||
parser.add_argument("--output-name", help="Output filename. Defaults to a slug from the fetched title.")
|
||||
args = parser.parse_args()
|
||||
|
||||
output_path = write_article(args.source, args.output_dir, args.output_name)
|
||||
print(output_path)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
raise SystemExit(main())
|
||||
except Exception as exc:
|
||||
print(f"error: {exc}", file=sys.stderr)
|
||||
raise SystemExit(1)
|
||||
@@ -1,86 +0,0 @@
|
||||
import ComponentCard from "@/components/common/ComponentCard";
|
||||
import PageBreadcrumb from "@/components/common/PageBreadCrumb";
|
||||
import Alert from "@/components/ui/alert/Alert";
|
||||
import { Metadata } from "next";
|
||||
import React from "react";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Next.js Alerts | TailAdmin - Next.js Dashboard Template",
|
||||
description:
|
||||
"This is Next.js Alerts page for TailAdmin - Next.js Tailwind CSS Admin Dashboard Template",
|
||||
// other metadata
|
||||
};
|
||||
|
||||
export default function Alerts() {
|
||||
return (
|
||||
<div>
|
||||
<PageBreadcrumb pageTitle="Alerts" />
|
||||
<div className="space-y-5 sm:space-y-6">
|
||||
<ComponentCard title="Success Alert">
|
||||
<Alert
|
||||
variant="success"
|
||||
title="Success Message"
|
||||
message="Be cautious when performing this action."
|
||||
showLink={true}
|
||||
linkHref="/"
|
||||
linkText="Learn more"
|
||||
/>
|
||||
<Alert
|
||||
variant="success"
|
||||
title="Success Message"
|
||||
message="Be cautious when performing this action."
|
||||
showLink={false}
|
||||
/>
|
||||
</ComponentCard>
|
||||
<ComponentCard title="Warning Alert">
|
||||
<Alert
|
||||
variant="warning"
|
||||
title="Warning Message"
|
||||
message="Be cautious when performing this action."
|
||||
showLink={true}
|
||||
linkHref="/"
|
||||
linkText="Learn more"
|
||||
/>
|
||||
<Alert
|
||||
variant="warning"
|
||||
title="Warning Message"
|
||||
message="Be cautious when performing this action."
|
||||
showLink={false}
|
||||
/>
|
||||
</ComponentCard>{" "}
|
||||
<ComponentCard title="Error Alert">
|
||||
<Alert
|
||||
variant="error"
|
||||
title="Error Message"
|
||||
message="Be cautious when performing this action."
|
||||
showLink={true}
|
||||
linkHref="/"
|
||||
linkText="Learn more"
|
||||
/>
|
||||
<Alert
|
||||
variant="error"
|
||||
title="Error Message"
|
||||
message="Be cautious when performing this action."
|
||||
showLink={false}
|
||||
/>
|
||||
</ComponentCard>{" "}
|
||||
<ComponentCard title="Info Alert">
|
||||
<Alert
|
||||
variant="info"
|
||||
title="Info Message"
|
||||
message="Be cautious when performing this action."
|
||||
showLink={true}
|
||||
linkHref="/"
|
||||
linkText="Learn more"
|
||||
/>
|
||||
<Alert
|
||||
variant="info"
|
||||
title="Info Message"
|
||||
message="Be cautious when performing this action."
|
||||
showLink={false}
|
||||
/>
|
||||
</ComponentCard>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
import ComponentCard from "@/components/common/ComponentCard";
|
||||
import PageBreadcrumb from "@/components/common/PageBreadCrumb";
|
||||
import Avatar from "@/components/ui/avatar/Avatar";
|
||||
import { Metadata } from "next";
|
||||
import React from "react";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Next.js Avatars | TailAdmin - Next.js Dashboard Template",
|
||||
description:
|
||||
"This is Next.js Avatars page for TailAdmin - Next.js Tailwind CSS Admin Dashboard Template",
|
||||
};
|
||||
|
||||
export default function AvatarPage() {
|
||||
return (
|
||||
<div>
|
||||
<PageBreadcrumb pageTitle="Avatar" />
|
||||
<div className="space-y-5 sm:space-y-6">
|
||||
<ComponentCard title="Default Avatar">
|
||||
{/* Default Avatar (No Status) */}
|
||||
<div className="flex flex-col items-center justify-center gap-5 sm:flex-row">
|
||||
<Avatar src="/images/user/user-01.jpg" size="xsmall" />
|
||||
<Avatar src="/images/user/user-01.jpg" size="small" />
|
||||
<Avatar src="/images/user/user-01.jpg" size="medium" />
|
||||
<Avatar src="/images/user/user-01.jpg" size="large" />
|
||||
<Avatar src="/images/user/user-01.jpg" size="xlarge" />
|
||||
<Avatar src="/images/user/user-01.jpg" size="xxlarge" />
|
||||
</div>
|
||||
</ComponentCard>
|
||||
<ComponentCard title="Avatar with online indicator">
|
||||
<div className="flex flex-col items-center justify-center gap-5 sm:flex-row">
|
||||
<Avatar
|
||||
src="/images/user/user-01.jpg"
|
||||
size="xsmall"
|
||||
status="online"
|
||||
/>
|
||||
<Avatar
|
||||
src="/images/user/user-01.jpg"
|
||||
size="small"
|
||||
status="online"
|
||||
/>
|
||||
<Avatar
|
||||
src="/images/user/user-01.jpg"
|
||||
size="medium"
|
||||
status="online"
|
||||
/>
|
||||
<Avatar
|
||||
src="/images/user/user-01.jpg"
|
||||
size="large"
|
||||
status="online"
|
||||
/>
|
||||
<Avatar
|
||||
src="/images/user/user-01.jpg"
|
||||
size="xlarge"
|
||||
status="online"
|
||||
/>
|
||||
<Avatar
|
||||
src="/images/user/user-01.jpg"
|
||||
size="xxlarge"
|
||||
status="online"
|
||||
/>
|
||||
</div>
|
||||
</ComponentCard>
|
||||
<ComponentCard title="Avatar with Offline indicator">
|
||||
<div className="flex flex-col items-center justify-center gap-5 sm:flex-row">
|
||||
<Avatar
|
||||
src="/images/user/user-01.jpg"
|
||||
size="xsmall"
|
||||
status="offline"
|
||||
/>
|
||||
<Avatar
|
||||
src="/images/user/user-01.jpg"
|
||||
size="small"
|
||||
status="offline"
|
||||
/>
|
||||
<Avatar
|
||||
src="/images/user/user-01.jpg"
|
||||
size="medium"
|
||||
status="offline"
|
||||
/>
|
||||
<Avatar
|
||||
src="/images/user/user-01.jpg"
|
||||
size="large"
|
||||
status="offline"
|
||||
/>
|
||||
<Avatar
|
||||
src="/images/user/user-01.jpg"
|
||||
size="xlarge"
|
||||
status="offline"
|
||||
/>
|
||||
<Avatar
|
||||
src="/images/user/user-01.jpg"
|
||||
size="xxlarge"
|
||||
status="offline"
|
||||
/>
|
||||
</div>
|
||||
</ComponentCard>{" "}
|
||||
<ComponentCard title="Avatar with busy indicator">
|
||||
<div className="flex flex-col items-center justify-center gap-5 sm:flex-row">
|
||||
<Avatar
|
||||
src="/images/user/user-01.jpg"
|
||||
size="xsmall"
|
||||
status="busy"
|
||||
/>
|
||||
<Avatar src="/images/user/user-01.jpg" size="small" status="busy" />
|
||||
<Avatar
|
||||
src="/images/user/user-01.jpg"
|
||||
size="medium"
|
||||
status="busy"
|
||||
/>
|
||||
<Avatar src="/images/user/user-01.jpg" size="large" status="busy" />
|
||||
<Avatar
|
||||
src="/images/user/user-01.jpg"
|
||||
size="xlarge"
|
||||
status="busy"
|
||||
/>
|
||||
<Avatar
|
||||
src="/images/user/user-01.jpg"
|
||||
size="xxlarge"
|
||||
status="busy"
|
||||
/>
|
||||
</div>
|
||||
</ComponentCard>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,221 +0,0 @@
|
||||
import PageBreadcrumb from "@/components/common/PageBreadCrumb";
|
||||
import Badge from "@/components/ui/badge/Badge";
|
||||
import { PlusIcon } from "@/icons";
|
||||
import { Metadata } from "next";
|
||||
import React from "react";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Next.js Badge | TailAdmin - Next.js Dashboard Template",
|
||||
description:
|
||||
"This is Next.js Badge page for TailAdmin - Next.js Tailwind CSS Admin Dashboard Template",
|
||||
// other metadata
|
||||
};
|
||||
|
||||
export default function BadgePage() {
|
||||
return (
|
||||
<div>
|
||||
<PageBreadcrumb pageTitle="Badges" />
|
||||
<div className="space-y-5 sm:space-y-6">
|
||||
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03]">
|
||||
<div className="px-6 py-5">
|
||||
<h3 className="text-base font-medium text-gray-800 dark:text-white/90">
|
||||
With Light Background
|
||||
</h3>
|
||||
</div>
|
||||
<div className="p-6 border-t border-gray-100 dark:border-gray-800 xl:p-10">
|
||||
<div className="flex flex-wrap gap-4 sm:items-center sm:justify-center">
|
||||
{/* Light Variant */}
|
||||
<Badge variant="light" color="primary">
|
||||
Primary
|
||||
</Badge>
|
||||
<Badge variant="light" color="success">
|
||||
Success
|
||||
</Badge>{" "}
|
||||
<Badge variant="light" color="error">
|
||||
Error
|
||||
</Badge>{" "}
|
||||
<Badge variant="light" color="warning">
|
||||
Warning
|
||||
</Badge>{" "}
|
||||
<Badge variant="light" color="info">
|
||||
Info
|
||||
</Badge>
|
||||
<Badge variant="light" color="light">
|
||||
Light
|
||||
</Badge>
|
||||
<Badge variant="light" color="dark">
|
||||
Dark
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03]">
|
||||
<div className="px-6 py-5">
|
||||
<h3 className="text-base font-medium text-gray-800 dark:text-white/90">
|
||||
With Solid Background
|
||||
</h3>
|
||||
</div>
|
||||
<div className="p-6 border-t border-gray-100 dark:border-gray-800 xl:p-10">
|
||||
<div className="flex flex-wrap gap-4 sm:items-center sm:justify-center">
|
||||
{/* Light Variant */}
|
||||
<Badge variant="solid" color="primary">
|
||||
Primary
|
||||
</Badge>
|
||||
<Badge variant="solid" color="success">
|
||||
Success
|
||||
</Badge>{" "}
|
||||
<Badge variant="solid" color="error">
|
||||
Error
|
||||
</Badge>{" "}
|
||||
<Badge variant="solid" color="warning">
|
||||
Warning
|
||||
</Badge>{" "}
|
||||
<Badge variant="solid" color="info">
|
||||
Info
|
||||
</Badge>
|
||||
<Badge variant="solid" color="light">
|
||||
Light
|
||||
</Badge>
|
||||
<Badge variant="solid" color="dark">
|
||||
Dark
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03]">
|
||||
<div className="px-6 py-5">
|
||||
<h3 className="text-base font-medium text-gray-800 dark:text-white/90">
|
||||
Light Background with Left Icon
|
||||
</h3>
|
||||
</div>
|
||||
<div className="p-6 border-t border-gray-100 dark:border-gray-800 xl:p-10">
|
||||
<div className="flex flex-wrap gap-4 sm:items-center sm:justify-center">
|
||||
<Badge variant="light" color="primary" startIcon={<PlusIcon />}>
|
||||
Primary
|
||||
</Badge>
|
||||
<Badge variant="light" color="success" startIcon={<PlusIcon />}>
|
||||
Success
|
||||
</Badge>{" "}
|
||||
<Badge variant="light" color="error" startIcon={<PlusIcon />}>
|
||||
Error
|
||||
</Badge>{" "}
|
||||
<Badge variant="light" color="warning" startIcon={<PlusIcon />}>
|
||||
Warning
|
||||
</Badge>{" "}
|
||||
<Badge variant="light" color="info" startIcon={<PlusIcon />}>
|
||||
Info
|
||||
</Badge>
|
||||
<Badge variant="light" color="light" startIcon={<PlusIcon />}>
|
||||
Light
|
||||
</Badge>
|
||||
<Badge variant="light" color="dark" startIcon={<PlusIcon />}>
|
||||
Dark
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03]">
|
||||
<div className="px-6 py-5">
|
||||
<h3 className="text-base font-medium text-gray-800 dark:text-white/90">
|
||||
Solid Background with Left Icon
|
||||
</h3>
|
||||
</div>
|
||||
<div className="p-6 border-t border-gray-100 dark:border-gray-800 xl:p-10">
|
||||
<div className="flex flex-wrap gap-4 sm:items-center sm:justify-center">
|
||||
<Badge variant="solid" color="primary" startIcon={<PlusIcon />}>
|
||||
Primary
|
||||
</Badge>
|
||||
<Badge variant="solid" color="success" startIcon={<PlusIcon />}>
|
||||
Success
|
||||
</Badge>{" "}
|
||||
<Badge variant="solid" color="error" startIcon={<PlusIcon />}>
|
||||
Error
|
||||
</Badge>{" "}
|
||||
<Badge variant="solid" color="warning" startIcon={<PlusIcon />}>
|
||||
Warning
|
||||
</Badge>{" "}
|
||||
<Badge variant="solid" color="info" startIcon={<PlusIcon />}>
|
||||
Info
|
||||
</Badge>
|
||||
<Badge variant="solid" color="light" startIcon={<PlusIcon />}>
|
||||
Light
|
||||
</Badge>
|
||||
<Badge variant="solid" color="dark" startIcon={<PlusIcon />}>
|
||||
Dark
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03]">
|
||||
<div className="px-6 py-5">
|
||||
<h3 className="text-base font-medium text-gray-800 dark:text-white/90">
|
||||
Light Background with Right Icon
|
||||
</h3>
|
||||
</div>
|
||||
<div className="p-6 border-t border-gray-100 dark:border-gray-800 xl:p-10">
|
||||
<div className="flex flex-wrap gap-4 sm:items-center sm:justify-center">
|
||||
<Badge variant="light" color="primary" endIcon={<PlusIcon />}>
|
||||
Primary
|
||||
</Badge>
|
||||
<Badge variant="light" color="success" endIcon={<PlusIcon />}>
|
||||
Success
|
||||
</Badge>{" "}
|
||||
<Badge variant="light" color="error" endIcon={<PlusIcon />}>
|
||||
Error
|
||||
</Badge>{" "}
|
||||
<Badge variant="light" color="warning" endIcon={<PlusIcon />}>
|
||||
Warning
|
||||
</Badge>{" "}
|
||||
<Badge variant="light" color="info" endIcon={<PlusIcon />}>
|
||||
Info
|
||||
</Badge>
|
||||
<Badge variant="light" color="light" endIcon={<PlusIcon />}>
|
||||
Light
|
||||
</Badge>
|
||||
<Badge variant="light" color="dark" endIcon={<PlusIcon />}>
|
||||
Dark
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03]">
|
||||
<div className="px-6 py-5">
|
||||
<h3 className="text-base font-medium text-gray-800 dark:text-white/90">
|
||||
Solid Background with Right Icon
|
||||
</h3>
|
||||
</div>
|
||||
<div className="p-6 border-t border-gray-100 dark:border-gray-800 xl:p-10">
|
||||
<div className="flex flex-wrap gap-4 sm:items-center sm:justify-center">
|
||||
<Badge variant="solid" color="primary" endIcon={<PlusIcon />}>
|
||||
Primary
|
||||
</Badge>
|
||||
<Badge variant="solid" color="success" endIcon={<PlusIcon />}>
|
||||
Success
|
||||
</Badge>{" "}
|
||||
<Badge variant="solid" color="error" endIcon={<PlusIcon />}>
|
||||
Error
|
||||
</Badge>{" "}
|
||||
<Badge variant="solid" color="warning" endIcon={<PlusIcon />}>
|
||||
Warning
|
||||
</Badge>{" "}
|
||||
<Badge variant="solid" color="info" endIcon={<PlusIcon />}>
|
||||
Info
|
||||
</Badge>
|
||||
<Badge variant="solid" color="light" endIcon={<PlusIcon />}>
|
||||
Light
|
||||
</Badge>
|
||||
<Badge variant="solid" color="dark" endIcon={<PlusIcon />}>
|
||||
Dark
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
import ComponentCard from "@/components/common/ComponentCard";
|
||||
import PageBreadcrumb from "@/components/common/PageBreadCrumb";
|
||||
import Button from "@/components/ui/button/Button";
|
||||
import { BoxIcon } from "@/icons";
|
||||
import { Metadata } from "next";
|
||||
import React from "react";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Next.js Buttons | TailAdmin - Next.js Dashboard Template",
|
||||
description:
|
||||
"This is Next.js Buttons page for TailAdmin - Next.js Tailwind CSS Admin Dashboard Template",
|
||||
};
|
||||
|
||||
export default function Buttons() {
|
||||
return (
|
||||
<div>
|
||||
<PageBreadcrumb pageTitle="Buttons" />
|
||||
<div className="space-y-5 sm:space-y-6">
|
||||
{/* Primary Button */}
|
||||
<ComponentCard title="Primary Button">
|
||||
<div className="flex items-center gap-5">
|
||||
<Button size="sm" variant="primary">
|
||||
Button Text
|
||||
</Button>
|
||||
<Button size="md" variant="primary">
|
||||
Button Text
|
||||
</Button>
|
||||
</div>
|
||||
</ComponentCard>
|
||||
{/* Primary Button with Start Icon */}
|
||||
<ComponentCard title="Primary Button with Left Icon">
|
||||
<div className="flex items-center gap-5">
|
||||
<Button size="sm" variant="primary" startIcon={<BoxIcon />}>
|
||||
Button Text
|
||||
</Button>
|
||||
<Button size="md" variant="primary" startIcon={<BoxIcon />}>
|
||||
Button Text
|
||||
</Button>
|
||||
</div>
|
||||
</ComponentCard>{" "}
|
||||
{/* Primary Button with Start Icon */}
|
||||
<ComponentCard title="Primary Button with Right Icon">
|
||||
<div className="flex items-center gap-5">
|
||||
<Button size="sm" variant="primary" endIcon={<BoxIcon />}>
|
||||
Button Text
|
||||
</Button>
|
||||
<Button size="md" variant="primary" endIcon={<BoxIcon />}>
|
||||
Button Text
|
||||
</Button>
|
||||
</div>
|
||||
</ComponentCard>
|
||||
{/* Outline Button */}
|
||||
<ComponentCard title="Secondary Button">
|
||||
<div className="flex items-center gap-5">
|
||||
{/* Outline Button */}
|
||||
<Button size="sm" variant="outline">
|
||||
Button Text
|
||||
</Button>
|
||||
<Button size="md" variant="outline">
|
||||
Button Text
|
||||
</Button>
|
||||
</div>
|
||||
</ComponentCard>
|
||||
{/* Outline Button with Start Icon */}
|
||||
<ComponentCard title="Outline Button with Left Icon">
|
||||
<div className="flex items-center gap-5">
|
||||
<Button size="sm" variant="outline" startIcon={<BoxIcon />}>
|
||||
Button Text
|
||||
</Button>
|
||||
<Button size="md" variant="outline" startIcon={<BoxIcon />}>
|
||||
Button Text
|
||||
</Button>
|
||||
</div>
|
||||
</ComponentCard>{" "}
|
||||
{/* Outline Button with Start Icon */}
|
||||
<ComponentCard title="Outline Button with Right Icon">
|
||||
<div className="flex items-center gap-5">
|
||||
<Button size="sm" variant="outline" endIcon={<BoxIcon />}>
|
||||
Button Text
|
||||
</Button>
|
||||
<Button size="md" variant="outline" endIcon={<BoxIcon />}>
|
||||
Button Text
|
||||
</Button>
|
||||
</div>
|
||||
</ComponentCard>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
import ComponentCard from "@/components/common/ComponentCard";
|
||||
import PageBreadcrumb from "@/components/common/PageBreadCrumb";
|
||||
import ResponsiveImage from "@/components/ui/images/ResponsiveImage";
|
||||
import ThreeColumnImageGrid from "@/components/ui/images/ThreeColumnImageGrid";
|
||||
import TwoColumnImageGrid from "@/components/ui/images/TwoColumnImageGrid";
|
||||
import { Metadata } from "next";
|
||||
import React from "react";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Next.js Images | TailAdmin - Next.js Dashboard Template",
|
||||
description:
|
||||
"This is Next.js Images page for TailAdmin - Next.js Tailwind CSS Admin Dashboard Template",
|
||||
// other metadata
|
||||
};
|
||||
|
||||
export default function Images() {
|
||||
return (
|
||||
<div>
|
||||
<PageBreadcrumb pageTitle="Images" />
|
||||
<div className="space-y-5 sm:space-y-6">
|
||||
<ComponentCard title="Responsive image">
|
||||
<ResponsiveImage />
|
||||
</ComponentCard>
|
||||
<ComponentCard title="Image in 2 Grid">
|
||||
<TwoColumnImageGrid />
|
||||
</ComponentCard>
|
||||
<ComponentCard title="Image in 3 Grid">
|
||||
<ThreeColumnImageGrid />
|
||||
</ComponentCard>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
import PageBreadcrumb from "@/components/common/PageBreadCrumb";
|
||||
import DefaultModal from "@/components/example/ModalExample/DefaultModal";
|
||||
import FormInModal from "@/components/example/ModalExample/FormInModal";
|
||||
import FullScreenModal from "@/components/example/ModalExample/FullScreenModal";
|
||||
import ModalBasedAlerts from "@/components/example/ModalExample/ModalBasedAlerts";
|
||||
import VerticallyCenteredModal from "@/components/example/ModalExample/VerticallyCenteredModal";
|
||||
import { Metadata } from "next";
|
||||
import React from "react";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Next.js Modals | TailAdmin - Next.js Dashboard Template",
|
||||
description:
|
||||
"This is Next.js Modals page for TailAdmin - Next.js Tailwind CSS Admin Dashboard Template",
|
||||
// other metadata
|
||||
};
|
||||
|
||||
export default function Modals() {
|
||||
return (
|
||||
<div>
|
||||
<PageBreadcrumb pageTitle="Modals" />
|
||||
<div className="grid grid-cols-1 gap-5 xl:grid-cols-2 xl:gap-6">
|
||||
<DefaultModal />
|
||||
<VerticallyCenteredModal />
|
||||
<FormInModal />
|
||||
<FullScreenModal />
|
||||
<ModalBasedAlerts />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import PageBreadcrumb from "@/components/common/PageBreadCrumb";
|
||||
import VideosExample from "@/components/ui/video/VideosExample";
|
||||
import { Metadata } from "next";
|
||||
import React from "react";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Next.js Videos | TailAdmin - Next.js Dashboard Template",
|
||||
description:
|
||||
"This is Next.js Videos page for TailAdmin - Next.js Tailwind CSS Admin Dashboard Template",
|
||||
};
|
||||
|
||||
export default function VideoPage() {
|
||||
return (
|
||||
<div>
|
||||
<PageBreadcrumb pageTitle="Videos" />
|
||||
|
||||
<VideosExample />
|
||||
</div>
|
||||
);
|
||||
}
|
||||