From a0e8ae2adc488d028b7fb06d864a835be87184a8 Mon Sep 17 00:00:00 2001 From: user Date: Tue, 12 May 2026 13:09:36 +0900 Subject: [PATCH] Add Linux basics mindmap --- README.md | 5 +- imgs/linux_filesystem.svg | 30 ++ imgs/linux_network_packages.svg | 24 ++ imgs/linux_overview.svg | 25 ++ imgs/linux_permissions.svg | 21 ++ imgs/linux_processes.svg | 24 ++ imgs/linux_shell.svg | 23 ++ index.html | 8 +- script.js | 539 +++++++++++++++++++++++++++++++- styles.css | 28 +- 10 files changed, 719 insertions(+), 8 deletions(-) create mode 100644 imgs/linux_filesystem.svg create mode 100644 imgs/linux_network_packages.svg create mode 100644 imgs/linux_overview.svg create mode 100644 imgs/linux_permissions.svg create mode 100644 imgs/linux_processes.svg create mode 100644 imgs/linux_shell.svg diff --git a/README.md b/README.md index 42bdef4..11fb9c6 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,11 @@ -# Web Mindmap +# Learning Mindmap -웹 개발 용어를 접을 수 있는 마인드맵으로 학습하는 정적 교육용 웹사이트입니다. +웹 개발 용어와 리눅스 기초 사용법을 접을 수 있는 마인드맵으로 학습하는 정적 교육용 웹사이트입니다. ## Features - 접힌 루트 노드에서 시작하는 인터랙티브 마인드맵 +- 웹 개발 / 리눅스 기초 주제 전환 - `+ / -` 버튼으로 하위 노드 펼침/접힘 - 노드 드래그로 위치 이동 - 배경 드래그로 viewport 이동 diff --git a/imgs/linux_filesystem.svg b/imgs/linux_filesystem.svg new file mode 100644 index 0000000..56d8a3d --- /dev/null +++ b/imgs/linux_filesystem.svg @@ -0,0 +1,30 @@ + + Linux filesystem + Linux directory tree with root, home, etc, var, usr, and mount points. + + Linux 파일 시스템 + 모든 것은 루트 / 아래의 경로로 연결되고, 장치도 마운트 지점에 붙습니다. + + + + + + + + + + + / + + /home + + /etc + + /var + + /usr + + /mnt + + 숨김 파일은 점(.)으로 시작하고, 설정 파일은 보통 홈 디렉터리나 /etc에서 만납니다. + diff --git a/imgs/linux_network_packages.svg b/imgs/linux_network_packages.svg new file mode 100644 index 0000000..2597a87 --- /dev/null +++ b/imgs/linux_network_packages.svg @@ -0,0 +1,24 @@ + + Linux packages and networking + Linux package management and networking tools including apt, dnf, ping, ss, curl, ssh, and firewall. + + 패키지와 네트워크 + 필요한 도구를 설치하고, 네트워크 상태를 확인하고, 원격 서버에 안전하게 접속합니다. + + + apt / dnf + 패키지 설치와 업데이트 + + ping / ss + 연결과 포트 확인 + + curl / wget + HTTP 요청과 다운로드 + + ssh + 원격 셸 접속 + + ufw / firewall + 접근 허용과 차단 + + diff --git a/imgs/linux_overview.svg b/imgs/linux_overview.svg new file mode 100644 index 0000000..bdb8235 --- /dev/null +++ b/imgs/linux_overview.svg @@ -0,0 +1,25 @@ + + Linux overview learning map + Linux basics organized around shell commands, files, permissions, processes, packages, and networking. + + + Linux 기초 개념 + 명령어, 파일 시스템, 권한, 프로세스, 패키지, 네트워크를 한 흐름으로 봅니다. + + + Shell + 명령 실행과 조합 + + Filesystem + 경로와 저장 위치 + + Permission + 사용자와 접근 제어 + + Process + 실행 중인 작업 + + Package & Network + 설치, 통신, 원격 접속 + + diff --git a/imgs/linux_permissions.svg b/imgs/linux_permissions.svg new file mode 100644 index 0000000..d64887f --- /dev/null +++ b/imgs/linux_permissions.svg @@ -0,0 +1,21 @@ + + Linux permissions + Linux permission model showing owner, group, others and read, write, execute bits. + + 권한과 사용자 + 파일마다 소유자, 그룹, 그 외 사용자에게 읽기/쓰기/실행 권한을 나누어 줍니다. + + - rwx r-x r-- user devs deploy.sh + + + Owner + 파일 주인 + + Group + 공동 작업 단위 + + Others + 나머지 사용자 + + chmod는 권한을 바꾸고, chown은 소유자를 바꾸며, sudo는 관리자 권한으로 실행합니다. + diff --git a/imgs/linux_processes.svg b/imgs/linux_processes.svg new file mode 100644 index 0000000..26e59c7 --- /dev/null +++ b/imgs/linux_processes.svg @@ -0,0 +1,24 @@ + + Linux processes and services + Linux process and service flow with systemd, processes, logs, and scheduled jobs. + + 프로세스와 서비스 + 실행 중인 프로그램을 관찰하고, 서비스로 등록하고, 로그와 예약 작업으로 운영합니다. + + + ps / top + 무엇이 실행 중인지 보기 + + systemd + 서비스 시작과 자동 실행 + + journalctl + 서비스 로그 확인 + + kill + 종료 신호 보내기 + + cron + 정해진 시간에 실행 + + diff --git a/imgs/linux_shell.svg b/imgs/linux_shell.svg new file mode 100644 index 0000000..fff45ff --- /dev/null +++ b/imgs/linux_shell.svg @@ -0,0 +1,23 @@ + + Linux shell commands + A terminal style diagram showing command structure, pipes, redirects, grep, find, environment variables, and history. + + + + + + + $ ls -la /var/log | grep error > errors.txt + + + 명령어 + + 옵션/인자 + + 파이프 + + 리다이렉트 + + Shell은 작은 명령을 조합해 원하는 결과를 만드는 작업대입니다. + pwd, cd, ls로 위치를 잡고 grep/find로 찾고, PATH와 history로 반복 작업을 줄입니다. + diff --git a/index.html b/index.html index 603c514..48a6c68 100644 --- a/index.html +++ b/index.html @@ -3,17 +3,21 @@ - 웹 개발 용어 마인드맵 + 학습 용어 마인드맵
-

Web Learning Map

+

Web Learning Map

웹 개발 용어 마인드맵

+
+ + +
diff --git a/script.js b/script.js index e74275a..7f5abdd 100644 --- a/script.js +++ b/script.js @@ -1,4 +1,4 @@ -const nodes = [ +const webNodes = [ { id: "root", type: "root", @@ -485,11 +485,517 @@ const nodes = [ }, ]; +const linuxNodes = [ + { + id: "root", + type: "root", + title: "리눅스", + subtitle: "클릭해서 펼치기", + image: "imgs/linux_overview.svg", + category: "전체 개요", + focus: "리눅스를 터미널, 파일 시스템, 권한, 프로세스, 패키지, 네트워크 흐름으로 나누어 봅니다.", + x: 1020, + y: 700, + children: ["linux-basics", "linux-shell", "linux-filesystem", "linux-permissions", "linux-processes", "linux-packages-network"], + }, + { + id: "linux-basics", + parent: "root", + type: "category", + title: "기초 개념", + subtitle: "운영체제와 도움말", + image: "imgs/linux_overview.svg", + category: "기초 개념", + focus: "리눅스가 커널, 배포판, 셸, 패키지 저장소로 구성된 운영체제 생태계라는 큰 그림을 봅니다.", + x: 1020, + y: 420, + children: ["linux-kernel", "linux-distro", "linux-terminal", "linux-man-pages", "linux-sudo-basics"], + }, + { + id: "linux-shell", + parent: "root", + type: "category", + title: "셸 명령어", + subtitle: "명령 실행과 조합", + image: "imgs/linux_shell.svg", + category: "셸 명령어", + focus: "셸은 명령어, 옵션, 인자, 파이프, 리다이렉트를 조합해 작업을 자동화하는 인터페이스입니다.", + x: 1360, + y: 560, + children: ["linux-command-shape", "linux-pwd-ls-cd", "linux-file-ops", "linux-pipes", "linux-grep-find", "linux-history", "linux-env-path"], + }, + { + id: "linux-filesystem", + parent: "root", + type: "category", + title: "파일 시스템", + subtitle: "경로와 디렉터리", + image: "imgs/linux_filesystem.svg", + category: "파일 시스템", + focus: "리눅스는 모든 경로가 루트(/)에서 시작하고, 설정·로그·사용자 파일이 관례적인 위치에 놓입니다.", + x: 1320, + y: 900, + children: ["linux-root-path", "linux-home-etc-var", "linux-hidden-files", "linux-mounts", "linux-links"], + }, + { + id: "linux-permissions", + parent: "root", + type: "category", + title: "권한", + subtitle: "사용자와 접근 제어", + image: "imgs/linux_permissions.svg", + category: "권한", + focus: "사용자, 그룹, 읽기/쓰기/실행 권한을 이해하면 파일 접근과 관리자 작업을 안전하게 다룰 수 있습니다.", + x: 1020, + y: 1030, + children: ["linux-users-groups", "linux-rwx", "linux-chmod-chown", "linux-sudo", "linux-ssh-keys"], + }, + { + id: "linux-processes", + parent: "root", + type: "category", + title: "프로세스", + subtitle: "실행 중인 작업", + image: "imgs/linux_processes.svg", + category: "프로세스", + focus: "프로세스와 서비스 상태를 보고, 필요하면 종료하거나 로그를 확인하고, 예약 실행까지 연결합니다.", + x: 660, + y: 900, + children: ["linux-ps-top", "linux-kill", "linux-systemd", "linux-logs", "linux-cron"], + }, + { + id: "linux-packages-network", + parent: "root", + type: "category", + title: "패키지·네트워크", + subtitle: "설치와 원격 접속", + image: "imgs/linux_network_packages.svg", + category: "패키지·네트워크", + focus: "패키지 관리자로 도구를 설치하고, 네트워크 명령과 SSH로 서버 상태를 확인합니다.", + x: 660, + y: 560, + children: ["linux-apt-dnf", "linux-update-upgrade", "linux-ping-ss", "linux-curl-wget", "linux-ssh", "linux-firewall"], + }, + { + id: "linux-kernel", + parent: "linux-basics", + type: "term", + title: "커널", + subtitle: "기초 개념", + image: "imgs/linux_overview.svg", + category: "기초 개념", + focus: "커널은 CPU, 메모리, 파일, 네트워크 같은 하드웨어 자원을 프로그램이 안전하게 쓰도록 중재합니다.", + x: 650, + y: 170, + }, + { + id: "linux-distro", + parent: "linux-basics", + type: "term", + title: "배포판", + subtitle: "기초 개념", + image: "imgs/linux_overview.svg", + category: "기초 개념", + focus: "Ubuntu, Debian, Fedora 같은 배포판은 커널 위에 기본 도구, 패키지 저장소, 설정 방식을 묶어 제공합니다.", + x: 720, + y: 330, + }, + { + id: "linux-terminal", + parent: "linux-basics", + type: "term", + title: "터미널", + subtitle: "기초 개념", + image: "imgs/linux_shell.svg", + category: "기초 개념", + focus: "터미널은 셸을 통해 명령을 입력하고 결과를 확인하는 창입니다.", + x: 1020, + y: 240, + }, + { + id: "linux-man-pages", + parent: "linux-basics", + type: "term", + title: "man · --help", + subtitle: "기초 개념", + image: "imgs/linux_shell.svg", + category: "기초 개념", + focus: "명령어가 헷갈릴 때는 man, --help, tldr 같은 도움말로 옵션과 사용 예를 먼저 확인합니다.", + x: 1320, + y: 330, + }, + { + id: "linux-sudo-basics", + parent: "linux-basics", + type: "term", + title: "관리자 작업", + subtitle: "기초 개념", + image: "imgs/linux_permissions.svg", + category: "기초 개념", + focus: "시스템 설정, 패키지 설치, 서비스 제어처럼 영향 범위가 큰 작업은 관리자 권한이 필요합니다.", + x: 1290, + y: 150, + }, + { + id: "linux-command-shape", + parent: "linux-shell", + type: "term", + title: "명령어 구조", + subtitle: "셸 명령어", + image: "imgs/linux_shell.svg", + category: "셸 명령어", + focus: "대부분의 명령은 command --option argument 형태이며, 옵션은 동작 방식을 바꾸고 인자는 대상을 지정합니다.", + x: 1530, + y: 380, + }, + { + id: "linux-pwd-ls-cd", + parent: "linux-shell", + type: "term", + title: "pwd · ls · cd", + subtitle: "셸 명령어", + image: "imgs/linux_shell.svg", + category: "셸 명령어", + focus: "pwd로 현재 위치를 보고, ls로 목록을 확인하고, cd로 디렉터리를 이동합니다.", + x: 1640, + y: 560, + }, + { + id: "linux-file-ops", + parent: "linux-shell", + type: "term", + title: "cp · mv · rm", + subtitle: "셸 명령어", + image: "imgs/linux_shell.svg", + category: "셸 명령어", + focus: "cp는 복사, mv는 이동/이름 변경, rm은 삭제입니다. 삭제 명령은 되돌리기 어렵기 때문에 대상 경로를 먼저 확인합니다.", + x: 1720, + y: 410, + }, + { + id: "linux-pipes", + parent: "linux-shell", + type: "term", + title: "파이프 · 리다이렉트", + subtitle: "셸 명령어", + image: "imgs/linux_shell.svg", + category: "셸 명령어", + focus: "파이프(|)는 한 명령의 출력을 다음 명령으로 넘기고, > 또는 >>는 출력을 파일에 저장합니다.", + x: 1530, + y: 740, + }, + { + id: "linux-grep-find", + parent: "linux-shell", + type: "term", + title: "grep · find", + subtitle: "셸 명령어", + image: "imgs/linux_shell.svg", + category: "셸 명령어", + focus: "grep은 텍스트 안에서 패턴을 찾고, find는 파일 시스템에서 조건에 맞는 파일과 디렉터리를 찾습니다.", + x: 1740, + y: 760, + }, + { + id: "linux-history", + parent: "linux-shell", + type: "term", + title: "history", + subtitle: "셸 명령어", + image: "imgs/linux_shell.svg", + category: "셸 명령어", + focus: "history와 방향키, Ctrl+R 검색을 쓰면 이전 명령을 빠르게 재사용할 수 있습니다.", + x: 1780, + y: 620, + }, + { + id: "linux-env-path", + parent: "linux-shell", + type: "term", + title: "환경 변수 · PATH", + subtitle: "셸 명령어", + image: "imgs/linux_shell.svg", + category: "셸 명령어", + focus: "환경 변수는 현재 셸과 프로그램에 전달되는 설정이고, PATH는 명령어 실행 파일을 찾는 디렉터리 목록입니다.", + x: 1470, + y: 240, + }, + { + id: "linux-root-path", + parent: "linux-filesystem", + type: "term", + title: "루트 경로 /", + subtitle: "파일 시스템", + image: "imgs/linux_filesystem.svg", + category: "파일 시스템", + focus: "리눅스의 모든 절대 경로는 루트(/)에서 시작합니다.", + x: 1510, + y: 810, + }, + { + id: "linux-home-etc-var", + parent: "linux-filesystem", + type: "term", + title: "/home · /etc · /var", + subtitle: "파일 시스템", + image: "imgs/linux_filesystem.svg", + category: "파일 시스템", + focus: "/home은 사용자 파일, /etc는 시스템 설정, /var는 로그와 변하는 데이터를 주로 담습니다.", + x: 1600, + y: 940, + }, + { + id: "linux-hidden-files", + parent: "linux-filesystem", + type: "term", + title: "숨김 파일", + subtitle: "파일 시스템", + image: "imgs/linux_filesystem.svg", + category: "파일 시스템", + focus: ".bashrc처럼 점(.)으로 시작하는 파일은 기본 목록에서 숨겨지며, 보통 사용자 설정을 담습니다.", + x: 1460, + y: 1080, + }, + { + id: "linux-mounts", + parent: "linux-filesystem", + type: "term", + title: "mount", + subtitle: "파일 시스템", + image: "imgs/linux_filesystem.svg", + category: "파일 시스템", + focus: "디스크, USB, 네트워크 저장소는 특정 디렉터리에 마운트되어 파일 시스템 일부처럼 보입니다.", + x: 1190, + y: 1160, + }, + { + id: "linux-links", + parent: "linux-filesystem", + type: "term", + title: "심볼릭 링크", + subtitle: "파일 시스템", + image: "imgs/linux_filesystem.svg", + category: "파일 시스템", + focus: "심볼릭 링크는 다른 파일이나 디렉터리를 가리키는 바로가기이며 ln -s로 만듭니다.", + x: 1740, + y: 1040, + }, + { + id: "linux-users-groups", + parent: "linux-permissions", + type: "term", + title: "사용자 · 그룹", + subtitle: "권한", + image: "imgs/linux_permissions.svg", + category: "권한", + focus: "리눅스는 사용자와 그룹 단위로 파일 접근, 서비스 실행, 관리자 작업 가능 여부를 나눕니다.", + x: 760, + y: 1010, + }, + { + id: "linux-rwx", + parent: "linux-permissions", + type: "term", + title: "rwx 권한", + subtitle: "권한", + image: "imgs/linux_permissions.svg", + category: "권한", + focus: "r은 읽기, w는 쓰기, x는 실행 권한입니다. 디렉터리의 x는 내부로 들어갈 수 있는 권한에 가깝습니다.", + x: 880, + y: 1280, + }, + { + id: "linux-chmod-chown", + parent: "linux-permissions", + type: "term", + title: "chmod · chown", + subtitle: "권한", + image: "imgs/linux_permissions.svg", + category: "권한", + focus: "chmod는 권한 비트를 바꾸고, chown은 파일의 소유자나 그룹을 바꿉니다.", + x: 1180, + y: 1300, + }, + { + id: "linux-sudo", + parent: "linux-permissions", + type: "term", + title: "sudo", + subtitle: "권한", + image: "imgs/linux_permissions.svg", + category: "권한", + focus: "sudo는 허용된 사용자가 한 명령을 관리자 권한으로 실행하게 해 줍니다.", + x: 810, + y: 1500, + }, + { + id: "linux-ssh-keys", + parent: "linux-permissions", + type: "term", + title: "SSH Key 권한", + subtitle: "권한", + image: "imgs/linux_permissions.svg", + category: "권한", + focus: "개인 키는 너무 열려 있으면 SSH가 거부할 수 있으므로 보통 chmod 600처럼 제한적으로 둡니다.", + x: 1420, + y: 1210, + }, + { + id: "linux-ps-top", + parent: "linux-processes", + type: "term", + title: "ps · top", + subtitle: "프로세스", + image: "imgs/linux_processes.svg", + category: "프로세스", + focus: "ps는 프로세스 목록을 출력하고, top/htop은 CPU와 메모리 사용량을 실시간으로 보여 줍니다.", + x: 390, + y: 820, + }, + { + id: "linux-kill", + parent: "linux-processes", + type: "term", + title: "kill", + subtitle: "프로세스", + image: "imgs/linux_processes.svg", + category: "프로세스", + focus: "kill은 프로세스에 종료 신호를 보내며, 강제 종료 전에 정상 종료 신호를 먼저 고려합니다.", + x: 420, + y: 1080, + }, + { + id: "linux-systemd", + parent: "linux-processes", + type: "term", + title: "systemd · service", + subtitle: "프로세스", + image: "imgs/linux_processes.svg", + category: "프로세스", + focus: "systemctl로 서비스를 시작, 중지, 재시작, 자동 실행 설정할 수 있습니다.", + x: 260, + y: 940, + }, + { + id: "linux-logs", + parent: "linux-processes", + type: "term", + title: "로그", + subtitle: "프로세스", + image: "imgs/linux_processes.svg", + category: "프로세스", + focus: "journalctl과 /var/log는 서비스 오류와 시스템 이벤트를 추적하는 첫 번째 단서입니다.", + x: 200, + y: 1190, + }, + { + id: "linux-cron", + parent: "linux-processes", + type: "term", + title: "cron", + subtitle: "프로세스", + image: "imgs/linux_processes.svg", + category: "프로세스", + focus: "cron은 정해진 시간에 백업, 정리, 점검 스크립트를 반복 실행할 때 사용합니다.", + x: 610, + y: 1190, + }, + { + id: "linux-apt-dnf", + parent: "linux-packages-network", + type: "term", + title: "apt · dnf", + subtitle: "패키지·네트워크", + image: "imgs/linux_network_packages.svg", + category: "패키지·네트워크", + focus: "apt는 Debian/Ubuntu 계열, dnf는 Fedora/RHEL 계열에서 패키지를 설치하고 제거하는 대표 도구입니다.", + x: 560, + y: 310, + }, + { + id: "linux-update-upgrade", + parent: "linux-packages-network", + type: "term", + title: "update · upgrade", + subtitle: "패키지·네트워크", + image: "imgs/linux_network_packages.svg", + category: "패키지·네트워크", + focus: "update는 패키지 목록을 새로 받고, upgrade는 설치된 패키지를 새 버전으로 올립니다.", + x: 390, + y: 470, + }, + { + id: "linux-ping-ss", + parent: "linux-packages-network", + type: "term", + title: "ping · ss", + subtitle: "패키지·네트워크", + image: "imgs/linux_network_packages.svg", + category: "패키지·네트워크", + focus: "ping은 연결 가능성을 확인하고, ss는 열린 포트와 소켓 상태를 확인합니다.", + x: 780, + y: 420, + }, + { + id: "linux-curl-wget", + parent: "linux-packages-network", + type: "term", + title: "curl · wget", + subtitle: "패키지·네트워크", + image: "imgs/linux_network_packages.svg", + category: "패키지·네트워크", + focus: "curl은 HTTP 요청과 응답 확인에 강하고, wget은 파일 다운로드에 자주 쓰입니다.", + x: 350, + y: 650, + }, + { + id: "linux-ssh", + parent: "linux-packages-network", + type: "term", + title: "ssh", + subtitle: "패키지·네트워크", + image: "imgs/linux_network_packages.svg", + category: "패키지·네트워크", + focus: "ssh는 원격 서버의 셸에 안전하게 접속하는 기본 도구입니다.", + x: 780, + y: 660, + }, + { + id: "linux-firewall", + parent: "linux-packages-network", + type: "term", + title: "방화벽", + subtitle: "패키지·네트워크", + image: "imgs/linux_network_packages.svg", + category: "패키지·네트워크", + focus: "ufw, firewalld, iptables 같은 도구로 외부에서 접근 가능한 포트와 규칙을 제한합니다.", + x: 480, + y: 210, + }, +]; + +const maps = { + web: { + eyebrow: "Web Learning Map", + title: "웹 개발 용어 마인드맵", + ariaLabel: "접을 수 있는 웹 개발 용어 지도", + nodes: webNodes, + }, + linux: { + eyebrow: "Linux Learning Map", + title: "리눅스 기초 마인드맵", + ariaLabel: "접을 수 있는 리눅스 기초 개념 지도", + nodes: linuxNodes, + }, +}; + const viewport = document.querySelector("#viewport"); const world = document.querySelector("#world"); const nodeLayer = document.querySelector("#nodeLayer"); const connectorLayer = document.querySelector("#connectorLayer"); const visibleCount = document.querySelector("#visibleCount"); +const pageTitle = document.querySelector("#page-title"); +const mapEyebrow = document.querySelector("#mapEyebrow"); const lightbox = document.querySelector("#lightbox"); const lightboxImage = document.querySelector("#lightboxImage"); const lightboxCaption = document.querySelector("#lightboxCaption"); @@ -502,7 +1008,9 @@ const zoomOutButton = document.querySelector("#zoomOut"); const zoomResetButton = document.querySelector("#zoomReset"); const fullscreenToggle = document.querySelector("#fullscreenToggle"); -const nodeMap = new Map(nodes.map((node) => [node.id, node])); +let activeMapId = "web"; +let nodes = maps[activeMapId].nodes; +let nodeMap = new Map(nodes.map((node) => [node.id, node])); const expanded = new Set(); let pan = { x: window.innerWidth / 2 - 1136, y: window.innerHeight / 2 - 764 }; let activePointer = null; @@ -526,6 +1034,29 @@ function setWorldTransform() { world.style.transform = `translate(${pan.x}px, ${pan.y}px)`; } +function syncMapChrome() { + const activeMap = maps[activeMapId]; + pageTitle.textContent = activeMap.title; + mapEyebrow.textContent = activeMap.eyebrow; + nodeLayer.setAttribute("aria-label", activeMap.ariaLabel); + for (const button of document.querySelectorAll(".map-tab")) { + const isSelected = button.dataset.map === activeMapId; + button.classList.toggle("is-selected", isSelected); + button.setAttribute("aria-pressed", String(isSelected)); + } +} + +function switchMap(mapId) { + if (!maps[mapId] || mapId === activeMapId) return; + activeMapId = mapId; + nodes = maps[activeMapId].nodes; + nodeMap = new Map(nodes.map((node) => [node.id, node])); + expanded.clear(); + syncMapChrome(); + resetView(); + render(); +} + function render() { const visible = new Set(visibleNodeIds()); nodeLayer.innerHTML = ""; @@ -820,6 +1351,9 @@ window.addEventListener("pointerup", onPointerUp); window.addEventListener("pointercancel", onPointerUp); document.querySelector("#resetView").addEventListener("click", resetView); document.querySelector("#foldAll").addEventListener("click", foldAll); +for (const button of document.querySelectorAll(".map-tab")) { + button.addEventListener("click", () => switchMap(button.dataset.map)); +} document.querySelector(".lightbox-backdrop").addEventListener("click", closeLightbox); document.querySelector("#closeLightbox").addEventListener("click", closeLightbox); zoomInButton.addEventListener("click", () => setZoom(zoomState.scale + 0.25)); @@ -843,4 +1377,5 @@ document.addEventListener("keydown", (event) => { window.addEventListener("resize", resetView); setWorldTransform(); +syncMapChrome(); render(); diff --git a/styles.css b/styles.css index c2e3e5b..fed607b 100644 --- a/styles.css +++ b/styles.css @@ -85,17 +85,24 @@ h1 { .hud-actions { display: flex; + align-items: flex-start; + flex-wrap: wrap; + justify-content: flex-end; gap: 8px; padding-top: 8px; } -.hud-actions button { +.hud-actions button, +.map-switcher { border: 1px solid rgba(191, 208, 232, 0.92); border-radius: 8px; - padding: 10px 13px; background: rgba(255, 255, 255, 0.9); color: var(--text); box-shadow: 0 12px 28px rgba(18, 32, 51, 0.1); +} + +.hud-actions button { + padding: 10px 13px; cursor: pointer; } @@ -103,6 +110,23 @@ h1 { border-color: var(--accent); } +.map-switcher { + display: flex; + gap: 2px; + padding: 3px; +} + +.map-switcher .map-tab { + border: 0; + box-shadow: none; + background: transparent; +} + +.map-switcher .map-tab.is-selected { + background: var(--accent-deep); + color: #fff; +} + .canvas-help { position: fixed; left: 18px;