8076 lines
259 KiB
HTML
8076 lines
259 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0OCIgaGVpZ2h0PSI0NiIgZmlsbD0ibm9uZSIgdmlld0JveD0iMCAwIDQ4IDQ2Ij48cGF0aCBmaWxsPSIjODYzYmZmIiBkPSJNMjUuOTQ2IDQ0LjkzOGMtLjY2NC44NDUtMi4wMjEuMzc1LTIuMDIxLS42OThWMzMuOTM3YTIuMjYgMi4yNiAwIDAgMC0yLjI2Mi0yLjI2MkgxMC4yODdjLS45MiAwLTEuNDU2LTEuMDQtLjkyLTEuNzg4bDcuNDgtMTAuNDcxYzEuMDctMS40OTcgMC0zLjU3OC0xLjg0Mi0zLjU3OEgxLjIzN2MtLjkyIDAtMS40NTYtMS4wNC0uOTItMS43ODhMMTAuMDEzLjQ3NGMuMjE0LS4yOTcuNTU2LS40NzQuOTItLjQ3NGgyOC44OTRjLjkyIDAgMS40NTYgMS4wNC45MiAxLjc4OGwtNy40OCAxMC40NzFjLTEuMDcgMS40OTggMCAzLjU3OSAxLjg0MiAzLjU3OWgxMS4zNzdjLjk0MyAwIDEuNDczIDEuMDg4Ljg5IDEuODNMMjUuOTQ3IDQ0Ljk0eiIgc3R5bGU9ImZpbGw6Izg2M2JmZjtmaWxsOmNvbG9yKGRpc3BsYXktcDMgLjUyNTIgLjIzIDEpO2ZpbGwtb3BhY2l0eToxIi8+PG1hc2sgaWQ9ImEiIHdpZHRoPSI0OCIgaGVpZ2h0PSI0NiIgeD0iMCIgeT0iMCIgbWFza1VuaXRzPSJ1c2VyU3BhY2VPblVzZSIgc3R5bGU9Im1hc2stdHlwZTphbHBoYSI+PHBhdGggZmlsbD0iIzAwMCIgZD0iTTI1Ljg0MiA0NC45MzhjLS42NjQuODQ0LTIuMDIxLjM3NS0yLjAyMS0uNjk4VjMzLjkzN2EyLjI2IDIuMjYgMCAwIDAtMi4yNjItMi4yNjJIMTAuMTgzYy0uOTIgMC0xLjQ1Ni0xLjA0LS45Mi0xLjc4OGw3LjQ4LTEwLjQ3MWMxLjA3LTEuNDk4IDAtMy41NzktMS44NDItMy41NzlIMS4xMzNjLS45MiAwLTEuNDU2LTEuMDQtLjkyLTEuNzg3TDkuOTEuNDczYy4yMTQtLjI5Ny41NTYtLjQ3NC45Mi0uNDc0aDI4Ljg5NGMuOTIgMCAxLjQ1NiAxLjA0LjkyIDEuNzg4bC03LjQ4IDEwLjQ3MWMtMS4wNyAxLjQ5OCAwIDMuNTc4IDEuODQyIDMuNTc4aDExLjM3N2MuOTQzIDAgMS40NzMgMS4wODguODkgMS44MzJMMjUuODQzIDQ0Ljk0eiIgc3R5bGU9ImZpbGw6IzAwMDtmaWxsLW9wYWNpdHk6MSIvPjwvbWFzaz48ZyBtYXNrPSJ1cmwoI2EpIj48ZyBmaWx0ZXI9InVybCgjYikiPjxlbGxpcHNlIGN4PSI1LjUwOCIgY3k9IjE0LjcwNCIgZmlsbD0iI2VkZTZmZiIgcng9IjUuNTA4IiByeT0iMTQuNzA0IiBzdHlsZT0iZmlsbDojZWRlNmZmO2ZpbGw6Y29sb3IoZGlzcGxheS1wMyAuOTI3NSAuOTAzMyAxKTtmaWxsLW9wYWNpdHk6MSIgdHJhbnNmb3JtPSJtYXRyaXgoLjAwMzI0IDEgMSAtLjAwMzI0IC00LjQ3IDMxLjUxNikiLz48L2c+PGcgZmlsdGVyPSJ1cmwoI2MpIj48ZWxsaXBzZSBjeD0iMTAuMzk5IiBjeT0iMjkuODUxIiBmaWxsPSIjZWRlNmZmIiByeD0iMTAuMzk5IiByeT0iMjkuODUxIiBzdHlsZT0iZmlsbDojZWRlNmZmO2ZpbGw6Y29sb3IoZGlzcGxheS1wMyAuOTI3NSAuOTAzMyAxKTtmaWxsLW9wYWNpdHk6MSIgdHJhbnNmb3JtPSJtYXRyaXgoLjAwMzI0IDEgMSAtLjAwMzI0IC0zOS4zMjggNy44ODMpIi8+PC9nPjxnIGZpbHRlcj0idXJsKCNkKSI+PGVsbGlwc2UgY3g9IjUuNTA4IiBjeT0iMzAuNDg3IiBmaWxsPSIjN2UxNGZmIiByeD0iNS41MDgiIHJ5PSIzMC40ODciIHN0eWxlPSJmaWxsOiM3ZTE0ZmY7ZmlsbDpjb2xvcihkaXNwbGF5LXAzIC40OTIyIC4wNzY3IDEpO2ZpbGwtb3BhY2l0eToxIiB0cmFuc2Zvcm09InJvdGF0ZSg4OS44MTQgLTI1LjkxMyAtMTQuNjM5KXNjYWxlKDEgLTEpIi8+PC9nPjxnIGZpbHRlcj0idXJsKCNlKSI+PGVsbGlwc2UgY3g9IjUuNTA4IiBjeT0iMzAuNTk5IiBmaWxsPSIjN2UxNGZmIiByeD0iNS41MDgiIHJ5PSIzMC41OTkiIHN0eWxlPSJmaWxsOiM3ZTE0ZmY7ZmlsbDpjb2xvcihkaXNwbGF5LXAzIC40OTIyIC4wNzY3IDEpO2ZpbGwtb3BhY2l0eToxIiB0cmFuc2Zvcm09InJvdGF0ZSg4OS44MTQgLTMyLjY0NCAtMy4zMzQpc2NhbGUoMSAtMSkiLz48L2c+PGcgZmlsdGVyPSJ1cmwoI2YpIj48ZWxsaXBzZSBjeD0iNS41MDgiIGN5PSIzMC41OTkiIGZpbGw9IiM3ZTE0ZmYiIHJ4PSI1LjUwOCIgcnk9IjMwLjU5OSIgc3R5bGU9ImZpbGw6IzdlMTRmZjtmaWxsOmNvbG9yKGRpc3BsYXktcDMgLjQ5MjIgLjA3NjcgMSk7ZmlsbC1vcGFjaXR5OjEiIHRyYW5zZm9ybT0ibWF0cml4KC4wMDMyNCAxIDEgLS4wMDMyNCAtMzQuMzQgMzAuNDcpIi8+PC9nPjxnIGZpbHRlcj0idXJsKCNnKSI+PGVsbGlwc2UgY3g9IjE0LjA3MiIgY3k9IjIyLjA3OCIgZmlsbD0iI2VkZTZmZiIgcng9IjE0LjA3MiIgcnk9IjIyLjA3OCIgc3R5bGU9ImZpbGw6I2VkZTZmZjtmaWxsOmNvbG9yKGRpc3BsYXktcDMgLjkyNzUgLjkwMzMgMSk7ZmlsbC1vcGFjaXR5OjEiIHRyYW5zZm9ybT0icm90YXRlKDkzLjM1IDI0LjUwNiA0OC40OTMpc2NhbGUoLTEgMSkiLz48L2c+PGcgZmlsdGVyPSJ1cmwoI2gpIj48ZWxsaXBzZSBjeD0iMy40NyIgY3k9IjIxLjUwMSIgZmlsbD0iIzdlMTRmZiIgcng9IjMuNDciIHJ5PSIyMS41MDEiIHN0eWxlPSJmaWxsOiM3ZTE0ZmY7ZmlsbDpjb2xvcihkaXNwbGF5LXAzIC40OTIyIC4wNzY3IDEpO2ZpbGwtb3BhY2l0eToxIiB0cmFuc2Zvcm09InJvdGF0ZSg4OS4wMDkgMjguNzA4IDQ3LjU5KXNjYWxlKC0xIDEpIi8+PC9nPjxnIGZpbHRlcj0idXJsKCNpKSI+PGVsbGlwc2UgY3g9IjMuNDciIGN5PSIyMS41MDEiIGZpbGw9IiM3ZTE0ZmYiIHJ4PSIzLjQ3IiByeT0iMjEuNTAxIiBzdHlsZT0iZmlsbDojN2UxNGZmO2ZpbGw6Y29sb3IoZGlzcGxheS1wMyAuNDkyMiAuMDc2NyAxKTtmaWxsLW9wYWNpdHk6MSIgdHJhbnNmb3JtPSJyb3RhdGUoODkuMDA5IDI4LjcwOCA0Ny41OSlzY2FsZSgtMSAxKSIvPjwvZz48ZyBmaWx0ZXI9InVybCgjaikiPjxlbGxpcHNlIGN4PSIuMzg3IiBjeT0iOC45NzIiIGZpbGw9IiM3ZTE0ZmYiIHJ4PSI0LjQwNyIgcnk9IjI5LjEwOCIgc3R5bGU9ImZpbGw6IzdlMTRmZjtmaWxsOmNvbG9yKGRpc3BsYXktcDMgLjQ5MjIgLjA3NjcgMSk7ZmlsbC1vcGFjaXR5OjEiIHRyYW5zZm9ybT0icm90YXRlKDM5LjUxIC4zODcgOC45NzIpIi8+PC9nPjxnIGZpbHRlcj0idXJsKCNrKSI+PGVsbGlwc2UgY3g9IjQ3LjUyMyIgY3k9Ii02LjA5MiIgZmlsbD0iIzdlMTRmZiIgcng9IjQuNDA3IiByeT0iMjkuMTA4IiBzdHlsZT0iZmlsbDojN2UxNGZmO2ZpbGw6Y29sb3IoZGlzcGxheS1wMyAuNDkyMiAuMDc2NyAxKTtmaWxsLW9wYWNpdHk6MSIgdHJhbnNmb3JtPSJyb3RhdGUoMzcuODkyIDQ3LjUyMyAtNi4wOTIpIi8+PC9nPjxnIGZpbHRlcj0idXJsKCNsKSI+PGVsbGlwc2UgY3g9IjQxLjQxMiIgY3k9IjYuMzMzIiBmaWxsPSIjNDdiZmZmIiByeD0iNS45NzEiIHJ5PSI5LjY2NSIgc3R5bGU9ImZpbGw6IzQ3YmZmZjtmaWxsOmNvbG9yKGRpc3BsYXktcDMgLjI3OTkgLjc0OCAxKTtmaWxsLW9wYWNpdHk6MSIgdHJhbnNmb3JtPSJyb3RhdGUoMzcuODkyIDQxLjQxMiA2LjMzMykiLz48L2c+PGcgZmlsdGVyPSJ1cmwoI20pIj48ZWxsaXBzZSBjeD0iLTEuODc5IiBjeT0iMzguMzMyIiBmaWxsPSIjN2UxNGZmIiByeD0iNC40MDciIHJ5PSIyOS4xMDgiIHN0eWxlPSJmaWxsOiM3ZTE0ZmY7ZmlsbDpjb2xvcihkaXNwbGF5LXAzIC40OTIyIC4wNzY3IDEpO2ZpbGwtb3BhY2l0eToxIiB0cmFuc2Zvcm09InJvdGF0ZSgzNy44OTIgLTEuODggMzguMzMyKSIvPjwvZz48ZyBmaWx0ZXI9InVybCgjbikiPjxlbGxpcHNlIGN4PSItMS44NzkiIGN5PSIzOC4zMzIiIGZpbGw9IiM3ZTE0ZmYiIHJ4PSI0LjQwNyIgcnk9IjI5LjEwOCIgc3R5bGU9ImZpbGw6IzdlMTRmZjtmaWxsOmNvbG9yKGRpc3BsYXktcDMgLjQ5MjIgLjA3NjcgMSk7ZmlsbC1vcGFjaXR5OjEiIHRyYW5zZm9ybT0icm90YXRlKDM3Ljg5MiAtMS44OCAzOC4zMzIpIi8+PC9nPjxnIGZpbHRlcj0idXJsKCNvKSI+PGVsbGlwc2UgY3g9IjM1LjY1MSIgY3k9IjI5LjkwNyIgZmlsbD0iIzdlMTRmZiIgcng9IjQuNDA3IiByeT0iMjkuMTA4IiBzdHlsZT0iZmlsbDojN2UxNGZmO2ZpbGw6Y29sb3IoZGlzcGxheS1wMyAuNDkyMiAuMDc2NyAxKTtmaWxsLW9wYWNpdHk6MSIgdHJhbnNmb3JtPSJyb3RhdGUoMzcuODkyIDM1LjY1MSAyOS45MDcpIi8+PC9nPjxnIGZpbHRlcj0idXJsKCNwKSI+PGVsbGlwc2UgY3g9IjM4LjQxOCIgY3k9IjMyLjQiIGZpbGw9IiM0N2JmZmYiIHJ4PSI1Ljk3MSIgcnk9IjE1LjI5NyIgc3R5bGU9ImZpbGw6IzQ3YmZmZjtmaWxsOmNvbG9yKGRpc3BsYXktcDMgLjI3OTkgLjc0OCAxKTtmaWxsLW9wYWNpdHk6MSIgdHJhbnNmb3JtPSJyb3RhdGUoMzcuODkyIDM4LjQxOCAzMi40KSIvPjwvZz48L2c+PGRlZnM+PGZpbHRlciBpZD0iYiIgd2lkdGg9IjYwLjA0NSIgaGVpZ2h0PSI0MS42NTQiIHg9Ii0xOS43NyIgeT0iMTYuMTQ5IiBjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM9InNSR0IiIGZpbHRlclVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PGZlRmxvb2QgZmxvb2Qtb3BhY2l0eT0iMCIgcmVzdWx0PSJCYWNrZ3JvdW5kSW1hZ2VGaXgiLz48ZmVCbGVuZCBpbj0iU291cmNlR3JhcGhpYyIgaW4yPSJCYWNrZ3JvdW5kSW1hZ2VGaXgiIHJlc3VsdD0ic2hhcGUiLz48ZmVHYXVzc2lhbkJsdXIgcmVzdWx0PSJlZmZlY3QxX2ZvcmVncm91bmRCbHVyXzIwMDJfMTcxNTgiIHN0ZERldmlhdGlvbj0iNy42NTkiLz48L2ZpbHRlcj48ZmlsdGVyIGlkPSJjIiB3aWR0aD0iOTAuMzQiIGhlaWdodD0iNTEuNDM3IiB4PSItNTQuNjEzIiB5PSItNy41MzMiIGNvbG9yLWludGVycG9sYXRpb24tZmlsdGVycz0ic1JHQiIgZmlsdGVyVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48ZmVGbG9vZCBmbG9vZC1vcGFjaXR5PSIwIiByZXN1bHQ9IkJhY2tncm91bmRJbWFnZUZpeCIvPjxmZUJsZW5kIGluPSJTb3VyY2VHcmFwaGljIiBpbjI9IkJhY2tncm91bmRJbWFnZUZpeCIgcmVzdWx0PSJzaGFwZSIvPjxmZUdhdXNzaWFuQmx1ciByZXN1bHQ9ImVmZmVjdDFfZm9yZWdyb3VuZEJsdXJfMjAwMl8xNzE1OCIgc3RkRGV2aWF0aW9uPSI3LjY1OSIvPjwvZmlsdGVyPjxmaWx0ZXIgaWQ9ImQiIHdpZHRoPSI3OS4zNTUiIGhlaWdodD0iMjkuNCIgeD0iLTQ5LjY0IiB5PSIyLjAzIiBjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM9InNSR0IiIGZpbHRlclVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PGZlRmxvb2QgZmxvb2Qtb3BhY2l0eT0iMCIgcmVzdWx0PSJCYWNrZ3JvdW5kSW1hZ2VGaXgiLz48ZmVCbGVuZCBpbj0iU291cmNlR3JhcGhpYyIgaW4yPSJCYWNrZ3JvdW5kSW1hZ2VGaXgiIHJlc3VsdD0ic2hhcGUiLz48ZmVHYXVzc2lhbkJsdXIgcmVzdWx0PSJlZmZlY3QxX2ZvcmVncm91bmRCbHVyXzIwMDJfMTcxNTgiIHN0ZERldmlhdGlvbj0iNC41OTYiLz48L2ZpbHRlcj48ZmlsdGVyIGlkPSJlIiB3aWR0aD0iNzkuNTc5IiBoZWlnaHQ9IjI5LjQiIHg9Ii00NS4wNDUiIHk9IjIwLjAyOSIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIiBmaWx0ZXJVbml0cz0idXNlclNwYWNlT25Vc2UiPjxmZUZsb29kIGZsb29kLW9wYWNpdHk9IjAiIHJlc3VsdD0iQmFja2dyb3VuZEltYWdlRml4Ii8+PGZlQmxlbmQgaW49IlNvdXJjZUdyYXBoaWMiIGluMj0iQmFja2dyb3VuZEltYWdlRml4IiByZXN1bHQ9InNoYXBlIi8+PGZlR2F1c3NpYW5CbHVyIHJlc3VsdD0iZWZmZWN0MV9mb3JlZ3JvdW5kQmx1cl8yMDAyXzE3MTU4IiBzdGREZXZpYXRpb249IjQuNTk2Ii8+PC9maWx0ZXI+PGZpbHRlciBpZD0iZiIgd2lkdGg9Ijc5LjU3OSIgaGVpZ2h0PSIyOS40IiB4PSItNDMuNTEzIiB5PSIyMS4xNzgiIGNvbG9yLWludGVycG9sYXRpb24tZmlsdGVycz0ic1JHQiIgZmlsdGVyVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48ZmVGbG9vZCBmbG9vZC1vcGFjaXR5PSIwIiByZXN1bHQ9IkJhY2tncm91bmRJbWFnZUZpeCIvPjxmZUJsZW5kIGluPSJTb3VyY2VHcmFwaGljIiBpbjI9IkJhY2tncm91bmRJbWFnZUZpeCIgcmVzdWx0PSJzaGFwZSIvPjxmZUdhdXNzaWFuQmx1ciByZXN1bHQ9ImVmZmVjdDFfZm9yZWdyb3VuZEJsdXJfMjAwMl8xNzE1OCIgc3RkRGV2aWF0aW9uPSI0LjU5NiIvPjwvZmlsdGVyPjxmaWx0ZXIgaWQ9ImciIHdpZHRoPSI3NC43NDkiIGhlaWdodD0iNTguODUyIiB4PSIxNS43NTYiIHk9Ii0xNy45MDEiIGNvbG9yLWludGVycG9sYXRpb24tZmlsdGVycz0ic1JHQiIgZmlsdGVyVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48ZmVGbG9vZCBmbG9vZC1vcGFjaXR5PSIwIiByZXN1bHQ9IkJhY2tncm91bmRJbWFnZUZpeCIvPjxmZUJsZW5kIGluPSJTb3VyY2VHcmFwaGljIiBpbjI9IkJhY2tncm91bmRJbWFnZUZpeCIgcmVzdWx0PSJzaGFwZSIvPjxmZUdhdXNzaWFuQmx1ciByZXN1bHQ9ImVmZmVjdDFfZm9yZWdyb3VuZEJsdXJfMjAwMl8xNzE1OCIgc3RkRGV2aWF0aW9uPSI3LjY1OSIvPjwvZmlsdGVyPjxmaWx0ZXIgaWQ9ImgiIHdpZHRoPSI2MS4zNzciIGhlaWdodD0iMjUuMzYyIiB4PSIyMy41NDgiIHk9IjIuMjg0IiBjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM9InNSR0IiIGZpbHRlclVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PGZlRmxvb2QgZmxvb2Qtb3BhY2l0eT0iMCIgcmVzdWx0PSJCYWNrZ3JvdW5kSW1hZ2VGaXgiLz48ZmVCbGVuZCBpbj0iU291cmNlR3JhcGhpYyIgaW4yPSJCYWNrZ3JvdW5kSW1hZ2VGaXgiIHJlc3VsdD0ic2hhcGUiLz48ZmVHYXVzc2lhbkJsdXIgcmVzdWx0PSJlZmZlY3QxX2ZvcmVncm91bmRCbHVyXzIwMDJfMTcxNTgiIHN0ZERldmlhdGlvbj0iNC41OTYiLz48L2ZpbHRlcj48ZmlsdGVyIGlkPSJpIiB3aWR0aD0iNjEuMzc3IiBoZWlnaHQ9IjI1LjM2MiIgeD0iMjMuNTQ4IiB5PSIyLjI4NCIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIiBmaWx0ZXJVbml0cz0idXNlclNwYWNlT25Vc2UiPjxmZUZsb29kIGZsb29kLW9wYWNpdHk9IjAiIHJlc3VsdD0iQmFja2dyb3VuZEltYWdlRml4Ii8+PGZlQmxlbmQgaW49IlNvdXJjZUdyYXBoaWMiIGluMj0iQmFja2dyb3VuZEltYWdlRml4IiByZXN1bHQ9InNoYXBlIi8+PGZlR2F1c3NpYW5CbHVyIHJlc3VsdD0iZWZmZWN0MV9mb3JlZ3JvdW5kQmx1cl8yMDAyXzE3MTU4IiBzdGREZXZpYXRpb249IjQuNTk2Ii8+PC9maWx0ZXI+PGZpbHRlciBpZD0iaiIgd2lkdGg9IjU2LjA0NSIgaGVpZ2h0PSI2My42NDkiIHg9Ii0yNy42MzYiIHk9Ii0yMi44NTMiIGNvbG9yLWludGVycG9sYXRpb24tZmlsdGVycz0ic1JHQiIgZmlsdGVyVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48ZmVGbG9vZCBmbG9vZC1vcGFjaXR5PSIwIiByZXN1bHQ9IkJhY2tncm91bmRJbWFnZUZpeCIvPjxmZUJsZW5kIGluPSJTb3VyY2VHcmFwaGljIiBpbjI9IkJhY2tncm91bmRJbWFnZUZpeCIgcmVzdWx0PSJzaGFwZSIvPjxmZUdhdXNzaWFuQmx1ciByZXN1bHQ9ImVmZmVjdDFfZm9yZWdyb3VuZEJsdXJfMjAwMl8xNzE1OCIgc3RkRGV2aWF0aW9uPSI0LjU5NiIvPjwvZmlsdGVyPjxmaWx0ZXIgaWQ9ImsiIHdpZHRoPSI1NC44MTQiIGhlaWdodD0iNjQuNjQ2IiB4PSIyMC4xMTYiIHk9Ii0zOC40MTUiIGNvbG9yLWludGVycG9sYXRpb24tZmlsdGVycz0ic1JHQiIgZmlsdGVyVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48ZmVGbG9vZCBmbG9vZC1vcGFjaXR5PSIwIiByZXN1bHQ9IkJhY2tncm91bmRJbWFnZUZpeCIvPjxmZUJsZW5kIGluPSJTb3VyY2VHcmFwaGljIiBpbjI9IkJhY2tncm91bmRJbWFnZUZpeCIgcmVzdWx0PSJzaGFwZSIvPjxmZUdhdXNzaWFuQmx1ciByZXN1bHQ9ImVmZmVjdDFfZm9yZWdyb3VuZEJsdXJfMjAwMl8xNzE1OCIgc3RkRGV2aWF0aW9uPSI0LjU5NiIvPjwvZmlsdGVyPjxmaWx0ZXIgaWQ9ImwiIHdpZHRoPSIzMy41NDEiIGhlaWdodD0iMzUuMzEzIiB4PSIyNC42NDEiIHk9Ii0xMS4zMjMiIGNvbG9yLWludGVycG9sYXRpb24tZmlsdGVycz0ic1JHQiIgZmlsdGVyVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48ZmVGbG9vZCBmbG9vZC1vcGFjaXR5PSIwIiByZXN1bHQ9IkJhY2tncm91bmRJbWFnZUZpeCIvPjxmZUJsZW5kIGluPSJTb3VyY2VHcmFwaGljIiBpbjI9IkJhY2tncm91bmRJbWFnZUZpeCIgcmVzdWx0PSJzaGFwZSIvPjxmZUdhdXNzaWFuQmx1ciByZXN1bHQ9ImVmZmVjdDFfZm9yZWdyb3VuZEJsdXJfMjAwMl8xNzE1OCIgc3RkRGV2aWF0aW9uPSI0LjU5NiIvPjwvZmlsdGVyPjxmaWx0ZXIgaWQ9Im0iIHdpZHRoPSI1NC44MTQiIGhlaWdodD0iNjQuNjQ2IiB4PSItMjkuMjg2IiB5PSI2LjAwOSIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIiBmaWx0ZXJVbml0cz0idXNlclNwYWNlT25Vc2UiPjxmZUZsb29kIGZsb29kLW9wYWNpdHk9IjAiIHJlc3VsdD0iQmFja2dyb3VuZEltYWdlRml4Ii8+PGZlQmxlbmQgaW49IlNvdXJjZUdyYXBoaWMiIGluMj0iQmFja2dyb3VuZEltYWdlRml4IiByZXN1bHQ9InNoYXBlIi8+PGZlR2F1c3NpYW5CbHVyIHJlc3VsdD0iZWZmZWN0MV9mb3JlZ3JvdW5kQmx1cl8yMDAyXzE3MTU4IiBzdGREZXZpYXRpb249IjQuNTk2Ii8+PC9maWx0ZXI+PGZpbHRlciBpZD0ibiIgd2lkdGg9IjU0LjgxNCIgaGVpZ2h0PSI2NC42NDYiIHg9Ii0yOS4yODYiIHk9IjYuMDA5IiBjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM9InNSR0IiIGZpbHRlclVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PGZlRmxvb2QgZmxvb2Qtb3BhY2l0eT0iMCIgcmVzdWx0PSJCYWNrZ3JvdW5kSW1hZ2VGaXgiLz48ZmVCbGVuZCBpbj0iU291cmNlR3JhcGhpYyIgaW4yPSJCYWNrZ3JvdW5kSW1hZ2VGaXgiIHJlc3VsdD0ic2hhcGUiLz48ZmVHYXVzc2lhbkJsdXIgcmVzdWx0PSJlZmZlY3QxX2ZvcmVncm91bmRCbHVyXzIwMDJfMTcxNTgiIHN0ZERldmlhdGlvbj0iNC41OTYiLz48L2ZpbHRlcj48ZmlsdGVyIGlkPSJvIiB3aWR0aD0iNTQuODE0IiBoZWlnaHQ9IjY0LjY0NiIgeD0iOC4yNDQiIHk9Ii0yLjQxNiIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIiBmaWx0ZXJVbml0cz0idXNlclNwYWNlT25Vc2UiPjxmZUZsb29kIGZsb29kLW9wYWNpdHk9IjAiIHJlc3VsdD0iQmFja2dyb3VuZEltYWdlRml4Ii8+PGZlQmxlbmQgaW49IlNvdXJjZUdyYXBoaWMiIGluMj0iQmFja2dyb3VuZEltYWdlRml4IiByZXN1bHQ9InNoYXBlIi8+PGZlR2F1c3NpYW5CbHVyIHJlc3VsdD0iZWZmZWN0MV9mb3JlZ3JvdW5kQmx1cl8yMDAyXzE3MTU4IiBzdGREZXZpYXRpb249IjQuNTk2Ii8+PC9maWx0ZXI+PGZpbHRlciBpZD0icCIgd2lkdGg9IjM5LjQwOSIgaGVpZ2h0PSI0My42MjMiIHg9IjE4LjcxMyIgeT0iMTAuNTg4IiBjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM9InNSR0IiIGZpbHRlclVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PGZlRmxvb2QgZmxvb2Qtb3BhY2l0eT0iMCIgcmVzdWx0PSJCYWNrZ3JvdW5kSW1hZ2VGaXgiLz48ZmVCbGVuZCBpbj0iU291cmNlR3JhcGhpYyIgaW4yPSJCYWNrZ3JvdW5kSW1hZ2VGaXgiIHJlc3VsdD0ic2hhcGUiLz48ZmVHYXVzc2lhbkJsdXIgcmVzdWx0PSJlZmZlY3QxX2ZvcmVncm91bmRCbHVyXzIwMDJfMTcxNTgiIHN0ZERldmlhdGlvbj0iNC41OTYiLz48L2ZpbHRlcj48L2RlZnM+PC9zdmc+" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<title>Password Vault</title>
|
||
<script type="module" crossorigin>//#region \0vite/modulepreload-polyfill.js
|
||
(function polyfill() {
|
||
const relList = document.createElement("link").relList;
|
||
if (relList && relList.supports && relList.supports("modulepreload")) return;
|
||
for (const link of document.querySelectorAll("link[rel=\"modulepreload\"]")) processPreload(link);
|
||
new MutationObserver((mutations) => {
|
||
for (const mutation of mutations) {
|
||
if (mutation.type !== "childList") continue;
|
||
for (const node of mutation.addedNodes) if (node.tagName === "LINK" && node.rel === "modulepreload") processPreload(node);
|
||
}
|
||
}).observe(document, {
|
||
childList: true,
|
||
subtree: true
|
||
});
|
||
function getFetchOpts(link) {
|
||
const fetchOpts = {};
|
||
if (link.integrity) fetchOpts.integrity = link.integrity;
|
||
if (link.referrerPolicy) fetchOpts.referrerPolicy = link.referrerPolicy;
|
||
if (link.crossOrigin === "use-credentials") fetchOpts.credentials = "include";
|
||
else if (link.crossOrigin === "anonymous") fetchOpts.credentials = "omit";
|
||
else fetchOpts.credentials = "same-origin";
|
||
return fetchOpts;
|
||
}
|
||
function processPreload(link) {
|
||
if (link.ep) return;
|
||
link.ep = true;
|
||
const fetchOpts = getFetchOpts(link);
|
||
fetch(link.href, fetchOpts);
|
||
}
|
||
})();
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/shared/utils.js
|
||
var is_array = Array.isArray;
|
||
var index_of = Array.prototype.indexOf;
|
||
var includes = Array.prototype.includes;
|
||
var array_from = Array.from;
|
||
var define_property = Object.defineProperty;
|
||
var get_descriptor = Object.getOwnPropertyDescriptor;
|
||
var get_descriptors = Object.getOwnPropertyDescriptors;
|
||
var object_prototype = Object.prototype;
|
||
var array_prototype = Array.prototype;
|
||
var get_prototype_of = Object.getPrototypeOf;
|
||
var is_extensible = Object.isExtensible;
|
||
var noop = () => {};
|
||
/** @param {Function} fn */
|
||
function run(fn) {
|
||
return fn();
|
||
}
|
||
/** @param {Array<() => void>} arr */
|
||
function run_all(arr) {
|
||
for (var i = 0; i < arr.length; i++) arr[i]();
|
||
}
|
||
/**
|
||
* TODO replace with Promise.withResolvers once supported widely enough
|
||
* @template [T=void]
|
||
*/
|
||
function deferred() {
|
||
/** @type {(value: T) => void} */
|
||
var resolve;
|
||
/** @type {(reason: any) => void} */
|
||
var reject;
|
||
return {
|
||
promise: new Promise((res, rej) => {
|
||
resolve = res;
|
||
reject = rej;
|
||
}),
|
||
resolve,
|
||
reject
|
||
};
|
||
}
|
||
var CLEAN = 1024;
|
||
var DIRTY = 2048;
|
||
var MAYBE_DIRTY = 4096;
|
||
var INERT = 8192;
|
||
var DESTROYED = 16384;
|
||
/** Set once a reaction has run for the first time */
|
||
var REACTION_RAN = 32768;
|
||
/** Effect is in the process of getting destroyed. Can be observed in child teardown functions */
|
||
var DESTROYING = 1 << 25;
|
||
/**
|
||
* 'Transparent' effects do not create a transition boundary.
|
||
* This is on a block effect 99% of the time but may also be on a branch effect if its parent block effect was pruned
|
||
*/
|
||
var EFFECT_TRANSPARENT = 65536;
|
||
var HEAD_EFFECT = 1 << 18;
|
||
var EFFECT_PRESERVED = 1 << 19;
|
||
var USER_EFFECT = 1 << 20;
|
||
var EFFECT_OFFSCREEN = 1 << 25;
|
||
/**
|
||
* Tells that we marked this derived and its reactions as visited during the "mark as (maybe) dirty"-phase.
|
||
* Will be lifted during execution of the derived and during checking its dirty state (both are necessary
|
||
* because a derived might be checked but not executed). This is a pure performance optimization flag and
|
||
* should not be used for any other purpose!
|
||
*/
|
||
var WAS_MARKED = 65536;
|
||
var REACTION_IS_UPDATING = 1 << 21;
|
||
var ASYNC = 1 << 22;
|
||
var ERROR_VALUE = 1 << 23;
|
||
var STATE_SYMBOL = Symbol("$state");
|
||
var LOADING_ATTR_SYMBOL = Symbol("");
|
||
/** allow users to ignore aborted signal errors if `reason.name === 'StaleReactionError` */
|
||
var STALE_REACTION = new class StaleReactionError extends Error {
|
||
name = "StaleReactionError";
|
||
message = "The reaction that called `getAbortSignal()` was re-run or destroyed";
|
||
}();
|
||
var IS_XHTML = !!globalThis.document?.contentType && /* @__PURE__ */ globalThis.document.contentType.includes("xml");
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/client/errors.js
|
||
/**
|
||
* Cannot create a `$derived(...)` with an `await` expression outside of an effect tree
|
||
* @returns {never}
|
||
*/
|
||
function async_derived_orphan() {
|
||
throw new Error(`https://svelte.dev/e/async_derived_orphan`);
|
||
}
|
||
/**
|
||
* Keyed each block has duplicate key `%value%` at indexes %a% and %b%
|
||
* @param {string} a
|
||
* @param {string} b
|
||
* @param {string | undefined | null} [value]
|
||
* @returns {never}
|
||
*/
|
||
function each_key_duplicate(a, b, value) {
|
||
throw new Error(`https://svelte.dev/e/each_key_duplicate`);
|
||
}
|
||
/**
|
||
* `%rune%` cannot be used inside an effect cleanup function
|
||
* @param {string} rune
|
||
* @returns {never}
|
||
*/
|
||
function effect_in_teardown(rune) {
|
||
throw new Error(`https://svelte.dev/e/effect_in_teardown`);
|
||
}
|
||
/**
|
||
* Effect cannot be created inside a `$derived` value that was not itself created inside an effect
|
||
* @returns {never}
|
||
*/
|
||
function effect_in_unowned_derived() {
|
||
throw new Error(`https://svelte.dev/e/effect_in_unowned_derived`);
|
||
}
|
||
/**
|
||
* `%rune%` can only be used inside an effect (e.g. during component initialisation)
|
||
* @param {string} rune
|
||
* @returns {never}
|
||
*/
|
||
function effect_orphan(rune) {
|
||
throw new Error(`https://svelte.dev/e/effect_orphan`);
|
||
}
|
||
/**
|
||
* Maximum update depth exceeded. This typically indicates that an effect reads and writes the same piece of state
|
||
* @returns {never}
|
||
*/
|
||
function effect_update_depth_exceeded() {
|
||
throw new Error(`https://svelte.dev/e/effect_update_depth_exceeded`);
|
||
}
|
||
/**
|
||
* Property descriptors defined on `$state` objects must contain `value` and always be `enumerable`, `configurable` and `writable`.
|
||
* @returns {never}
|
||
*/
|
||
function state_descriptors_fixed() {
|
||
throw new Error(`https://svelte.dev/e/state_descriptors_fixed`);
|
||
}
|
||
/**
|
||
* Cannot set prototype of `$state` object
|
||
* @returns {never}
|
||
*/
|
||
function state_prototype_fixed() {
|
||
throw new Error(`https://svelte.dev/e/state_prototype_fixed`);
|
||
}
|
||
/**
|
||
* Updating state inside `$derived(...)`, `$inspect(...)` or a template expression is forbidden. If the value should not be reactive, declare it without `$state`
|
||
* @returns {never}
|
||
*/
|
||
function state_unsafe_mutation() {
|
||
throw new Error(`https://svelte.dev/e/state_unsafe_mutation`);
|
||
}
|
||
/**
|
||
* A `<svelte:boundary>` `reset` function cannot be called while an error is still being handled
|
||
* @returns {never}
|
||
*/
|
||
function svelte_boundary_reset_onerror() {
|
||
throw new Error(`https://svelte.dev/e/svelte_boundary_reset_onerror`);
|
||
}
|
||
//#endregion
|
||
//#region node_modules/svelte/src/constants.js
|
||
var HYDRATION_ERROR = {};
|
||
var UNINITIALIZED = Symbol();
|
||
var NAMESPACE_HTML = "http://www.w3.org/1999/xhtml";
|
||
/**
|
||
* Reading a derived belonging to a now-destroyed effect may result in stale values
|
||
*/
|
||
function derived_inert() {
|
||
console.warn(`https://svelte.dev/e/derived_inert`);
|
||
}
|
||
/**
|
||
* Hydration failed because the initial UI does not match what was rendered on the server. The error occurred near %location%
|
||
* @param {string | undefined | null} [location]
|
||
*/
|
||
function hydration_mismatch(location) {
|
||
console.warn(`https://svelte.dev/e/hydration_mismatch`);
|
||
}
|
||
/**
|
||
* The `value` property of a `<select multiple>` element should be an array, but it received a non-array value. The selection will be kept as is.
|
||
*/
|
||
function select_multiple_invalid_value() {
|
||
console.warn(`https://svelte.dev/e/select_multiple_invalid_value`);
|
||
}
|
||
/**
|
||
* A `<svelte:boundary>` `reset` function only resets the boundary the first time it is called
|
||
*/
|
||
function svelte_boundary_reset_noop() {
|
||
console.warn(`https://svelte.dev/e/svelte_boundary_reset_noop`);
|
||
}
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/client/dom/hydration.js
|
||
/** @import { TemplateNode } from '#client' */
|
||
/**
|
||
* Use this variable to guard everything related to hydration code so it can be treeshaken out
|
||
* if the user doesn't use the `hydrate` method and these code paths are therefore not needed.
|
||
*/
|
||
var hydrating = false;
|
||
/** @param {boolean} value */
|
||
function set_hydrating(value) {
|
||
hydrating = value;
|
||
}
|
||
/**
|
||
* The node that is currently being hydrated. This starts out as the first node inside the opening
|
||
* \x3C!--[--> comment, and updates each time a component calls `$.child(...)` or `$.sibling(...)`.
|
||
* When entering a block (e.g. `{#if ...}`), `hydrate_node` is the block opening comment; by the
|
||
* time we leave the block it is the closing comment, which serves as the block's anchor.
|
||
* @type {TemplateNode}
|
||
*/
|
||
var hydrate_node;
|
||
/** @param {TemplateNode | null} node */
|
||
function set_hydrate_node(node) {
|
||
if (node === null) {
|
||
hydration_mismatch();
|
||
throw HYDRATION_ERROR;
|
||
}
|
||
return hydrate_node = node;
|
||
}
|
||
function hydrate_next() {
|
||
return set_hydrate_node(/* @__PURE__ */ get_next_sibling(hydrate_node));
|
||
}
|
||
/** @param {TemplateNode} node */
|
||
function reset(node) {
|
||
if (!hydrating) return;
|
||
if (/* @__PURE__ */ get_next_sibling(hydrate_node) !== null) {
|
||
hydration_mismatch();
|
||
throw HYDRATION_ERROR;
|
||
}
|
||
hydrate_node = node;
|
||
}
|
||
function next(count = 1) {
|
||
if (hydrating) {
|
||
var i = count;
|
||
var node = hydrate_node;
|
||
while (i--) node = /* @__PURE__ */ get_next_sibling(node);
|
||
hydrate_node = node;
|
||
}
|
||
}
|
||
/**
|
||
* Skips or removes (depending on {@link remove}) all nodes starting at `hydrate_node` up until the next hydration end comment
|
||
* @param {boolean} remove
|
||
*/
|
||
function skip_nodes(remove = true) {
|
||
var depth = 0;
|
||
var node = hydrate_node;
|
||
while (true) {
|
||
if (node.nodeType === 8) {
|
||
var data = node.data;
|
||
if (data === "]") {
|
||
if (depth === 0) return node;
|
||
depth -= 1;
|
||
} else if (data === "[" || data === "[!" || data[0] === "[" && !isNaN(Number(data.slice(1)))) depth += 1;
|
||
}
|
||
var next = /* @__PURE__ */ get_next_sibling(node);
|
||
if (remove) node.remove();
|
||
node = next;
|
||
}
|
||
}
|
||
/**
|
||
*
|
||
* @param {TemplateNode} node
|
||
*/
|
||
function read_hydration_instruction(node) {
|
||
if (!node || node.nodeType !== 8) {
|
||
hydration_mismatch();
|
||
throw HYDRATION_ERROR;
|
||
}
|
||
return node.data;
|
||
}
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/client/reactivity/equality.js
|
||
/** @import { Equals } from '#client' */
|
||
/** @type {Equals} */
|
||
function equals(value) {
|
||
return value === this.v;
|
||
}
|
||
/**
|
||
* @param {unknown} a
|
||
* @param {unknown} b
|
||
* @returns {boolean}
|
||
*/
|
||
function safe_not_equal(a, b) {
|
||
return a != a ? b == b : a !== b || a !== null && typeof a === "object" || typeof a === "function";
|
||
}
|
||
/** @type {Equals} */
|
||
function safe_equals(value) {
|
||
return !safe_not_equal(value, this.v);
|
||
}
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/flags/index.js
|
||
/** True if experimental.async=true */
|
||
var async_mode_flag = false;
|
||
/** True if we're not certain that we only have Svelte 5 code in the compilation */
|
||
var legacy_mode_flag = false;
|
||
function enable_legacy_mode_flag() {
|
||
legacy_mode_flag = true;
|
||
}
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/client/context.js
|
||
/** @import { ComponentContext, DevStackEntry, Effect } from '#client' */
|
||
/** @type {ComponentContext | null} */
|
||
var component_context = null;
|
||
/** @param {ComponentContext | null} context */
|
||
function set_component_context(context) {
|
||
component_context = context;
|
||
}
|
||
/**
|
||
* @param {Record<string, unknown>} props
|
||
* @param {any} runes
|
||
* @param {Function} [fn]
|
||
* @returns {void}
|
||
*/
|
||
function push(props, runes = false, fn) {
|
||
component_context = {
|
||
p: component_context,
|
||
i: false,
|
||
c: null,
|
||
e: null,
|
||
s: props,
|
||
x: null,
|
||
r: active_effect,
|
||
l: legacy_mode_flag && !runes ? {
|
||
s: null,
|
||
u: null,
|
||
$: []
|
||
} : null
|
||
};
|
||
}
|
||
/**
|
||
* @template {Record<string, any>} T
|
||
* @param {T} [component]
|
||
* @returns {T}
|
||
*/
|
||
function pop(component) {
|
||
var context = component_context;
|
||
var effects = context.e;
|
||
if (effects !== null) {
|
||
context.e = null;
|
||
for (var fn of effects) create_user_effect(fn);
|
||
}
|
||
if (component !== void 0) context.x = component;
|
||
context.i = true;
|
||
component_context = context.p;
|
||
return component ?? {};
|
||
}
|
||
/** @returns {boolean} */
|
||
function is_runes() {
|
||
return !legacy_mode_flag || component_context !== null && component_context.l === null;
|
||
}
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/client/dom/task.js
|
||
/** @type {Array<() => void>} */
|
||
var micro_tasks = [];
|
||
function run_micro_tasks() {
|
||
var tasks = micro_tasks;
|
||
micro_tasks = [];
|
||
run_all(tasks);
|
||
}
|
||
/**
|
||
* @param {() => void} fn
|
||
*/
|
||
function queue_micro_task(fn) {
|
||
if (micro_tasks.length === 0 && !is_flushing_sync) {
|
||
var tasks = micro_tasks;
|
||
queueMicrotask(() => {
|
||
if (tasks === micro_tasks) run_micro_tasks();
|
||
});
|
||
}
|
||
micro_tasks.push(fn);
|
||
}
|
||
/**
|
||
* Synchronously run any queued tasks.
|
||
*/
|
||
function flush_tasks() {
|
||
while (micro_tasks.length > 0) run_micro_tasks();
|
||
}
|
||
/**
|
||
* @param {unknown} error
|
||
*/
|
||
function handle_error(error) {
|
||
var effect = active_effect;
|
||
if (effect === null) {
|
||
/** @type {Derived} */ active_reaction.f |= ERROR_VALUE;
|
||
return error;
|
||
}
|
||
if ((effect.f & 32768) === 0 && (effect.f & 4) === 0) throw error;
|
||
invoke_error_boundary(error, effect);
|
||
}
|
||
/**
|
||
* @param {unknown} error
|
||
* @param {Effect | null} effect
|
||
*/
|
||
function invoke_error_boundary(error, effect) {
|
||
while (effect !== null) {
|
||
if ((effect.f & 128) !== 0) {
|
||
if ((effect.f & 32768) === 0) throw error;
|
||
try {
|
||
/** @type {Boundary} */ effect.b.error(error);
|
||
return;
|
||
} catch (e) {
|
||
error = e;
|
||
}
|
||
}
|
||
effect = effect.parent;
|
||
}
|
||
throw error;
|
||
}
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/client/reactivity/status.js
|
||
/** @import { Derived, Signal } from '#client' */
|
||
var STATUS_MASK = ~(DIRTY | MAYBE_DIRTY | CLEAN);
|
||
/**
|
||
* @param {Signal} signal
|
||
* @param {number} status
|
||
*/
|
||
function set_signal_status(signal, status) {
|
||
signal.f = signal.f & STATUS_MASK | status;
|
||
}
|
||
/**
|
||
* Set a derived's status to CLEAN or MAYBE_DIRTY based on its connection state.
|
||
* @param {Derived} derived
|
||
*/
|
||
function update_derived_status(derived) {
|
||
if ((derived.f & 512) !== 0 || derived.deps === null) set_signal_status(derived, CLEAN);
|
||
else set_signal_status(derived, MAYBE_DIRTY);
|
||
}
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/client/reactivity/utils.js
|
||
/** @import { Derived, Effect, Value } from '#client' */
|
||
/**
|
||
* @param {Value[] | null} deps
|
||
*/
|
||
function clear_marked(deps) {
|
||
if (deps === null) return;
|
||
for (const dep of deps) {
|
||
if ((dep.f & 2) === 0 || (dep.f & 65536) === 0) continue;
|
||
dep.f ^= WAS_MARKED;
|
||
clear_marked(
|
||
/** @type {Derived} */
|
||
dep.deps
|
||
);
|
||
}
|
||
}
|
||
/**
|
||
* @param {Effect} effect
|
||
* @param {Set<Effect>} dirty_effects
|
||
* @param {Set<Effect>} maybe_dirty_effects
|
||
*/
|
||
function defer_effect(effect, dirty_effects, maybe_dirty_effects) {
|
||
if ((effect.f & 2048) !== 0) dirty_effects.add(effect);
|
||
else if ((effect.f & 4096) !== 0) maybe_dirty_effects.add(effect);
|
||
clear_marked(effect.deps);
|
||
set_signal_status(effect, CLEAN);
|
||
}
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/client/reactivity/store.js
|
||
/**
|
||
* We set this to `true` when updating a store so that we correctly
|
||
* schedule effects if the update takes place inside a `$:` effect
|
||
*/
|
||
var legacy_is_updating_store = false;
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/client/reactivity/batch.js
|
||
/** @import { Fork } from 'svelte' */
|
||
/** @import { Derived, Effect, Reaction, Source, Value } from '#client' */
|
||
/** @type {Set<Batch>} */
|
||
var batches = /* @__PURE__ */ new Set();
|
||
/** @type {Batch | null} */
|
||
var current_batch = null;
|
||
/**
|
||
* This is needed to avoid overwriting inputs
|
||
* @type {Batch | null}
|
||
*/
|
||
var previous_batch = null;
|
||
/**
|
||
* When time travelling (i.e. working in one batch, while other batches
|
||
* still have ongoing work), we ignore the real values of affected
|
||
* signals in favour of their values within the batch
|
||
* @type {Map<Value, any> | null}
|
||
*/
|
||
var batch_values = null;
|
||
/** @type {Effect | null} */
|
||
var last_scheduled_effect = null;
|
||
var is_flushing_sync = false;
|
||
var is_processing = false;
|
||
/**
|
||
* During traversal, this is an array. Newly created effects are (if not immediately
|
||
* executed) pushed to this array, rather than going through the scheduling
|
||
* rigamarole that would cause another turn of the flush loop.
|
||
* @type {Effect[] | null}
|
||
*/
|
||
var collected_effects = null;
|
||
/**
|
||
* An array of effects that are marked during traversal as a result of a `set`
|
||
* (not `internal_set`) call. These will be added to the next batch and
|
||
* trigger another `batch.process()`
|
||
* @type {Effect[] | null}
|
||
* @deprecated when we get rid of legacy mode and stores, we can get rid of this
|
||
*/
|
||
var legacy_updates = null;
|
||
var flush_count = 0;
|
||
var uid = 1;
|
||
var Batch = class Batch {
|
||
id = uid++;
|
||
/**
|
||
* The current values of any signals that are updated in this batch.
|
||
* Tuple format: [value, is_derived] (note: is_derived is false for deriveds, too, if they were overridden via assignment)
|
||
* They keys of this map are identical to `this.#previous`
|
||
* @type {Map<Value, [any, boolean]>}
|
||
*/
|
||
current = /* @__PURE__ */ new Map();
|
||
/**
|
||
* The values of any signals (sources and deriveds) that are updated in this batch _before_ those updates took place.
|
||
* They keys of this map are identical to `this.#current`
|
||
* @type {Map<Value, any>}
|
||
*/
|
||
previous = /* @__PURE__ */ new Map();
|
||
/**
|
||
* When the batch is committed (and the DOM is updated), we need to remove old branches
|
||
* and append new ones by calling the functions added inside (if/each/key/etc) blocks
|
||
* @type {Set<(batch: Batch) => void>}
|
||
*/
|
||
#commit_callbacks = /* @__PURE__ */ new Set();
|
||
/**
|
||
* If a fork is discarded, we need to destroy any effects that are no longer needed
|
||
* @type {Set<(batch: Batch) => void>}
|
||
*/
|
||
#discard_callbacks = /* @__PURE__ */ new Set();
|
||
/**
|
||
* Callbacks that should run only when a fork is committed.
|
||
* @type {Set<(batch: Batch) => void>}
|
||
*/
|
||
#fork_commit_callbacks = /* @__PURE__ */ new Set();
|
||
/**
|
||
* Async effects that are currently in flight
|
||
* @type {Map<Effect, number>}
|
||
*/
|
||
#pending = /* @__PURE__ */ new Map();
|
||
/**
|
||
* Async effects that are currently in flight, _not_ inside a pending boundary
|
||
* @type {Map<Effect, number>}
|
||
*/
|
||
#blocking_pending = /* @__PURE__ */ new Map();
|
||
/**
|
||
* A deferred that resolves when the batch is committed, used with `settled()`
|
||
* TODO replace with Promise.withResolvers once supported widely enough
|
||
* @type {{ promise: Promise<void>, resolve: (value?: any) => void, reject: (reason: unknown) => void } | null}
|
||
*/
|
||
#deferred = null;
|
||
/**
|
||
* The root effects that need to be flushed
|
||
* @type {Effect[]}
|
||
*/
|
||
#roots = [];
|
||
/**
|
||
* Effects created while this batch was active.
|
||
* @type {Effect[]}
|
||
*/
|
||
#new_effects = [];
|
||
/**
|
||
* Deferred effects (which run after async work has completed) that are DIRTY
|
||
* @type {Set<Effect>}
|
||
*/
|
||
#dirty_effects = /* @__PURE__ */ new Set();
|
||
/**
|
||
* Deferred effects that are MAYBE_DIRTY
|
||
* @type {Set<Effect>}
|
||
*/
|
||
#maybe_dirty_effects = /* @__PURE__ */ new Set();
|
||
/**
|
||
* A map of branches that still exist, but will be destroyed when this batch
|
||
* is committed — we skip over these during `process`.
|
||
* The value contains child effects that were dirty/maybe_dirty before being reset,
|
||
* so they can be rescheduled if the branch survives.
|
||
* @type {Map<Effect, { d: Effect[], m: Effect[] }>}
|
||
*/
|
||
#skipped_branches = /* @__PURE__ */ new Map();
|
||
/**
|
||
* Inverse of #skipped_branches which we need to tell prior batches to unskip them when committing
|
||
* @type {Set<Effect>}
|
||
*/
|
||
#unskipped_branches = /* @__PURE__ */ new Set();
|
||
is_fork = false;
|
||
#decrement_queued = false;
|
||
/** @type {Set<Batch>} */
|
||
#blockers = /* @__PURE__ */ new Set();
|
||
#is_deferred() {
|
||
return this.is_fork || this.#blocking_pending.size > 0;
|
||
}
|
||
#is_blocked() {
|
||
for (const batch of this.#blockers) for (const effect of batch.#blocking_pending.keys()) {
|
||
var skipped = false;
|
||
var e = effect;
|
||
while (e.parent !== null) {
|
||
if (this.#skipped_branches.has(e)) {
|
||
skipped = true;
|
||
break;
|
||
}
|
||
e = e.parent;
|
||
}
|
||
if (!skipped) return true;
|
||
}
|
||
return false;
|
||
}
|
||
/**
|
||
* Add an effect to the #skipped_branches map and reset its children
|
||
* @param {Effect} effect
|
||
*/
|
||
skip_effect(effect) {
|
||
if (!this.#skipped_branches.has(effect)) this.#skipped_branches.set(effect, {
|
||
d: [],
|
||
m: []
|
||
});
|
||
this.#unskipped_branches.delete(effect);
|
||
}
|
||
/**
|
||
* Remove an effect from the #skipped_branches map and reschedule
|
||
* any tracked dirty/maybe_dirty child effects
|
||
* @param {Effect} effect
|
||
* @param {(e: Effect) => void} callback
|
||
*/
|
||
unskip_effect(effect, callback = (e) => this.schedule(e)) {
|
||
var tracked = this.#skipped_branches.get(effect);
|
||
if (tracked) {
|
||
this.#skipped_branches.delete(effect);
|
||
for (var e of tracked.d) {
|
||
set_signal_status(e, DIRTY);
|
||
callback(e);
|
||
}
|
||
for (e of tracked.m) {
|
||
set_signal_status(e, MAYBE_DIRTY);
|
||
callback(e);
|
||
}
|
||
}
|
||
this.#unskipped_branches.add(effect);
|
||
}
|
||
#process() {
|
||
if (flush_count++ > 1e3) {
|
||
batches.delete(this);
|
||
infinite_loop_guard();
|
||
}
|
||
if (!this.#is_deferred()) {
|
||
for (const e of this.#dirty_effects) {
|
||
this.#maybe_dirty_effects.delete(e);
|
||
set_signal_status(e, DIRTY);
|
||
this.schedule(e);
|
||
}
|
||
for (const e of this.#maybe_dirty_effects) {
|
||
set_signal_status(e, MAYBE_DIRTY);
|
||
this.schedule(e);
|
||
}
|
||
}
|
||
const roots = this.#roots;
|
||
this.#roots = [];
|
||
this.apply();
|
||
/** @type {Effect[]} */
|
||
var effects = collected_effects = [];
|
||
/** @type {Effect[]} */
|
||
var render_effects = [];
|
||
/**
|
||
* @type {Effect[]}
|
||
* @deprecated when we get rid of legacy mode and stores, we can get rid of this
|
||
*/
|
||
var updates = legacy_updates = [];
|
||
for (const root of roots) try {
|
||
this.#traverse(root, effects, render_effects);
|
||
} catch (e) {
|
||
reset_all(root);
|
||
throw e;
|
||
}
|
||
current_batch = null;
|
||
if (updates.length > 0) {
|
||
var batch = Batch.ensure();
|
||
for (const e of updates) batch.schedule(e);
|
||
}
|
||
collected_effects = null;
|
||
legacy_updates = null;
|
||
if (this.#is_deferred() || this.#is_blocked()) {
|
||
this.#defer_effects(render_effects);
|
||
this.#defer_effects(effects);
|
||
for (const [e, t] of this.#skipped_branches) reset_branch(e, t);
|
||
} else {
|
||
if (this.#pending.size === 0) batches.delete(this);
|
||
this.#dirty_effects.clear();
|
||
this.#maybe_dirty_effects.clear();
|
||
for (const fn of this.#commit_callbacks) fn(this);
|
||
this.#commit_callbacks.clear();
|
||
previous_batch = this;
|
||
flush_queued_effects(render_effects);
|
||
flush_queued_effects(effects);
|
||
previous_batch = null;
|
||
this.#deferred?.resolve();
|
||
}
|
||
var next_batch = current_batch;
|
||
if (this.#roots.length > 0) {
|
||
const batch = next_batch ??= this;
|
||
batch.#roots.push(...this.#roots.filter((r) => !batch.#roots.includes(r)));
|
||
}
|
||
if (next_batch !== null) {
|
||
batches.add(next_batch);
|
||
next_batch.#process();
|
||
}
|
||
if (async_mode_flag && !batches.has(this)) this.#commit();
|
||
}
|
||
/**
|
||
* Traverse the effect tree, executing effects or stashing
|
||
* them for later execution as appropriate
|
||
* @param {Effect} root
|
||
* @param {Effect[]} effects
|
||
* @param {Effect[]} render_effects
|
||
*/
|
||
#traverse(root, effects, render_effects) {
|
||
root.f ^= CLEAN;
|
||
var effect = root.first;
|
||
while (effect !== null) {
|
||
var flags = effect.f;
|
||
var is_branch = (flags & 96) !== 0;
|
||
if (!(is_branch && (flags & 1024) !== 0 || (flags & 8192) !== 0 || this.#skipped_branches.has(effect)) && effect.fn !== null) {
|
||
if (is_branch) effect.f ^= CLEAN;
|
||
else if ((flags & 4) !== 0) effects.push(effect);
|
||
else if (async_mode_flag && (flags & 16777224) !== 0) render_effects.push(effect);
|
||
else if (is_dirty(effect)) {
|
||
if ((flags & 16) !== 0) this.#maybe_dirty_effects.add(effect);
|
||
update_effect(effect);
|
||
}
|
||
var child = effect.first;
|
||
if (child !== null) {
|
||
effect = child;
|
||
continue;
|
||
}
|
||
}
|
||
while (effect !== null) {
|
||
var next = effect.next;
|
||
if (next !== null) {
|
||
effect = next;
|
||
break;
|
||
}
|
||
effect = effect.parent;
|
||
}
|
||
}
|
||
}
|
||
/**
|
||
* @param {Effect[]} effects
|
||
*/
|
||
#defer_effects(effects) {
|
||
for (var i = 0; i < effects.length; i += 1) defer_effect(effects[i], this.#dirty_effects, this.#maybe_dirty_effects);
|
||
}
|
||
/**
|
||
* Associate a change to a given source with the current
|
||
* batch, noting its previous and current values
|
||
* @param {Value} source
|
||
* @param {any} value
|
||
* @param {boolean} [is_derived]
|
||
*/
|
||
capture(source, value, is_derived = false) {
|
||
if (source.v !== UNINITIALIZED && !this.previous.has(source)) this.previous.set(source, source.v);
|
||
if ((source.f & 8388608) === 0) {
|
||
this.current.set(source, [value, is_derived]);
|
||
batch_values?.set(source, value);
|
||
}
|
||
if (!this.is_fork) source.v = value;
|
||
}
|
||
activate() {
|
||
current_batch = this;
|
||
}
|
||
deactivate() {
|
||
current_batch = null;
|
||
batch_values = null;
|
||
}
|
||
flush() {
|
||
try {
|
||
is_processing = true;
|
||
current_batch = this;
|
||
this.#process();
|
||
} finally {
|
||
flush_count = 0;
|
||
last_scheduled_effect = null;
|
||
collected_effects = null;
|
||
legacy_updates = null;
|
||
is_processing = false;
|
||
current_batch = null;
|
||
batch_values = null;
|
||
old_values.clear();
|
||
}
|
||
}
|
||
discard() {
|
||
for (const fn of this.#discard_callbacks) fn(this);
|
||
this.#discard_callbacks.clear();
|
||
this.#fork_commit_callbacks.clear();
|
||
batches.delete(this);
|
||
}
|
||
/**
|
||
* @param {Effect} effect
|
||
*/
|
||
register_created_effect(effect) {
|
||
this.#new_effects.push(effect);
|
||
}
|
||
#commit() {
|
||
for (const batch of batches) {
|
||
var is_earlier = batch.id < this.id;
|
||
/** @type {Source[]} */
|
||
var sources = [];
|
||
for (const [source, [value, is_derived]] of this.current) {
|
||
if (batch.current.has(source)) {
|
||
var batch_value = batch.current.get(source)[0];
|
||
if (is_earlier && value !== batch_value) batch.current.set(source, [value, is_derived]);
|
||
else continue;
|
||
}
|
||
sources.push(source);
|
||
}
|
||
var others = [...batch.current.keys()].filter((s) => !this.current.has(s));
|
||
if (others.length === 0) {
|
||
if (is_earlier) batch.discard();
|
||
} else if (sources.length > 0) {
|
||
if (is_earlier) for (const unskipped of this.#unskipped_branches) batch.unskip_effect(unskipped, (e) => {
|
||
if ((e.f & 4194320) !== 0) batch.schedule(e);
|
||
else batch.#defer_effects([e]);
|
||
});
|
||
batch.activate();
|
||
/** @type {Set<Value>} */
|
||
var marked = /* @__PURE__ */ new Set();
|
||
/** @type {Map<Reaction, boolean>} */
|
||
var checked = /* @__PURE__ */ new Map();
|
||
for (var source of sources) mark_effects(source, others, marked, checked);
|
||
checked = /* @__PURE__ */ new Map();
|
||
var current_unequal = [...batch.current.keys()].filter((c) => this.current.has(c) ? this.current.get(c)[0] !== c : true);
|
||
for (const effect of this.#new_effects) if ((effect.f & 155648) === 0 && depends_on(effect, current_unequal, checked)) if ((effect.f & 4194320) !== 0) {
|
||
set_signal_status(effect, DIRTY);
|
||
batch.schedule(effect);
|
||
} else batch.#dirty_effects.add(effect);
|
||
if (batch.#roots.length > 0) {
|
||
batch.apply();
|
||
for (var root of batch.#roots) batch.#traverse(root, [], []);
|
||
batch.#roots = [];
|
||
}
|
||
batch.deactivate();
|
||
}
|
||
}
|
||
for (const batch of batches) if (batch.#blockers.has(this)) {
|
||
batch.#blockers.delete(this);
|
||
if (batch.#blockers.size === 0 && !batch.#is_deferred()) {
|
||
batch.activate();
|
||
batch.#process();
|
||
}
|
||
}
|
||
}
|
||
/**
|
||
* @param {boolean} blocking
|
||
* @param {Effect} effect
|
||
*/
|
||
increment(blocking, effect) {
|
||
let pending_count = this.#pending.get(effect) ?? 0;
|
||
this.#pending.set(effect, pending_count + 1);
|
||
if (blocking) {
|
||
let blocking_pending_count = this.#blocking_pending.get(effect) ?? 0;
|
||
this.#blocking_pending.set(effect, blocking_pending_count + 1);
|
||
}
|
||
}
|
||
/**
|
||
* @param {boolean} blocking
|
||
* @param {Effect} effect
|
||
* @param {boolean} skip - whether to skip updates (because this is triggered by a stale reaction)
|
||
*/
|
||
decrement(blocking, effect, skip) {
|
||
let pending_count = this.#pending.get(effect) ?? 0;
|
||
if (pending_count === 1) this.#pending.delete(effect);
|
||
else this.#pending.set(effect, pending_count - 1);
|
||
if (blocking) {
|
||
let blocking_pending_count = this.#blocking_pending.get(effect) ?? 0;
|
||
if (blocking_pending_count === 1) this.#blocking_pending.delete(effect);
|
||
else this.#blocking_pending.set(effect, blocking_pending_count - 1);
|
||
}
|
||
if (this.#decrement_queued || skip) return;
|
||
this.#decrement_queued = true;
|
||
queue_micro_task(() => {
|
||
this.#decrement_queued = false;
|
||
this.flush();
|
||
});
|
||
}
|
||
/**
|
||
* @param {Set<Effect>} dirty_effects
|
||
* @param {Set<Effect>} maybe_dirty_effects
|
||
*/
|
||
transfer_effects(dirty_effects, maybe_dirty_effects) {
|
||
for (const e of dirty_effects) this.#dirty_effects.add(e);
|
||
for (const e of maybe_dirty_effects) this.#maybe_dirty_effects.add(e);
|
||
dirty_effects.clear();
|
||
maybe_dirty_effects.clear();
|
||
}
|
||
/** @param {(batch: Batch) => void} fn */
|
||
oncommit(fn) {
|
||
this.#commit_callbacks.add(fn);
|
||
}
|
||
/** @param {(batch: Batch) => void} fn */
|
||
ondiscard(fn) {
|
||
this.#discard_callbacks.add(fn);
|
||
}
|
||
/** @param {(batch: Batch) => void} fn */
|
||
on_fork_commit(fn) {
|
||
this.#fork_commit_callbacks.add(fn);
|
||
}
|
||
run_fork_commit_callbacks() {
|
||
for (const fn of this.#fork_commit_callbacks) fn(this);
|
||
this.#fork_commit_callbacks.clear();
|
||
}
|
||
settled() {
|
||
return (this.#deferred ??= deferred()).promise;
|
||
}
|
||
static ensure() {
|
||
if (current_batch === null) {
|
||
const batch = current_batch = new Batch();
|
||
if (!is_processing) {
|
||
batches.add(current_batch);
|
||
if (!is_flushing_sync) queue_micro_task(() => {
|
||
if (current_batch !== batch) return;
|
||
batch.flush();
|
||
});
|
||
}
|
||
}
|
||
return current_batch;
|
||
}
|
||
apply() {
|
||
if (!async_mode_flag || !this.is_fork && batches.size === 1) {
|
||
batch_values = null;
|
||
return;
|
||
}
|
||
batch_values = /* @__PURE__ */ new Map();
|
||
for (const [source, [value]] of this.current) batch_values.set(source, value);
|
||
for (const batch of batches) {
|
||
if (batch === this || batch.is_fork) continue;
|
||
var intersects = false;
|
||
var differs = false;
|
||
if (batch.id < this.id) for (const [source, [, is_derived]] of batch.current) {
|
||
if (is_derived) continue;
|
||
intersects ||= this.current.has(source);
|
||
differs ||= !this.current.has(source);
|
||
}
|
||
if (intersects && differs) this.#blockers.add(batch);
|
||
else for (const [source, previous] of batch.previous) if (!batch_values.has(source)) batch_values.set(source, previous);
|
||
}
|
||
}
|
||
/**
|
||
*
|
||
* @param {Effect} effect
|
||
*/
|
||
schedule(effect) {
|
||
last_scheduled_effect = effect;
|
||
if (effect.b?.is_pending && (effect.f & 16777228) !== 0 && (effect.f & 32768) === 0) {
|
||
effect.b.defer_effect(effect);
|
||
return;
|
||
}
|
||
var e = effect;
|
||
while (e.parent !== null) {
|
||
e = e.parent;
|
||
var flags = e.f;
|
||
if (collected_effects !== null && e === active_effect) {
|
||
if (async_mode_flag) return;
|
||
if ((active_reaction === null || (active_reaction.f & 2) === 0) && !legacy_is_updating_store) return;
|
||
}
|
||
if ((flags & 96) !== 0) {
|
||
if ((flags & 1024) === 0) return;
|
||
e.f ^= CLEAN;
|
||
}
|
||
}
|
||
this.#roots.push(e);
|
||
}
|
||
};
|
||
/**
|
||
* Synchronously flush any pending updates.
|
||
* Returns void if no callback is provided, otherwise returns the result of calling the callback.
|
||
* @template [T=void]
|
||
* @param {(() => T) | undefined} [fn]
|
||
* @returns {T}
|
||
*/
|
||
function flushSync(fn) {
|
||
var was_flushing_sync = is_flushing_sync;
|
||
is_flushing_sync = true;
|
||
try {
|
||
var result;
|
||
if (fn) {
|
||
if (current_batch !== null && !current_batch.is_fork) current_batch.flush();
|
||
result = fn();
|
||
}
|
||
while (true) {
|
||
flush_tasks();
|
||
if (current_batch === null) return result;
|
||
current_batch.flush();
|
||
}
|
||
} finally {
|
||
is_flushing_sync = was_flushing_sync;
|
||
}
|
||
}
|
||
function infinite_loop_guard() {
|
||
try {
|
||
effect_update_depth_exceeded();
|
||
} catch (error) {
|
||
invoke_error_boundary(error, last_scheduled_effect);
|
||
}
|
||
}
|
||
/** @type {Set<Effect> | null} */
|
||
var eager_block_effects = null;
|
||
/**
|
||
* @param {Array<Effect>} effects
|
||
* @returns {void}
|
||
*/
|
||
function flush_queued_effects(effects) {
|
||
var length = effects.length;
|
||
if (length === 0) return;
|
||
var i = 0;
|
||
while (i < length) {
|
||
var effect = effects[i++];
|
||
if ((effect.f & 24576) === 0 && is_dirty(effect)) {
|
||
eager_block_effects = /* @__PURE__ */ new Set();
|
||
update_effect(effect);
|
||
if (effect.deps === null && effect.first === null && effect.nodes === null && effect.teardown === null && effect.ac === null) unlink_effect(effect);
|
||
if (eager_block_effects?.size > 0) {
|
||
old_values.clear();
|
||
for (const e of eager_block_effects) {
|
||
if ((e.f & 24576) !== 0) continue;
|
||
/** @type {Effect[]} */
|
||
const ordered_effects = [e];
|
||
let ancestor = e.parent;
|
||
while (ancestor !== null) {
|
||
if (eager_block_effects.has(ancestor)) {
|
||
eager_block_effects.delete(ancestor);
|
||
ordered_effects.push(ancestor);
|
||
}
|
||
ancestor = ancestor.parent;
|
||
}
|
||
for (let j = ordered_effects.length - 1; j >= 0; j--) {
|
||
const e = ordered_effects[j];
|
||
if ((e.f & 24576) !== 0) continue;
|
||
update_effect(e);
|
||
}
|
||
}
|
||
eager_block_effects.clear();
|
||
}
|
||
}
|
||
}
|
||
eager_block_effects = null;
|
||
}
|
||
/**
|
||
* This is similar to `mark_reactions`, but it only marks async/block effects
|
||
* depending on `value` and at least one of the other `sources`, so that
|
||
* these effects can re-run after another batch has been committed
|
||
* @param {Value} value
|
||
* @param {Source[]} sources
|
||
* @param {Set<Value>} marked
|
||
* @param {Map<Reaction, boolean>} checked
|
||
*/
|
||
function mark_effects(value, sources, marked, checked) {
|
||
if (marked.has(value)) return;
|
||
marked.add(value);
|
||
if (value.reactions !== null) for (const reaction of value.reactions) {
|
||
const flags = reaction.f;
|
||
if ((flags & 2) !== 0) mark_effects(reaction, sources, marked, checked);
|
||
else if ((flags & 4194320) !== 0 && (flags & 2048) === 0 && depends_on(reaction, sources, checked)) {
|
||
set_signal_status(reaction, DIRTY);
|
||
schedule_effect(reaction);
|
||
}
|
||
}
|
||
}
|
||
/**
|
||
* @param {Reaction} reaction
|
||
* @param {Source[]} sources
|
||
* @param {Map<Reaction, boolean>} checked
|
||
*/
|
||
function depends_on(reaction, sources, checked) {
|
||
const depends = checked.get(reaction);
|
||
if (depends !== void 0) return depends;
|
||
if (reaction.deps !== null) for (const dep of reaction.deps) {
|
||
if (includes.call(sources, dep)) return true;
|
||
if ((dep.f & 2) !== 0 && depends_on(dep, sources, checked)) {
|
||
checked.set(dep, true);
|
||
return true;
|
||
}
|
||
}
|
||
checked.set(reaction, false);
|
||
return false;
|
||
}
|
||
/**
|
||
* @param {Effect} effect
|
||
* @returns {void}
|
||
*/
|
||
function schedule_effect(effect) {
|
||
/** @type {Batch} */ current_batch.schedule(effect);
|
||
}
|
||
/**
|
||
* Mark all the effects inside a skipped branch CLEAN, so that
|
||
* they can be correctly rescheduled later. Tracks dirty and maybe_dirty
|
||
* effects so they can be rescheduled if the branch survives.
|
||
* @param {Effect} effect
|
||
* @param {{ d: Effect[], m: Effect[] }} tracked
|
||
*/
|
||
function reset_branch(effect, tracked) {
|
||
if ((effect.f & 32) !== 0 && (effect.f & 1024) !== 0) return;
|
||
if ((effect.f & 2048) !== 0) tracked.d.push(effect);
|
||
else if ((effect.f & 4096) !== 0) tracked.m.push(effect);
|
||
set_signal_status(effect, CLEAN);
|
||
var e = effect.first;
|
||
while (e !== null) {
|
||
reset_branch(e, tracked);
|
||
e = e.next;
|
||
}
|
||
}
|
||
/**
|
||
* Mark an entire effect tree clean following an error
|
||
* @param {Effect} effect
|
||
*/
|
||
function reset_all(effect) {
|
||
set_signal_status(effect, CLEAN);
|
||
var e = effect.first;
|
||
while (e !== null) {
|
||
reset_all(e);
|
||
e = e.next;
|
||
}
|
||
}
|
||
//#endregion
|
||
//#region node_modules/svelte/src/reactivity/create-subscriber.js
|
||
/**
|
||
* Returns a `subscribe` function that integrates external event-based systems with Svelte's reactivity.
|
||
* It's particularly useful for integrating with web APIs like `MediaQuery`, `IntersectionObserver`, or `WebSocket`.
|
||
*
|
||
* If `subscribe` is called inside an effect (including indirectly, for example inside a getter),
|
||
* the `start` callback will be called with an `update` function. Whenever `update` is called, the effect re-runs.
|
||
*
|
||
* If `start` returns a cleanup function, it will be called when the effect is destroyed.
|
||
*
|
||
* If `subscribe` is called in multiple effects, `start` will only be called once as long as the effects
|
||
* are active, and the returned teardown function will only be called when all effects are destroyed.
|
||
*
|
||
* It's best understood with an example. Here's an implementation of [`MediaQuery`](https://svelte.dev/docs/svelte/svelte-reactivity#MediaQuery):
|
||
*
|
||
* ```js
|
||
* import { createSubscriber } from 'svelte/reactivity';
|
||
* import { on } from 'svelte/events';
|
||
*
|
||
* export class MediaQuery {
|
||
* #query;
|
||
* #subscribe;
|
||
*
|
||
* constructor(query) {
|
||
* this.#query = window.matchMedia(`(${query})`);
|
||
*
|
||
* this.#subscribe = createSubscriber((update) => {
|
||
* // when the `change` event occurs, re-run any effects that read `this.current`
|
||
* const off = on(this.#query, 'change', update);
|
||
*
|
||
* // stop listening when all the effects are destroyed
|
||
* return () => off();
|
||
* });
|
||
* }
|
||
*
|
||
* get current() {
|
||
* // This makes the getter reactive, if read in an effect
|
||
* this.#subscribe();
|
||
*
|
||
* // Return the current state of the query, whether or not we're in an effect
|
||
* return this.#query.matches;
|
||
* }
|
||
* }
|
||
* ```
|
||
* @param {(update: () => void) => (() => void) | void} start
|
||
* @since 5.7.0
|
||
*/
|
||
function createSubscriber(start) {
|
||
let subscribers = 0;
|
||
let version = source(0);
|
||
/** @type {(() => void) | void} */
|
||
let stop;
|
||
return () => {
|
||
if (effect_tracking()) {
|
||
get(version);
|
||
render_effect(() => {
|
||
if (subscribers === 0) stop = untrack(() => start(() => increment(version)));
|
||
subscribers += 1;
|
||
return () => {
|
||
queue_micro_task(() => {
|
||
subscribers -= 1;
|
||
if (subscribers === 0) {
|
||
stop?.();
|
||
stop = void 0;
|
||
increment(version);
|
||
}
|
||
});
|
||
};
|
||
});
|
||
}
|
||
};
|
||
}
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/client/dom/blocks/boundary.js
|
||
/** @import { Effect, Source, TemplateNode, } from '#client' */
|
||
/**
|
||
* @typedef {{
|
||
* onerror?: (error: unknown, reset: () => void) => void;
|
||
* failed?: (anchor: Node, error: () => unknown, reset: () => () => void) => void;
|
||
* pending?: (anchor: Node) => void;
|
||
* }} BoundaryProps
|
||
*/
|
||
var flags = EFFECT_TRANSPARENT | EFFECT_PRESERVED;
|
||
/**
|
||
* @param {TemplateNode} node
|
||
* @param {BoundaryProps} props
|
||
* @param {((anchor: Node) => void)} children
|
||
* @param {((error: unknown) => unknown) | undefined} [transform_error]
|
||
* @returns {void}
|
||
*/
|
||
function boundary(node, props, children, transform_error) {
|
||
new Boundary(node, props, children, transform_error);
|
||
}
|
||
var Boundary = class {
|
||
/** @type {Boundary | null} */
|
||
parent;
|
||
is_pending = false;
|
||
/**
|
||
* API-level transformError transform function. Transforms errors before they reach the `failed` snippet.
|
||
* Inherited from parent boundary, or defaults to identity.
|
||
* @type {(error: unknown) => unknown}
|
||
*/
|
||
transform_error;
|
||
/** @type {TemplateNode} */
|
||
#anchor;
|
||
/** @type {TemplateNode | null} */
|
||
#hydrate_open = hydrating ? hydrate_node : null;
|
||
/** @type {BoundaryProps} */
|
||
#props;
|
||
/** @type {((anchor: Node) => void)} */
|
||
#children;
|
||
/** @type {Effect} */
|
||
#effect;
|
||
/** @type {Effect | null} */
|
||
#main_effect = null;
|
||
/** @type {Effect | null} */
|
||
#pending_effect = null;
|
||
/** @type {Effect | null} */
|
||
#failed_effect = null;
|
||
/** @type {DocumentFragment | null} */
|
||
#offscreen_fragment = null;
|
||
#local_pending_count = 0;
|
||
#pending_count = 0;
|
||
#pending_count_update_queued = false;
|
||
/** @type {Set<Effect>} */
|
||
#dirty_effects = /* @__PURE__ */ new Set();
|
||
/** @type {Set<Effect>} */
|
||
#maybe_dirty_effects = /* @__PURE__ */ new Set();
|
||
/**
|
||
* A source containing the number of pending async deriveds/expressions.
|
||
* Only created if `$effect.pending()` is used inside the boundary,
|
||
* otherwise updating the source results in needless `Batch.ensure()`
|
||
* calls followed by no-op flushes
|
||
* @type {Source<number> | null}
|
||
*/
|
||
#effect_pending = null;
|
||
#effect_pending_subscriber = createSubscriber(() => {
|
||
this.#effect_pending = source(this.#local_pending_count);
|
||
return () => {
|
||
this.#effect_pending = null;
|
||
};
|
||
});
|
||
/**
|
||
* @param {TemplateNode} node
|
||
* @param {BoundaryProps} props
|
||
* @param {((anchor: Node) => void)} children
|
||
* @param {((error: unknown) => unknown) | undefined} [transform_error]
|
||
*/
|
||
constructor(node, props, children, transform_error) {
|
||
this.#anchor = node;
|
||
this.#props = props;
|
||
this.#children = (anchor) => {
|
||
var effect = active_effect;
|
||
effect.b = this;
|
||
effect.f |= 128;
|
||
children(anchor);
|
||
};
|
||
this.parent = active_effect.b;
|
||
this.transform_error = transform_error ?? this.parent?.transform_error ?? ((e) => e);
|
||
this.#effect = block(() => {
|
||
if (hydrating) {
|
||
const comment = this.#hydrate_open;
|
||
hydrate_next();
|
||
const server_rendered_pending = comment.data === "[!";
|
||
if (comment.data.startsWith("[?")) {
|
||
const serialized_error = JSON.parse(comment.data.slice(2));
|
||
this.#hydrate_failed_content(serialized_error);
|
||
} else if (server_rendered_pending) this.#hydrate_pending_content();
|
||
else this.#hydrate_resolved_content();
|
||
} else this.#render();
|
||
}, flags);
|
||
if (hydrating) this.#anchor = hydrate_node;
|
||
}
|
||
#hydrate_resolved_content() {
|
||
try {
|
||
this.#main_effect = branch(() => this.#children(this.#anchor));
|
||
} catch (error) {
|
||
this.error(error);
|
||
}
|
||
}
|
||
/**
|
||
* @param {unknown} error The deserialized error from the server's hydration comment
|
||
*/
|
||
#hydrate_failed_content(error) {
|
||
const failed = this.#props.failed;
|
||
if (!failed) return;
|
||
this.#failed_effect = branch(() => {
|
||
failed(this.#anchor, () => error, () => () => {});
|
||
});
|
||
}
|
||
#hydrate_pending_content() {
|
||
const pending = this.#props.pending;
|
||
if (!pending) return;
|
||
this.is_pending = true;
|
||
this.#pending_effect = branch(() => pending(this.#anchor));
|
||
queue_micro_task(() => {
|
||
var fragment = this.#offscreen_fragment = document.createDocumentFragment();
|
||
var anchor = create_text();
|
||
fragment.append(anchor);
|
||
this.#main_effect = this.#run(() => {
|
||
return branch(() => this.#children(anchor));
|
||
});
|
||
if (this.#pending_count === 0) {
|
||
this.#anchor.before(fragment);
|
||
this.#offscreen_fragment = null;
|
||
pause_effect(this.#pending_effect, () => {
|
||
this.#pending_effect = null;
|
||
});
|
||
this.#resolve(current_batch);
|
||
}
|
||
});
|
||
}
|
||
#render() {
|
||
try {
|
||
this.is_pending = this.has_pending_snippet();
|
||
this.#pending_count = 0;
|
||
this.#local_pending_count = 0;
|
||
this.#main_effect = branch(() => {
|
||
this.#children(this.#anchor);
|
||
});
|
||
if (this.#pending_count > 0) {
|
||
var fragment = this.#offscreen_fragment = document.createDocumentFragment();
|
||
move_effect(this.#main_effect, fragment);
|
||
const pending = this.#props.pending;
|
||
this.#pending_effect = branch(() => pending(this.#anchor));
|
||
} else this.#resolve(current_batch);
|
||
} catch (error) {
|
||
this.error(error);
|
||
}
|
||
}
|
||
/**
|
||
* @param {Batch} batch
|
||
*/
|
||
#resolve(batch) {
|
||
this.is_pending = false;
|
||
batch.transfer_effects(this.#dirty_effects, this.#maybe_dirty_effects);
|
||
}
|
||
/**
|
||
* Defer an effect inside a pending boundary until the boundary resolves
|
||
* @param {Effect} effect
|
||
*/
|
||
defer_effect(effect) {
|
||
defer_effect(effect, this.#dirty_effects, this.#maybe_dirty_effects);
|
||
}
|
||
/**
|
||
* Returns `false` if the effect exists inside a boundary whose pending snippet is shown
|
||
* @returns {boolean}
|
||
*/
|
||
is_rendered() {
|
||
return !this.is_pending && (!this.parent || this.parent.is_rendered());
|
||
}
|
||
has_pending_snippet() {
|
||
return !!this.#props.pending;
|
||
}
|
||
/**
|
||
* @template T
|
||
* @param {() => T} fn
|
||
*/
|
||
#run(fn) {
|
||
var previous_effect = active_effect;
|
||
var previous_reaction = active_reaction;
|
||
var previous_ctx = component_context;
|
||
set_active_effect(this.#effect);
|
||
set_active_reaction(this.#effect);
|
||
set_component_context(this.#effect.ctx);
|
||
try {
|
||
Batch.ensure();
|
||
return fn();
|
||
} catch (e) {
|
||
handle_error(e);
|
||
return null;
|
||
} finally {
|
||
set_active_effect(previous_effect);
|
||
set_active_reaction(previous_reaction);
|
||
set_component_context(previous_ctx);
|
||
}
|
||
}
|
||
/**
|
||
* Updates the pending count associated with the currently visible pending snippet,
|
||
* if any, such that we can replace the snippet with content once work is done
|
||
* @param {1 | -1} d
|
||
* @param {Batch} batch
|
||
*/
|
||
#update_pending_count(d, batch) {
|
||
if (!this.has_pending_snippet()) {
|
||
if (this.parent) this.parent.#update_pending_count(d, batch);
|
||
return;
|
||
}
|
||
this.#pending_count += d;
|
||
if (this.#pending_count === 0) {
|
||
this.#resolve(batch);
|
||
if (this.#pending_effect) pause_effect(this.#pending_effect, () => {
|
||
this.#pending_effect = null;
|
||
});
|
||
if (this.#offscreen_fragment) {
|
||
this.#anchor.before(this.#offscreen_fragment);
|
||
this.#offscreen_fragment = null;
|
||
}
|
||
}
|
||
}
|
||
/**
|
||
* Update the source that powers `$effect.pending()` inside this boundary,
|
||
* and controls when the current `pending` snippet (if any) is removed.
|
||
* Do not call from inside the class
|
||
* @param {1 | -1} d
|
||
* @param {Batch} batch
|
||
*/
|
||
update_pending_count(d, batch) {
|
||
this.#update_pending_count(d, batch);
|
||
this.#local_pending_count += d;
|
||
if (!this.#effect_pending || this.#pending_count_update_queued) return;
|
||
this.#pending_count_update_queued = true;
|
||
queue_micro_task(() => {
|
||
this.#pending_count_update_queued = false;
|
||
if (this.#effect_pending) internal_set(this.#effect_pending, this.#local_pending_count);
|
||
});
|
||
}
|
||
get_effect_pending() {
|
||
this.#effect_pending_subscriber();
|
||
return get(this.#effect_pending);
|
||
}
|
||
/** @param {unknown} error */
|
||
error(error) {
|
||
if (!this.#props.onerror && !this.#props.failed) throw error;
|
||
if (current_batch?.is_fork) {
|
||
if (this.#main_effect) current_batch.skip_effect(this.#main_effect);
|
||
if (this.#pending_effect) current_batch.skip_effect(this.#pending_effect);
|
||
if (this.#failed_effect) current_batch.skip_effect(this.#failed_effect);
|
||
current_batch.on_fork_commit(() => {
|
||
this.#handle_error(error);
|
||
});
|
||
} else this.#handle_error(error);
|
||
}
|
||
/**
|
||
* @param {unknown} error
|
||
*/
|
||
#handle_error(error) {
|
||
if (this.#main_effect) {
|
||
destroy_effect(this.#main_effect);
|
||
this.#main_effect = null;
|
||
}
|
||
if (this.#pending_effect) {
|
||
destroy_effect(this.#pending_effect);
|
||
this.#pending_effect = null;
|
||
}
|
||
if (this.#failed_effect) {
|
||
destroy_effect(this.#failed_effect);
|
||
this.#failed_effect = null;
|
||
}
|
||
if (hydrating) {
|
||
set_hydrate_node(this.#hydrate_open);
|
||
next();
|
||
set_hydrate_node(skip_nodes());
|
||
}
|
||
var onerror = this.#props.onerror;
|
||
let failed = this.#props.failed;
|
||
var did_reset = false;
|
||
var calling_on_error = false;
|
||
const reset = () => {
|
||
if (did_reset) {
|
||
svelte_boundary_reset_noop();
|
||
return;
|
||
}
|
||
did_reset = true;
|
||
if (calling_on_error) svelte_boundary_reset_onerror();
|
||
if (this.#failed_effect !== null) pause_effect(this.#failed_effect, () => {
|
||
this.#failed_effect = null;
|
||
});
|
||
this.#run(() => {
|
||
this.#render();
|
||
});
|
||
};
|
||
/** @param {unknown} transformed_error */
|
||
const handle_error_result = (transformed_error) => {
|
||
try {
|
||
calling_on_error = true;
|
||
onerror?.(transformed_error, reset);
|
||
calling_on_error = false;
|
||
} catch (error) {
|
||
invoke_error_boundary(error, this.#effect && this.#effect.parent);
|
||
}
|
||
if (failed) this.#failed_effect = this.#run(() => {
|
||
try {
|
||
return branch(() => {
|
||
var effect = active_effect;
|
||
effect.b = this;
|
||
effect.f |= 128;
|
||
failed(this.#anchor, () => transformed_error, () => reset);
|
||
});
|
||
} catch (error) {
|
||
invoke_error_boundary(error, this.#effect.parent);
|
||
return null;
|
||
}
|
||
});
|
||
};
|
||
queue_micro_task(() => {
|
||
/** @type {unknown} */
|
||
var result;
|
||
try {
|
||
result = this.transform_error(error);
|
||
} catch (e) {
|
||
invoke_error_boundary(e, this.#effect && this.#effect.parent);
|
||
return;
|
||
}
|
||
if (result !== null && typeof result === "object" && typeof result.then === "function")
|
||
/** @type {any} */ result.then(
|
||
handle_error_result,
|
||
/** @param {unknown} e */
|
||
(e) => invoke_error_boundary(e, this.#effect && this.#effect.parent)
|
||
);
|
||
else handle_error_result(result);
|
||
});
|
||
}
|
||
};
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/client/reactivity/async.js
|
||
/** @import { Blocker, Effect, Value } from '#client' */
|
||
/**
|
||
* @param {Blocker[]} blockers
|
||
* @param {Array<() => any>} sync
|
||
* @param {Array<() => Promise<any>>} async
|
||
* @param {(values: Value[]) => any} fn
|
||
*/
|
||
function flatten(blockers, sync, async, fn) {
|
||
const d = is_runes() ? derived : derived_safe_equal;
|
||
var pending = blockers.filter((b) => !b.settled);
|
||
if (async.length === 0 && pending.length === 0) {
|
||
fn(sync.map(d));
|
||
return;
|
||
}
|
||
var parent = active_effect;
|
||
var restore = capture();
|
||
var blocker_promise = pending.length === 1 ? pending[0].promise : pending.length > 1 ? Promise.all(pending.map((b) => b.promise)) : null;
|
||
/** @param {Value[]} values */
|
||
function finish(values) {
|
||
restore();
|
||
try {
|
||
fn(values);
|
||
} catch (error) {
|
||
if ((parent.f & 16384) === 0) invoke_error_boundary(error, parent);
|
||
}
|
||
unset_context();
|
||
}
|
||
if (async.length === 0) {
|
||
/** @type {Promise<any>} */ blocker_promise.then(() => finish(sync.map(d)));
|
||
return;
|
||
}
|
||
var decrement_pending = increment_pending();
|
||
function run() {
|
||
Promise.all(async.map((expression) => /* @__PURE__ */ async_derived(expression))).then((result) => finish([...sync.map(d), ...result])).catch((error) => invoke_error_boundary(error, parent)).finally(() => decrement_pending());
|
||
}
|
||
if (blocker_promise) blocker_promise.then(() => {
|
||
restore();
|
||
run();
|
||
unset_context();
|
||
});
|
||
else run();
|
||
}
|
||
/**
|
||
* Captures the current effect context so that we can restore it after
|
||
* some asynchronous work has happened (so that e.g. `await a + b`
|
||
* causes `b` to be registered as a dependency).
|
||
*/
|
||
function capture() {
|
||
var previous_effect = active_effect;
|
||
var previous_reaction = active_reaction;
|
||
var previous_component_context = component_context;
|
||
var previous_batch = current_batch;
|
||
return function restore(activate_batch = true) {
|
||
set_active_effect(previous_effect);
|
||
set_active_reaction(previous_reaction);
|
||
set_component_context(previous_component_context);
|
||
if (activate_batch && (previous_effect.f & 16384) === 0) {
|
||
previous_batch?.activate();
|
||
previous_batch?.apply();
|
||
}
|
||
};
|
||
}
|
||
function unset_context(deactivate_batch = true) {
|
||
set_active_effect(null);
|
||
set_active_reaction(null);
|
||
set_component_context(null);
|
||
if (deactivate_batch) current_batch?.deactivate();
|
||
}
|
||
/**
|
||
* @returns {(skip?: boolean) => void}
|
||
*/
|
||
function increment_pending() {
|
||
var effect = active_effect;
|
||
var boundary = effect.b;
|
||
var batch = current_batch;
|
||
var blocking = boundary.is_rendered();
|
||
boundary.update_pending_count(1, batch);
|
||
batch.increment(blocking, effect);
|
||
return (skip = false) => {
|
||
boundary.update_pending_count(-1, batch);
|
||
batch.decrement(blocking, effect, skip);
|
||
};
|
||
}
|
||
/**
|
||
* @template V
|
||
* @param {() => V} fn
|
||
* @returns {Derived<V>}
|
||
*/
|
||
/* @__NO_SIDE_EFFECTS__ */
|
||
function derived(fn) {
|
||
var flags = 2 | DIRTY;
|
||
if (active_effect !== null) active_effect.f |= EFFECT_PRESERVED;
|
||
return {
|
||
ctx: component_context,
|
||
deps: null,
|
||
effects: null,
|
||
equals,
|
||
f: flags,
|
||
fn,
|
||
reactions: null,
|
||
rv: 0,
|
||
v: UNINITIALIZED,
|
||
wv: 0,
|
||
parent: active_effect,
|
||
ac: null
|
||
};
|
||
}
|
||
/**
|
||
* @template V
|
||
* @param {() => V | Promise<V>} fn
|
||
* @param {string} [label]
|
||
* @param {string} [location] If provided, print a warning if the value is not read immediately after update
|
||
* @returns {Promise<Source<V>>}
|
||
*/
|
||
/* @__NO_SIDE_EFFECTS__ */
|
||
function async_derived(fn, label, location) {
|
||
let parent = active_effect;
|
||
if (parent === null) async_derived_orphan();
|
||
var promise = void 0;
|
||
var signal = source(UNINITIALIZED);
|
||
var should_suspend = !active_reaction;
|
||
/** @type {Map<Batch, ReturnType<typeof deferred<V>>>} */
|
||
var deferreds = /* @__PURE__ */ new Map();
|
||
async_effect(() => {
|
||
var effect = active_effect;
|
||
/** @type {ReturnType<typeof deferred<V>>} */
|
||
var d = deferred();
|
||
promise = d.promise;
|
||
try {
|
||
Promise.resolve(fn()).then(d.resolve, d.reject).finally(unset_context);
|
||
} catch (error) {
|
||
d.reject(error);
|
||
unset_context();
|
||
}
|
||
var batch = current_batch;
|
||
if (should_suspend) {
|
||
if ((effect.f & 32768) !== 0) var decrement_pending = increment_pending();
|
||
if (parent.b.is_rendered()) {
|
||
deferreds.get(batch)?.reject(STALE_REACTION);
|
||
deferreds.delete(batch);
|
||
} else {
|
||
for (const d of deferreds.values()) d.reject(STALE_REACTION);
|
||
deferreds.clear();
|
||
}
|
||
deferreds.set(batch, d);
|
||
}
|
||
/**
|
||
* @param {any} value
|
||
* @param {unknown} error
|
||
*/
|
||
const handler = (value, error = void 0) => {
|
||
if (decrement_pending) decrement_pending(error === STALE_REACTION);
|
||
if (error === STALE_REACTION || (effect.f & 16384) !== 0) return;
|
||
batch.activate();
|
||
if (error) {
|
||
signal.f |= ERROR_VALUE;
|
||
internal_set(signal, error);
|
||
} else {
|
||
if ((signal.f & 8388608) !== 0) signal.f ^= ERROR_VALUE;
|
||
internal_set(signal, value);
|
||
for (const [b, d] of deferreds) {
|
||
deferreds.delete(b);
|
||
if (b === batch) break;
|
||
d.reject(STALE_REACTION);
|
||
}
|
||
}
|
||
batch.deactivate();
|
||
};
|
||
d.promise.then(handler, (e) => handler(null, e || "unknown"));
|
||
});
|
||
teardown(() => {
|
||
for (const d of deferreds.values()) d.reject(STALE_REACTION);
|
||
});
|
||
return new Promise((fulfil) => {
|
||
/** @param {Promise<V>} p */
|
||
function next(p) {
|
||
function go() {
|
||
if (p === promise) fulfil(signal);
|
||
else next(promise);
|
||
}
|
||
p.then(go, go);
|
||
}
|
||
next(promise);
|
||
});
|
||
}
|
||
/**
|
||
* @template V
|
||
* @param {() => V} fn
|
||
* @returns {Derived<V>}
|
||
*/
|
||
/* @__NO_SIDE_EFFECTS__ */
|
||
function user_derived(fn) {
|
||
const d = /* @__PURE__ */ derived(fn);
|
||
if (!async_mode_flag) push_reaction_value(d);
|
||
return d;
|
||
}
|
||
/**
|
||
* @template V
|
||
* @param {() => V} fn
|
||
* @returns {Derived<V>}
|
||
*/
|
||
/* @__NO_SIDE_EFFECTS__ */
|
||
function derived_safe_equal(fn) {
|
||
const signal = /* @__PURE__ */ derived(fn);
|
||
signal.equals = safe_equals;
|
||
return signal;
|
||
}
|
||
/**
|
||
* @param {Derived} derived
|
||
* @returns {void}
|
||
*/
|
||
function destroy_derived_effects(derived) {
|
||
var effects = derived.effects;
|
||
if (effects !== null) {
|
||
derived.effects = null;
|
||
for (var i = 0; i < effects.length; i += 1) destroy_effect(effects[i]);
|
||
}
|
||
}
|
||
/**
|
||
* @template T
|
||
* @param {Derived} derived
|
||
* @returns {T}
|
||
*/
|
||
function execute_derived(derived) {
|
||
var value;
|
||
var prev_active_effect = active_effect;
|
||
var parent = derived.parent;
|
||
if (!is_destroying_effect && parent !== null && (parent.f & 24576) !== 0) {
|
||
derived_inert();
|
||
return derived.v;
|
||
}
|
||
set_active_effect(parent);
|
||
try {
|
||
derived.f &= ~WAS_MARKED;
|
||
destroy_derived_effects(derived);
|
||
value = update_reaction(derived);
|
||
} finally {
|
||
set_active_effect(prev_active_effect);
|
||
}
|
||
return value;
|
||
}
|
||
/**
|
||
* @param {Derived} derived
|
||
* @returns {void}
|
||
*/
|
||
function update_derived(derived) {
|
||
var value = execute_derived(derived);
|
||
if (!derived.equals(value)) {
|
||
derived.wv = increment_write_version();
|
||
if (!current_batch?.is_fork || derived.deps === null) {
|
||
if (current_batch !== null) current_batch.capture(derived, value, true);
|
||
else derived.v = value;
|
||
if (derived.deps === null) {
|
||
set_signal_status(derived, CLEAN);
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
if (is_destroying_effect) return;
|
||
if (batch_values !== null) {
|
||
if (effect_tracking() || current_batch?.is_fork) batch_values.set(derived, value);
|
||
} else update_derived_status(derived);
|
||
}
|
||
/**
|
||
* @param {Derived} derived
|
||
*/
|
||
function freeze_derived_effects(derived) {
|
||
if (derived.effects === null) return;
|
||
for (const e of derived.effects) if (e.teardown || e.ac) {
|
||
e.teardown?.();
|
||
e.ac?.abort(STALE_REACTION);
|
||
e.teardown = noop;
|
||
e.ac = null;
|
||
remove_reactions(e, 0);
|
||
destroy_effect_children(e);
|
||
}
|
||
}
|
||
/**
|
||
* @param {Derived} derived
|
||
*/
|
||
function unfreeze_derived_effects(derived) {
|
||
if (derived.effects === null) return;
|
||
for (const e of derived.effects) if (e.teardown) update_effect(e);
|
||
}
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/client/reactivity/sources.js
|
||
/** @import { Derived, Effect, Source, Value } from '#client' */
|
||
/** @type {Set<any>} */
|
||
var eager_effects = /* @__PURE__ */ new Set();
|
||
/** @type {Map<Source, any>} */
|
||
var old_values = /* @__PURE__ */ new Map();
|
||
var eager_effects_deferred = false;
|
||
/**
|
||
* @template V
|
||
* @param {V} v
|
||
* @param {Error | null} [stack]
|
||
* @returns {Source<V>}
|
||
*/
|
||
function source(v, stack) {
|
||
return {
|
||
f: 0,
|
||
v,
|
||
reactions: null,
|
||
equals,
|
||
rv: 0,
|
||
wv: 0
|
||
};
|
||
}
|
||
/**
|
||
* @template V
|
||
* @param {V} v
|
||
* @param {Error | null} [stack]
|
||
*/
|
||
/* @__NO_SIDE_EFFECTS__ */
|
||
function state(v, stack) {
|
||
const s = source(v, stack);
|
||
push_reaction_value(s);
|
||
return s;
|
||
}
|
||
/**
|
||
* @template V
|
||
* @param {V} initial_value
|
||
* @param {boolean} [immutable]
|
||
* @returns {Source<V>}
|
||
*/
|
||
/* @__NO_SIDE_EFFECTS__ */
|
||
function mutable_source(initial_value, immutable = false, trackable = true) {
|
||
const s = source(initial_value);
|
||
if (!immutable) s.equals = safe_equals;
|
||
if (legacy_mode_flag && trackable && component_context !== null && component_context.l !== null) (component_context.l.s ??= []).push(s);
|
||
return s;
|
||
}
|
||
/**
|
||
* @template V
|
||
* @param {Source<V>} source
|
||
* @param {V} value
|
||
* @param {boolean} [should_proxy]
|
||
* @returns {V}
|
||
*/
|
||
function set(source, value, should_proxy = false) {
|
||
if (active_reaction !== null && (!untracking || (active_reaction.f & 131072) !== 0) && is_runes() && (active_reaction.f & 4325394) !== 0 && (current_sources === null || !includes.call(current_sources, source))) state_unsafe_mutation();
|
||
return internal_set(source, should_proxy ? proxy(value) : value, legacy_updates);
|
||
}
|
||
/**
|
||
* @template V
|
||
* @param {Source<V>} source
|
||
* @param {V} value
|
||
* @param {Effect[] | null} [updated_during_traversal]
|
||
* @returns {V}
|
||
*/
|
||
function internal_set(source, value, updated_during_traversal = null) {
|
||
if (!source.equals(value)) {
|
||
old_values.set(source, is_destroying_effect ? value : source.v);
|
||
var batch = Batch.ensure();
|
||
batch.capture(source, value);
|
||
if ((source.f & 2) !== 0) {
|
||
const derived = source;
|
||
if ((source.f & 2048) !== 0) execute_derived(derived);
|
||
if (batch_values === null) update_derived_status(derived);
|
||
}
|
||
source.wv = increment_write_version();
|
||
mark_reactions(source, DIRTY, updated_during_traversal);
|
||
if (is_runes() && active_effect !== null && (active_effect.f & 1024) !== 0 && (active_effect.f & 96) === 0) if (untracked_writes === null) set_untracked_writes([source]);
|
||
else untracked_writes.push(source);
|
||
if (!batch.is_fork && eager_effects.size > 0 && !eager_effects_deferred) flush_eager_effects();
|
||
}
|
||
return value;
|
||
}
|
||
function flush_eager_effects() {
|
||
eager_effects_deferred = false;
|
||
for (const effect of eager_effects) {
|
||
if ((effect.f & 1024) !== 0) set_signal_status(effect, MAYBE_DIRTY);
|
||
if (is_dirty(effect)) update_effect(effect);
|
||
}
|
||
eager_effects.clear();
|
||
}
|
||
/**
|
||
* Silently (without using `get`) increment a source
|
||
* @param {Source<number>} source
|
||
*/
|
||
function increment(source) {
|
||
set(source, source.v + 1);
|
||
}
|
||
/**
|
||
* @param {Value} signal
|
||
* @param {number} status should be DIRTY or MAYBE_DIRTY
|
||
* @param {Effect[] | null} updated_during_traversal
|
||
* @returns {void}
|
||
*/
|
||
function mark_reactions(signal, status, updated_during_traversal) {
|
||
var reactions = signal.reactions;
|
||
if (reactions === null) return;
|
||
var runes = is_runes();
|
||
var length = reactions.length;
|
||
for (var i = 0; i < length; i++) {
|
||
var reaction = reactions[i];
|
||
var flags = reaction.f;
|
||
if (!runes && reaction === active_effect) continue;
|
||
var not_dirty = (flags & DIRTY) === 0;
|
||
if (not_dirty) set_signal_status(reaction, status);
|
||
if ((flags & 2) !== 0) {
|
||
var derived = reaction;
|
||
batch_values?.delete(derived);
|
||
if ((flags & 65536) === 0) {
|
||
if (flags & 512 && (active_effect === null || (active_effect.f & 2097152) === 0)) reaction.f |= WAS_MARKED;
|
||
mark_reactions(derived, MAYBE_DIRTY, updated_during_traversal);
|
||
}
|
||
} else if (not_dirty) {
|
||
var effect = reaction;
|
||
if ((flags & 16) !== 0 && eager_block_effects !== null) eager_block_effects.add(effect);
|
||
if (updated_during_traversal !== null) updated_during_traversal.push(effect);
|
||
else schedule_effect(effect);
|
||
}
|
||
}
|
||
}
|
||
/**
|
||
* @template T
|
||
* @param {T} value
|
||
* @returns {T}
|
||
*/
|
||
function proxy(value) {
|
||
if (typeof value !== "object" || value === null || STATE_SYMBOL in value) return value;
|
||
const prototype = get_prototype_of(value);
|
||
if (prototype !== object_prototype && prototype !== array_prototype) return value;
|
||
/** @type {Map<any, Source<any>>} */
|
||
var sources = /* @__PURE__ */ new Map();
|
||
var is_proxied_array = is_array(value);
|
||
var version = /* @__PURE__ */ state(0);
|
||
var stack = null;
|
||
var parent_version = update_version;
|
||
/**
|
||
* Executes the proxy in the context of the reaction it was originally created in, if any
|
||
* @template T
|
||
* @param {() => T} fn
|
||
*/
|
||
var with_parent = (fn) => {
|
||
if (update_version === parent_version) return fn();
|
||
var reaction = active_reaction;
|
||
var version = update_version;
|
||
set_active_reaction(null);
|
||
set_update_version(parent_version);
|
||
var result = fn();
|
||
set_active_reaction(reaction);
|
||
set_update_version(version);
|
||
return result;
|
||
};
|
||
if (is_proxied_array) sources.set("length", /* @__PURE__ */ state(
|
||
/** @type {any[]} */
|
||
value.length,
|
||
stack
|
||
));
|
||
return new Proxy(value, {
|
||
defineProperty(_, prop, descriptor) {
|
||
if (!("value" in descriptor) || descriptor.configurable === false || descriptor.enumerable === false || descriptor.writable === false) state_descriptors_fixed();
|
||
var s = sources.get(prop);
|
||
if (s === void 0) with_parent(() => {
|
||
var s = /* @__PURE__ */ state(descriptor.value, stack);
|
||
sources.set(prop, s);
|
||
return s;
|
||
});
|
||
else set(s, descriptor.value, true);
|
||
return true;
|
||
},
|
||
deleteProperty(target, prop) {
|
||
var s = sources.get(prop);
|
||
if (s === void 0) {
|
||
if (prop in target) {
|
||
const s = with_parent(() => /* @__PURE__ */ state(UNINITIALIZED, stack));
|
||
sources.set(prop, s);
|
||
increment(version);
|
||
}
|
||
} else {
|
||
set(s, UNINITIALIZED);
|
||
increment(version);
|
||
}
|
||
return true;
|
||
},
|
||
get(target, prop, receiver) {
|
||
if (prop === STATE_SYMBOL) return value;
|
||
var s = sources.get(prop);
|
||
var exists = prop in target;
|
||
if (s === void 0 && (!exists || get_descriptor(target, prop)?.writable)) {
|
||
s = with_parent(() => {
|
||
return /* @__PURE__ */ state(proxy(exists ? target[prop] : UNINITIALIZED), stack);
|
||
});
|
||
sources.set(prop, s);
|
||
}
|
||
if (s !== void 0) {
|
||
var v = get(s);
|
||
return v === UNINITIALIZED ? void 0 : v;
|
||
}
|
||
return Reflect.get(target, prop, receiver);
|
||
},
|
||
getOwnPropertyDescriptor(target, prop) {
|
||
var descriptor = Reflect.getOwnPropertyDescriptor(target, prop);
|
||
if (descriptor && "value" in descriptor) {
|
||
var s = sources.get(prop);
|
||
if (s) descriptor.value = get(s);
|
||
} else if (descriptor === void 0) {
|
||
var source = sources.get(prop);
|
||
var value = source?.v;
|
||
if (source !== void 0 && value !== UNINITIALIZED) return {
|
||
enumerable: true,
|
||
configurable: true,
|
||
value,
|
||
writable: true
|
||
};
|
||
}
|
||
return descriptor;
|
||
},
|
||
has(target, prop) {
|
||
if (prop === STATE_SYMBOL) return true;
|
||
var s = sources.get(prop);
|
||
var has = s !== void 0 && s.v !== UNINITIALIZED || Reflect.has(target, prop);
|
||
if (s !== void 0 || active_effect !== null && (!has || get_descriptor(target, prop)?.writable)) {
|
||
if (s === void 0) {
|
||
s = with_parent(() => {
|
||
return /* @__PURE__ */ state(has ? proxy(target[prop]) : UNINITIALIZED, stack);
|
||
});
|
||
sources.set(prop, s);
|
||
}
|
||
if (get(s) === UNINITIALIZED) return false;
|
||
}
|
||
return has;
|
||
},
|
||
set(target, prop, value, receiver) {
|
||
var s = sources.get(prop);
|
||
var has = prop in target;
|
||
if (is_proxied_array && prop === "length") for (var i = value; i < s.v; i += 1) {
|
||
var other_s = sources.get(i + "");
|
||
if (other_s !== void 0) set(other_s, UNINITIALIZED);
|
||
else if (i in target) {
|
||
other_s = with_parent(() => /* @__PURE__ */ state(UNINITIALIZED, stack));
|
||
sources.set(i + "", other_s);
|
||
}
|
||
}
|
||
if (s === void 0) {
|
||
if (!has || get_descriptor(target, prop)?.writable) {
|
||
s = with_parent(() => /* @__PURE__ */ state(void 0, stack));
|
||
set(s, proxy(value));
|
||
sources.set(prop, s);
|
||
}
|
||
} else {
|
||
has = s.v !== UNINITIALIZED;
|
||
var p = with_parent(() => proxy(value));
|
||
set(s, p);
|
||
}
|
||
var descriptor = Reflect.getOwnPropertyDescriptor(target, prop);
|
||
if (descriptor?.set) descriptor.set.call(receiver, value);
|
||
if (!has) {
|
||
if (is_proxied_array && typeof prop === "string") {
|
||
var ls = sources.get("length");
|
||
var n = Number(prop);
|
||
if (Number.isInteger(n) && n >= ls.v) set(ls, n + 1);
|
||
}
|
||
increment(version);
|
||
}
|
||
return true;
|
||
},
|
||
ownKeys(target) {
|
||
get(version);
|
||
var own_keys = Reflect.ownKeys(target).filter((key) => {
|
||
var source = sources.get(key);
|
||
return source === void 0 || source.v !== UNINITIALIZED;
|
||
});
|
||
for (var [key, source] of sources) if (source.v !== UNINITIALIZED && !(key in target)) own_keys.push(key);
|
||
return own_keys;
|
||
},
|
||
setPrototypeOf() {
|
||
state_prototype_fixed();
|
||
}
|
||
});
|
||
}
|
||
/**
|
||
* @param {any} value
|
||
*/
|
||
function get_proxied_value(value) {
|
||
try {
|
||
if (value !== null && typeof value === "object" && STATE_SYMBOL in value) return value[STATE_SYMBOL];
|
||
} catch {}
|
||
return value;
|
||
}
|
||
/**
|
||
* @param {any} a
|
||
* @param {any} b
|
||
*/
|
||
function is(a, b) {
|
||
return Object.is(get_proxied_value(a), get_proxied_value(b));
|
||
}
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/client/dom/operations.js
|
||
/** @import { Effect, TemplateNode } from '#client' */
|
||
/** @type {Window} */
|
||
var $window;
|
||
/** @type {boolean} */
|
||
var is_firefox;
|
||
/** @type {() => Node | null} */
|
||
var first_child_getter;
|
||
/** @type {() => Node | null} */
|
||
var next_sibling_getter;
|
||
/**
|
||
* Initialize these lazily to avoid issues when using the runtime in a server context
|
||
* where these globals are not available while avoiding a separate server entry point
|
||
*/
|
||
function init_operations() {
|
||
if ($window !== void 0) return;
|
||
$window = window;
|
||
is_firefox = /Firefox/.test(navigator.userAgent);
|
||
var element_prototype = Element.prototype;
|
||
var node_prototype = Node.prototype;
|
||
var text_prototype = Text.prototype;
|
||
first_child_getter = get_descriptor(node_prototype, "firstChild").get;
|
||
next_sibling_getter = get_descriptor(node_prototype, "nextSibling").get;
|
||
if (is_extensible(element_prototype)) {
|
||
element_prototype.__click = void 0;
|
||
element_prototype.__className = void 0;
|
||
element_prototype.__attributes = null;
|
||
element_prototype.__style = void 0;
|
||
element_prototype.__e = void 0;
|
||
}
|
||
if (is_extensible(text_prototype)) text_prototype.__t = void 0;
|
||
}
|
||
/**
|
||
* @param {string} value
|
||
* @returns {Text}
|
||
*/
|
||
function create_text(value = "") {
|
||
return document.createTextNode(value);
|
||
}
|
||
/**
|
||
* @template {Node} N
|
||
* @param {N} node
|
||
*/
|
||
/* @__NO_SIDE_EFFECTS__ */
|
||
function get_first_child(node) {
|
||
return first_child_getter.call(node);
|
||
}
|
||
/**
|
||
* @template {Node} N
|
||
* @param {N} node
|
||
*/
|
||
/* @__NO_SIDE_EFFECTS__ */
|
||
function get_next_sibling(node) {
|
||
return next_sibling_getter.call(node);
|
||
}
|
||
/**
|
||
* Don't mark this as side-effect-free, hydration needs to walk all nodes
|
||
* @template {Node} N
|
||
* @param {N} node
|
||
* @param {boolean} is_text
|
||
* @returns {TemplateNode | null}
|
||
*/
|
||
function child(node, is_text) {
|
||
if (!hydrating) return /* @__PURE__ */ get_first_child(node);
|
||
var child = /* @__PURE__ */ get_first_child(hydrate_node);
|
||
if (child === null) child = hydrate_node.appendChild(create_text());
|
||
else if (is_text && child.nodeType !== 3) {
|
||
var text = create_text();
|
||
child?.before(text);
|
||
set_hydrate_node(text);
|
||
return text;
|
||
}
|
||
if (is_text) merge_text_nodes(child);
|
||
set_hydrate_node(child);
|
||
return child;
|
||
}
|
||
/**
|
||
* Don't mark this as side-effect-free, hydration needs to walk all nodes
|
||
* @param {TemplateNode} node
|
||
* @param {boolean} [is_text]
|
||
* @returns {TemplateNode | null}
|
||
*/
|
||
function first_child(node, is_text = false) {
|
||
if (!hydrating) {
|
||
var first = /* @__PURE__ */ get_first_child(node);
|
||
if (first instanceof Comment && first.data === "") return /* @__PURE__ */ get_next_sibling(first);
|
||
return first;
|
||
}
|
||
if (is_text) {
|
||
if (hydrate_node?.nodeType !== 3) {
|
||
var text = create_text();
|
||
hydrate_node?.before(text);
|
||
set_hydrate_node(text);
|
||
return text;
|
||
}
|
||
merge_text_nodes(hydrate_node);
|
||
}
|
||
return hydrate_node;
|
||
}
|
||
/**
|
||
* Don't mark this as side-effect-free, hydration needs to walk all nodes
|
||
* @param {TemplateNode} node
|
||
* @param {number} count
|
||
* @param {boolean} is_text
|
||
* @returns {TemplateNode | null}
|
||
*/
|
||
function sibling(node, count = 1, is_text = false) {
|
||
let next_sibling = hydrating ? hydrate_node : node;
|
||
var last_sibling;
|
||
while (count--) {
|
||
last_sibling = next_sibling;
|
||
next_sibling = /* @__PURE__ */ get_next_sibling(next_sibling);
|
||
}
|
||
if (!hydrating) return next_sibling;
|
||
if (is_text) {
|
||
if (next_sibling?.nodeType !== 3) {
|
||
var text = create_text();
|
||
if (next_sibling === null) last_sibling?.after(text);
|
||
else next_sibling.before(text);
|
||
set_hydrate_node(text);
|
||
return text;
|
||
}
|
||
merge_text_nodes(next_sibling);
|
||
}
|
||
set_hydrate_node(next_sibling);
|
||
return next_sibling;
|
||
}
|
||
/**
|
||
* @template {Node} N
|
||
* @param {N} node
|
||
* @returns {void}
|
||
*/
|
||
function clear_text_content(node) {
|
||
node.textContent = "";
|
||
}
|
||
/**
|
||
* Returns `true` if we're updating the current block, for example `condition` in
|
||
* an `{#if condition}` block just changed. In this case, the branch should be
|
||
* appended (or removed) at the same time as other updates within the
|
||
* current `<svelte:boundary>`
|
||
*/
|
||
function should_defer_append() {
|
||
if (!async_mode_flag) return false;
|
||
if (eager_block_effects !== null) return false;
|
||
return (active_effect.f & REACTION_RAN) !== 0;
|
||
}
|
||
/**
|
||
* @template {keyof HTMLElementTagNameMap | string} T
|
||
* @param {T} tag
|
||
* @param {string} [namespace]
|
||
* @param {string} [is]
|
||
* @returns {T extends keyof HTMLElementTagNameMap ? HTMLElementTagNameMap[T] : Element}
|
||
*/
|
||
function create_element(tag, namespace, is) {
|
||
let options = is ? { is } : void 0;
|
||
return document.createElementNS(namespace ?? "http://www.w3.org/1999/xhtml", tag, options);
|
||
}
|
||
/**
|
||
* Browsers split text nodes larger than 65536 bytes when parsing.
|
||
* For hydration to succeed, we need to stitch them back together
|
||
* @param {Text} text
|
||
*/
|
||
function merge_text_nodes(text) {
|
||
if (text.nodeValue.length < 65536) return;
|
||
let next = text.nextSibling;
|
||
while (next !== null && next.nodeType === 3) {
|
||
next.remove();
|
||
/** @type {string} */ text.nodeValue += next.nodeValue;
|
||
next = text.nextSibling;
|
||
}
|
||
}
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/client/dom/elements/misc.js
|
||
/**
|
||
* The child of a textarea actually corresponds to the defaultValue property, so we need
|
||
* to remove it upon hydration to avoid a bug when someone resets the form value.
|
||
* @param {HTMLTextAreaElement} dom
|
||
* @returns {void}
|
||
*/
|
||
function remove_textarea_child(dom) {
|
||
if (hydrating && /* @__PURE__ */ get_first_child(dom) !== null) clear_text_content(dom);
|
||
}
|
||
var listening_to_form_reset = false;
|
||
function add_form_reset_listener() {
|
||
if (!listening_to_form_reset) {
|
||
listening_to_form_reset = true;
|
||
document.addEventListener("reset", (evt) => {
|
||
Promise.resolve().then(() => {
|
||
if (!evt.defaultPrevented) for (const e of evt.target.elements) e.__on_r?.();
|
||
});
|
||
}, { capture: true });
|
||
}
|
||
}
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/client/dom/elements/bindings/shared.js
|
||
/**
|
||
* @template T
|
||
* @param {() => T} fn
|
||
*/
|
||
function without_reactive_context(fn) {
|
||
var previous_reaction = active_reaction;
|
||
var previous_effect = active_effect;
|
||
set_active_reaction(null);
|
||
set_active_effect(null);
|
||
try {
|
||
return fn();
|
||
} finally {
|
||
set_active_reaction(previous_reaction);
|
||
set_active_effect(previous_effect);
|
||
}
|
||
}
|
||
/**
|
||
* Listen to the given event, and then instantiate a global form reset listener if not already done,
|
||
* to notify all bindings when the form is reset
|
||
* @param {HTMLElement} element
|
||
* @param {string} event
|
||
* @param {(is_reset?: true) => void} handler
|
||
* @param {(is_reset?: true) => void} [on_reset]
|
||
*/
|
||
function listen_to_event_and_reset_event(element, event, handler, on_reset = handler) {
|
||
element.addEventListener(event, () => without_reactive_context(handler));
|
||
const prev = element.__on_r;
|
||
if (prev) element.__on_r = () => {
|
||
prev();
|
||
on_reset(true);
|
||
};
|
||
else element.__on_r = () => on_reset(true);
|
||
add_form_reset_listener();
|
||
}
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/client/reactivity/effects.js
|
||
/** @import { Blocker, ComponentContext, ComponentContextLegacy, Derived, Effect, TemplateNode, TransitionManager } from '#client' */
|
||
/**
|
||
* @param {'$effect' | '$effect.pre' | '$inspect'} rune
|
||
*/
|
||
function validate_effect(rune) {
|
||
if (active_effect === null) {
|
||
if (active_reaction === null) effect_orphan(rune);
|
||
effect_in_unowned_derived();
|
||
}
|
||
if (is_destroying_effect) effect_in_teardown(rune);
|
||
}
|
||
/**
|
||
* @param {Effect} effect
|
||
* @param {Effect} parent_effect
|
||
*/
|
||
function push_effect(effect, parent_effect) {
|
||
var parent_last = parent_effect.last;
|
||
if (parent_last === null) parent_effect.last = parent_effect.first = effect;
|
||
else {
|
||
parent_last.next = effect;
|
||
effect.prev = parent_last;
|
||
parent_effect.last = effect;
|
||
}
|
||
}
|
||
/**
|
||
* @param {number} type
|
||
* @param {null | (() => void | (() => void))} fn
|
||
* @returns {Effect}
|
||
*/
|
||
function create_effect(type, fn) {
|
||
var parent = active_effect;
|
||
if (parent !== null && (parent.f & 8192) !== 0) type |= INERT;
|
||
/** @type {Effect} */
|
||
var effect = {
|
||
ctx: component_context,
|
||
deps: null,
|
||
nodes: null,
|
||
f: type | DIRTY | 512,
|
||
first: null,
|
||
fn,
|
||
last: null,
|
||
next: null,
|
||
parent,
|
||
b: parent && parent.b,
|
||
prev: null,
|
||
teardown: null,
|
||
wv: 0,
|
||
ac: null
|
||
};
|
||
current_batch?.register_created_effect(effect);
|
||
/** @type {Effect | null} */
|
||
var e = effect;
|
||
if ((type & 4) !== 0) if (collected_effects !== null) collected_effects.push(effect);
|
||
else Batch.ensure().schedule(effect);
|
||
else if (fn !== null) {
|
||
try {
|
||
update_effect(effect);
|
||
} catch (e) {
|
||
destroy_effect(effect);
|
||
throw e;
|
||
}
|
||
if (e.deps === null && e.teardown === null && e.nodes === null && e.first === e.last && (e.f & 524288) === 0) {
|
||
e = e.first;
|
||
if ((type & 16) !== 0 && (type & 65536) !== 0 && e !== null) e.f |= EFFECT_TRANSPARENT;
|
||
}
|
||
}
|
||
if (e !== null) {
|
||
e.parent = parent;
|
||
if (parent !== null) push_effect(e, parent);
|
||
if (active_reaction !== null && (active_reaction.f & 2) !== 0 && (type & 64) === 0) {
|
||
var derived = active_reaction;
|
||
(derived.effects ??= []).push(e);
|
||
}
|
||
}
|
||
return effect;
|
||
}
|
||
/**
|
||
* Internal representation of `$effect.tracking()`
|
||
* @returns {boolean}
|
||
*/
|
||
function effect_tracking() {
|
||
return active_reaction !== null && !untracking;
|
||
}
|
||
/**
|
||
* @param {() => void} fn
|
||
*/
|
||
function teardown(fn) {
|
||
const effect = create_effect(8, null);
|
||
set_signal_status(effect, CLEAN);
|
||
effect.teardown = fn;
|
||
return effect;
|
||
}
|
||
/**
|
||
* Internal representation of `$effect(...)`
|
||
* @param {() => void | (() => void)} fn
|
||
*/
|
||
function user_effect(fn) {
|
||
validate_effect("$effect");
|
||
var flags = active_effect.f;
|
||
if (!active_reaction && (flags & 32) !== 0 && (flags & 32768) === 0) {
|
||
var context = component_context;
|
||
(context.e ??= []).push(fn);
|
||
} else return create_user_effect(fn);
|
||
}
|
||
/**
|
||
* @param {() => void | (() => void)} fn
|
||
*/
|
||
function create_user_effect(fn) {
|
||
return create_effect(4 | USER_EFFECT, fn);
|
||
}
|
||
/**
|
||
* Internal representation of `$effect.pre(...)`
|
||
* @param {() => void | (() => void)} fn
|
||
* @returns {Effect}
|
||
*/
|
||
function user_pre_effect(fn) {
|
||
validate_effect("$effect.pre");
|
||
return create_effect(8 | USER_EFFECT, fn);
|
||
}
|
||
/**
|
||
* An effect root whose children can transition out
|
||
* @param {() => void} fn
|
||
* @returns {(options?: { outro?: boolean }) => Promise<void>}
|
||
*/
|
||
function component_root(fn) {
|
||
Batch.ensure();
|
||
const effect = create_effect(64 | EFFECT_PRESERVED, fn);
|
||
return (options = {}) => {
|
||
return new Promise((fulfil) => {
|
||
if (options.outro) pause_effect(effect, () => {
|
||
destroy_effect(effect);
|
||
fulfil(void 0);
|
||
});
|
||
else {
|
||
destroy_effect(effect);
|
||
fulfil(void 0);
|
||
}
|
||
});
|
||
};
|
||
}
|
||
/**
|
||
* @param {() => void | (() => void)} fn
|
||
* @returns {Effect}
|
||
*/
|
||
function effect(fn) {
|
||
return create_effect(4, fn);
|
||
}
|
||
/**
|
||
* @param {() => void | (() => void)} fn
|
||
* @returns {Effect}
|
||
*/
|
||
function async_effect(fn) {
|
||
return create_effect(ASYNC | EFFECT_PRESERVED, fn);
|
||
}
|
||
/**
|
||
* @param {() => void | (() => void)} fn
|
||
* @returns {Effect}
|
||
*/
|
||
function render_effect(fn, flags = 0) {
|
||
return create_effect(8 | flags, fn);
|
||
}
|
||
/**
|
||
* @param {(...expressions: any) => void | (() => void)} fn
|
||
* @param {Array<() => any>} sync
|
||
* @param {Array<() => Promise<any>>} async
|
||
* @param {Blocker[]} blockers
|
||
*/
|
||
function template_effect(fn, sync = [], async = [], blockers = []) {
|
||
flatten(blockers, sync, async, (values) => {
|
||
create_effect(8, () => fn(...values.map(get)));
|
||
});
|
||
}
|
||
/**
|
||
* @param {(() => void)} fn
|
||
* @param {number} flags
|
||
*/
|
||
function block(fn, flags = 0) {
|
||
return create_effect(16 | flags, fn);
|
||
}
|
||
/**
|
||
* @param {(() => void)} fn
|
||
*/
|
||
function branch(fn) {
|
||
return create_effect(32 | EFFECT_PRESERVED, fn);
|
||
}
|
||
/**
|
||
* @param {Effect} effect
|
||
*/
|
||
function execute_effect_teardown(effect) {
|
||
var teardown = effect.teardown;
|
||
if (teardown !== null) {
|
||
const previously_destroying_effect = is_destroying_effect;
|
||
const previous_reaction = active_reaction;
|
||
set_is_destroying_effect(true);
|
||
set_active_reaction(null);
|
||
try {
|
||
teardown.call(null);
|
||
} finally {
|
||
set_is_destroying_effect(previously_destroying_effect);
|
||
set_active_reaction(previous_reaction);
|
||
}
|
||
}
|
||
}
|
||
/**
|
||
* @param {Effect} signal
|
||
* @param {boolean} remove_dom
|
||
* @returns {void}
|
||
*/
|
||
function destroy_effect_children(signal, remove_dom = false) {
|
||
var effect = signal.first;
|
||
signal.first = signal.last = null;
|
||
while (effect !== null) {
|
||
const controller = effect.ac;
|
||
if (controller !== null) without_reactive_context(() => {
|
||
controller.abort(STALE_REACTION);
|
||
});
|
||
var next = effect.next;
|
||
if ((effect.f & 64) !== 0) effect.parent = null;
|
||
else destroy_effect(effect, remove_dom);
|
||
effect = next;
|
||
}
|
||
}
|
||
/**
|
||
* @param {Effect} signal
|
||
* @returns {void}
|
||
*/
|
||
function destroy_block_effect_children(signal) {
|
||
var effect = signal.first;
|
||
while (effect !== null) {
|
||
var next = effect.next;
|
||
if ((effect.f & 32) === 0) destroy_effect(effect);
|
||
effect = next;
|
||
}
|
||
}
|
||
/**
|
||
* @param {Effect} effect
|
||
* @param {boolean} [remove_dom]
|
||
* @returns {void}
|
||
*/
|
||
function destroy_effect(effect, remove_dom = true) {
|
||
var removed = false;
|
||
if ((remove_dom || (effect.f & 262144) !== 0) && effect.nodes !== null && effect.nodes.end !== null) {
|
||
remove_effect_dom(effect.nodes.start, effect.nodes.end);
|
||
removed = true;
|
||
}
|
||
set_signal_status(effect, DESTROYING);
|
||
destroy_effect_children(effect, remove_dom && !removed);
|
||
remove_reactions(effect, 0);
|
||
var transitions = effect.nodes && effect.nodes.t;
|
||
if (transitions !== null) for (const transition of transitions) transition.stop();
|
||
execute_effect_teardown(effect);
|
||
effect.f ^= DESTROYING;
|
||
effect.f |= DESTROYED;
|
||
var parent = effect.parent;
|
||
if (parent !== null && parent.first !== null) unlink_effect(effect);
|
||
effect.next = effect.prev = effect.teardown = effect.ctx = effect.deps = effect.fn = effect.nodes = effect.ac = effect.b = null;
|
||
}
|
||
/**
|
||
*
|
||
* @param {TemplateNode | null} node
|
||
* @param {TemplateNode} end
|
||
*/
|
||
function remove_effect_dom(node, end) {
|
||
while (node !== null) {
|
||
/** @type {TemplateNode | null} */
|
||
var next = node === end ? null : /* @__PURE__ */ get_next_sibling(node);
|
||
node.remove();
|
||
node = next;
|
||
}
|
||
}
|
||
/**
|
||
* Detach an effect from the effect tree, freeing up memory and
|
||
* reducing the amount of work that happens on subsequent traversals
|
||
* @param {Effect} effect
|
||
*/
|
||
function unlink_effect(effect) {
|
||
var parent = effect.parent;
|
||
var prev = effect.prev;
|
||
var next = effect.next;
|
||
if (prev !== null) prev.next = next;
|
||
if (next !== null) next.prev = prev;
|
||
if (parent !== null) {
|
||
if (parent.first === effect) parent.first = next;
|
||
if (parent.last === effect) parent.last = prev;
|
||
}
|
||
}
|
||
/**
|
||
* When a block effect is removed, we don't immediately destroy it or yank it
|
||
* out of the DOM, because it might have transitions. Instead, we 'pause' it.
|
||
* It stays around (in memory, and in the DOM) until outro transitions have
|
||
* completed, and if the state change is reversed then we _resume_ it.
|
||
* A paused effect does not update, and the DOM subtree becomes inert.
|
||
* @param {Effect} effect
|
||
* @param {() => void} [callback]
|
||
* @param {boolean} [destroy]
|
||
*/
|
||
function pause_effect(effect, callback, destroy = true) {
|
||
/** @type {TransitionManager[]} */
|
||
var transitions = [];
|
||
pause_children(effect, transitions, true);
|
||
var fn = () => {
|
||
if (destroy) destroy_effect(effect);
|
||
if (callback) callback();
|
||
};
|
||
var remaining = transitions.length;
|
||
if (remaining > 0) {
|
||
var check = () => --remaining || fn();
|
||
for (var transition of transitions) transition.out(check);
|
||
} else fn();
|
||
}
|
||
/**
|
||
* @param {Effect} effect
|
||
* @param {TransitionManager[]} transitions
|
||
* @param {boolean} local
|
||
*/
|
||
function pause_children(effect, transitions, local) {
|
||
if ((effect.f & 8192) !== 0) return;
|
||
effect.f ^= INERT;
|
||
var t = effect.nodes && effect.nodes.t;
|
||
if (t !== null) {
|
||
for (const transition of t) if (transition.is_global || local) transitions.push(transition);
|
||
}
|
||
var child = effect.first;
|
||
while (child !== null) {
|
||
var sibling = child.next;
|
||
if ((child.f & 64) === 0) {
|
||
var transparent = (child.f & 65536) !== 0 || (child.f & 32) !== 0 && (effect.f & 16) !== 0;
|
||
pause_children(child, transitions, transparent ? local : false);
|
||
}
|
||
child = sibling;
|
||
}
|
||
}
|
||
/**
|
||
* The opposite of `pause_effect`. We call this if (for example)
|
||
* `x` becomes falsy then truthy: `{#if x}...{/if}`
|
||
* @param {Effect} effect
|
||
*/
|
||
function resume_effect(effect) {
|
||
resume_children(effect, true);
|
||
}
|
||
/**
|
||
* @param {Effect} effect
|
||
* @param {boolean} local
|
||
*/
|
||
function resume_children(effect, local) {
|
||
if ((effect.f & 8192) === 0) return;
|
||
effect.f ^= INERT;
|
||
if ((effect.f & 1024) === 0) {
|
||
set_signal_status(effect, DIRTY);
|
||
Batch.ensure().schedule(effect);
|
||
}
|
||
var child = effect.first;
|
||
while (child !== null) {
|
||
var sibling = child.next;
|
||
var transparent = (child.f & 65536) !== 0 || (child.f & 32) !== 0;
|
||
resume_children(child, transparent ? local : false);
|
||
child = sibling;
|
||
}
|
||
var t = effect.nodes && effect.nodes.t;
|
||
if (t !== null) {
|
||
for (const transition of t) if (transition.is_global || local) transition.in();
|
||
}
|
||
}
|
||
/**
|
||
* @param {Effect} effect
|
||
* @param {DocumentFragment} fragment
|
||
*/
|
||
function move_effect(effect, fragment) {
|
||
if (!effect.nodes) return;
|
||
/** @type {TemplateNode | null} */
|
||
var node = effect.nodes.start;
|
||
var end = effect.nodes.end;
|
||
while (node !== null) {
|
||
/** @type {TemplateNode | null} */
|
||
var next = node === end ? null : /* @__PURE__ */ get_next_sibling(node);
|
||
fragment.append(node);
|
||
node = next;
|
||
}
|
||
}
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/client/legacy.js
|
||
/**
|
||
* @type {Set<Value> | null}
|
||
* @deprecated
|
||
*/
|
||
var captured_signals = null;
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/client/runtime.js
|
||
/** @import { Derived, Effect, Reaction, Source, Value } from '#client' */
|
||
var is_updating_effect = false;
|
||
var is_destroying_effect = false;
|
||
/** @param {boolean} value */
|
||
function set_is_destroying_effect(value) {
|
||
is_destroying_effect = value;
|
||
}
|
||
/** @type {null | Reaction} */
|
||
var active_reaction = null;
|
||
var untracking = false;
|
||
/** @param {null | Reaction} reaction */
|
||
function set_active_reaction(reaction) {
|
||
active_reaction = reaction;
|
||
}
|
||
/** @type {null | Effect} */
|
||
var active_effect = null;
|
||
/** @param {null | Effect} effect */
|
||
function set_active_effect(effect) {
|
||
active_effect = effect;
|
||
}
|
||
/**
|
||
* When sources are created within a reaction, reading and writing
|
||
* them within that reaction should not cause a re-run
|
||
* @type {null | Source[]}
|
||
*/
|
||
var current_sources = null;
|
||
/** @param {Value} value */
|
||
function push_reaction_value(value) {
|
||
if (active_reaction !== null && (!async_mode_flag || (active_reaction.f & 2) !== 0)) if (current_sources === null) current_sources = [value];
|
||
else current_sources.push(value);
|
||
}
|
||
/**
|
||
* The dependencies of the reaction that is currently being executed. In many cases,
|
||
* the dependencies are unchanged between runs, and so this will be `null` unless
|
||
* and until a new dependency is accessed — we track this via `skipped_deps`
|
||
* @type {null | Value[]}
|
||
*/
|
||
var new_deps = null;
|
||
var skipped_deps = 0;
|
||
/**
|
||
* Tracks writes that the effect it's executed in doesn't listen to yet,
|
||
* so that the dependency can be added to the effect later on if it then reads it
|
||
* @type {null | Source[]}
|
||
*/
|
||
var untracked_writes = null;
|
||
/** @param {null | Source[]} value */
|
||
function set_untracked_writes(value) {
|
||
untracked_writes = value;
|
||
}
|
||
/**
|
||
* @type {number} Used by sources and deriveds for handling updates.
|
||
* Version starts from 1 so that unowned deriveds differentiate between a created effect and a run one for tracing
|
||
**/
|
||
var write_version = 1;
|
||
/** @type {number} Used to version each read of a source of derived to avoid duplicating depedencies inside a reaction */
|
||
var read_version = 0;
|
||
var update_version = read_version;
|
||
/** @param {number} value */
|
||
function set_update_version(value) {
|
||
update_version = value;
|
||
}
|
||
function increment_write_version() {
|
||
return ++write_version;
|
||
}
|
||
/**
|
||
* Determines whether a derived or effect is dirty.
|
||
* If it is MAYBE_DIRTY, will set the status to CLEAN
|
||
* @param {Reaction} reaction
|
||
* @returns {boolean}
|
||
*/
|
||
function is_dirty(reaction) {
|
||
var flags = reaction.f;
|
||
if ((flags & 2048) !== 0) return true;
|
||
if (flags & 2) reaction.f &= ~WAS_MARKED;
|
||
if ((flags & 4096) !== 0) {
|
||
var dependencies = reaction.deps;
|
||
var length = dependencies.length;
|
||
for (var i = 0; i < length; i++) {
|
||
var dependency = dependencies[i];
|
||
if (is_dirty(dependency)) update_derived(dependency);
|
||
if (dependency.wv > reaction.wv) return true;
|
||
}
|
||
if ((flags & 512) !== 0 && batch_values === null) set_signal_status(reaction, CLEAN);
|
||
}
|
||
return false;
|
||
}
|
||
/**
|
||
* @param {Value} signal
|
||
* @param {Effect} effect
|
||
* @param {boolean} [root]
|
||
*/
|
||
function schedule_possible_effect_self_invalidation(signal, effect, root = true) {
|
||
var reactions = signal.reactions;
|
||
if (reactions === null) return;
|
||
if (!async_mode_flag && current_sources !== null && includes.call(current_sources, signal)) return;
|
||
for (var i = 0; i < reactions.length; i++) {
|
||
var reaction = reactions[i];
|
||
if ((reaction.f & 2) !== 0) schedule_possible_effect_self_invalidation(reaction, effect, false);
|
||
else if (effect === reaction) {
|
||
if (root) set_signal_status(reaction, DIRTY);
|
||
else if ((reaction.f & 1024) !== 0) set_signal_status(reaction, MAYBE_DIRTY);
|
||
schedule_effect(reaction);
|
||
}
|
||
}
|
||
}
|
||
/** @param {Reaction} reaction */
|
||
function update_reaction(reaction) {
|
||
var previous_deps = new_deps;
|
||
var previous_skipped_deps = skipped_deps;
|
||
var previous_untracked_writes = untracked_writes;
|
||
var previous_reaction = active_reaction;
|
||
var previous_sources = current_sources;
|
||
var previous_component_context = component_context;
|
||
var previous_untracking = untracking;
|
||
var previous_update_version = update_version;
|
||
var flags = reaction.f;
|
||
new_deps = null;
|
||
skipped_deps = 0;
|
||
untracked_writes = null;
|
||
active_reaction = (flags & 96) === 0 ? reaction : null;
|
||
current_sources = null;
|
||
set_component_context(reaction.ctx);
|
||
untracking = false;
|
||
update_version = ++read_version;
|
||
if (reaction.ac !== null) {
|
||
without_reactive_context(() => {
|
||
/** @type {AbortController} */ reaction.ac.abort(STALE_REACTION);
|
||
});
|
||
reaction.ac = null;
|
||
}
|
||
try {
|
||
reaction.f |= REACTION_IS_UPDATING;
|
||
var fn = reaction.fn;
|
||
var result = fn();
|
||
reaction.f |= REACTION_RAN;
|
||
var deps = reaction.deps;
|
||
var is_fork = current_batch?.is_fork;
|
||
if (new_deps !== null) {
|
||
var i;
|
||
if (!is_fork) remove_reactions(reaction, skipped_deps);
|
||
if (deps !== null && skipped_deps > 0) {
|
||
deps.length = skipped_deps + new_deps.length;
|
||
for (i = 0; i < new_deps.length; i++) deps[skipped_deps + i] = new_deps[i];
|
||
} else reaction.deps = deps = new_deps;
|
||
if (effect_tracking() && (reaction.f & 512) !== 0) for (i = skipped_deps; i < deps.length; i++) (deps[i].reactions ??= []).push(reaction);
|
||
} else if (!is_fork && deps !== null && skipped_deps < deps.length) {
|
||
remove_reactions(reaction, skipped_deps);
|
||
deps.length = skipped_deps;
|
||
}
|
||
if (is_runes() && untracked_writes !== null && !untracking && deps !== null && (reaction.f & 6146) === 0) for (i = 0; i < untracked_writes.length; i++) schedule_possible_effect_self_invalidation(untracked_writes[i], reaction);
|
||
if (previous_reaction !== null && previous_reaction !== reaction) {
|
||
read_version++;
|
||
if (previous_reaction.deps !== null) for (let i = 0; i < previous_skipped_deps; i += 1) previous_reaction.deps[i].rv = read_version;
|
||
if (previous_deps !== null) for (const dep of previous_deps) dep.rv = read_version;
|
||
if (untracked_writes !== null) if (previous_untracked_writes === null) previous_untracked_writes = untracked_writes;
|
||
else previous_untracked_writes.push(...untracked_writes);
|
||
}
|
||
if ((reaction.f & 8388608) !== 0) reaction.f ^= ERROR_VALUE;
|
||
return result;
|
||
} catch (error) {
|
||
return handle_error(error);
|
||
} finally {
|
||
reaction.f ^= REACTION_IS_UPDATING;
|
||
new_deps = previous_deps;
|
||
skipped_deps = previous_skipped_deps;
|
||
untracked_writes = previous_untracked_writes;
|
||
active_reaction = previous_reaction;
|
||
current_sources = previous_sources;
|
||
set_component_context(previous_component_context);
|
||
untracking = previous_untracking;
|
||
update_version = previous_update_version;
|
||
}
|
||
}
|
||
/**
|
||
* @template V
|
||
* @param {Reaction} signal
|
||
* @param {Value<V>} dependency
|
||
* @returns {void}
|
||
*/
|
||
function remove_reaction(signal, dependency) {
|
||
let reactions = dependency.reactions;
|
||
if (reactions !== null) {
|
||
var index = index_of.call(reactions, signal);
|
||
if (index !== -1) {
|
||
var new_length = reactions.length - 1;
|
||
if (new_length === 0) reactions = dependency.reactions = null;
|
||
else {
|
||
reactions[index] = reactions[new_length];
|
||
reactions.pop();
|
||
}
|
||
}
|
||
}
|
||
if (reactions === null && (dependency.f & 2) !== 0 && (new_deps === null || !includes.call(new_deps, dependency))) {
|
||
var derived = dependency;
|
||
if ((derived.f & 512) !== 0) {
|
||
derived.f ^= 512;
|
||
derived.f &= ~WAS_MARKED;
|
||
}
|
||
if (derived.v !== UNINITIALIZED) update_derived_status(derived);
|
||
freeze_derived_effects(derived);
|
||
remove_reactions(derived, 0);
|
||
}
|
||
}
|
||
/**
|
||
* @param {Reaction} signal
|
||
* @param {number} start_index
|
||
* @returns {void}
|
||
*/
|
||
function remove_reactions(signal, start_index) {
|
||
var dependencies = signal.deps;
|
||
if (dependencies === null) return;
|
||
for (var i = start_index; i < dependencies.length; i++) remove_reaction(signal, dependencies[i]);
|
||
}
|
||
/**
|
||
* @param {Effect} effect
|
||
* @returns {void}
|
||
*/
|
||
function update_effect(effect) {
|
||
var flags = effect.f;
|
||
if ((flags & 16384) !== 0) return;
|
||
set_signal_status(effect, CLEAN);
|
||
var previous_effect = active_effect;
|
||
var was_updating_effect = is_updating_effect;
|
||
active_effect = effect;
|
||
is_updating_effect = true;
|
||
try {
|
||
if ((flags & 16777232) !== 0) destroy_block_effect_children(effect);
|
||
else destroy_effect_children(effect);
|
||
execute_effect_teardown(effect);
|
||
var teardown = update_reaction(effect);
|
||
effect.teardown = typeof teardown === "function" ? teardown : null;
|
||
effect.wv = write_version;
|
||
} finally {
|
||
is_updating_effect = was_updating_effect;
|
||
active_effect = previous_effect;
|
||
}
|
||
}
|
||
/**
|
||
* Returns a promise that resolves once any pending state changes have been applied.
|
||
* @returns {Promise<void>}
|
||
*/
|
||
async function tick() {
|
||
if (async_mode_flag) return new Promise((f) => {
|
||
requestAnimationFrame(() => f());
|
||
setTimeout(() => f());
|
||
});
|
||
await Promise.resolve();
|
||
flushSync();
|
||
}
|
||
/**
|
||
* @template V
|
||
* @param {Value<V>} signal
|
||
* @returns {V}
|
||
*/
|
||
function get(signal) {
|
||
var is_derived = (signal.f & 2) !== 0;
|
||
captured_signals?.add(signal);
|
||
if (active_reaction !== null && !untracking) {
|
||
if (!(active_effect !== null && (active_effect.f & 16384) !== 0) && (current_sources === null || !includes.call(current_sources, signal))) {
|
||
var deps = active_reaction.deps;
|
||
if ((active_reaction.f & 2097152) !== 0) {
|
||
if (signal.rv < read_version) {
|
||
signal.rv = read_version;
|
||
if (new_deps === null && deps !== null && deps[skipped_deps] === signal) skipped_deps++;
|
||
else if (new_deps === null) new_deps = [signal];
|
||
else new_deps.push(signal);
|
||
}
|
||
} else {
|
||
(active_reaction.deps ??= []).push(signal);
|
||
var reactions = signal.reactions;
|
||
if (reactions === null) signal.reactions = [active_reaction];
|
||
else if (!includes.call(reactions, active_reaction)) reactions.push(active_reaction);
|
||
}
|
||
}
|
||
}
|
||
if (is_destroying_effect && old_values.has(signal)) return old_values.get(signal);
|
||
if (is_derived) {
|
||
var derived = signal;
|
||
if (is_destroying_effect) {
|
||
var value = derived.v;
|
||
if ((derived.f & 1024) === 0 && derived.reactions !== null || depends_on_old_values(derived)) value = execute_derived(derived);
|
||
old_values.set(derived, value);
|
||
return value;
|
||
}
|
||
var should_connect = (derived.f & 512) === 0 && !untracking && active_reaction !== null && (is_updating_effect || (active_reaction.f & 512) !== 0);
|
||
var is_new = (derived.f & REACTION_RAN) === 0;
|
||
if (is_dirty(derived)) {
|
||
if (should_connect) derived.f |= 512;
|
||
update_derived(derived);
|
||
}
|
||
if (should_connect && !is_new) {
|
||
unfreeze_derived_effects(derived);
|
||
reconnect(derived);
|
||
}
|
||
}
|
||
if (batch_values?.has(signal)) return batch_values.get(signal);
|
||
if ((signal.f & 8388608) !== 0) throw signal.v;
|
||
return signal.v;
|
||
}
|
||
/**
|
||
* (Re)connect a disconnected derived, so that it is notified
|
||
* of changes in `mark_reactions`
|
||
* @param {Derived} derived
|
||
*/
|
||
function reconnect(derived) {
|
||
derived.f |= 512;
|
||
if (derived.deps === null) return;
|
||
for (const dep of derived.deps) {
|
||
(dep.reactions ??= []).push(derived);
|
||
if ((dep.f & 2) !== 0 && (dep.f & 512) === 0) {
|
||
unfreeze_derived_effects(dep);
|
||
reconnect(dep);
|
||
}
|
||
}
|
||
}
|
||
/** @param {Derived} derived */
|
||
function depends_on_old_values(derived) {
|
||
if (derived.v === UNINITIALIZED) return true;
|
||
if (derived.deps === null) return false;
|
||
for (const dep of derived.deps) {
|
||
if (old_values.has(dep)) return true;
|
||
if ((dep.f & 2) !== 0 && depends_on_old_values(dep)) return true;
|
||
}
|
||
return false;
|
||
}
|
||
/**
|
||
* When used inside a [`$derived`](https://svelte.dev/docs/svelte/$derived) or [`$effect`](https://svelte.dev/docs/svelte/$effect),
|
||
* any state read inside `fn` will not be treated as a dependency.
|
||
*
|
||
* ```ts
|
||
* $effect(() => {
|
||
* // this will run when `data` changes, but not when `time` changes
|
||
* save(data, {
|
||
* timestamp: untrack(() => time)
|
||
* });
|
||
* });
|
||
* ```
|
||
* @template T
|
||
* @param {() => T} fn
|
||
* @returns {T}
|
||
*/
|
||
function untrack(fn) {
|
||
var previous_untracking = untracking;
|
||
try {
|
||
untracking = true;
|
||
return fn();
|
||
} finally {
|
||
untracking = previous_untracking;
|
||
}
|
||
}
|
||
/**
|
||
* Possibly traverse an object and read all its properties so that they're all reactive in case this is `$state`.
|
||
* Does only check first level of an object for performance reasons (heuristic should be good for 99% of all cases).
|
||
* @param {any} value
|
||
* @returns {void}
|
||
*/
|
||
function deep_read_state(value) {
|
||
if (typeof value !== "object" || !value || value instanceof EventTarget) return;
|
||
if (STATE_SYMBOL in value) deep_read(value);
|
||
else if (!Array.isArray(value)) for (let key in value) {
|
||
const prop = value[key];
|
||
if (typeof prop === "object" && prop && STATE_SYMBOL in prop) deep_read(prop);
|
||
}
|
||
}
|
||
/**
|
||
* Deeply traverse an object and read all its properties
|
||
* so that they're all reactive in case this is `$state`
|
||
* @param {any} value
|
||
* @param {Set<any>} visited
|
||
* @returns {void}
|
||
*/
|
||
function deep_read(value, visited = /* @__PURE__ */ new Set()) {
|
||
if (typeof value === "object" && value !== null && !(value instanceof EventTarget) && !visited.has(value)) {
|
||
visited.add(value);
|
||
if (value instanceof Date) value.getTime();
|
||
for (let key in value) try {
|
||
deep_read(value[key], visited);
|
||
} catch (e) {}
|
||
const proto = get_prototype_of(value);
|
||
if (proto !== Object.prototype && proto !== Array.prototype && proto !== Map.prototype && proto !== Set.prototype && proto !== Date.prototype) {
|
||
const descriptors = get_descriptors(proto);
|
||
for (let key in descriptors) {
|
||
const get = descriptors[key].get;
|
||
if (get) try {
|
||
get.call(value);
|
||
} catch (e) {}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
/**
|
||
* Subset of delegated events which should be passive by default.
|
||
* These two are already passive via browser defaults on window, document and body.
|
||
* But since
|
||
* - we're delegating them
|
||
* - they happen often
|
||
* - they apply to mobile which is generally less performant
|
||
* we're marking them as passive by default for other elements, too.
|
||
*/
|
||
var PASSIVE_EVENTS = ["touchstart", "touchmove"];
|
||
/**
|
||
* Returns `true` if `name` is a passive event
|
||
* @param {string} name
|
||
*/
|
||
function is_passive_event(name) {
|
||
return PASSIVE_EVENTS.includes(name);
|
||
}
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/client/dom/elements/events.js
|
||
/**
|
||
* Used on elements, as a map of event type -> event handler,
|
||
* and on events themselves to track which element handled an event
|
||
*/
|
||
var event_symbol = Symbol("events");
|
||
/** @type {Set<string>} */
|
||
var all_registered_events = /* @__PURE__ */ new Set();
|
||
/** @type {Set<(events: Array<string>) => void>} */
|
||
var root_event_handles = /* @__PURE__ */ new Set();
|
||
/**
|
||
* @param {string} event_name
|
||
* @param {EventTarget} dom
|
||
* @param {EventListener} [handler]
|
||
* @param {AddEventListenerOptions} [options]
|
||
*/
|
||
function create_event(event_name, dom, handler, options = {}) {
|
||
/**
|
||
* @this {EventTarget}
|
||
*/
|
||
function target_handler(event) {
|
||
if (!options.capture) handle_event_propagation.call(dom, event);
|
||
if (!event.cancelBubble) return without_reactive_context(() => {
|
||
return handler?.call(this, event);
|
||
});
|
||
}
|
||
if (event_name.startsWith("pointer") || event_name.startsWith("touch") || event_name === "wheel") queue_micro_task(() => {
|
||
dom.addEventListener(event_name, target_handler, options);
|
||
});
|
||
else dom.addEventListener(event_name, target_handler, options);
|
||
return target_handler;
|
||
}
|
||
/**
|
||
* @param {string} event_name
|
||
* @param {Element} dom
|
||
* @param {EventListener} [handler]
|
||
* @param {boolean} [capture]
|
||
* @param {boolean} [passive]
|
||
* @returns {void}
|
||
*/
|
||
function event(event_name, dom, handler, capture, passive) {
|
||
var options = {
|
||
capture,
|
||
passive
|
||
};
|
||
var target_handler = create_event(event_name, dom, handler, options);
|
||
if (dom === document.body || dom === window || dom === document || dom instanceof HTMLMediaElement) teardown(() => {
|
||
dom.removeEventListener(event_name, target_handler, options);
|
||
});
|
||
}
|
||
/**
|
||
* @param {string} event_name
|
||
* @param {Element} element
|
||
* @param {EventListener} [handler]
|
||
* @returns {void}
|
||
*/
|
||
function delegated(event_name, element, handler) {
|
||
(element[event_symbol] ??= {})[event_name] = handler;
|
||
}
|
||
/**
|
||
* @param {Array<string>} events
|
||
* @returns {void}
|
||
*/
|
||
function delegate(events) {
|
||
for (var i = 0; i < events.length; i++) all_registered_events.add(events[i]);
|
||
for (var fn of root_event_handles) fn(events);
|
||
}
|
||
var last_propagated_event = null;
|
||
/**
|
||
* @this {EventTarget}
|
||
* @param {Event} event
|
||
* @returns {void}
|
||
*/
|
||
function handle_event_propagation(event) {
|
||
var handler_element = this;
|
||
var owner_document = handler_element.ownerDocument;
|
||
var event_name = event.type;
|
||
var path = event.composedPath?.() || [];
|
||
var current_target = path[0] || event.target;
|
||
last_propagated_event = event;
|
||
var path_idx = 0;
|
||
var handled_at = last_propagated_event === event && event[event_symbol];
|
||
if (handled_at) {
|
||
var at_idx = path.indexOf(handled_at);
|
||
if (at_idx !== -1 && (handler_element === document || handler_element === window)) {
|
||
event[event_symbol] = handler_element;
|
||
return;
|
||
}
|
||
var handler_idx = path.indexOf(handler_element);
|
||
if (handler_idx === -1) return;
|
||
if (at_idx <= handler_idx) path_idx = at_idx;
|
||
}
|
||
current_target = path[path_idx] || event.target;
|
||
if (current_target === handler_element) return;
|
||
define_property(event, "currentTarget", {
|
||
configurable: true,
|
||
get() {
|
||
return current_target || owner_document;
|
||
}
|
||
});
|
||
var previous_reaction = active_reaction;
|
||
var previous_effect = active_effect;
|
||
set_active_reaction(null);
|
||
set_active_effect(null);
|
||
try {
|
||
/**
|
||
* @type {unknown}
|
||
*/
|
||
var throw_error;
|
||
/**
|
||
* @type {unknown[]}
|
||
*/
|
||
var other_errors = [];
|
||
while (current_target !== null) {
|
||
/** @type {null | Element} */
|
||
var parent_element = current_target.assignedSlot || current_target.parentNode || current_target.host || null;
|
||
try {
|
||
var delegated = current_target[event_symbol]?.[event_name];
|
||
if (delegated != null && (!current_target.disabled || event.target === current_target)) delegated.call(current_target, event);
|
||
} catch (error) {
|
||
if (throw_error) other_errors.push(error);
|
||
else throw_error = error;
|
||
}
|
||
if (event.cancelBubble || parent_element === handler_element || parent_element === null) break;
|
||
current_target = parent_element;
|
||
}
|
||
if (throw_error) {
|
||
for (let error of other_errors) queueMicrotask(() => {
|
||
throw error;
|
||
});
|
||
throw throw_error;
|
||
}
|
||
} finally {
|
||
event[event_symbol] = handler_element;
|
||
delete event.currentTarget;
|
||
set_active_reaction(previous_reaction);
|
||
set_active_effect(previous_effect);
|
||
}
|
||
}
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/client/dom/reconciler.js
|
||
var policy = globalThis?.window?.trustedTypes && /* @__PURE__ */ globalThis.window.trustedTypes.createPolicy("svelte-trusted-html", {
|
||
/** @param {string} html */
|
||
createHTML: (html) => {
|
||
return html;
|
||
} });
|
||
/** @param {string} html */
|
||
function create_trusted_html(html) {
|
||
return policy?.createHTML(html) ?? html;
|
||
}
|
||
/**
|
||
* @param {string} html
|
||
*/
|
||
function create_fragment_from_html(html) {
|
||
var elem = create_element("template");
|
||
elem.innerHTML = create_trusted_html(html.replaceAll("<!>", "\x3C!---->"));
|
||
return elem.content;
|
||
}
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/client/dom/template.js
|
||
/** @import { Effect, EffectNodes, TemplateNode } from '#client' */
|
||
/** @import { TemplateStructure } from './types' */
|
||
/**
|
||
* @param {TemplateNode} start
|
||
* @param {TemplateNode | null} end
|
||
*/
|
||
function assign_nodes(start, end) {
|
||
var effect = active_effect;
|
||
if (effect.nodes === null) effect.nodes = {
|
||
start,
|
||
end,
|
||
a: null,
|
||
t: null
|
||
};
|
||
}
|
||
/**
|
||
* @param {string} content
|
||
* @param {number} flags
|
||
* @returns {() => Node | Node[]}
|
||
*/
|
||
/* @__NO_SIDE_EFFECTS__ */
|
||
function from_html(content, flags) {
|
||
var is_fragment = (flags & 1) !== 0;
|
||
var use_import_node = (flags & 2) !== 0;
|
||
/** @type {Node} */
|
||
var node;
|
||
/**
|
||
* Whether or not the first item is a text/element node. If not, we need to
|
||
* create an additional comment node to act as `effect.nodes.start`
|
||
*/
|
||
var has_start = !content.startsWith("<!>");
|
||
return () => {
|
||
if (hydrating) {
|
||
assign_nodes(hydrate_node, null);
|
||
return hydrate_node;
|
||
}
|
||
if (node === void 0) {
|
||
node = create_fragment_from_html(has_start ? content : "<!>" + content);
|
||
if (!is_fragment) node = /* @__PURE__ */ get_first_child(node);
|
||
}
|
||
var clone = use_import_node || is_firefox ? document.importNode(node, true) : node.cloneNode(true);
|
||
if (is_fragment) {
|
||
var start = /* @__PURE__ */ get_first_child(clone);
|
||
var end = clone.lastChild;
|
||
assign_nodes(start, end);
|
||
} else assign_nodes(clone, clone);
|
||
return clone;
|
||
};
|
||
}
|
||
/**
|
||
* Don't mark this as side-effect-free, hydration needs to walk all nodes
|
||
* @param {any} value
|
||
*/
|
||
function text(value = "") {
|
||
if (!hydrating) {
|
||
var t = create_text(value + "");
|
||
assign_nodes(t, t);
|
||
return t;
|
||
}
|
||
var node = hydrate_node;
|
||
if (node.nodeType !== 3) {
|
||
node.before(node = create_text());
|
||
set_hydrate_node(node);
|
||
} else merge_text_nodes(node);
|
||
assign_nodes(node, node);
|
||
return node;
|
||
}
|
||
/**
|
||
* @returns {TemplateNode | DocumentFragment}
|
||
*/
|
||
function comment() {
|
||
if (hydrating) {
|
||
assign_nodes(hydrate_node, null);
|
||
return hydrate_node;
|
||
}
|
||
var frag = document.createDocumentFragment();
|
||
var start = document.createComment("");
|
||
var anchor = create_text();
|
||
frag.append(start, anchor);
|
||
assign_nodes(start, anchor);
|
||
return frag;
|
||
}
|
||
/**
|
||
* Assign the created (or in hydration mode, traversed) dom elements to the current block
|
||
* and insert the elements into the dom (in client mode).
|
||
* @param {Text | Comment | Element} anchor
|
||
* @param {DocumentFragment | Element} dom
|
||
*/
|
||
function append(anchor, dom) {
|
||
if (hydrating) {
|
||
var effect = active_effect;
|
||
if ((effect.f & 32768) === 0 || effect.nodes.end === null) effect.nodes.end = hydrate_node;
|
||
hydrate_next();
|
||
return;
|
||
}
|
||
if (anchor === null) return;
|
||
anchor.before(dom);
|
||
}
|
||
/**
|
||
* @param {Element} text
|
||
* @param {string} value
|
||
* @returns {void}
|
||
*/
|
||
function set_text(text, value) {
|
||
var str = value == null ? "" : typeof value === "object" ? `${value}` : value;
|
||
if (str !== (text.__t ??= text.nodeValue)) {
|
||
text.__t = str;
|
||
text.nodeValue = `${str}`;
|
||
}
|
||
}
|
||
/**
|
||
* Mounts a component to the given target and returns the exports and potentially the props (if compiled with `accessors: true`) of the component.
|
||
* Transitions will play during the initial render unless the `intro` option is set to `false`.
|
||
*
|
||
* @template {Record<string, any>} Props
|
||
* @template {Record<string, any>} Exports
|
||
* @param {ComponentType<SvelteComponent<Props>> | Component<Props, Exports, any>} component
|
||
* @param {MountOptions<Props>} options
|
||
* @returns {Exports}
|
||
*/
|
||
function mount(component, options) {
|
||
return _mount(component, options);
|
||
}
|
||
/** @type {Map<EventTarget, Map<string, number>>} */
|
||
var listeners = /* @__PURE__ */ new Map();
|
||
/**
|
||
* @template {Record<string, any>} Exports
|
||
* @param {ComponentType<SvelteComponent<any>> | Component<any>} Component
|
||
* @param {MountOptions} options
|
||
* @returns {Exports}
|
||
*/
|
||
function _mount(Component, { target, anchor, props = {}, events, context, intro = true, transformError }) {
|
||
init_operations();
|
||
/** @type {Exports} */
|
||
var component = void 0;
|
||
var unmount = component_root(() => {
|
||
var anchor_node = anchor ?? target.appendChild(create_text());
|
||
boundary(anchor_node, { pending: () => {} }, (anchor_node) => {
|
||
push({});
|
||
var ctx = component_context;
|
||
if (context) ctx.c = context;
|
||
if (events)
|
||
/** @type {any} */ props.$$events = events;
|
||
if (hydrating) assign_nodes(anchor_node, null);
|
||
component = Component(anchor_node, props) || {};
|
||
if (hydrating) {
|
||
/** @type {Effect & { nodes: EffectNodes }} */ active_effect.nodes.end = hydrate_node;
|
||
if (hydrate_node === null || hydrate_node.nodeType !== 8 || hydrate_node.data !== "]") {
|
||
hydration_mismatch();
|
||
throw HYDRATION_ERROR;
|
||
}
|
||
}
|
||
pop();
|
||
}, transformError);
|
||
/** @type {Set<string>} */
|
||
var registered_events = /* @__PURE__ */ new Set();
|
||
/** @param {Array<string>} events */
|
||
var event_handle = (events) => {
|
||
for (var i = 0; i < events.length; i++) {
|
||
var event_name = events[i];
|
||
if (registered_events.has(event_name)) continue;
|
||
registered_events.add(event_name);
|
||
var passive = is_passive_event(event_name);
|
||
for (const node of [target, document]) {
|
||
var counts = listeners.get(node);
|
||
if (counts === void 0) {
|
||
counts = /* @__PURE__ */ new Map();
|
||
listeners.set(node, counts);
|
||
}
|
||
var count = counts.get(event_name);
|
||
if (count === void 0) {
|
||
node.addEventListener(event_name, handle_event_propagation, { passive });
|
||
counts.set(event_name, 1);
|
||
} else counts.set(event_name, count + 1);
|
||
}
|
||
}
|
||
};
|
||
event_handle(array_from(all_registered_events));
|
||
root_event_handles.add(event_handle);
|
||
return () => {
|
||
for (var event_name of registered_events) for (const node of [target, document]) {
|
||
var counts = listeners.get(node);
|
||
var count = counts.get(event_name);
|
||
if (--count == 0) {
|
||
node.removeEventListener(event_name, handle_event_propagation);
|
||
counts.delete(event_name);
|
||
if (counts.size === 0) listeners.delete(node);
|
||
} else counts.set(event_name, count);
|
||
}
|
||
root_event_handles.delete(event_handle);
|
||
if (anchor_node !== anchor) anchor_node.parentNode?.removeChild(anchor_node);
|
||
};
|
||
});
|
||
mounted_components.set(component, unmount);
|
||
return component;
|
||
}
|
||
/**
|
||
* References of the components that were mounted or hydrated.
|
||
* Uses a `WeakMap` to avoid memory leaks.
|
||
*/
|
||
var mounted_components = /* @__PURE__ */ new WeakMap();
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/client/dom/blocks/branches.js
|
||
/** @import { Effect, TemplateNode } from '#client' */
|
||
/**
|
||
* @typedef {{ effect: Effect, fragment: DocumentFragment }} Branch
|
||
*/
|
||
/**
|
||
* @template Key
|
||
*/
|
||
var BranchManager = class {
|
||
/** @type {TemplateNode} */
|
||
anchor;
|
||
/** @type {Map<Batch, Key>} */
|
||
#batches = /* @__PURE__ */ new Map();
|
||
/**
|
||
* Map of keys to effects that are currently rendered in the DOM.
|
||
* These effects are visible and actively part of the document tree.
|
||
* Example:
|
||
* ```
|
||
* {#if condition}
|
||
* foo
|
||
* {:else}
|
||
* bar
|
||
* {/if}
|
||
* ```
|
||
* Can result in the entries `true->Effect` and `false->Effect`
|
||
* @type {Map<Key, Effect>}
|
||
*/
|
||
#onscreen = /* @__PURE__ */ new Map();
|
||
/**
|
||
* Similar to #onscreen with respect to the keys, but contains branches that are not yet
|
||
* in the DOM, because their insertion is deferred.
|
||
* @type {Map<Key, Branch>}
|
||
*/
|
||
#offscreen = /* @__PURE__ */ new Map();
|
||
/**
|
||
* Keys of effects that are currently outroing
|
||
* @type {Set<Key>}
|
||
*/
|
||
#outroing = /* @__PURE__ */ new Set();
|
||
/**
|
||
* Whether to pause (i.e. outro) on change, or destroy immediately.
|
||
* This is necessary for `<svelte:element>`
|
||
*/
|
||
#transition = true;
|
||
/**
|
||
* @param {TemplateNode} anchor
|
||
* @param {boolean} transition
|
||
*/
|
||
constructor(anchor, transition = true) {
|
||
this.anchor = anchor;
|
||
this.#transition = transition;
|
||
}
|
||
/**
|
||
* @param {Batch} batch
|
||
*/
|
||
#commit = (batch) => {
|
||
if (!this.#batches.has(batch)) return;
|
||
var key = this.#batches.get(batch);
|
||
var onscreen = this.#onscreen.get(key);
|
||
if (onscreen) {
|
||
resume_effect(onscreen);
|
||
this.#outroing.delete(key);
|
||
} else {
|
||
var offscreen = this.#offscreen.get(key);
|
||
if (offscreen) {
|
||
this.#onscreen.set(key, offscreen.effect);
|
||
this.#offscreen.delete(key);
|
||
/** @type {TemplateNode} */ offscreen.fragment.lastChild.remove();
|
||
this.anchor.before(offscreen.fragment);
|
||
onscreen = offscreen.effect;
|
||
}
|
||
}
|
||
for (const [b, k] of this.#batches) {
|
||
this.#batches.delete(b);
|
||
if (b === batch) break;
|
||
const offscreen = this.#offscreen.get(k);
|
||
if (offscreen) {
|
||
destroy_effect(offscreen.effect);
|
||
this.#offscreen.delete(k);
|
||
}
|
||
}
|
||
for (const [k, effect] of this.#onscreen) {
|
||
if (k === key || this.#outroing.has(k)) continue;
|
||
const on_destroy = () => {
|
||
if (Array.from(this.#batches.values()).includes(k)) {
|
||
var fragment = document.createDocumentFragment();
|
||
move_effect(effect, fragment);
|
||
fragment.append(create_text());
|
||
this.#offscreen.set(k, {
|
||
effect,
|
||
fragment
|
||
});
|
||
} else destroy_effect(effect);
|
||
this.#outroing.delete(k);
|
||
this.#onscreen.delete(k);
|
||
};
|
||
if (this.#transition || !onscreen) {
|
||
this.#outroing.add(k);
|
||
pause_effect(effect, on_destroy, false);
|
||
} else on_destroy();
|
||
}
|
||
};
|
||
/**
|
||
* @param {Batch} batch
|
||
*/
|
||
#discard = (batch) => {
|
||
this.#batches.delete(batch);
|
||
const keys = Array.from(this.#batches.values());
|
||
for (const [k, branch] of this.#offscreen) if (!keys.includes(k)) {
|
||
destroy_effect(branch.effect);
|
||
this.#offscreen.delete(k);
|
||
}
|
||
};
|
||
/**
|
||
*
|
||
* @param {any} key
|
||
* @param {null | ((target: TemplateNode) => void)} fn
|
||
*/
|
||
ensure(key, fn) {
|
||
var batch = current_batch;
|
||
var defer = should_defer_append();
|
||
if (fn && !this.#onscreen.has(key) && !this.#offscreen.has(key)) if (defer) {
|
||
var fragment = document.createDocumentFragment();
|
||
var target = create_text();
|
||
fragment.append(target);
|
||
this.#offscreen.set(key, {
|
||
effect: branch(() => fn(target)),
|
||
fragment
|
||
});
|
||
} else this.#onscreen.set(key, branch(() => fn(this.anchor)));
|
||
this.#batches.set(batch, key);
|
||
if (defer) {
|
||
for (const [k, effect] of this.#onscreen) if (k === key) batch.unskip_effect(effect);
|
||
else batch.skip_effect(effect);
|
||
for (const [k, branch] of this.#offscreen) if (k === key) batch.unskip_effect(branch.effect);
|
||
else batch.skip_effect(branch.effect);
|
||
batch.oncommit(this.#commit);
|
||
batch.ondiscard(this.#discard);
|
||
} else {
|
||
if (hydrating) this.anchor = hydrate_node;
|
||
this.#commit(batch);
|
||
}
|
||
}
|
||
};
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/client/dom/blocks/if.js
|
||
/** @import { TemplateNode } from '#client' */
|
||
/**
|
||
* @param {TemplateNode} node
|
||
* @param {(branch: (fn: (anchor: Node) => void, key?: number | false) => void) => void} fn
|
||
* @param {boolean} [elseif] True if this is an `{:else if ...}` block rather than an `{#if ...}`, as that affects which transitions are considered 'local'
|
||
* @returns {void}
|
||
*/
|
||
function if_block(node, fn, elseif = false) {
|
||
/** @type {TemplateNode | undefined} */
|
||
var marker;
|
||
if (hydrating) {
|
||
marker = hydrate_node;
|
||
hydrate_next();
|
||
}
|
||
var branches = new BranchManager(node);
|
||
var flags = elseif ? EFFECT_TRANSPARENT : 0;
|
||
/**
|
||
* @param {number | false} key
|
||
* @param {null | ((anchor: Node) => void)} fn
|
||
*/
|
||
function update_branch(key, fn) {
|
||
if (hydrating) {
|
||
var data = read_hydration_instruction(marker);
|
||
if (key !== parseInt(data.substring(1))) {
|
||
var anchor = skip_nodes();
|
||
set_hydrate_node(anchor);
|
||
branches.anchor = anchor;
|
||
set_hydrating(false);
|
||
branches.ensure(key, fn);
|
||
set_hydrating(true);
|
||
return;
|
||
}
|
||
}
|
||
branches.ensure(key, fn);
|
||
}
|
||
block(() => {
|
||
var has_branch = false;
|
||
fn((fn, key = 0) => {
|
||
has_branch = true;
|
||
update_branch(key, fn);
|
||
});
|
||
if (!has_branch) update_branch(-1, null);
|
||
}, flags);
|
||
}
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/client/dom/blocks/each.js
|
||
/** @import { EachItem, EachOutroGroup, EachState, Effect, EffectNodes, MaybeSource, Source, TemplateNode, TransitionManager, Value } from '#client' */
|
||
/** @import { Batch } from '../../reactivity/batch.js'; */
|
||
/**
|
||
* @param {any} _
|
||
* @param {number} i
|
||
*/
|
||
function index(_, i) {
|
||
return i;
|
||
}
|
||
/**
|
||
* Pause multiple effects simultaneously, and coordinate their
|
||
* subsequent destruction. Used in each blocks
|
||
* @param {EachState} state
|
||
* @param {Effect[]} to_destroy
|
||
* @param {null | Node} controlled_anchor
|
||
*/
|
||
function pause_effects(state, to_destroy, controlled_anchor) {
|
||
/** @type {TransitionManager[]} */
|
||
var transitions = [];
|
||
var length = to_destroy.length;
|
||
/** @type {EachOutroGroup} */
|
||
var group;
|
||
var remaining = to_destroy.length;
|
||
for (var i = 0; i < length; i++) {
|
||
let effect = to_destroy[i];
|
||
pause_effect(effect, () => {
|
||
if (group) {
|
||
group.pending.delete(effect);
|
||
group.done.add(effect);
|
||
if (group.pending.size === 0) {
|
||
var groups = state.outrogroups;
|
||
destroy_effects(state, array_from(group.done));
|
||
groups.delete(group);
|
||
if (groups.size === 0) state.outrogroups = null;
|
||
}
|
||
} else remaining -= 1;
|
||
}, false);
|
||
}
|
||
if (remaining === 0) {
|
||
var fast_path = transitions.length === 0 && controlled_anchor !== null;
|
||
if (fast_path) {
|
||
var anchor = controlled_anchor;
|
||
var parent_node = anchor.parentNode;
|
||
clear_text_content(parent_node);
|
||
parent_node.append(anchor);
|
||
state.items.clear();
|
||
}
|
||
destroy_effects(state, to_destroy, !fast_path);
|
||
} else {
|
||
group = {
|
||
pending: new Set(to_destroy),
|
||
done: /* @__PURE__ */ new Set()
|
||
};
|
||
(state.outrogroups ??= /* @__PURE__ */ new Set()).add(group);
|
||
}
|
||
}
|
||
/**
|
||
* @param {EachState} state
|
||
* @param {Effect[]} to_destroy
|
||
* @param {boolean} remove_dom
|
||
*/
|
||
function destroy_effects(state, to_destroy, remove_dom = true) {
|
||
/** @type {Set<Effect> | undefined} */
|
||
var preserved_effects;
|
||
if (state.pending.size > 0) {
|
||
preserved_effects = /* @__PURE__ */ new Set();
|
||
for (const keys of state.pending.values()) for (const key of keys) preserved_effects.add(
|
||
/** @type {EachItem} */
|
||
state.items.get(key).e
|
||
);
|
||
}
|
||
for (var i = 0; i < to_destroy.length; i++) {
|
||
var e = to_destroy[i];
|
||
if (preserved_effects?.has(e)) {
|
||
e.f |= EFFECT_OFFSCREEN;
|
||
move_effect(e, document.createDocumentFragment());
|
||
} else destroy_effect(to_destroy[i], remove_dom);
|
||
}
|
||
}
|
||
/** @type {TemplateNode} */
|
||
var offscreen_anchor;
|
||
/**
|
||
* @template V
|
||
* @param {Element | Comment} node The next sibling node, or the parent node if this is a 'controlled' block
|
||
* @param {number} flags
|
||
* @param {() => V[]} get_collection
|
||
* @param {(value: V, index: number) => any} get_key
|
||
* @param {(anchor: Node, item: MaybeSource<V>, index: MaybeSource<number>) => void} render_fn
|
||
* @param {null | ((anchor: Node) => void)} fallback_fn
|
||
* @returns {void}
|
||
*/
|
||
function each(node, flags, get_collection, get_key, render_fn, fallback_fn = null) {
|
||
var anchor = node;
|
||
/** @type {Map<any, EachItem>} */
|
||
var items = /* @__PURE__ */ new Map();
|
||
if ((flags & 4) !== 0) {
|
||
var parent_node = node;
|
||
anchor = hydrating ? set_hydrate_node(/* @__PURE__ */ get_first_child(parent_node)) : parent_node.appendChild(create_text());
|
||
}
|
||
if (hydrating) hydrate_next();
|
||
/** @type {Effect | null} */
|
||
var fallback = null;
|
||
var each_array = /* @__PURE__ */ derived_safe_equal(() => {
|
||
var collection = get_collection();
|
||
return is_array(collection) ? collection : collection == null ? [] : array_from(collection);
|
||
});
|
||
/** @type {V[]} */
|
||
var array;
|
||
/** @type {Map<Batch, Set<any>>} */
|
||
var pending = /* @__PURE__ */ new Map();
|
||
var first_run = true;
|
||
/**
|
||
* @param {Batch} batch
|
||
*/
|
||
function commit(batch) {
|
||
if ((state.effect.f & 16384) !== 0) return;
|
||
state.pending.delete(batch);
|
||
state.fallback = fallback;
|
||
reconcile(state, array, anchor, flags, get_key);
|
||
if (fallback !== null) if (array.length === 0) if ((fallback.f & 33554432) === 0) resume_effect(fallback);
|
||
else {
|
||
fallback.f ^= EFFECT_OFFSCREEN;
|
||
move(fallback, null, anchor);
|
||
}
|
||
else pause_effect(fallback, () => {
|
||
fallback = null;
|
||
});
|
||
}
|
||
/**
|
||
* @param {Batch} batch
|
||
*/
|
||
function discard(batch) {
|
||
state.pending.delete(batch);
|
||
}
|
||
/** @type {EachState} */
|
||
var state = {
|
||
effect: block(() => {
|
||
array = get(each_array);
|
||
var length = array.length;
|
||
/** `true` if there was a hydration mismatch. Needs to be a `let` or else it isn't treeshaken out */
|
||
let mismatch = false;
|
||
if (hydrating) {
|
||
if (read_hydration_instruction(anchor) === "[!" !== (length === 0)) {
|
||
anchor = skip_nodes();
|
||
set_hydrate_node(anchor);
|
||
set_hydrating(false);
|
||
mismatch = true;
|
||
}
|
||
}
|
||
var keys = /* @__PURE__ */ new Set();
|
||
var batch = current_batch;
|
||
var defer = should_defer_append();
|
||
for (var index = 0; index < length; index += 1) {
|
||
if (hydrating && hydrate_node.nodeType === 8 && hydrate_node.data === "]") {
|
||
anchor = hydrate_node;
|
||
mismatch = true;
|
||
set_hydrating(false);
|
||
}
|
||
var value = array[index];
|
||
var key = get_key(value, index);
|
||
var item = first_run ? null : items.get(key);
|
||
if (item) {
|
||
if (item.v) internal_set(item.v, value);
|
||
if (item.i) internal_set(item.i, index);
|
||
if (defer) batch.unskip_effect(item.e);
|
||
} else {
|
||
item = create_item(items, first_run ? anchor : offscreen_anchor ??= create_text(), value, key, index, render_fn, flags, get_collection);
|
||
if (!first_run) item.e.f |= EFFECT_OFFSCREEN;
|
||
items.set(key, item);
|
||
}
|
||
keys.add(key);
|
||
}
|
||
if (length === 0 && fallback_fn && !fallback) if (first_run) fallback = branch(() => fallback_fn(anchor));
|
||
else {
|
||
fallback = branch(() => fallback_fn(offscreen_anchor ??= create_text()));
|
||
fallback.f |= EFFECT_OFFSCREEN;
|
||
}
|
||
if (length > keys.size) each_key_duplicate("", "", "");
|
||
if (hydrating && length > 0) set_hydrate_node(skip_nodes());
|
||
if (!first_run) {
|
||
pending.set(batch, keys);
|
||
if (defer) {
|
||
for (const [key, item] of items) if (!keys.has(key)) batch.skip_effect(item.e);
|
||
batch.oncommit(commit);
|
||
batch.ondiscard(discard);
|
||
} else commit(batch);
|
||
}
|
||
if (mismatch) set_hydrating(true);
|
||
get(each_array);
|
||
}),
|
||
flags,
|
||
items,
|
||
pending,
|
||
outrogroups: null,
|
||
fallback
|
||
};
|
||
first_run = false;
|
||
if (hydrating) anchor = hydrate_node;
|
||
}
|
||
/**
|
||
* Skip past any non-branch effects (which could be created with `createSubscriber`, for example) to find the next branch effect
|
||
* @param {Effect | null} effect
|
||
* @returns {Effect | null}
|
||
*/
|
||
function skip_to_branch(effect) {
|
||
while (effect !== null && (effect.f & 32) === 0) effect = effect.next;
|
||
return effect;
|
||
}
|
||
/**
|
||
* Add, remove, or reorder items output by an each block as its input changes
|
||
* @template V
|
||
* @param {EachState} state
|
||
* @param {Array<V>} array
|
||
* @param {Element | Comment | Text} anchor
|
||
* @param {number} flags
|
||
* @param {(value: V, index: number) => any} get_key
|
||
* @returns {void}
|
||
*/
|
||
function reconcile(state, array, anchor, flags, get_key) {
|
||
var is_animated = (flags & 8) !== 0;
|
||
var length = array.length;
|
||
var items = state.items;
|
||
var current = skip_to_branch(state.effect.first);
|
||
/** @type {undefined | Set<Effect>} */
|
||
var seen;
|
||
/** @type {Effect | null} */
|
||
var prev = null;
|
||
/** @type {undefined | Set<Effect>} */
|
||
var to_animate;
|
||
/** @type {Effect[]} */
|
||
var matched = [];
|
||
/** @type {Effect[]} */
|
||
var stashed = [];
|
||
/** @type {V} */
|
||
var value;
|
||
/** @type {any} */
|
||
var key;
|
||
/** @type {Effect | undefined} */
|
||
var effect;
|
||
/** @type {number} */
|
||
var i;
|
||
if (is_animated) for (i = 0; i < length; i += 1) {
|
||
value = array[i];
|
||
key = get_key(value, i);
|
||
effect = items.get(key).e;
|
||
if ((effect.f & 33554432) === 0) {
|
||
effect.nodes?.a?.measure();
|
||
(to_animate ??= /* @__PURE__ */ new Set()).add(effect);
|
||
}
|
||
}
|
||
for (i = 0; i < length; i += 1) {
|
||
value = array[i];
|
||
key = get_key(value, i);
|
||
effect = items.get(key).e;
|
||
if (state.outrogroups !== null) for (const group of state.outrogroups) {
|
||
group.pending.delete(effect);
|
||
group.done.delete(effect);
|
||
}
|
||
if ((effect.f & 8192) !== 0) {
|
||
resume_effect(effect);
|
||
if (is_animated) {
|
||
effect.nodes?.a?.unfix();
|
||
(to_animate ??= /* @__PURE__ */ new Set()).delete(effect);
|
||
}
|
||
}
|
||
if ((effect.f & 33554432) !== 0) {
|
||
effect.f ^= EFFECT_OFFSCREEN;
|
||
if (effect === current) move(effect, null, anchor);
|
||
else {
|
||
var next = prev ? prev.next : current;
|
||
if (effect === state.effect.last) state.effect.last = effect.prev;
|
||
if (effect.prev) effect.prev.next = effect.next;
|
||
if (effect.next) effect.next.prev = effect.prev;
|
||
link(state, prev, effect);
|
||
link(state, effect, next);
|
||
move(effect, next, anchor);
|
||
prev = effect;
|
||
matched = [];
|
||
stashed = [];
|
||
current = skip_to_branch(prev.next);
|
||
continue;
|
||
}
|
||
}
|
||
if (effect !== current) {
|
||
if (seen !== void 0 && seen.has(effect)) {
|
||
if (matched.length < stashed.length) {
|
||
var start = stashed[0];
|
||
var j;
|
||
prev = start.prev;
|
||
var a = matched[0];
|
||
var b = matched[matched.length - 1];
|
||
for (j = 0; j < matched.length; j += 1) move(matched[j], start, anchor);
|
||
for (j = 0; j < stashed.length; j += 1) seen.delete(stashed[j]);
|
||
link(state, a.prev, b.next);
|
||
link(state, prev, a);
|
||
link(state, b, start);
|
||
current = start;
|
||
prev = b;
|
||
i -= 1;
|
||
matched = [];
|
||
stashed = [];
|
||
} else {
|
||
seen.delete(effect);
|
||
move(effect, current, anchor);
|
||
link(state, effect.prev, effect.next);
|
||
link(state, effect, prev === null ? state.effect.first : prev.next);
|
||
link(state, prev, effect);
|
||
prev = effect;
|
||
}
|
||
continue;
|
||
}
|
||
matched = [];
|
||
stashed = [];
|
||
while (current !== null && current !== effect) {
|
||
(seen ??= /* @__PURE__ */ new Set()).add(current);
|
||
stashed.push(current);
|
||
current = skip_to_branch(current.next);
|
||
}
|
||
if (current === null) continue;
|
||
}
|
||
if ((effect.f & 33554432) === 0) matched.push(effect);
|
||
prev = effect;
|
||
current = skip_to_branch(effect.next);
|
||
}
|
||
if (state.outrogroups !== null) {
|
||
for (const group of state.outrogroups) if (group.pending.size === 0) {
|
||
destroy_effects(state, array_from(group.done));
|
||
state.outrogroups?.delete(group);
|
||
}
|
||
if (state.outrogroups.size === 0) state.outrogroups = null;
|
||
}
|
||
if (current !== null || seen !== void 0) {
|
||
/** @type {Effect[]} */
|
||
var to_destroy = [];
|
||
if (seen !== void 0) {
|
||
for (effect of seen) if ((effect.f & 8192) === 0) to_destroy.push(effect);
|
||
}
|
||
while (current !== null) {
|
||
if ((current.f & 8192) === 0 && current !== state.fallback) to_destroy.push(current);
|
||
current = skip_to_branch(current.next);
|
||
}
|
||
var destroy_length = to_destroy.length;
|
||
if (destroy_length > 0) {
|
||
var controlled_anchor = (flags & 4) !== 0 && length === 0 ? anchor : null;
|
||
if (is_animated) {
|
||
for (i = 0; i < destroy_length; i += 1) to_destroy[i].nodes?.a?.measure();
|
||
for (i = 0; i < destroy_length; i += 1) to_destroy[i].nodes?.a?.fix();
|
||
}
|
||
pause_effects(state, to_destroy, controlled_anchor);
|
||
}
|
||
}
|
||
if (is_animated) queue_micro_task(() => {
|
||
if (to_animate === void 0) return;
|
||
for (effect of to_animate) effect.nodes?.a?.apply();
|
||
});
|
||
}
|
||
/**
|
||
* @template V
|
||
* @param {Map<any, EachItem>} items
|
||
* @param {Node} anchor
|
||
* @param {V} value
|
||
* @param {unknown} key
|
||
* @param {number} index
|
||
* @param {(anchor: Node, item: V | Source<V>, index: number | Value<number>, collection: () => V[]) => void} render_fn
|
||
* @param {number} flags
|
||
* @param {() => V[]} get_collection
|
||
* @returns {EachItem}
|
||
*/
|
||
function create_item(items, anchor, value, key, index, render_fn, flags, get_collection) {
|
||
var v = (flags & 1) !== 0 ? (flags & 16) === 0 ? /* @__PURE__ */ mutable_source(value, false, false) : source(value) : null;
|
||
var i = (flags & 2) !== 0 ? source(index) : null;
|
||
return {
|
||
v,
|
||
i,
|
||
e: branch(() => {
|
||
render_fn(anchor, v ?? value, i ?? index, get_collection);
|
||
return () => {
|
||
items.delete(key);
|
||
};
|
||
})
|
||
};
|
||
}
|
||
/**
|
||
* @param {Effect} effect
|
||
* @param {Effect | null} next
|
||
* @param {Text | Element | Comment} anchor
|
||
*/
|
||
function move(effect, next, anchor) {
|
||
if (!effect.nodes) return;
|
||
var node = effect.nodes.start;
|
||
var end = effect.nodes.end;
|
||
var dest = next && (next.f & 33554432) === 0 ? next.nodes.start : anchor;
|
||
while (node !== null) {
|
||
var next_node = /* @__PURE__ */ get_next_sibling(node);
|
||
dest.before(node);
|
||
if (node === end) return;
|
||
node = next_node;
|
||
}
|
||
}
|
||
/**
|
||
* @param {EachState} state
|
||
* @param {Effect | null} prev
|
||
* @param {Effect | null} next
|
||
*/
|
||
function link(state, prev, next) {
|
||
if (prev === null) state.effect.first = next;
|
||
else prev.next = next;
|
||
if (next === null) state.effect.last = prev;
|
||
else next.prev = prev;
|
||
}
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/client/dom/blocks/svelte-head.js
|
||
/** @import { TemplateNode } from '#client' */
|
||
/**
|
||
* @param {string} hash
|
||
* @param {(anchor: Node) => void} render_fn
|
||
* @returns {void}
|
||
*/
|
||
function head(hash, render_fn) {
|
||
let previous_hydrate_node = null;
|
||
let was_hydrating = hydrating;
|
||
/** @type {Comment | Text} */
|
||
var anchor;
|
||
if (hydrating) {
|
||
previous_hydrate_node = hydrate_node;
|
||
var head_anchor = /* @__PURE__ */ get_first_child(document.head);
|
||
while (head_anchor !== null && (head_anchor.nodeType !== 8 || head_anchor.data !== hash)) head_anchor = /* @__PURE__ */ get_next_sibling(head_anchor);
|
||
if (head_anchor === null) set_hydrating(false);
|
||
else {
|
||
var start = /* @__PURE__ */ get_next_sibling(head_anchor);
|
||
head_anchor.remove();
|
||
set_hydrate_node(start);
|
||
}
|
||
}
|
||
if (!hydrating) anchor = document.head.appendChild(create_text());
|
||
try {
|
||
block(() => render_fn(anchor), HEAD_EFFECT | EFFECT_PRESERVED);
|
||
} finally {
|
||
if (was_hydrating) {
|
||
set_hydrating(true);
|
||
set_hydrate_node(previous_hydrate_node);
|
||
}
|
||
}
|
||
}
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/shared/attributes.js
|
||
var whitespace = [..." \n\r\f\xA0\v"];
|
||
/**
|
||
* @param {any} value
|
||
* @param {string | null} [hash]
|
||
* @param {Record<string, boolean>} [directives]
|
||
* @returns {string | null}
|
||
*/
|
||
function to_class(value, hash, directives) {
|
||
var classname = value == null ? "" : "" + value;
|
||
if (hash) classname = classname ? classname + " " + hash : hash;
|
||
if (directives) {
|
||
for (var key of Object.keys(directives)) if (directives[key]) classname = classname ? classname + " " + key : key;
|
||
else if (classname.length) {
|
||
var len = key.length;
|
||
var a = 0;
|
||
while ((a = classname.indexOf(key, a)) >= 0) {
|
||
var b = a + len;
|
||
if ((a === 0 || whitespace.includes(classname[a - 1])) && (b === classname.length || whitespace.includes(classname[b]))) classname = (a === 0 ? "" : classname.substring(0, a)) + classname.substring(b + 1);
|
||
else a = b;
|
||
}
|
||
}
|
||
}
|
||
return classname === "" ? null : classname;
|
||
}
|
||
/**
|
||
*
|
||
* @param {Record<string,any>} styles
|
||
* @param {boolean} important
|
||
*/
|
||
function append_styles(styles, important = false) {
|
||
var separator = important ? " !important;" : ";";
|
||
var css = "";
|
||
for (var key of Object.keys(styles)) {
|
||
var value = styles[key];
|
||
if (value != null && value !== "") css += " " + key + ": " + value + separator;
|
||
}
|
||
return css;
|
||
}
|
||
/**
|
||
* @param {string} name
|
||
* @returns {string}
|
||
*/
|
||
function to_css_name(name) {
|
||
if (name[0] !== "-" || name[1] !== "-") return name.toLowerCase();
|
||
return name;
|
||
}
|
||
/**
|
||
* @param {any} value
|
||
* @param {Record<string, any> | [Record<string, any>, Record<string, any>]} [styles]
|
||
* @returns {string | null}
|
||
*/
|
||
function to_style(value, styles) {
|
||
if (styles) {
|
||
var new_style = "";
|
||
/** @type {Record<string,any> | undefined} */
|
||
var normal_styles;
|
||
/** @type {Record<string,any> | undefined} */
|
||
var important_styles;
|
||
if (Array.isArray(styles)) {
|
||
normal_styles = styles[0];
|
||
important_styles = styles[1];
|
||
} else normal_styles = styles;
|
||
if (value) {
|
||
value = String(value).replaceAll(/\s*\/\*.*?\*\/\s*/g, "").trim();
|
||
/** @type {boolean | '"' | "'"} */
|
||
var in_str = false;
|
||
var in_apo = 0;
|
||
var in_comment = false;
|
||
var reserved_names = [];
|
||
if (normal_styles) reserved_names.push(...Object.keys(normal_styles).map(to_css_name));
|
||
if (important_styles) reserved_names.push(...Object.keys(important_styles).map(to_css_name));
|
||
var start_index = 0;
|
||
var name_index = -1;
|
||
const len = value.length;
|
||
for (var i = 0; i < len; i++) {
|
||
var c = value[i];
|
||
if (in_comment) {
|
||
if (c === "/" && value[i - 1] === "*") in_comment = false;
|
||
} else if (in_str) {
|
||
if (in_str === c) in_str = false;
|
||
} else if (c === "/" && value[i + 1] === "*") in_comment = true;
|
||
else if (c === "\"" || c === "'") in_str = c;
|
||
else if (c === "(") in_apo++;
|
||
else if (c === ")") in_apo--;
|
||
if (!in_comment && in_str === false && in_apo === 0) {
|
||
if (c === ":" && name_index === -1) name_index = i;
|
||
else if (c === ";" || i === len - 1) {
|
||
if (name_index !== -1) {
|
||
var name = to_css_name(value.substring(start_index, name_index).trim());
|
||
if (!reserved_names.includes(name)) {
|
||
if (c !== ";") i++;
|
||
var property = value.substring(start_index, i).trim();
|
||
new_style += " " + property + ";";
|
||
}
|
||
}
|
||
start_index = i + 1;
|
||
name_index = -1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (normal_styles) new_style += append_styles(normal_styles);
|
||
if (important_styles) new_style += append_styles(important_styles, true);
|
||
new_style = new_style.trim();
|
||
return new_style === "" ? null : new_style;
|
||
}
|
||
return value == null ? null : String(value);
|
||
}
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/client/dom/elements/class.js
|
||
/**
|
||
* @param {Element} dom
|
||
* @param {boolean | number} is_html
|
||
* @param {string | null} value
|
||
* @param {string} [hash]
|
||
* @param {Record<string, any>} [prev_classes]
|
||
* @param {Record<string, any>} [next_classes]
|
||
* @returns {Record<string, boolean> | undefined}
|
||
*/
|
||
function set_class(dom, is_html, value, hash, prev_classes, next_classes) {
|
||
var prev = dom.__className;
|
||
if (hydrating || prev !== value || prev === void 0) {
|
||
var next_class_name = to_class(value, hash, next_classes);
|
||
if (!hydrating || next_class_name !== dom.getAttribute("class")) if (next_class_name == null) dom.removeAttribute("class");
|
||
else if (is_html) dom.className = next_class_name;
|
||
else dom.setAttribute("class", next_class_name);
|
||
dom.__className = value;
|
||
} else if (next_classes && prev_classes !== next_classes) for (var key in next_classes) {
|
||
var is_present = !!next_classes[key];
|
||
if (prev_classes == null || is_present !== !!prev_classes[key]) dom.classList.toggle(key, is_present);
|
||
}
|
||
return next_classes;
|
||
}
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/client/dom/elements/style.js
|
||
/**
|
||
* @param {Element & ElementCSSInlineStyle} dom
|
||
* @param {Record<string, any>} prev
|
||
* @param {Record<string, any>} next
|
||
* @param {string} [priority]
|
||
*/
|
||
function update_styles(dom, prev = {}, next, priority) {
|
||
for (var key in next) {
|
||
var value = next[key];
|
||
if (prev[key] !== value) if (next[key] == null) dom.style.removeProperty(key);
|
||
else dom.style.setProperty(key, value, priority);
|
||
}
|
||
}
|
||
/**
|
||
* @param {Element & ElementCSSInlineStyle} dom
|
||
* @param {string | null} value
|
||
* @param {Record<string, any> | [Record<string, any>, Record<string, any>]} [prev_styles]
|
||
* @param {Record<string, any> | [Record<string, any>, Record<string, any>]} [next_styles]
|
||
*/
|
||
function set_style(dom, value, prev_styles, next_styles) {
|
||
var prev = dom.__style;
|
||
if (hydrating || prev !== value) {
|
||
var next_style_attr = to_style(value, next_styles);
|
||
if (!hydrating || next_style_attr !== dom.getAttribute("style")) if (next_style_attr == null) dom.removeAttribute("style");
|
||
else dom.style.cssText = next_style_attr;
|
||
dom.__style = value;
|
||
} else if (next_styles) if (Array.isArray(next_styles)) {
|
||
update_styles(dom, prev_styles?.[0], next_styles[0]);
|
||
update_styles(dom, prev_styles?.[1], next_styles[1], "important");
|
||
} else update_styles(dom, prev_styles, next_styles);
|
||
return next_styles;
|
||
}
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/client/dom/elements/bindings/select.js
|
||
/**
|
||
* Selects the correct option(s) (depending on whether this is a multiple select)
|
||
* @template V
|
||
* @param {HTMLSelectElement} select
|
||
* @param {V} value
|
||
* @param {boolean} mounting
|
||
*/
|
||
function select_option(select, value, mounting = false) {
|
||
if (select.multiple) {
|
||
if (value == void 0) return;
|
||
if (!is_array(value)) return select_multiple_invalid_value();
|
||
for (var option of select.options) option.selected = value.includes(get_option_value(option));
|
||
return;
|
||
}
|
||
for (option of select.options) if (is(get_option_value(option), value)) {
|
||
option.selected = true;
|
||
return;
|
||
}
|
||
if (!mounting || value !== void 0) select.selectedIndex = -1;
|
||
}
|
||
/**
|
||
* Selects the correct option(s) if `value` is given,
|
||
* and then sets up a mutation observer to sync the
|
||
* current selection to the dom when it changes. Such
|
||
* changes could for example occur when options are
|
||
* inside an `#each` block.
|
||
* @param {HTMLSelectElement} select
|
||
*/
|
||
function init_select(select) {
|
||
var observer = new MutationObserver(() => {
|
||
select_option(select, select.__value);
|
||
});
|
||
observer.observe(select, {
|
||
childList: true,
|
||
subtree: true,
|
||
attributes: true,
|
||
attributeFilter: ["value"]
|
||
});
|
||
teardown(() => {
|
||
observer.disconnect();
|
||
});
|
||
}
|
||
/**
|
||
* @param {HTMLSelectElement} select
|
||
* @param {() => unknown} get
|
||
* @param {(value: unknown) => void} set
|
||
* @returns {void}
|
||
*/
|
||
function bind_select_value(select, get, set = get) {
|
||
var batches = /* @__PURE__ */ new WeakSet();
|
||
var mounting = true;
|
||
listen_to_event_and_reset_event(select, "change", (is_reset) => {
|
||
var query = is_reset ? "[selected]" : ":checked";
|
||
/** @type {unknown} */
|
||
var value;
|
||
if (select.multiple) value = [].map.call(select.querySelectorAll(query), get_option_value);
|
||
else {
|
||
/** @type {HTMLOptionElement | null} */
|
||
var selected_option = select.querySelector(query) ?? select.querySelector("option:not([disabled])");
|
||
value = selected_option && get_option_value(selected_option);
|
||
}
|
||
set(value);
|
||
select.__value = value;
|
||
if (current_batch !== null) batches.add(current_batch);
|
||
});
|
||
effect(() => {
|
||
var value = get();
|
||
if (select === document.activeElement) {
|
||
var batch = async_mode_flag ? previous_batch : current_batch;
|
||
if (batches.has(batch)) return;
|
||
}
|
||
select_option(select, value, mounting);
|
||
if (mounting && value === void 0) {
|
||
/** @type {HTMLOptionElement | null} */
|
||
var selected_option = select.querySelector(":checked");
|
||
if (selected_option !== null) {
|
||
value = get_option_value(selected_option);
|
||
set(value);
|
||
}
|
||
}
|
||
select.__value = value;
|
||
mounting = false;
|
||
});
|
||
init_select(select);
|
||
}
|
||
/** @param {HTMLOptionElement} option */
|
||
function get_option_value(option) {
|
||
if ("__value" in option) return option.__value;
|
||
else return option.value;
|
||
}
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/client/dom/elements/attributes.js
|
||
/** @import { Blocker, Effect } from '#client' */
|
||
var IS_CUSTOM_ELEMENT = Symbol("is custom element");
|
||
var IS_HTML = Symbol("is html");
|
||
var LINK_TAG = IS_XHTML ? "link" : "LINK";
|
||
var PROGRESS_TAG = IS_XHTML ? "progress" : "PROGRESS";
|
||
/**
|
||
* The value/checked attribute in the template actually corresponds to the defaultValue property, so we need
|
||
* to remove it upon hydration to avoid a bug when someone resets the form value.
|
||
* @param {HTMLInputElement} input
|
||
* @returns {void}
|
||
*/
|
||
function remove_input_defaults(input) {
|
||
if (!hydrating) return;
|
||
var already_removed = false;
|
||
var remove_defaults = () => {
|
||
if (already_removed) return;
|
||
already_removed = true;
|
||
if (input.hasAttribute("value")) {
|
||
var value = input.value;
|
||
set_attribute(input, "value", null);
|
||
input.value = value;
|
||
}
|
||
if (input.hasAttribute("checked")) {
|
||
var checked = input.checked;
|
||
set_attribute(input, "checked", null);
|
||
input.checked = checked;
|
||
}
|
||
};
|
||
input.__on_r = remove_defaults;
|
||
queue_micro_task(remove_defaults);
|
||
add_form_reset_listener();
|
||
}
|
||
/**
|
||
* @param {Element} element
|
||
* @param {any} value
|
||
*/
|
||
function set_value(element, value) {
|
||
var attributes = get_attributes(element);
|
||
if (attributes.value === (attributes.value = value ?? void 0) || element.value === value && (value !== 0 || element.nodeName !== PROGRESS_TAG)) return;
|
||
element.value = value ?? "";
|
||
}
|
||
/**
|
||
* @param {Element} element
|
||
* @param {string} attribute
|
||
* @param {string | null} value
|
||
* @param {boolean} [skip_warning]
|
||
*/
|
||
function set_attribute(element, attribute, value, skip_warning) {
|
||
var attributes = get_attributes(element);
|
||
if (hydrating) {
|
||
attributes[attribute] = element.getAttribute(attribute);
|
||
if (attribute === "src" || attribute === "srcset" || attribute === "href" && element.nodeName === LINK_TAG) {
|
||
if (!skip_warning);
|
||
return;
|
||
}
|
||
}
|
||
if (attributes[attribute] === (attributes[attribute] = value)) return;
|
||
if (attribute === "loading") element[LOADING_ATTR_SYMBOL] = value;
|
||
if (value == null) element.removeAttribute(attribute);
|
||
else if (typeof value !== "string" && get_setters(element).includes(attribute)) element[attribute] = value;
|
||
else element.setAttribute(attribute, value);
|
||
}
|
||
/**
|
||
*
|
||
* @param {Element} element
|
||
*/
|
||
function get_attributes(element) {
|
||
return element.__attributes ??= {
|
||
[IS_CUSTOM_ELEMENT]: element.nodeName.includes("-"),
|
||
[IS_HTML]: element.namespaceURI === NAMESPACE_HTML
|
||
};
|
||
}
|
||
/** @type {Map<string, string[]>} */
|
||
var setters_cache = /* @__PURE__ */ new Map();
|
||
/** @param {Element} element */
|
||
function get_setters(element) {
|
||
var cache_key = element.getAttribute("is") || element.nodeName;
|
||
var setters = setters_cache.get(cache_key);
|
||
if (setters) return setters;
|
||
setters_cache.set(cache_key, setters = []);
|
||
var descriptors;
|
||
var proto = element;
|
||
var element_proto = Element.prototype;
|
||
while (element_proto !== proto) {
|
||
descriptors = get_descriptors(proto);
|
||
for (var key in descriptors) if (descriptors[key].set) setters.push(key);
|
||
proto = get_prototype_of(proto);
|
||
}
|
||
return setters;
|
||
}
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/client/dom/elements/bindings/input.js
|
||
/** @import { Batch } from '../../../reactivity/batch.js' */
|
||
/**
|
||
* @param {HTMLInputElement} input
|
||
* @param {() => unknown} get
|
||
* @param {(value: unknown) => void} set
|
||
* @returns {void}
|
||
*/
|
||
function bind_value(input, get, set = get) {
|
||
var batches = /* @__PURE__ */ new WeakSet();
|
||
listen_to_event_and_reset_event(input, "input", async (is_reset) => {
|
||
/** @type {any} */
|
||
var value = is_reset ? input.defaultValue : input.value;
|
||
value = is_numberlike_input(input) ? to_number(value) : value;
|
||
set(value);
|
||
if (current_batch !== null) batches.add(current_batch);
|
||
await tick();
|
||
if (value !== (value = get())) {
|
||
var start = input.selectionStart;
|
||
var end = input.selectionEnd;
|
||
var length = input.value.length;
|
||
input.value = value ?? "";
|
||
if (end !== null) {
|
||
var new_length = input.value.length;
|
||
if (start === end && end === length && new_length > length) {
|
||
input.selectionStart = new_length;
|
||
input.selectionEnd = new_length;
|
||
} else {
|
||
input.selectionStart = start;
|
||
input.selectionEnd = Math.min(end, new_length);
|
||
}
|
||
}
|
||
}
|
||
});
|
||
if (hydrating && input.defaultValue !== input.value || untrack(get) == null && input.value) {
|
||
set(is_numberlike_input(input) ? to_number(input.value) : input.value);
|
||
if (current_batch !== null) batches.add(current_batch);
|
||
}
|
||
render_effect(() => {
|
||
var value = get();
|
||
if (input === document.activeElement) {
|
||
var batch = async_mode_flag ? previous_batch : current_batch;
|
||
if (batches.has(batch)) return;
|
||
}
|
||
if (is_numberlike_input(input) && value === to_number(input.value)) return;
|
||
if (input.type === "date" && !value && !input.value) return;
|
||
if (value !== input.value) input.value = value ?? "";
|
||
});
|
||
}
|
||
/** @type {Set<HTMLInputElement[]>} */
|
||
var pending = /* @__PURE__ */ new Set();
|
||
/**
|
||
* @param {HTMLInputElement[]} inputs
|
||
* @param {null | [number]} group_index
|
||
* @param {HTMLInputElement} input
|
||
* @param {() => unknown} get
|
||
* @param {(value: unknown) => void} set
|
||
* @returns {void}
|
||
*/
|
||
function bind_group(inputs, group_index, input, get, set = get) {
|
||
var is_checkbox = input.getAttribute("type") === "checkbox";
|
||
var binding_group = inputs;
|
||
let hydration_mismatch = false;
|
||
if (group_index !== null) for (var index of group_index) binding_group = binding_group[index] ??= [];
|
||
binding_group.push(input);
|
||
listen_to_event_and_reset_event(input, "change", () => {
|
||
var value = input.__value;
|
||
if (is_checkbox) value = get_binding_group_value(binding_group, value, input.checked);
|
||
set(value);
|
||
}, () => set(is_checkbox ? [] : null));
|
||
render_effect(() => {
|
||
var value = get();
|
||
if (hydrating && input.defaultChecked !== input.checked) {
|
||
hydration_mismatch = true;
|
||
return;
|
||
}
|
||
if (is_checkbox) {
|
||
value = value || [];
|
||
input.checked = value.includes(input.__value);
|
||
} else input.checked = is(input.__value, value);
|
||
});
|
||
teardown(() => {
|
||
var index = binding_group.indexOf(input);
|
||
if (index !== -1) binding_group.splice(index, 1);
|
||
});
|
||
if (!pending.has(binding_group)) {
|
||
pending.add(binding_group);
|
||
queue_micro_task(() => {
|
||
binding_group.sort((a, b) => a.compareDocumentPosition(b) === 4 ? -1 : 1);
|
||
pending.delete(binding_group);
|
||
});
|
||
}
|
||
queue_micro_task(() => {
|
||
if (hydration_mismatch) {
|
||
var value;
|
||
if (is_checkbox) value = get_binding_group_value(binding_group, value, input.checked);
|
||
else value = binding_group.find((input) => input.checked)?.__value;
|
||
set(value);
|
||
}
|
||
});
|
||
}
|
||
/**
|
||
* @template V
|
||
* @param {Array<HTMLInputElement>} group
|
||
* @param {V} __value
|
||
* @param {boolean} checked
|
||
* @returns {V[]}
|
||
*/
|
||
function get_binding_group_value(group, __value, checked) {
|
||
/** @type {Set<V>} */
|
||
var value = /* @__PURE__ */ new Set();
|
||
for (var i = 0; i < group.length; i += 1) if (group[i].checked) value.add(group[i].__value);
|
||
if (!checked) value.delete(__value);
|
||
return Array.from(value);
|
||
}
|
||
/**
|
||
* @param {HTMLInputElement} input
|
||
*/
|
||
function is_numberlike_input(input) {
|
||
var type = input.type;
|
||
return type === "number" || type === "range";
|
||
}
|
||
/**
|
||
* @param {string} value
|
||
*/
|
||
function to_number(value) {
|
||
return value === "" ? null : +value;
|
||
}
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/client/dom/legacy/lifecycle.js
|
||
/** @import { ComponentContextLegacy } from '#client' */
|
||
/**
|
||
* Legacy-mode only: Call `onMount` callbacks and set up `beforeUpdate`/`afterUpdate` effects
|
||
* @param {boolean} [immutable]
|
||
*/
|
||
function init(immutable = false) {
|
||
const context = component_context;
|
||
const callbacks = context.l.u;
|
||
if (!callbacks) return;
|
||
let props = () => deep_read_state(context.s);
|
||
if (immutable) {
|
||
let version = 0;
|
||
let prev = {};
|
||
const d = /* @__PURE__ */ derived(() => {
|
||
let changed = false;
|
||
const props = context.s;
|
||
for (const key in props) if (props[key] !== prev[key]) {
|
||
prev[key] = props[key];
|
||
changed = true;
|
||
}
|
||
if (changed) version++;
|
||
return version;
|
||
});
|
||
props = () => get(d);
|
||
}
|
||
if (callbacks.b.length) user_pre_effect(() => {
|
||
observe_all(context, props);
|
||
run_all(callbacks.b);
|
||
});
|
||
user_effect(() => {
|
||
const fns = untrack(() => callbacks.m.map(run));
|
||
return () => {
|
||
for (const fn of fns) if (typeof fn === "function") fn();
|
||
};
|
||
});
|
||
if (callbacks.a.length) user_effect(() => {
|
||
observe_all(context, props);
|
||
run_all(callbacks.a);
|
||
});
|
||
}
|
||
/**
|
||
* Invoke the getter of all signals associated with a component
|
||
* so they can be registered to the effect this function is called in.
|
||
* @param {ComponentContextLegacy} context
|
||
* @param {(() => void)} props
|
||
*/
|
||
function observe_all(context, props) {
|
||
if (context.l.s) for (const signal of context.l.s) get(signal);
|
||
props();
|
||
}
|
||
if (typeof HTMLElement === "function");
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/disclose-version.js
|
||
if (typeof window !== "undefined") ((window.__svelte ??= {}).v ??= /* @__PURE__ */ new Set()).add("5");
|
||
//#endregion
|
||
//#region node_modules/svelte/src/internal/flags/legacy.js
|
||
enable_legacy_mode_flag();
|
||
//#endregion
|
||
//#region src/lib/stores/security.svelte.js
|
||
var DEFAULT_AUTO_LOCK_MINUTES = 5;
|
||
var autoLockTimer = null;
|
||
var autoLockMinutes = 5;
|
||
function startAutoLock(minutes = DEFAULT_AUTO_LOCK_MINUTES) {
|
||
autoLockMinutes = minutes;
|
||
resetAutoLock();
|
||
const events = [
|
||
"mousedown",
|
||
"keydown",
|
||
"scroll",
|
||
"touchstart"
|
||
];
|
||
const handler = () => resetAutoLock();
|
||
events.forEach((evt) => window.addEventListener(evt, handler, { passive: true }));
|
||
document.addEventListener("visibilitychange", handleVisibilityChange);
|
||
window.addEventListener("beforeunload", clearKeyOnExit);
|
||
window.__vaultCleanup = () => {
|
||
events.forEach((evt) => window.removeEventListener(evt, handler));
|
||
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
||
window.removeEventListener("beforeunload", clearKeyOnExit);
|
||
if (autoLockTimer) clearTimeout(autoLockTimer);
|
||
};
|
||
}
|
||
/**
|
||
* Reset the auto-lock timer.
|
||
*/
|
||
function resetAutoLock() {
|
||
if (autoLockTimer) clearTimeout(autoLockTimer);
|
||
autoLockTimer = setTimeout(() => {
|
||
app$1.lockVault();
|
||
}, autoLockMinutes * 60 * 1e3);
|
||
}
|
||
/**
|
||
* Handle visibility change — lock when user switches away from tab.
|
||
*/
|
||
function handleVisibilityChange() {
|
||
if (document.hidden && app$1.isUnlocked) app$1.lockVault();
|
||
}
|
||
/**
|
||
* Clear the encryption key when the page is closing.
|
||
*/
|
||
function clearKeyOnExit() {
|
||
app$1.encryptionKey = null;
|
||
}
|
||
/**
|
||
* Stop auto-lock (e.g., when manually locking).
|
||
*/
|
||
function stopAutoLock() {
|
||
if (autoLockTimer) {
|
||
clearTimeout(autoLockTimer);
|
||
autoLockTimer = null;
|
||
}
|
||
}
|
||
//#endregion
|
||
//#region src/lib/stores/app.svelte.js
|
||
var AppStore = class {
|
||
#isUnlocked = /* @__PURE__ */ state(false);
|
||
get isUnlocked() {
|
||
return get(this.#isUnlocked);
|
||
}
|
||
set isUnlocked(value) {
|
||
set(this.#isUnlocked, value, true);
|
||
}
|
||
#encryptionKey = /* @__PURE__ */ state(null);
|
||
get encryptionKey() {
|
||
return get(this.#encryptionKey);
|
||
}
|
||
set encryptionKey(value) {
|
||
set(this.#encryptionKey, value, true);
|
||
}
|
||
#salt = /* @__PURE__ */ state(null);
|
||
get salt() {
|
||
return get(this.#salt);
|
||
}
|
||
set salt(value) {
|
||
set(this.#salt, value, true);
|
||
}
|
||
lockVault() {
|
||
stopAutoLock();
|
||
this.encryptionKey = null;
|
||
this.isUnlocked = false;
|
||
}
|
||
};
|
||
var app$1 = new AppStore();
|
||
//#endregion
|
||
//#region src/lib/models/schema.js
|
||
/**
|
||
* Data model definitions and factory functions.
|
||
*
|
||
* All IDs are generated with a simple ULID-like timestamp + random suffix
|
||
* to keep things sortable and collision-resistant without external deps.
|
||
*/
|
||
/**
|
||
* Generate a unique ID (timestamp-based, sortable).
|
||
* @returns {string}
|
||
*/
|
||
function generateId() {
|
||
return `${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
|
||
}
|
||
/**
|
||
* @typedef {Object} CredentialEntry
|
||
* @property {string} id - Unique identifier
|
||
* @property {string} title - Display name (e.g. "GitHub", "Gmail")
|
||
* @property {string} username - Login username or email
|
||
* @property {string} encryptedPassword - AES-GCM encrypted password blob (JSON string)
|
||
* @property {string} [url] - Website URL
|
||
* @property {string} [notes] - Free-form notes
|
||
* @property {string} [groupId] - Reference to a Group id (empty string = no group)
|
||
* @property {string[]} [tags] - Free-form tags
|
||
* @property {string} createdAt - ISO timestamp
|
||
* @property {string} updatedAt - ISO timestamp
|
||
*/
|
||
/**
|
||
* Create a new CredentialEntry.
|
||
*
|
||
* @param {Object} data
|
||
* @param {string} data.title
|
||
* @param {string} data.username
|
||
* @param {string} data.encryptedPassword - Must already be encrypted
|
||
* @param {string} [data.url]
|
||
* @param {string} [data.notes]
|
||
* @param {string} [data.groupId]
|
||
* @param {string[]} [data.tags]
|
||
* @returns {CredentialEntry}
|
||
*/
|
||
function createEntry(data) {
|
||
const now = (/* @__PURE__ */ new Date()).toISOString();
|
||
return {
|
||
id: generateId(),
|
||
title: data.title.trim(),
|
||
username: data.username.trim(),
|
||
encryptedPassword: data.encryptedPassword,
|
||
url: data.url?.trim() || "",
|
||
notes: data.notes?.trim() || "",
|
||
groupId: data.groupId || "",
|
||
tags: data.tags || [],
|
||
createdAt: now,
|
||
updatedAt: now
|
||
};
|
||
}
|
||
/**
|
||
* Update an existing entry, preserving id and createdAt.
|
||
*
|
||
* @param {CredentialEntry} existing
|
||
* @param {Object} data - Fields to update
|
||
* @returns {CredentialEntry}
|
||
*/
|
||
function updateEntry$1(existing, data) {
|
||
return {
|
||
...existing,
|
||
title: data.title !== void 0 ? data.title.trim() : existing.title,
|
||
username: data.username !== void 0 ? data.username.trim() : existing.username,
|
||
encryptedPassword: data.encryptedPassword !== void 0 ? data.encryptedPassword : existing.encryptedPassword,
|
||
url: data.url !== void 0 ? data.url.trim() : existing.url,
|
||
notes: data.notes !== void 0 ? data.notes.trim() : existing.notes,
|
||
groupId: data.groupId !== void 0 ? data.groupId : existing.groupId,
|
||
tags: data.tags !== void 0 ? data.tags : existing.tags,
|
||
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
||
};
|
||
}
|
||
/**
|
||
* @typedef {Object} Group
|
||
* @property {string} id - Unique identifier
|
||
* @property {string} name - Display name
|
||
* @property {string} [color] - Hex color for UI accent
|
||
* @property {string} createdAt - ISO timestamp
|
||
*/
|
||
var GROUP_COLORS = [
|
||
"#6c63ff",
|
||
"#e5484d",
|
||
"#34d399",
|
||
"#fbbf24",
|
||
"#3b82f6",
|
||
"#ec4899",
|
||
"#8b5cf6",
|
||
"#14b8a6",
|
||
"#f97316",
|
||
"#06b6d4"
|
||
];
|
||
/**
|
||
* Create a new Group.
|
||
*
|
||
* @param {string} name
|
||
* @param {string} [color]
|
||
* @returns {Group}
|
||
*/
|
||
function createGroup(name, color) {
|
||
return {
|
||
id: generateId(),
|
||
name: name.trim(),
|
||
color: color || GROUP_COLORS[Math.floor(Math.random() * GROUP_COLORS.length)],
|
||
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
||
};
|
||
}
|
||
/**
|
||
* Validate a credential entry form submission.
|
||
*
|
||
* @param {Object} data
|
||
* @returns {{ valid: boolean, errors: string[] }}
|
||
*/
|
||
function validateEntry(data) {
|
||
const errors = [];
|
||
if (!data.title || !data.title.trim()) errors.push("Title is required");
|
||
if (!data.username || !data.username.trim()) errors.push("Username is required");
|
||
if (!data.encryptedPassword) errors.push("Password is required");
|
||
return {
|
||
valid: errors.length === 0,
|
||
errors
|
||
};
|
||
}
|
||
/**
|
||
* Validate a group name.
|
||
*
|
||
* @param {string} name
|
||
* @returns {{ valid: boolean, errors: string[] }}
|
||
*/
|
||
function validateGroup(name) {
|
||
const errors = [];
|
||
if (!name || !name.trim()) errors.push("Group name is required");
|
||
else if (name.trim().length > 50) errors.push("Group name must be 50 characters or less");
|
||
return {
|
||
valid: errors.length === 0,
|
||
errors
|
||
};
|
||
}
|
||
//#endregion
|
||
//#region src/lib/crypto/crypto.js
|
||
/**
|
||
* Crypto module — Web Crypto API wrapper.
|
||
*
|
||
* Uses PBKDF2 for key derivation and AES-GCM for symmetric encryption.
|
||
* All operations are async and use the browser's native Web Crypto API.
|
||
*
|
||
* The derived encryption key is kept in memory only — never written to disk.
|
||
*/
|
||
var PBKDF2_ITERATIONS = 1e5;
|
||
var SALT_LENGTH = 16;
|
||
var IV_LENGTH = 12;
|
||
/**
|
||
* Generate a random salt.
|
||
* @returns {Uint8Array}
|
||
*/
|
||
function generateSalt() {
|
||
return crypto.getRandomValues(new Uint8Array(SALT_LENGTH));
|
||
}
|
||
/**
|
||
* Derive an AES-GCM encryption key from a master password and salt.
|
||
*
|
||
* @param {string} masterPassword
|
||
* @param {Uint8Array} salt
|
||
* @returns {Promise<CryptoKey>}
|
||
*/
|
||
async function deriveKey(masterPassword, salt) {
|
||
const keyMaterial = await crypto.subtle.importKey("raw", new TextEncoder().encode(masterPassword), "PBKDF2", false, ["deriveKey"]);
|
||
return crypto.subtle.deriveKey({
|
||
name: "PBKDF2",
|
||
salt,
|
||
iterations: PBKDF2_ITERATIONS,
|
||
hash: "SHA-256"
|
||
}, keyMaterial, {
|
||
name: "AES-GCM",
|
||
length: 256
|
||
}, false, ["encrypt", "decrypt"]);
|
||
}
|
||
/**
|
||
* Encrypt a plaintext string.
|
||
*
|
||
* @param {string} plaintext
|
||
* @param {CryptoKey} key
|
||
* @returns {Promise<string>} JSON string containing { iv, ciphertext }
|
||
* (salt is stored separately in the app store)
|
||
*/
|
||
async function encrypt(plaintext, key) {
|
||
const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH));
|
||
const encoded = new TextEncoder().encode(plaintext);
|
||
const ciphertext = await crypto.subtle.encrypt({
|
||
name: "AES-GCM",
|
||
iv
|
||
}, key, encoded);
|
||
return JSON.stringify({
|
||
iv: uint8ArrayToBase64(iv),
|
||
ciphertext: uint8ArrayToBase64(new Uint8Array(ciphertext))
|
||
});
|
||
}
|
||
/**
|
||
* Decrypt an encrypted blob back to plaintext.
|
||
*
|
||
* @param {string} encryptedJson - JSON string from encrypt()
|
||
* @param {CryptoKey} key
|
||
* @returns {Promise<string>}
|
||
*/
|
||
async function decrypt(encryptedJson, key) {
|
||
const { iv, ciphertext } = JSON.parse(encryptedJson);
|
||
const ciphertextBuffer = base64ToUint8Array$1(ciphertext);
|
||
const ivBuffer = base64ToUint8Array$1(iv);
|
||
const decrypted = await crypto.subtle.decrypt({
|
||
name: "AES-GCM",
|
||
iv: ivBuffer
|
||
}, key, ciphertextBuffer);
|
||
return new TextDecoder().decode(decrypted);
|
||
}
|
||
/**
|
||
* Verify that a master password is correct by attempting to decrypt a test payload.
|
||
*
|
||
* @param {string} masterPassword
|
||
* @param {Uint8Array} salt
|
||
* @param {string} testEncrypted - A known encrypted test string
|
||
* @param {string} testPlaintext - The expected plaintext
|
||
* @returns {Promise<boolean>}
|
||
*/
|
||
async function verifyPassword(masterPassword, salt, testEncrypted, testPlaintext) {
|
||
try {
|
||
return await decrypt(testEncrypted, await deriveKey(masterPassword, salt)) === testPlaintext;
|
||
} catch {
|
||
return false;
|
||
}
|
||
}
|
||
/**
|
||
* Create a test payload for password verification on first setup.
|
||
*
|
||
* @param {string} masterPassword
|
||
* @returns {Promise<{ salt: Uint8Array, testEncrypted: string }>}
|
||
*/
|
||
async function createTestPayload(masterPassword) {
|
||
const salt = generateSalt();
|
||
const key = await deriveKey(masterPassword, salt);
|
||
const testPlaintext = "vault_test_" + generateId();
|
||
return {
|
||
salt,
|
||
testEncrypted: await encrypt(testPlaintext, key),
|
||
testPlaintext
|
||
};
|
||
}
|
||
function uint8ArrayToBase64(buffer) {
|
||
const bytes = new Uint8Array(buffer);
|
||
let binary = "";
|
||
for (let i = 0; i < bytes.byteLength; i++) binary += String.fromCharCode(bytes[i]);
|
||
return btoa(binary);
|
||
}
|
||
function base64ToUint8Array$1(base64) {
|
||
const binary = atob(base64);
|
||
const bytes = new Uint8Array(binary.length);
|
||
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
||
return bytes;
|
||
}
|
||
/**
|
||
* Generate a random password.
|
||
*
|
||
* @param {Object} options
|
||
* @param {number} [options.length=16]
|
||
* @param {boolean} [options.uppercase=true]
|
||
* @param {boolean} [options.lowercase=true]
|
||
* @param {boolean} [options.digits=true]
|
||
* @param {boolean} [options.symbols=true]
|
||
* @param {string} [options.exclude='']
|
||
* @returns {string}
|
||
*/
|
||
function generatePassword({ length = 16, uppercase = true, lowercase = true, digits = true, symbols = true, exclude = "" } = {}) {
|
||
let charset = "";
|
||
if (uppercase) charset += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||
if (lowercase) charset += "abcdefghijklmnopqrstuvwxyz";
|
||
if (digits) charset += "0123456789";
|
||
if (symbols) charset += "!@#$%^&*()_+-=[]{}|;:,.<>?";
|
||
if (exclude) {
|
||
const excludeSet = new Set(exclude.split(""));
|
||
charset = charset.split("").filter((c) => !excludeSet.has(c)).join("");
|
||
}
|
||
if (!charset) throw new Error("Password charset is empty — enable at least one character type");
|
||
const randomValues = crypto.getRandomValues(new Uint8Array(length));
|
||
let password = "";
|
||
for (let i = 0; i < length; i++) password += charset[randomValues[i] % charset.length];
|
||
return password;
|
||
}
|
||
//#endregion
|
||
//#region node_modules/idb/build/index.js
|
||
var instanceOfAny = (object, constructors) => constructors.some((c) => object instanceof c);
|
||
var idbProxyableTypes;
|
||
var cursorAdvanceMethods;
|
||
function getIdbProxyableTypes() {
|
||
return idbProxyableTypes || (idbProxyableTypes = [
|
||
IDBDatabase,
|
||
IDBObjectStore,
|
||
IDBIndex,
|
||
IDBCursor,
|
||
IDBTransaction
|
||
]);
|
||
}
|
||
function getCursorAdvanceMethods() {
|
||
return cursorAdvanceMethods || (cursorAdvanceMethods = [
|
||
IDBCursor.prototype.advance,
|
||
IDBCursor.prototype.continue,
|
||
IDBCursor.prototype.continuePrimaryKey
|
||
]);
|
||
}
|
||
var transactionDoneMap = /* @__PURE__ */ new WeakMap();
|
||
var transformCache = /* @__PURE__ */ new WeakMap();
|
||
var reverseTransformCache = /* @__PURE__ */ new WeakMap();
|
||
function promisifyRequest(request) {
|
||
const promise = new Promise((resolve, reject) => {
|
||
const unlisten = () => {
|
||
request.removeEventListener("success", success);
|
||
request.removeEventListener("error", error);
|
||
};
|
||
const success = () => {
|
||
resolve(wrap(request.result));
|
||
unlisten();
|
||
};
|
||
const error = () => {
|
||
reject(request.error);
|
||
unlisten();
|
||
};
|
||
request.addEventListener("success", success);
|
||
request.addEventListener("error", error);
|
||
});
|
||
reverseTransformCache.set(promise, request);
|
||
return promise;
|
||
}
|
||
function cacheDonePromiseForTransaction(tx) {
|
||
if (transactionDoneMap.has(tx)) return;
|
||
const done = new Promise((resolve, reject) => {
|
||
const unlisten = () => {
|
||
tx.removeEventListener("complete", complete);
|
||
tx.removeEventListener("error", error);
|
||
tx.removeEventListener("abort", error);
|
||
};
|
||
const complete = () => {
|
||
resolve();
|
||
unlisten();
|
||
};
|
||
const error = () => {
|
||
reject(tx.error || new DOMException("AbortError", "AbortError"));
|
||
unlisten();
|
||
};
|
||
tx.addEventListener("complete", complete);
|
||
tx.addEventListener("error", error);
|
||
tx.addEventListener("abort", error);
|
||
});
|
||
transactionDoneMap.set(tx, done);
|
||
}
|
||
var idbProxyTraps = {
|
||
get(target, prop, receiver) {
|
||
if (target instanceof IDBTransaction) {
|
||
if (prop === "done") return transactionDoneMap.get(target);
|
||
if (prop === "store") return receiver.objectStoreNames[1] ? void 0 : receiver.objectStore(receiver.objectStoreNames[0]);
|
||
}
|
||
return wrap(target[prop]);
|
||
},
|
||
set(target, prop, value) {
|
||
target[prop] = value;
|
||
return true;
|
||
},
|
||
has(target, prop) {
|
||
if (target instanceof IDBTransaction && (prop === "done" || prop === "store")) return true;
|
||
return prop in target;
|
||
}
|
||
};
|
||
function replaceTraps(callback) {
|
||
idbProxyTraps = callback(idbProxyTraps);
|
||
}
|
||
function wrapFunction(func) {
|
||
if (getCursorAdvanceMethods().includes(func)) return function(...args) {
|
||
func.apply(unwrap(this), args);
|
||
return wrap(this.request);
|
||
};
|
||
return function(...args) {
|
||
return wrap(func.apply(unwrap(this), args));
|
||
};
|
||
}
|
||
function transformCachableValue(value) {
|
||
if (typeof value === "function") return wrapFunction(value);
|
||
if (value instanceof IDBTransaction) cacheDonePromiseForTransaction(value);
|
||
if (instanceOfAny(value, getIdbProxyableTypes())) return new Proxy(value, idbProxyTraps);
|
||
return value;
|
||
}
|
||
function wrap(value) {
|
||
if (value instanceof IDBRequest) return promisifyRequest(value);
|
||
if (transformCache.has(value)) return transformCache.get(value);
|
||
const newValue = transformCachableValue(value);
|
||
if (newValue !== value) {
|
||
transformCache.set(value, newValue);
|
||
reverseTransformCache.set(newValue, value);
|
||
}
|
||
return newValue;
|
||
}
|
||
var unwrap = (value) => reverseTransformCache.get(value);
|
||
/**
|
||
* Open a database.
|
||
*
|
||
* @param name Name of the database.
|
||
* @param version Schema version.
|
||
* @param callbacks Additional callbacks.
|
||
*/
|
||
function openDB(name, version, { blocked, upgrade, blocking, terminated } = {}) {
|
||
const request = indexedDB.open(name, version);
|
||
const openPromise = wrap(request);
|
||
if (upgrade) request.addEventListener("upgradeneeded", (event) => {
|
||
upgrade(wrap(request.result), event.oldVersion, event.newVersion, wrap(request.transaction), event);
|
||
});
|
||
if (blocked) request.addEventListener("blocked", (event) => blocked(event.oldVersion, event.newVersion, event));
|
||
openPromise.then((db) => {
|
||
if (terminated) db.addEventListener("close", () => terminated());
|
||
if (blocking) db.addEventListener("versionchange", (event) => blocking(event.oldVersion, event.newVersion, event));
|
||
}).catch(() => {});
|
||
return openPromise;
|
||
}
|
||
var readMethods = [
|
||
"get",
|
||
"getKey",
|
||
"getAll",
|
||
"getAllKeys",
|
||
"count"
|
||
];
|
||
var writeMethods = [
|
||
"put",
|
||
"add",
|
||
"delete",
|
||
"clear"
|
||
];
|
||
var cachedMethods = /* @__PURE__ */ new Map();
|
||
function getMethod(target, prop) {
|
||
if (!(target instanceof IDBDatabase && !(prop in target) && typeof prop === "string")) return;
|
||
if (cachedMethods.get(prop)) return cachedMethods.get(prop);
|
||
const targetFuncName = prop.replace(/FromIndex$/, "");
|
||
const useIndex = prop !== targetFuncName;
|
||
const isWrite = writeMethods.includes(targetFuncName);
|
||
if (!(targetFuncName in (useIndex ? IDBIndex : IDBObjectStore).prototype) || !(isWrite || readMethods.includes(targetFuncName))) return;
|
||
const method = async function(storeName, ...args) {
|
||
const tx = this.transaction(storeName, isWrite ? "readwrite" : "readonly");
|
||
let target = tx.store;
|
||
if (useIndex) target = target.index(args.shift());
|
||
return (await Promise.all([target[targetFuncName](...args), isWrite && tx.done]))[0];
|
||
};
|
||
cachedMethods.set(prop, method);
|
||
return method;
|
||
}
|
||
replaceTraps((oldTraps) => ({
|
||
...oldTraps,
|
||
get: (target, prop, receiver) => getMethod(target, prop) || oldTraps.get(target, prop, receiver),
|
||
has: (target, prop) => !!getMethod(target, prop) || oldTraps.has(target, prop)
|
||
}));
|
||
var advanceMethodProps = [
|
||
"continue",
|
||
"continuePrimaryKey",
|
||
"advance"
|
||
];
|
||
var methodMap = {};
|
||
var advanceResults = /* @__PURE__ */ new WeakMap();
|
||
var ittrProxiedCursorToOriginalProxy = /* @__PURE__ */ new WeakMap();
|
||
var cursorIteratorTraps = { get(target, prop) {
|
||
if (!advanceMethodProps.includes(prop)) return target[prop];
|
||
let cachedFunc = methodMap[prop];
|
||
if (!cachedFunc) cachedFunc = methodMap[prop] = function(...args) {
|
||
advanceResults.set(this, ittrProxiedCursorToOriginalProxy.get(this)[prop](...args));
|
||
};
|
||
return cachedFunc;
|
||
} };
|
||
async function* iterate(...args) {
|
||
let cursor = this;
|
||
if (!(cursor instanceof IDBCursor)) cursor = await cursor.openCursor(...args);
|
||
if (!cursor) return;
|
||
cursor = cursor;
|
||
const proxiedCursor = new Proxy(cursor, cursorIteratorTraps);
|
||
ittrProxiedCursorToOriginalProxy.set(proxiedCursor, cursor);
|
||
reverseTransformCache.set(proxiedCursor, unwrap(cursor));
|
||
while (cursor) {
|
||
yield proxiedCursor;
|
||
cursor = await (advanceResults.get(proxiedCursor) || cursor.continue());
|
||
advanceResults.delete(proxiedCursor);
|
||
}
|
||
}
|
||
function isIteratorProp(target, prop) {
|
||
return prop === Symbol.asyncIterator && instanceOfAny(target, [
|
||
IDBIndex,
|
||
IDBObjectStore,
|
||
IDBCursor
|
||
]) || prop === "iterate" && instanceOfAny(target, [IDBIndex, IDBObjectStore]);
|
||
}
|
||
replaceTraps((oldTraps) => ({
|
||
...oldTraps,
|
||
get(target, prop, receiver) {
|
||
if (isIteratorProp(target, prop)) return iterate;
|
||
return oldTraps.get(target, prop, receiver);
|
||
},
|
||
has(target, prop) {
|
||
return isIteratorProp(target, prop) || oldTraps.has(target, prop);
|
||
}
|
||
}));
|
||
//#endregion
|
||
//#region src/lib/storage/db.js
|
||
/**
|
||
* IndexedDB storage layer using the `idb` wrapper.
|
||
*
|
||
* Database: "password-vault"
|
||
* - Object store "entries": stores CredentialEntry objects
|
||
* - Object store "groups": stores Group objects
|
||
* - Object store "meta": stores app metadata (salt, test payload, version)
|
||
*
|
||
* All passwords are stored as encrypted blobs (encryptedPassword field).
|
||
* The encryption key is never stored — only the salt and a test payload
|
||
* for password verification.
|
||
*/
|
||
var DB_NAME = "password-vault";
|
||
var DB_VERSION = 1;
|
||
/**
|
||
* Open (or create) the database.
|
||
* @returns {Promise<IDBPDatabase>}
|
||
*/
|
||
async function getDb() {
|
||
return openDB(DB_NAME, DB_VERSION, { upgrade(db) {
|
||
if (!db.objectStoreNames.contains("entries")) {
|
||
const entryStore = db.createObjectStore("entries", { keyPath: "id" });
|
||
entryStore.createIndex("groupId", "groupId");
|
||
entryStore.createIndex("updatedAt", "updatedAt");
|
||
}
|
||
if (!db.objectStoreNames.contains("groups")) db.createObjectStore("groups", { keyPath: "id" });
|
||
if (!db.objectStoreNames.contains("meta")) db.createObjectStore("meta", { keyPath: "key" });
|
||
} });
|
||
}
|
||
/**
|
||
* Store the vault's salt and test payload (used for password verification).
|
||
*
|
||
* @param {Uint8Array} salt
|
||
* @param {string} testEncrypted
|
||
* @param {string} testPlaintext
|
||
*/
|
||
async function saveVaultMeta(salt, testEncrypted, testPlaintext) {
|
||
const tx = (await getDb()).transaction("meta", "readwrite");
|
||
let binary = "";
|
||
for (let i = 0; i < salt.byteLength; i++) binary += String.fromCharCode(salt[i]);
|
||
const saltBase64 = btoa(binary);
|
||
await tx.store.put({
|
||
key: "salt",
|
||
value: saltBase64
|
||
});
|
||
await tx.store.put({
|
||
key: "testEncrypted",
|
||
value: testEncrypted
|
||
});
|
||
await tx.store.put({
|
||
key: "testPlaintext",
|
||
value: testPlaintext
|
||
});
|
||
await tx.store.put({
|
||
key: "dbVersion",
|
||
value: DB_VERSION
|
||
});
|
||
await tx.done;
|
||
}
|
||
/**
|
||
* Load the vault's salt and test payload.
|
||
*
|
||
* @returns {Promise<{ salt: Uint8Array|null, testEncrypted: string|null, testPlaintext: string|null }>}
|
||
*/
|
||
async function loadVaultMeta() {
|
||
const store = (await getDb()).transaction("meta", "readonly").store;
|
||
const saltRow = await store.get("salt");
|
||
const testEncryptedRow = await store.get("testEncrypted");
|
||
const testPlaintextRow = await store.get("testPlaintext");
|
||
let salt = null;
|
||
if (saltRow?.value) {
|
||
const binary = atob(saltRow.value);
|
||
const bytes = new Uint8Array(binary.length);
|
||
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
||
salt = bytes;
|
||
}
|
||
return {
|
||
salt,
|
||
testEncrypted: testEncryptedRow?.value || null,
|
||
testPlaintext: testPlaintextRow?.value || null
|
||
};
|
||
}
|
||
/**
|
||
* Check if the vault has been initialized (has a salt stored).
|
||
* @returns {Promise<boolean>}
|
||
*/
|
||
async function isVaultInitialized() {
|
||
return (await loadVaultMeta()).salt !== null;
|
||
}
|
||
/**
|
||
* @typedef {import('../models/schema.js').Group} Group
|
||
*/
|
||
/**
|
||
* Add a group.
|
||
* @param {Group} group
|
||
* @returns {Promise<void>}
|
||
*/
|
||
async function addGroup(group) {
|
||
await (await getDb()).put("groups", group);
|
||
}
|
||
/**
|
||
* Update a group.
|
||
* @param {Group} group
|
||
* @returns {Promise<void>}
|
||
*/
|
||
async function updateGroup(group) {
|
||
await (await getDb()).put("groups", group);
|
||
}
|
||
/**
|
||
* Delete a group (does NOT delete associated entries — they become ungrouped).
|
||
* @param {string} groupId
|
||
* @returns {Promise<void>}
|
||
*/
|
||
async function deleteGroup(groupId) {
|
||
await (await getDb()).delete("groups", groupId);
|
||
}
|
||
/**
|
||
* Get all groups, sorted by creation date.
|
||
* @returns {Promise<Group[]>}
|
||
*/
|
||
async function getGroups() {
|
||
return (await (await getDb()).transaction("groups", "readonly").store.getAll()).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
||
}
|
||
/**
|
||
* @typedef {import('../models/schema.js').CredentialEntry} CredentialEntry
|
||
*/
|
||
/**
|
||
* Add an entry.
|
||
* @param {CredentialEntry} entry
|
||
* @returns {Promise<void>}
|
||
*/
|
||
async function addEntry(entry) {
|
||
await (await getDb()).put("entries", entry);
|
||
}
|
||
/**
|
||
* Update an entry.
|
||
* @param {CredentialEntry} entry
|
||
* @returns {Promise<void>}
|
||
*/
|
||
async function updateEntry(entry) {
|
||
await (await getDb()).put("entries", entry);
|
||
}
|
||
/**
|
||
* Delete an entry.
|
||
* @param {string} entryId
|
||
* @returns {Promise<void>}
|
||
*/
|
||
async function deleteEntry(entryId) {
|
||
await (await getDb()).delete("entries", entryId);
|
||
}
|
||
/**
|
||
* Get a single entry by ID.
|
||
* @param {string} entryId
|
||
* @returns {Promise<CredentialEntry | undefined>}
|
||
*/
|
||
async function getEntryById(entryId) {
|
||
return (await getDb()).get("entries", entryId);
|
||
}
|
||
/**
|
||
* Get all entries. Optionally filter by groupId.
|
||
* Results sorted by updatedAt descending (most recent first).
|
||
*
|
||
* @param {Object} [options]
|
||
* @param {string} [options.groupId] - Filter by group (empty string = ungrouped)
|
||
* @returns {Promise<CredentialEntry[]>}
|
||
*/
|
||
async function getEntries(options = {}) {
|
||
const db = await getDb();
|
||
let entries;
|
||
if (options.groupId !== void 0) entries = await db.transaction("entries").store.index("groupId").getAll(options.groupId);
|
||
else entries = await db.getAll("entries");
|
||
return entries.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
||
}
|
||
/**
|
||
* Search entries by query string (matches title, username, url, notes).
|
||
*
|
||
* @param {string} query
|
||
* @param {Object} [options]
|
||
* @param {string} [options.groupId]
|
||
* @returns {Promise<CredentialEntry[]>}
|
||
*/
|
||
async function searchEntries(query, options = {}) {
|
||
const entries = await getEntries(options);
|
||
const lower = query.toLowerCase();
|
||
return entries.filter((e) => e.title.toLowerCase().includes(lower) || e.username.toLowerCase().includes(lower) || e.url && e.url.toLowerCase().includes(lower) || e.notes && e.notes.toLowerCase().includes(lower));
|
||
}
|
||
/**
|
||
* Count entries per group.
|
||
* @returns {Promise<Map<string, number>>}
|
||
*/
|
||
async function getEntryCountsByGroup() {
|
||
const all = await (await getDb()).getAll("entries");
|
||
const counts = /* @__PURE__ */ new Map();
|
||
for (const entry of all) {
|
||
const gid = entry.groupId || "";
|
||
counts.set(gid, (counts.get(gid) || 0) + 1);
|
||
}
|
||
return counts;
|
||
}
|
||
/**
|
||
* Export all data (entries + groups + meta) as a JSON object.
|
||
* Entries remain encrypted with the source vault's key. The import function
|
||
* requires the source vault's master password to decrypt and re-encrypt
|
||
* entries under the target vault's key.
|
||
*
|
||
* @returns {Promise<Object>}
|
||
*/
|
||
async function exportAll() {
|
||
const db = await getDb();
|
||
const entries = await db.getAll("entries");
|
||
const groups = await db.getAll("groups");
|
||
const saltRow = await db.get("meta", "salt");
|
||
const testEncryptedRow = await db.get("meta", "testEncrypted");
|
||
const testPlaintextRow = await db.get("meta", "testPlaintext");
|
||
return {
|
||
version: DB_VERSION,
|
||
exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
||
meta: {
|
||
salt: saltRow?.value || null,
|
||
testEncrypted: testEncryptedRow?.value || null,
|
||
testPlaintext: testPlaintextRow?.value || null
|
||
},
|
||
groups,
|
||
entries
|
||
};
|
||
}
|
||
/**
|
||
* Convert a base64 string back to Uint8Array.
|
||
* @param {string} base64
|
||
* @returns {Uint8Array}
|
||
*/
|
||
function base64ToUint8Array(base64) {
|
||
const binary = atob(base64);
|
||
const bytes = new Uint8Array(binary.length);
|
||
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
||
return bytes;
|
||
}
|
||
/**
|
||
* Import data from a previously exported JSON object.
|
||
*
|
||
* Requires the source vault's master password to decrypt entries, then
|
||
* re-encrypts them under the target vault's current encryption key.
|
||
* The target vault's meta (salt, test payload) is never overwritten.
|
||
*
|
||
* @param {Object} data
|
||
* @param {'merge'|'replace'} mode - 'merge' adds to existing, 'replace' clears first
|
||
* @param {string} sourcePassword - Master password of the source vault
|
||
* @param {CryptoKey} targetKey - Current encryption key of the target vault
|
||
* @returns {Promise<{ imported: { entries: number, groups: number }, skipped: number }>}
|
||
*/
|
||
async function importAll(data, mode = "merge", sourcePassword = "", targetKey = null) {
|
||
if (!data || !Array.isArray(data.entries) || !Array.isArray(data.groups)) throw new Error("Invalid import data format");
|
||
let sourceKey = null;
|
||
if (data.meta?.salt && sourcePassword) sourceKey = await deriveKey(sourcePassword, base64ToUint8Array(data.meta.salt));
|
||
const db = await getDb();
|
||
if (mode === "replace") {
|
||
await db.clear("entries");
|
||
await db.clear("groups");
|
||
}
|
||
let skipped = 0;
|
||
let importedEntries = 0;
|
||
let importedGroups = 0;
|
||
for (const group of data.groups) try {
|
||
await db.put("groups", group);
|
||
importedGroups++;
|
||
} catch {
|
||
skipped++;
|
||
}
|
||
for (const entry of data.entries) try {
|
||
let reencryptedEntry = { ...entry };
|
||
if (sourceKey && targetKey && entry.encryptedPassword) reencryptedEntry.encryptedPassword = await encrypt(await decrypt(entry.encryptedPassword, sourceKey), targetKey);
|
||
else if (!sourceKey || !targetKey) {
|
||
console.warn("Skipping entry (missing source password or target key):", entry.title);
|
||
skipped++;
|
||
continue;
|
||
}
|
||
await db.put("entries", reencryptedEntry);
|
||
importedEntries++;
|
||
} catch (e) {
|
||
console.warn("Failed to import entry:", entry.title, e);
|
||
skipped++;
|
||
}
|
||
return {
|
||
imported: {
|
||
entries: importedEntries,
|
||
groups: importedGroups
|
||
},
|
||
skipped
|
||
};
|
||
}
|
||
//#endregion
|
||
//#region src/components/LockScreen.svelte
|
||
var root_1$8 = /* @__PURE__ */ from_html(`<div class="error-banner svelte-7sq1ct" role="alert"> </div>`);
|
||
var root_2$6 = /* @__PURE__ */ from_html(`<div class="form-group"><label for="confirm-password">Confirm Password</label> <input id="confirm-password" type="password" placeholder="Confirm master password" autocomplete="new-password"/></div>`);
|
||
var root$7 = /* @__PURE__ */ from_html(`<div class="lock-screen svelte-7sq1ct"><div class="lock-card svelte-7sq1ct"><div class="lock-icon svelte-7sq1ct">🔐</div> <h1 class="svelte-7sq1ct">Password Vault</h1> <p class="subtitle svelte-7sq1ct"> </p> <!> <form class="lock-form svelte-7sq1ct"><div class="form-group"><label for="master-password">Master Password</label> <input id="master-password" type="password" placeholder="Enter master password" autocomplete="current-password"/></div> <!> <button type="submit" class="btn btn-primary w-full"> </button></form> <p class="hint svelte-7sq1ct"> </p></div></div>`);
|
||
function LockScreen($$anchor, $$props) {
|
||
push($$props, true);
|
||
let masterPassword = /* @__PURE__ */ state("");
|
||
let confirmPassword = /* @__PURE__ */ state("");
|
||
let error = /* @__PURE__ */ state("");
|
||
let loading = /* @__PURE__ */ state(false);
|
||
let isSetup = /* @__PURE__ */ state(false);
|
||
async function checkVault() {
|
||
set(isSetup, !await isVaultInitialized());
|
||
}
|
||
checkVault();
|
||
async function handleSubmit() {
|
||
set(error, "");
|
||
set(loading, true);
|
||
try {
|
||
if (get(isSetup)) {
|
||
if (!get(masterPassword) || get(masterPassword).length < 4) {
|
||
set(error, "Password must be at least 4 characters");
|
||
set(loading, false);
|
||
return;
|
||
}
|
||
if (get(masterPassword) !== get(confirmPassword)) {
|
||
set(error, "Passwords do not match");
|
||
set(loading, false);
|
||
return;
|
||
}
|
||
const { salt, testEncrypted, testPlaintext } = await createTestPayload(get(masterPassword));
|
||
app$1.salt = salt;
|
||
app$1.encryptionKey = await deriveKey(get(masterPassword), salt);
|
||
await saveVaultMeta(salt, testEncrypted, testPlaintext);
|
||
app$1.isUnlocked = true;
|
||
startAutoLock();
|
||
} else {
|
||
const meta = await loadVaultMeta();
|
||
if (!meta.salt || !meta.testEncrypted || !meta.testPlaintext) {
|
||
set(error, "Vault data corrupted");
|
||
set(loading, false);
|
||
return;
|
||
}
|
||
const key = await deriveKey(get(masterPassword), meta.salt);
|
||
if (!await verifyPassword(get(masterPassword), meta.salt, meta.testEncrypted, meta.testPlaintext)) {
|
||
set(error, "Incorrect password");
|
||
set(loading, false);
|
||
return;
|
||
}
|
||
app$1.salt = meta.salt;
|
||
app$1.encryptionKey = key;
|
||
app$1.isUnlocked = true;
|
||
startAutoLock();
|
||
}
|
||
} catch (e) {
|
||
console.error(e);
|
||
set(error, "An error occurred: " + e.message);
|
||
}
|
||
set(loading, false);
|
||
set(masterPassword, "");
|
||
set(confirmPassword, "");
|
||
}
|
||
var div = root$7();
|
||
var div_1 = child(div);
|
||
var p = sibling(child(div_1), 4);
|
||
var text = child(p, true);
|
||
reset(p);
|
||
var node = sibling(p, 2);
|
||
var consequent = ($$anchor) => {
|
||
var div_2 = root_1$8();
|
||
var text_1 = child(div_2, true);
|
||
reset(div_2);
|
||
template_effect(() => set_text(text_1, get(error)));
|
||
append($$anchor, div_2);
|
||
};
|
||
if_block(node, ($$render) => {
|
||
if (get(error)) $$render(consequent);
|
||
});
|
||
var form = sibling(node, 2);
|
||
var div_3 = child(form);
|
||
var input = sibling(child(div_3), 2);
|
||
remove_input_defaults(input);
|
||
reset(div_3);
|
||
var node_1 = sibling(div_3, 2);
|
||
var consequent_1 = ($$anchor) => {
|
||
var div_4 = root_2$6();
|
||
var input_1 = sibling(child(div_4), 2);
|
||
remove_input_defaults(input_1);
|
||
reset(div_4);
|
||
template_effect(() => input_1.disabled = get(loading));
|
||
bind_value(input_1, () => get(confirmPassword), ($$value) => set(confirmPassword, $$value));
|
||
append($$anchor, div_4);
|
||
};
|
||
if_block(node_1, ($$render) => {
|
||
if (get(isSetup)) $$render(consequent_1);
|
||
});
|
||
var button = sibling(node_1, 2);
|
||
var text_2 = child(button, true);
|
||
reset(button);
|
||
reset(form);
|
||
var p_1 = sibling(form, 2);
|
||
var text_3 = child(p_1, true);
|
||
reset(p_1);
|
||
reset(div_1);
|
||
reset(div);
|
||
template_effect(() => {
|
||
set_text(text, get(isSetup) ? "Create your vault" : "Unlock your vault");
|
||
input.disabled = get(loading);
|
||
button.disabled = get(loading);
|
||
set_text(text_2, get(loading) ? "Processing..." : get(isSetup) ? "Create Vault" : "Unlock");
|
||
set_text(text_3, get(isSetup) ? "Your master password encrypts all data locally. It cannot be recovered if lost." : "Your data is encrypted with AES-256-GCM. Key is stored only in memory.");
|
||
});
|
||
event("submit", form, (e) => {
|
||
e.preventDefault();
|
||
handleSubmit();
|
||
});
|
||
bind_value(input, () => get(masterPassword), ($$value) => set(masterPassword, $$value));
|
||
append($$anchor, div);
|
||
pop();
|
||
}
|
||
//#endregion
|
||
//#region src/lib/stores/search.svelte.js
|
||
var SearchStore = class {
|
||
#query = /* @__PURE__ */ state("");
|
||
get query() {
|
||
return get(this.#query);
|
||
}
|
||
set query(value) {
|
||
set(this.#query, value, true);
|
||
}
|
||
#activeGroupId = /* @__PURE__ */ state("all");
|
||
get activeGroupId() {
|
||
return get(this.#activeGroupId);
|
||
}
|
||
set activeGroupId(value) {
|
||
set(this.#activeGroupId, value, true);
|
||
}
|
||
#refreshTrigger = /* @__PURE__ */ state(0);
|
||
get refreshTrigger() {
|
||
return get(this.#refreshTrigger);
|
||
}
|
||
set refreshTrigger(value) {
|
||
set(this.#refreshTrigger, value, true);
|
||
}
|
||
clear() {
|
||
this.query = "";
|
||
this.activeGroupId = "all";
|
||
}
|
||
/** Force subscribed components to re-fetch data. */
|
||
refresh() {
|
||
this.refreshTrigger++;
|
||
}
|
||
};
|
||
var search = new SearchStore();
|
||
//#endregion
|
||
//#region src/components/Sidebar.svelte
|
||
var root_1$7 = /* @__PURE__ */ from_html(`<div role="button" tabindex="0"><button><span class="group-color svelte-181dlmc"></span> <span class="group-name svelte-181dlmc"> </span></button> <div class="group-actions svelte-181dlmc"><button class="group-action-btn svelte-181dlmc" title="Edit group">✏️</button> <button class="group-action-btn svelte-181dlmc" title="Delete group">🗑</button></div></div>`);
|
||
var root_3$5 = /* @__PURE__ */ from_html(`<div class="error-banner svelte-181dlmc"> </div>`);
|
||
var root_4$5 = /* @__PURE__ */ from_html(`<button></button>`);
|
||
var root_2$5 = /* @__PURE__ */ from_html(`<div class="modal-overlay svelte-181dlmc" role="presentation"><div class="modal svelte-181dlmc" role="dialog" aria-modal="true" aria-label="Group settings" tabindex="-1"><h3 class="svelte-181dlmc"> </h3> <!> <div class="form-group"><label for="group-name">Group Name</label> <input id="group-name" type="text" placeholder="e.g. Work, Personal"/></div> <div class="form-group"><span class="field-label">Color</span> <div class="color-picker svelte-181dlmc"></div></div> <div class="modal-actions svelte-181dlmc"><button class="btn btn-primary"> </button> <button class="btn btn-ghost">Cancel</button></div></div></div>`);
|
||
var root_5$4 = /* @__PURE__ */ from_html(`<div class="drop-indicator svelte-181dlmc">Drop here to move</div>`);
|
||
var root_6$5 = /* @__PURE__ */ from_html(`<div class="modal-overlay svelte-181dlmc" role="presentation"><div class="modal svelte-181dlmc" role="dialog" aria-modal="true" aria-label="Delete group confirmation" tabindex="-1"><h3 class="svelte-181dlmc">Delete Group</h3> <p class="svelte-181dlmc">Delete "<strong> </strong>"? Entries in this group will become ungrouped.</p> <div class="modal-actions svelte-181dlmc"><button class="btn btn-danger">Yes, delete</button> <button class="btn btn-ghost">Cancel</button></div></div></div>`);
|
||
var root$6 = /* @__PURE__ */ from_html(`<div class="sidebar-content svelte-181dlmc"><div class="sidebar-header svelte-181dlmc"><h2 class="svelte-181dlmc">🔐 Vault</h2></div> <div class="search-box svelte-181dlmc"><input type="text" placeholder="Search entries..." class="svelte-181dlmc"/></div> <nav class="groups-nav svelte-181dlmc"><div role="button" tabindex="0" aria-label="Drop here to remove from group"><button><span class="group-icon svelte-181dlmc">📋</span> <span class="group-name svelte-181dlmc">All Entries</span></button></div> <!></nav> <div class="sidebar-footer svelte-181dlmc"><button class="btn btn-ghost btn-sm w-full">+ New Group</button></div> <!> <!> <!></div>`);
|
||
function Sidebar($$anchor, $$props) {
|
||
push($$props, true);
|
||
let groups = /* @__PURE__ */ state(proxy([]));
|
||
let entryCounts = /* @__PURE__ */ state(proxy(/* @__PURE__ */ new Map()));
|
||
let showGroupForm = /* @__PURE__ */ state(false);
|
||
let editingGroupId = /* @__PURE__ */ state(null);
|
||
let groupName = /* @__PURE__ */ state("");
|
||
let groupColor = /* @__PURE__ */ state("#6c63ff");
|
||
let groupError = /* @__PURE__ */ state("");
|
||
let showDeleteGroupConfirm = /* @__PURE__ */ state(null);
|
||
let deletingGroup = /* @__PURE__ */ user_derived(() => get(groups).find((g) => g.id === get(showDeleteGroupConfirm)));
|
||
let dropTargetGroupId = /* @__PURE__ */ state(null);
|
||
const GROUP_COLORS = [
|
||
"#6c63ff",
|
||
"#e5484d",
|
||
"#34d399",
|
||
"#fbbf24",
|
||
"#3b82f6",
|
||
"#ec4899",
|
||
"#8b5cf6",
|
||
"#14b8a6",
|
||
"#f97316",
|
||
"#06b6d4",
|
||
"#a855f7",
|
||
"#ef4444",
|
||
"#22c55e",
|
||
"#eab308",
|
||
"#6366f1"
|
||
];
|
||
async function loadData() {
|
||
const [g, counts] = await Promise.all([getGroups(), getEntryCountsByGroup()]);
|
||
set(groups, g, true);
|
||
set(entryCounts, counts, true);
|
||
}
|
||
user_effect(() => {
|
||
search.refreshTrigger;
|
||
loadData();
|
||
});
|
||
function openGroupForm(group = null) {
|
||
if (group) {
|
||
set(editingGroupId, group.id, true);
|
||
set(groupName, group.name, true);
|
||
set(groupColor, group.color || "#6c63ff", true);
|
||
} else {
|
||
set(editingGroupId, null);
|
||
set(groupName, "");
|
||
set(groupColor, GROUP_COLORS[Math.floor(Math.random() * GROUP_COLORS.length)], true);
|
||
}
|
||
set(groupError, "");
|
||
set(showGroupForm, true);
|
||
}
|
||
async function saveGroup() {
|
||
set(groupError, "");
|
||
const validation = validateGroup(get(groupName));
|
||
if (!validation.valid) {
|
||
set(groupError, validation.errors[0], true);
|
||
return;
|
||
}
|
||
try {
|
||
if (get(editingGroupId)) await updateGroup({
|
||
...get(groups).find((g) => g.id === get(editingGroupId)),
|
||
name: get(groupName).trim(),
|
||
color: get(groupColor)
|
||
});
|
||
else await addGroup(createGroup(get(groupName), get(groupColor)));
|
||
set(showGroupForm, false);
|
||
await loadData();
|
||
} catch (e) {
|
||
set(groupError, "Failed to save group: " + e.message);
|
||
}
|
||
}
|
||
async function confirmDeleteGroup(groupId) {
|
||
try {
|
||
await deleteGroup(groupId);
|
||
if (search.activeGroupId === groupId) search.activeGroupId = "all";
|
||
set(showDeleteGroupConfirm, null);
|
||
await loadData();
|
||
} catch (e) {
|
||
set(groupError, "Failed to delete group: " + e.message);
|
||
}
|
||
}
|
||
function onDragOverGroup(e, groupId) {
|
||
e.preventDefault();
|
||
e.dataTransfer.dropEffect = "move";
|
||
set(dropTargetGroupId, groupId, true);
|
||
}
|
||
function onDragLeaveGroup() {
|
||
set(dropTargetGroupId, null);
|
||
}
|
||
function resetDropTarget() {
|
||
set(dropTargetGroupId, null);
|
||
}
|
||
async function onDropGroup(groupId, e) {
|
||
e.preventDefault();
|
||
set(dropTargetGroupId, groupId, true);
|
||
const entryId = e.dataTransfer.getData("text/plain");
|
||
if (!entryId) return;
|
||
try {
|
||
const entry = await getEntryById(entryId);
|
||
if (!entry) return;
|
||
const newGroupId = groupId === "all" ? "" : groupId;
|
||
await updateEntry({
|
||
...entry,
|
||
groupId: newGroupId,
|
||
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
||
});
|
||
await loadData();
|
||
resetDropTarget();
|
||
search.refresh();
|
||
} catch (err) {
|
||
console.error("Failed to move entry:", err);
|
||
resetDropTarget();
|
||
}
|
||
}
|
||
var div = root$6();
|
||
var div_1 = sibling(child(div), 2);
|
||
var input = child(div_1);
|
||
remove_input_defaults(input);
|
||
reset(div_1);
|
||
var nav = sibling(div_1, 2);
|
||
var div_2 = child(nav);
|
||
var button = child(div_2);
|
||
reset(div_2);
|
||
each(sibling(div_2, 2), 17, () => get(groups), index, ($$anchor, group) => {
|
||
var div_3 = root_1$7();
|
||
var button_1 = child(div_3);
|
||
var span = child(button_1);
|
||
var span_1 = sibling(span, 2);
|
||
var text = child(span_1, true);
|
||
reset(span_1);
|
||
reset(button_1);
|
||
var div_4 = sibling(button_1, 2);
|
||
var button_2 = child(div_4);
|
||
var button_3 = sibling(button_2, 2);
|
||
reset(div_4);
|
||
reset(div_3);
|
||
template_effect(() => {
|
||
set_class(div_3, 1, `group-row ${get(dropTargetGroupId) === get(group).id ? "drop-target" : ""}`, "svelte-181dlmc");
|
||
set_attribute(div_3, "aria-label", `Drop here to move to ${get(group).name}`);
|
||
set_class(button_1, 1, `group-item ${search.activeGroupId === get(group).id ? "active" : ""}`, "svelte-181dlmc");
|
||
set_style(span, `background-color: ${(get(group).color || "#6c63ff") ?? ""}`);
|
||
set_text(text, get(group).name);
|
||
});
|
||
event("dragover", div_3, (e) => onDragOverGroup(e, get(group).id));
|
||
event("dragleave", div_3, onDragLeaveGroup);
|
||
event("drop", div_3, (e) => onDropGroup(get(group).id, e));
|
||
delegated("pointerup", button_1, () => {
|
||
if (get(dropTargetGroupId) === get(group).id) {
|
||
resetDropTarget();
|
||
return;
|
||
}
|
||
search.activeGroupId = get(group).id;
|
||
});
|
||
delegated("click", button_2, () => openGroupForm(get(group)));
|
||
delegated("click", button_3, () => set(showDeleteGroupConfirm, get(group).id, true));
|
||
append($$anchor, div_3);
|
||
});
|
||
reset(nav);
|
||
var div_5 = sibling(nav, 2);
|
||
var button_4 = child(div_5);
|
||
reset(div_5);
|
||
var node_1 = sibling(div_5, 2);
|
||
var consequent_1 = ($$anchor) => {
|
||
var div_6 = root_2$5();
|
||
var div_7 = child(div_6);
|
||
var h3 = child(div_7);
|
||
var text_1 = child(h3, true);
|
||
reset(h3);
|
||
var node_2 = sibling(h3, 2);
|
||
var consequent = ($$anchor) => {
|
||
var div_8 = root_3$5();
|
||
var text_2 = child(div_8, true);
|
||
reset(div_8);
|
||
template_effect(() => set_text(text_2, get(groupError)));
|
||
append($$anchor, div_8);
|
||
};
|
||
if_block(node_2, ($$render) => {
|
||
if (get(groupError)) $$render(consequent);
|
||
});
|
||
var div_9 = sibling(node_2, 2);
|
||
var input_1 = sibling(child(div_9), 2);
|
||
remove_input_defaults(input_1);
|
||
reset(div_9);
|
||
var div_10 = sibling(div_9, 2);
|
||
var div_11 = sibling(child(div_10), 2);
|
||
each(div_11, 21, () => GROUP_COLORS, index, ($$anchor, color) => {
|
||
var button_5 = root_4$5();
|
||
template_effect(() => {
|
||
set_class(button_5, 1, `color-swatch ${get(groupColor) === get(color) ? "selected" : ""}`, "svelte-181dlmc");
|
||
set_style(button_5, `background-color: ${get(color) ?? ""}`);
|
||
set_attribute(button_5, "title", get(color));
|
||
});
|
||
delegated("click", button_5, () => set(groupColor, get(color), true));
|
||
append($$anchor, button_5);
|
||
});
|
||
reset(div_11);
|
||
reset(div_10);
|
||
var div_12 = sibling(div_10, 2);
|
||
var button_6 = child(div_12);
|
||
var text_3 = child(button_6, true);
|
||
reset(button_6);
|
||
var button_7 = sibling(button_6, 2);
|
||
reset(div_12);
|
||
reset(div_7);
|
||
reset(div_6);
|
||
template_effect(() => {
|
||
set_text(text_1, get(editingGroupId) ? "Edit Group" : "New Group");
|
||
set_text(text_3, get(editingGroupId) ? "Update" : "Create");
|
||
});
|
||
delegated("click", div_6, () => set(showGroupForm, false));
|
||
delegated("click", div_7, (e) => e.stopPropagation());
|
||
bind_value(input_1, () => get(groupName), ($$value) => set(groupName, $$value));
|
||
delegated("click", button_6, saveGroup);
|
||
delegated("click", button_7, () => set(showGroupForm, false));
|
||
append($$anchor, div_6);
|
||
};
|
||
if_block(node_1, ($$render) => {
|
||
if (get(showGroupForm)) $$render(consequent_1);
|
||
});
|
||
var node_3 = sibling(node_1, 2);
|
||
var consequent_2 = ($$anchor) => {
|
||
append($$anchor, root_5$4());
|
||
};
|
||
if_block(node_3, ($$render) => {
|
||
if (get(dropTargetGroupId)) $$render(consequent_2);
|
||
});
|
||
var node_4 = sibling(node_3, 2);
|
||
var consequent_3 = ($$anchor) => {
|
||
var div_14 = root_6$5();
|
||
var div_15 = child(div_14);
|
||
var p = sibling(child(div_15), 2);
|
||
var strong = sibling(child(p));
|
||
var text_4 = child(strong, true);
|
||
reset(strong);
|
||
next();
|
||
reset(p);
|
||
var div_16 = sibling(p, 2);
|
||
var button_8 = child(div_16);
|
||
var button_9 = sibling(button_8, 2);
|
||
reset(div_16);
|
||
reset(div_15);
|
||
reset(div_14);
|
||
template_effect(() => set_text(text_4, get(deletingGroup).name));
|
||
delegated("click", div_14, () => set(showDeleteGroupConfirm, null));
|
||
delegated("click", div_15, (e) => e.stopPropagation());
|
||
delegated("click", button_8, () => confirmDeleteGroup(get(deletingGroup).id));
|
||
delegated("click", button_9, () => set(showDeleteGroupConfirm, null));
|
||
append($$anchor, div_14);
|
||
};
|
||
if_block(node_4, ($$render) => {
|
||
if (get(deletingGroup)) $$render(consequent_3);
|
||
});
|
||
reset(div);
|
||
template_effect(() => {
|
||
set_value(input, search.query);
|
||
set_class(div_2, 1, `group-wrapper ${get(dropTargetGroupId) === "all" ? "drop-target" : ""}`, "svelte-181dlmc");
|
||
set_class(button, 1, `group-item ${search.activeGroupId === "all" ? "active" : ""}`, "svelte-181dlmc");
|
||
});
|
||
event("Input", input, (e) => search.query = e.target.value);
|
||
event("dragover", div_2, (e) => onDragOverGroup(e, "all"));
|
||
event("dragleave", div_2, onDragLeaveGroup);
|
||
event("drop", div_2, (e) => onDropGroup("all", e));
|
||
delegated("pointerup", button, () => {
|
||
if (get(dropTargetGroupId) === "all") {
|
||
resetDropTarget();
|
||
return;
|
||
}
|
||
search.activeGroupId = "all";
|
||
});
|
||
delegated("click", button_4, () => openGroupForm(null));
|
||
append($$anchor, div);
|
||
pop();
|
||
}
|
||
delegate(["pointerup", "click"]);
|
||
//#endregion
|
||
//#region src/components/EntryList.svelte
|
||
var root_1$6 = /* @__PURE__ */ from_html(`<div class="loading svelte-13s7gu4">Loading entries...</div>`);
|
||
var root_2$4 = /* @__PURE__ */ from_html(`<div class="error-banner svelte-13s7gu4"> </div>`);
|
||
var root_4$4 = /* @__PURE__ */ from_html(`<button class="btn btn-primary mt-3">+ New Entry</button>`);
|
||
var root_3$4 = /* @__PURE__ */ from_html(`<div class="empty-state svelte-13s7gu4"><p class="empty-icon svelte-13s7gu4"> </p> <p class="empty-text svelte-13s7gu4"> </p> <p class="empty-hint svelte-13s7gu4"> </p> <!></div>`);
|
||
var root_6$4 = /* @__PURE__ */ from_html(`matching "<strong> </strong>"`, 1);
|
||
var root_7$2 = /* @__PURE__ */ from_html(`<tr draggable="true"><td class="svelte-13s7gu4"><span class="drag-handle svelte-13s7gu4" title="Drag to move to another group">⠿</span> <span class="entry-title svelte-13s7gu4"> </span></td><td class="svelte-13s7gu4"><span class="entry-username svelte-13s7gu4"> </span></td><td class="svelte-13s7gu4"><span class="entry-url truncate svelte-13s7gu4"> </span></td></tr>`);
|
||
var root_5$3 = /* @__PURE__ */ from_html(`<div class="results-info svelte-13s7gu4"><span class="text-sm text-muted"> <!></span></div> <table class="entries-table svelte-13s7gu4"><thead><tr><th class="svelte-13s7gu4">Title</th><th class="svelte-13s7gu4">Username</th><th class="svelte-13s7gu4">URL</th></tr></thead><tbody></tbody></table>`, 1);
|
||
var root$5 = /* @__PURE__ */ from_html(`<div class="entry-list"><!></div>`);
|
||
function EntryList($$anchor, $$props) {
|
||
push($$props, true);
|
||
let entries = /* @__PURE__ */ state(proxy([]));
|
||
let loading = /* @__PURE__ */ state(true);
|
||
let error = /* @__PURE__ */ state("");
|
||
let resultCount = /* @__PURE__ */ state(0);
|
||
let draggedEntryId = /* @__PURE__ */ state(null);
|
||
function handleDragStart(entryId) {
|
||
set(draggedEntryId, entryId, true);
|
||
}
|
||
function handleDragEnd() {
|
||
set(draggedEntryId, null);
|
||
}
|
||
async function loadEntries() {
|
||
set(loading, true);
|
||
set(error, "");
|
||
try {
|
||
const query = search.query.trim();
|
||
const groupId = search.activeGroupId;
|
||
if (query) set(entries, await searchEntries(query, groupId !== "all" ? { groupId } : {}), true);
|
||
else if (groupId !== "all") set(entries, await getEntries({ groupId }), true);
|
||
else set(entries, await getEntries(), true);
|
||
set(resultCount, get(entries).length, true);
|
||
} catch (e) {
|
||
set(error, "Failed to load entries: " + e.message);
|
||
}
|
||
set(loading, false);
|
||
}
|
||
user_effect(() => {
|
||
search.query;
|
||
search.activeGroupId;
|
||
search.refreshTrigger;
|
||
loadEntries();
|
||
});
|
||
var div = root$5();
|
||
var node = child(div);
|
||
var consequent = ($$anchor) => {
|
||
append($$anchor, root_1$6());
|
||
};
|
||
var consequent_1 = ($$anchor) => {
|
||
var div_2 = root_2$4();
|
||
var text = child(div_2, true);
|
||
reset(div_2);
|
||
template_effect(() => set_text(text, get(error)));
|
||
append($$anchor, div_2);
|
||
};
|
||
var consequent_3 = ($$anchor) => {
|
||
var div_3 = root_3$4();
|
||
var p = child(div_3);
|
||
var text_1 = child(p, true);
|
||
reset(p);
|
||
var p_1 = sibling(p, 2);
|
||
var text_2 = child(p_1, true);
|
||
reset(p_1);
|
||
var p_2 = sibling(p_1, 2);
|
||
var text_3 = child(p_2, true);
|
||
reset(p_2);
|
||
var node_1 = sibling(p_2, 2);
|
||
var consequent_2 = ($$anchor) => {
|
||
var button = root_4$4();
|
||
delegated("click", button, function(...$$args) {
|
||
$$props.onAdd?.apply(this, $$args);
|
||
});
|
||
append($$anchor, button);
|
||
};
|
||
if_block(node_1, ($$render) => {
|
||
if (!search.query) $$render(consequent_2);
|
||
});
|
||
reset(div_3);
|
||
template_effect(() => {
|
||
set_text(text_1, search.query ? "🔍" : "🔑");
|
||
set_text(text_2, search.query ? "No results found" : "No entries yet");
|
||
set_text(text_3, search.query ? "Try a different search term" : "Add your first login credential to get started");
|
||
});
|
||
append($$anchor, div_3);
|
||
};
|
||
var alternate = ($$anchor) => {
|
||
var fragment = root_5$3();
|
||
var div_4 = first_child(fragment);
|
||
var span = child(div_4);
|
||
var text_4 = child(span);
|
||
var node_2 = sibling(text_4);
|
||
var consequent_4 = ($$anchor) => {
|
||
var fragment_1 = root_6$4();
|
||
var strong = sibling(first_child(fragment_1));
|
||
var text_5 = child(strong, true);
|
||
reset(strong);
|
||
next();
|
||
template_effect(() => set_text(text_5, search.query));
|
||
append($$anchor, fragment_1);
|
||
};
|
||
if_block(node_2, ($$render) => {
|
||
if (search.query) $$render(consequent_4);
|
||
});
|
||
reset(span);
|
||
reset(div_4);
|
||
var table = sibling(div_4, 2);
|
||
var tbody = sibling(child(table));
|
||
each(tbody, 21, () => get(entries), (entry) => entry.id, ($$anchor, entry) => {
|
||
var tr = root_7$2();
|
||
var td = child(tr);
|
||
var span_1 = sibling(child(td), 2);
|
||
var text_6 = child(span_1, true);
|
||
reset(span_1);
|
||
reset(td);
|
||
var td_1 = sibling(td);
|
||
var span_2 = child(td_1);
|
||
var text_7 = child(span_2, true);
|
||
reset(span_2);
|
||
reset(td_1);
|
||
var td_2 = sibling(td_1);
|
||
var span_3 = child(td_2);
|
||
var text_8 = child(span_3, true);
|
||
reset(span_3);
|
||
reset(td_2);
|
||
reset(tr);
|
||
template_effect(() => {
|
||
set_class(tr, 1, `entry-row ${get(draggedEntryId) === get(entry).id ? "dragging" : ""}`, "svelte-13s7gu4");
|
||
set_text(text_6, get(entry).title);
|
||
set_text(text_7, get(entry).username);
|
||
set_text(text_8, get(entry).url || "—");
|
||
});
|
||
delegated("click", tr, () => $$props.onSelect(get(entry).id));
|
||
event("DragStart", tr, (e) => {
|
||
e.dataTransfer.setData("text/plain", get(entry).id);
|
||
e.dataTransfer.effectAllowed = "move";
|
||
handleDragStart(get(entry).id);
|
||
});
|
||
event("DragEnd", tr, handleDragEnd);
|
||
append($$anchor, tr);
|
||
});
|
||
reset(tbody);
|
||
reset(table);
|
||
template_effect(() => set_text(text_4, `${get(resultCount) ?? ""} entr${get(resultCount) === 1 ? "y" : "ies"} `));
|
||
append($$anchor, fragment);
|
||
};
|
||
if_block(node, ($$render) => {
|
||
if (get(loading)) $$render(consequent);
|
||
else if (get(error)) $$render(consequent_1, 1);
|
||
else if (get(entries).length === 0) $$render(consequent_3, 2);
|
||
else $$render(alternate, -1);
|
||
});
|
||
reset(div);
|
||
append($$anchor, div);
|
||
pop();
|
||
}
|
||
delegate(["click"]);
|
||
//#endregion
|
||
//#region src/components/EntryDetail.svelte
|
||
var root_1$5 = /* @__PURE__ */ from_html(`<div class="toast svelte-dssgjx"> </div>`);
|
||
var root_2$3 = /* @__PURE__ */ from_html(`<div class="loading svelte-dssgjx">Loading...</div>`);
|
||
var root_3$3 = /* @__PURE__ */ from_html(`<div class="error-banner svelte-dssgjx"> </div>`);
|
||
var root_4$3 = /* @__PURE__ */ from_html(`<div class="empty-state svelte-dssgjx">Entry not found</div>`);
|
||
var root_6$3 = /* @__PURE__ */ from_html(`<div class="detail-field"><span class="field-label svelte-dssgjx">URL</span> <div class="field-value svelte-dssgjx"><a target="_blank" rel="noopener noreferrer" class="svelte-dssgjx"> </a> <button class="btn btn-ghost btn-sm copy-btn svelte-dssgjx" title="Copy URL">📋</button></div></div>`);
|
||
var root_7$1 = /* @__PURE__ */ from_html(`<div class="detail-field"><span class="field-label svelte-dssgjx">Notes</span> <div class="field-value notes svelte-dssgjx"> </div></div>`);
|
||
var root_8 = /* @__PURE__ */ from_html(`<div class="modal-overlay svelte-dssgjx" role="presentation"><div class="modal svelte-dssgjx" role="dialog" aria-modal="true" aria-label="Delete confirmation" tabindex="-1"><h3 class="svelte-dssgjx">Delete Entry</h3> <p class="svelte-dssgjx">Are you sure you want to delete "<strong> </strong>"? This cannot be undone.</p> <div class="modal-actions svelte-dssgjx"><button class="btn btn-danger"> </button> <button class="btn btn-ghost">Cancel</button></div></div></div>`);
|
||
var root_5$2 = /* @__PURE__ */ from_html(`<div class="detail-card svelte-dssgjx"><div class="detail-header svelte-dssgjx"><h2 class="svelte-dssgjx"> </h2> <div class="header-actions svelte-dssgjx"><button class="btn btn-ghost btn-sm">✏️ Edit</button> <button class="btn btn-danger btn-sm">🗑 Delete</button></div></div> <div class="detail-fields svelte-dssgjx"><div class="detail-field"><span class="field-label svelte-dssgjx">Username</span> <div class="field-value svelte-dssgjx"><span> </span> <button class="btn btn-ghost btn-sm copy-btn svelte-dssgjx" title="Copy username">📋</button></div></div> <div class="detail-field"><span class="field-label svelte-dssgjx">Password</span> <div class="field-value svelte-dssgjx"><span> </span> <button class="btn btn-ghost btn-sm" title="Toggle visibility"> </button> <button class="btn btn-ghost btn-sm copy-btn svelte-dssgjx" title="Copy password">📋</button></div></div> <!> <!></div> <div class="detail-meta svelte-dssgjx"><span class="text-xs text-muted"> </span> <span class="text-xs text-muted"> </span></div></div> <!>`, 1);
|
||
var root$4 = /* @__PURE__ */ from_html(`<div class="entry-detail"><!> <!></div>`);
|
||
function EntryDetail($$anchor, $$props) {
|
||
push($$props, true);
|
||
let entry = /* @__PURE__ */ state(null);
|
||
let passwordVisible = /* @__PURE__ */ state(false);
|
||
let decryptedPassword = /* @__PURE__ */ state("");
|
||
let loading = /* @__PURE__ */ state(true);
|
||
let error = /* @__PURE__ */ state("");
|
||
let showDeleteConfirm = /* @__PURE__ */ state(false);
|
||
let deleting = /* @__PURE__ */ state(false);
|
||
let toast = /* @__PURE__ */ state("");
|
||
let toastTimer = null;
|
||
async function loadEntry() {
|
||
set(loading, true);
|
||
set(error, "");
|
||
try {
|
||
set(entry, await getEntryById($$props.entryId), true);
|
||
if (get(entry) && app$1.encryptionKey) set(decryptedPassword, await decrypt(get(entry).encryptedPassword, app$1.encryptionKey), true);
|
||
} catch (e) {
|
||
set(error, "Failed to load entry: " + e.message);
|
||
}
|
||
set(loading, false);
|
||
}
|
||
loadEntry();
|
||
function showToast(message) {
|
||
set(toast, message, true);
|
||
if (toastTimer) clearTimeout(toastTimer);
|
||
toastTimer = setTimeout(() => {
|
||
set(toast, "");
|
||
}, 3e3);
|
||
}
|
||
async function copyToClipboard(text, label) {
|
||
try {
|
||
await navigator.clipboard.writeText(text);
|
||
showToast(`✓ ${label} copied (auto-clear in 15s)`);
|
||
setTimeout(async () => {
|
||
try {
|
||
await navigator.clipboard.writeText("");
|
||
} catch {}
|
||
}, 15e3);
|
||
} catch (e) {
|
||
const textarea = document.createElement("textarea");
|
||
textarea.value = text;
|
||
textarea.style.position = "fixed";
|
||
textarea.style.opacity = "0";
|
||
document.body.appendChild(textarea);
|
||
textarea.select();
|
||
document.execCommand("copy");
|
||
document.body.removeChild(textarea);
|
||
showToast(`✓ ${label} copied`);
|
||
}
|
||
}
|
||
async function handleDelete() {
|
||
set(deleting, true);
|
||
try {
|
||
await deleteEntry($$props.entryId);
|
||
$$props.onBack();
|
||
} catch (e) {
|
||
set(error, "Failed to delete: " + e.message);
|
||
}
|
||
set(deleting, false);
|
||
set(showDeleteConfirm, false);
|
||
}
|
||
var div = root$4();
|
||
var node = child(div);
|
||
var consequent = ($$anchor) => {
|
||
var div_1 = root_1$5();
|
||
var text_1 = child(div_1, true);
|
||
reset(div_1);
|
||
template_effect(() => set_text(text_1, get(toast)));
|
||
append($$anchor, div_1);
|
||
};
|
||
if_block(node, ($$render) => {
|
||
if (get(toast)) $$render(consequent);
|
||
});
|
||
var node_1 = sibling(node, 2);
|
||
var consequent_1 = ($$anchor) => {
|
||
append($$anchor, root_2$3());
|
||
};
|
||
var consequent_2 = ($$anchor) => {
|
||
var div_3 = root_3$3();
|
||
var text_2 = child(div_3, true);
|
||
reset(div_3);
|
||
template_effect(() => set_text(text_2, get(error)));
|
||
append($$anchor, div_3);
|
||
};
|
||
var consequent_3 = ($$anchor) => {
|
||
append($$anchor, root_4$3());
|
||
};
|
||
var alternate = ($$anchor) => {
|
||
var fragment = root_5$2();
|
||
var div_5 = first_child(fragment);
|
||
var div_6 = child(div_5);
|
||
var h2 = child(div_6);
|
||
var text_3 = child(h2, true);
|
||
reset(h2);
|
||
var div_7 = sibling(h2, 2);
|
||
var button = child(div_7);
|
||
var button_1 = sibling(button, 2);
|
||
reset(div_7);
|
||
reset(div_6);
|
||
var div_8 = sibling(div_6, 2);
|
||
var div_9 = child(div_8);
|
||
var div_10 = sibling(child(div_9), 2);
|
||
var span = child(div_10);
|
||
var text_4 = child(span, true);
|
||
reset(span);
|
||
var button_2 = sibling(span, 2);
|
||
reset(div_10);
|
||
reset(div_9);
|
||
var div_11 = sibling(div_9, 2);
|
||
var div_12 = sibling(child(div_11), 2);
|
||
var span_1 = child(div_12);
|
||
var text_5 = child(span_1, true);
|
||
reset(span_1);
|
||
var button_3 = sibling(span_1, 2);
|
||
var text_6 = child(button_3, true);
|
||
reset(button_3);
|
||
var button_4 = sibling(button_3, 2);
|
||
reset(div_12);
|
||
reset(div_11);
|
||
var node_2 = sibling(div_11, 2);
|
||
var consequent_4 = ($$anchor) => {
|
||
var div_13 = root_6$3();
|
||
var div_14 = sibling(child(div_13), 2);
|
||
var a = child(div_14);
|
||
var text_7 = child(a, true);
|
||
reset(a);
|
||
var button_5 = sibling(a, 2);
|
||
reset(div_14);
|
||
reset(div_13);
|
||
template_effect(() => {
|
||
set_attribute(a, "href", get(entry).url);
|
||
set_text(text_7, get(entry).url);
|
||
});
|
||
delegated("click", button_5, () => copyToClipboard(get(entry).url, "URL"));
|
||
append($$anchor, div_13);
|
||
};
|
||
if_block(node_2, ($$render) => {
|
||
if (get(entry).url) $$render(consequent_4);
|
||
});
|
||
var node_3 = sibling(node_2, 2);
|
||
var consequent_5 = ($$anchor) => {
|
||
var div_15 = root_7$1();
|
||
var div_16 = sibling(child(div_15), 2);
|
||
var text_8 = child(div_16, true);
|
||
reset(div_16);
|
||
reset(div_15);
|
||
template_effect(() => set_text(text_8, get(entry).notes));
|
||
append($$anchor, div_15);
|
||
};
|
||
if_block(node_3, ($$render) => {
|
||
if (get(entry).notes) $$render(consequent_5);
|
||
});
|
||
reset(div_8);
|
||
var div_17 = sibling(div_8, 2);
|
||
var span_2 = child(div_17);
|
||
var text_9 = child(span_2);
|
||
reset(span_2);
|
||
var span_3 = sibling(span_2, 2);
|
||
var text_10 = child(span_3);
|
||
reset(span_3);
|
||
reset(div_17);
|
||
reset(div_5);
|
||
var node_4 = sibling(div_5, 2);
|
||
var consequent_6 = ($$anchor) => {
|
||
var div_18 = root_8();
|
||
var div_19 = child(div_18);
|
||
var p = sibling(child(div_19), 2);
|
||
var strong = sibling(child(p));
|
||
var text_11 = child(strong, true);
|
||
reset(strong);
|
||
next();
|
||
reset(p);
|
||
var div_20 = sibling(p, 2);
|
||
var button_6 = child(div_20);
|
||
var text_12 = child(button_6, true);
|
||
reset(button_6);
|
||
var button_7 = sibling(button_6, 2);
|
||
reset(div_20);
|
||
reset(div_19);
|
||
reset(div_18);
|
||
template_effect(() => {
|
||
set_text(text_11, get(entry).title);
|
||
button_6.disabled = get(deleting);
|
||
set_text(text_12, get(deleting) ? "Deleting..." : "Yes, delete");
|
||
});
|
||
delegated("click", div_18, () => set(showDeleteConfirm, false));
|
||
delegated("click", div_19, (e) => e.stopPropagation());
|
||
delegated("click", button_6, handleDelete);
|
||
delegated("click", button_7, () => set(showDeleteConfirm, false));
|
||
append($$anchor, div_18);
|
||
};
|
||
if_block(node_4, ($$render) => {
|
||
if (get(showDeleteConfirm)) $$render(consequent_6);
|
||
});
|
||
template_effect(($0, $1) => {
|
||
set_text(text_3, get(entry).title);
|
||
set_text(text_4, get(entry).username);
|
||
set_text(text_5, get(passwordVisible) ? get(decryptedPassword) : "••••••••••••");
|
||
set_text(text_6, get(passwordVisible) ? "🙈" : "👁");
|
||
set_text(text_9, `Created: ${$0 ?? ""}`);
|
||
set_text(text_10, `Updated: ${$1 ?? ""}`);
|
||
}, [() => new Date(get(entry).createdAt).toLocaleString(), () => new Date(get(entry).updatedAt).toLocaleString()]);
|
||
delegated("click", button, () => $$props.onEdit(get(entry).id));
|
||
delegated("click", button_1, () => set(showDeleteConfirm, true));
|
||
delegated("click", button_2, () => copyToClipboard(get(entry).username, "Username"));
|
||
delegated("click", button_3, () => set(passwordVisible, !get(passwordVisible)));
|
||
delegated("click", button_4, () => copyToClipboard(get(decryptedPassword), "Password"));
|
||
append($$anchor, fragment);
|
||
};
|
||
if_block(node_1, ($$render) => {
|
||
if (get(loading)) $$render(consequent_1);
|
||
else if (get(error)) $$render(consequent_2, 1);
|
||
else if (!get(entry)) $$render(consequent_3, 2);
|
||
else $$render(alternate, -1);
|
||
});
|
||
reset(div);
|
||
append($$anchor, div);
|
||
pop();
|
||
}
|
||
delegate(["click"]);
|
||
delegate(["click"]);
|
||
//#endregion
|
||
//#region src/components/EntryForm.svelte
|
||
var root_1$3 = /* @__PURE__ */ from_html(`<div class="loading svelte-pafazm">Loading...</div>`);
|
||
var root_3$2 = /* @__PURE__ */ from_html(`<div class="error-banner svelte-pafazm"> </div>`);
|
||
var root_5$1 = /* @__PURE__ */ from_html(`<div class="validation-error svelte-pafazm"> </div>`);
|
||
var root_4$2 = /* @__PURE__ */ from_html(`<div class="validation-errors svelte-pafazm"></div>`);
|
||
var root_6$2 = /* @__PURE__ */ from_html(`<option> </option>`);
|
||
var root_2$2 = /* @__PURE__ */ from_html(`<!> <form class="form-card svelte-pafazm"><!> <div class="form-group"><label for="title">Title *</label> <input id="title" type="text" placeholder="e.g. GitHub, Gmail"/></div> <div class="form-group"><label for="username">Username / Email *</label> <input id="username" type="text" placeholder="username or email"/></div> <div class="form-group"><label for="password">Password *</label> <div class="password-input-group svelte-pafazm"><input id="password" placeholder="Password" class="svelte-pafazm"/> <button type="button" class="btn btn-ghost btn-sm" title="Toggle visibility"> </button> <button type="button" class="btn btn-ghost btn-sm" title="Generate password">🎲</button></div></div> <div class="form-group"><label for="url">URL</label> <input id="url" type="url" placeholder="https://example.com"/></div> <div class="form-group"><label for="group">Group</label> <select id="group"><option>No group</option><!></select></div> <div class="form-group"><label for="notes">Notes</label> <textarea id="notes" placeholder="Any additional notes..."></textarea></div> <div class="form-actions svelte-pafazm"><button type="submit" class="btn btn-primary"> </button> <button type="button" class="btn btn-ghost">Cancel</button></div></form>`, 1);
|
||
var root$2 = /* @__PURE__ */ from_html(`<div class="entry-form"><!></div>`);
|
||
function EntryForm($$anchor, $$props) {
|
||
push($$props, true);
|
||
let title = /* @__PURE__ */ state("");
|
||
let username = /* @__PURE__ */ state("");
|
||
let password = /* @__PURE__ */ state("");
|
||
let url = /* @__PURE__ */ state("");
|
||
let notes = /* @__PURE__ */ state("");
|
||
let groupId = /* @__PURE__ */ state("");
|
||
let passwordVisible = /* @__PURE__ */ state(false);
|
||
let groups = /* @__PURE__ */ state(proxy([]));
|
||
let loading = /* @__PURE__ */ state(true);
|
||
let error = /* @__PURE__ */ state("");
|
||
let saving = /* @__PURE__ */ state(false);
|
||
let isEdit = /* @__PURE__ */ state(false);
|
||
let formErrors = /* @__PURE__ */ state(proxy([]));
|
||
async function loadForm() {
|
||
set(loading, true);
|
||
try {
|
||
set(groups, await getGroups(), true);
|
||
if ($$props.entryId) {
|
||
set(isEdit, true);
|
||
const entry = await getEntryById($$props.entryId);
|
||
if (entry) {
|
||
set(title, entry.title, true);
|
||
set(username, entry.username, true);
|
||
set(password, await decrypt(entry.encryptedPassword, app$1.encryptionKey), true);
|
||
set(url, entry.url || "", true);
|
||
set(notes, entry.notes || "", true);
|
||
set(groupId, entry.groupId || "", true);
|
||
} else set(error, "Entry not found");
|
||
}
|
||
} catch (e) {
|
||
set(error, "Failed to load form: " + e.message);
|
||
}
|
||
set(loading, false);
|
||
}
|
||
loadForm();
|
||
async function handleSubmit() {
|
||
set(formErrors, [], true);
|
||
set(error, "");
|
||
set(saving, true);
|
||
try {
|
||
const validation = validateEntry({
|
||
title: get(title),
|
||
username: get(username),
|
||
encryptedPassword: get(password)
|
||
});
|
||
if (!validation.valid) {
|
||
set(formErrors, validation.errors, true);
|
||
set(saving, false);
|
||
return;
|
||
}
|
||
const encryptedPassword = await encrypt(get(password), app$1.encryptionKey);
|
||
if (get(isEdit)) await updateEntry(updateEntry$1(await getEntryById($$props.entryId), {
|
||
title: get(title),
|
||
username: get(username),
|
||
encryptedPassword,
|
||
url: get(url),
|
||
notes: get(notes),
|
||
groupId: get(groupId)
|
||
}));
|
||
else await addEntry(createEntry({
|
||
title: get(title),
|
||
username: get(username),
|
||
encryptedPassword,
|
||
url: get(url),
|
||
notes: get(notes),
|
||
groupId: get(groupId)
|
||
}));
|
||
$$props.onSave();
|
||
} catch (e) {
|
||
set(error, "Failed to save: " + e.message);
|
||
}
|
||
set(saving, false);
|
||
}
|
||
var div = root$2();
|
||
var node = child(div);
|
||
var consequent = ($$anchor) => {
|
||
append($$anchor, root_1$3());
|
||
};
|
||
var alternate = ($$anchor) => {
|
||
var fragment = root_2$2();
|
||
var node_1 = first_child(fragment);
|
||
var consequent_1 = ($$anchor) => {
|
||
var div_2 = root_3$2();
|
||
var text = child(div_2, true);
|
||
reset(div_2);
|
||
template_effect(() => set_text(text, get(error)));
|
||
append($$anchor, div_2);
|
||
};
|
||
if_block(node_1, ($$render) => {
|
||
if (get(error)) $$render(consequent_1);
|
||
});
|
||
var form = sibling(node_1, 2);
|
||
var node_2 = child(form);
|
||
var consequent_2 = ($$anchor) => {
|
||
var div_3 = root_4$2();
|
||
each(div_3, 21, () => get(formErrors), index, ($$anchor, err) => {
|
||
var div_4 = root_5$1();
|
||
var text_1 = child(div_4);
|
||
reset(div_4);
|
||
template_effect(() => set_text(text_1, `⚠ ${get(err) ?? ""}`));
|
||
append($$anchor, div_4);
|
||
});
|
||
reset(div_3);
|
||
append($$anchor, div_3);
|
||
};
|
||
if_block(node_2, ($$render) => {
|
||
if (get(formErrors).length > 0) $$render(consequent_2);
|
||
});
|
||
var div_5 = sibling(node_2, 2);
|
||
var input = sibling(child(div_5), 2);
|
||
remove_input_defaults(input);
|
||
reset(div_5);
|
||
var div_6 = sibling(div_5, 2);
|
||
var input_1 = sibling(child(div_6), 2);
|
||
remove_input_defaults(input_1);
|
||
reset(div_6);
|
||
var div_7 = sibling(div_6, 2);
|
||
var div_8 = sibling(child(div_7), 2);
|
||
var input_2 = child(div_8);
|
||
remove_input_defaults(input_2);
|
||
var button = sibling(input_2, 2);
|
||
var text_2 = child(button, true);
|
||
reset(button);
|
||
var button_1 = sibling(button, 2);
|
||
reset(div_8);
|
||
reset(div_7);
|
||
var div_9 = sibling(div_7, 2);
|
||
var input_3 = sibling(child(div_9), 2);
|
||
remove_input_defaults(input_3);
|
||
reset(div_9);
|
||
var div_10 = sibling(div_9, 2);
|
||
var select = sibling(child(div_10), 2);
|
||
var option = child(select);
|
||
option.value = option.__value = "";
|
||
each(sibling(option), 17, () => get(groups), index, ($$anchor, group) => {
|
||
var option_1 = root_6$2();
|
||
var text_3 = child(option_1, true);
|
||
reset(option_1);
|
||
var option_1_value = {};
|
||
template_effect(() => {
|
||
set_text(text_3, get(group).name);
|
||
if (option_1_value !== (option_1_value = get(group).id)) option_1.value = (option_1.__value = get(group).id) ?? "";
|
||
});
|
||
append($$anchor, option_1);
|
||
});
|
||
reset(select);
|
||
reset(div_10);
|
||
var div_11 = sibling(div_10, 2);
|
||
var textarea = sibling(child(div_11), 2);
|
||
remove_textarea_child(textarea);
|
||
reset(div_11);
|
||
var div_12 = sibling(div_11, 2);
|
||
var button_2 = child(div_12);
|
||
var text_4 = child(button_2, true);
|
||
reset(button_2);
|
||
var button_3 = sibling(button_2, 2);
|
||
reset(div_12);
|
||
reset(form);
|
||
template_effect(() => {
|
||
set_attribute(input_2, "type", get(passwordVisible) ? "text" : "password");
|
||
set_text(text_2, get(passwordVisible) ? "🙈" : "👁");
|
||
button_2.disabled = get(saving);
|
||
set_text(text_4, get(saving) ? "Saving..." : get(isEdit) ? "💾 Update" : "➕ Create");
|
||
});
|
||
event("submit", form, (e) => {
|
||
e.preventDefault();
|
||
handleSubmit();
|
||
});
|
||
bind_value(input, () => get(title), ($$value) => set(title, $$value));
|
||
bind_value(input_1, () => get(username), ($$value) => set(username, $$value));
|
||
bind_value(input_2, () => get(password), ($$value) => set(password, $$value));
|
||
delegated("click", button, () => set(passwordVisible, !get(passwordVisible)));
|
||
delegated("click", button_1, () => set(password, generatePassword({ length: 16 }), true));
|
||
bind_value(input_3, () => get(url), ($$value) => set(url, $$value));
|
||
bind_select_value(select, () => get(groupId), ($$value) => set(groupId, $$value));
|
||
bind_value(textarea, () => get(notes), ($$value) => set(notes, $$value));
|
||
delegated("click", button_3, function(...$$args) {
|
||
$$props.onCancel?.apply(this, $$args);
|
||
});
|
||
append($$anchor, fragment);
|
||
};
|
||
if_block(node, ($$render) => {
|
||
if (get(loading)) $$render(consequent);
|
||
else $$render(alternate, -1);
|
||
});
|
||
reset(div);
|
||
append($$anchor, div);
|
||
pop();
|
||
}
|
||
delegate(["click"]);
|
||
//#endregion
|
||
//#region src/components/ImportExport.svelte
|
||
var root_1$2 = /* @__PURE__ */ from_html(`<div class="modal-overlay svelte-17di1i9" role="presentation"><div class="modal svelte-17di1i9" role="dialog" aria-modal="true" aria-label="Export vault" tabindex="-1"><h3 class="svelte-17di1i9">Export Vault</h3> <p class="svelte-17di1i9">All entries and groups will be exported. You'll need the source vault's master password when importing into another vault.</p> <div class="modal-actions svelte-17di1i9"><button class="btn btn-primary"> </button> <button class="btn btn-ghost">Cancel</button></div></div></div>`);
|
||
var root_3$1 = /* @__PURE__ */ from_html(`<div class="error-banner svelte-17di1i9"> </div>`);
|
||
var root_4$1 = /* @__PURE__ */ from_html(`<div class="success-banner svelte-17di1i9"> <!></div>`);
|
||
var root_6$1 = /* @__PURE__ */ from_html(`<p class="svelte-17di1i9">File loaded. Enter the <strong>source vault's master password</strong> to decrypt and re-encrypt entries under your current vault.</p> <div class="form-group svelte-17di1i9"><label for="source-password" class="file-label svelte-17di1i9">Source vault password</label> <input id="source-password" type="password" placeholder="Enter source vault password" autocomplete="current-password" class="svelte-17di1i9"/></div> <div class="import-mode svelte-17di1i9"><label class="radio-label svelte-17di1i9"><input type="radio" name="importMode" class="svelte-17di1i9"/> <span class="svelte-17di1i9">Merge — add to existing data</span></label> <label class="radio-label svelte-17di1i9"><input type="radio" name="importMode" class="svelte-17di1i9"/> <span class="svelte-17di1i9">Replace — clear all existing data first</span></label></div> <div class="modal-actions svelte-17di1i9"><button class="btn btn-primary"> </button> <button class="btn btn-ghost">Cancel</button></div>`, 1);
|
||
var root_7 = /* @__PURE__ */ from_html(`<p class="svelte-17di1i9">Select how to handle existing data:</p> <div class="import-mode svelte-17di1i9"><label class="radio-label svelte-17di1i9"><input type="radio" name="importMode" class="svelte-17di1i9"/> <span class="svelte-17di1i9">Merge — add to existing data</span></label> <label class="radio-label svelte-17di1i9"><input type="radio" name="importMode" class="svelte-17di1i9"/> <span class="svelte-17di1i9">Replace — clear all existing data first</span></label></div> <div class="form-group svelte-17di1i9"><label for="import-file" class="file-label svelte-17di1i9">Choose JSON file</label> <input id="import-file" type="file" accept=".json,application/json" class="svelte-17di1i9"/></div>`, 1);
|
||
var root_2$1 = /* @__PURE__ */ from_html(`<div class="modal-overlay svelte-17di1i9" role="presentation"><div class="modal svelte-17di1i9" role="dialog" aria-modal="true" aria-label="Import vault data" tabindex="-1"><h3 class="svelte-17di1i9">Import Vault Data</h3> <!> <!> <div class="modal-actions svelte-17di1i9"><button class="btn btn-ghost">Close</button></div></div></div>`);
|
||
var root$1 = /* @__PURE__ */ from_html(`<div class="import-export"><button class="btn btn-ghost btn-sm" title="Export">📤 Export</button> <button class="btn btn-ghost btn-sm" title="Import">📥 Import</button> <!> <!></div>`);
|
||
function ImportExport($$anchor, $$props) {
|
||
push($$props, true);
|
||
const binding_group = [];
|
||
let showExport = /* @__PURE__ */ state(false);
|
||
let showImport = /* @__PURE__ */ state(false);
|
||
let importMode = /* @__PURE__ */ state("merge");
|
||
let importResult = /* @__PURE__ */ state(null);
|
||
let importError = /* @__PURE__ */ state("");
|
||
let importing = /* @__PURE__ */ state(false);
|
||
let exportData = /* @__PURE__ */ state(null);
|
||
let exporting = /* @__PURE__ */ state(false);
|
||
let sourcePassword = /* @__PURE__ */ state("");
|
||
let parsedFileData = /* @__PURE__ */ state(null);
|
||
async function handleExport() {
|
||
set(exporting, true);
|
||
try {
|
||
set(exportData, await exportAll(), true);
|
||
const json = JSON.stringify(get(exportData), null, 2);
|
||
const blob = new Blob([json], { type: "application/json" });
|
||
const url = URL.createObjectURL(blob);
|
||
const a = document.createElement("a");
|
||
a.href = url;
|
||
a.download = `password-vault-export-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.json`;
|
||
a.click();
|
||
URL.revokeObjectURL(url);
|
||
set(showExport, false);
|
||
} catch (e) {
|
||
set(importError, "Export failed: " + e.message);
|
||
}
|
||
set(exporting, false);
|
||
}
|
||
async function handleFileSelect(event) {
|
||
const file = event.target.files[0];
|
||
if (!file) return;
|
||
set(importError, "");
|
||
set(importResult, null);
|
||
set(sourcePassword, "");
|
||
try {
|
||
const text = await file.text();
|
||
const data = JSON.parse(text);
|
||
if (!data.entries || !data.groups) {
|
||
set(importError, "Invalid file format — missing entries or groups data");
|
||
return;
|
||
}
|
||
set(parsedFileData, data, true);
|
||
} catch (e) {
|
||
set(importError, "Failed to parse file: " + e.message);
|
||
}
|
||
event.target.value = "";
|
||
}
|
||
async function handleImportSubmit() {
|
||
if (!get(parsedFileData)) return;
|
||
if (!get(sourcePassword).trim()) {
|
||
set(importError, "Source vault password is required");
|
||
return;
|
||
}
|
||
set(importing, true);
|
||
set(importError, "");
|
||
set(importResult, null);
|
||
try {
|
||
set(importResult, await importAll(get(parsedFileData), get(importMode), get(sourcePassword), app$1.encryptionKey), true);
|
||
set(sourcePassword, "");
|
||
set(parsedFileData, null);
|
||
search.refresh();
|
||
} catch (e) {
|
||
set(importError, "Import failed: " + e.message);
|
||
}
|
||
set(importing, false);
|
||
}
|
||
var div = root$1();
|
||
var button = child(div);
|
||
var button_1 = sibling(button, 2);
|
||
var node = sibling(button_1, 2);
|
||
var consequent = ($$anchor) => {
|
||
var div_1 = root_1$2();
|
||
var div_2 = child(div_1);
|
||
var div_3 = sibling(child(div_2), 4);
|
||
var button_2 = child(div_3);
|
||
var text_1 = child(button_2, true);
|
||
reset(button_2);
|
||
var button_3 = sibling(button_2, 2);
|
||
reset(div_3);
|
||
reset(div_2);
|
||
reset(div_1);
|
||
template_effect(() => {
|
||
button_2.disabled = get(exporting);
|
||
set_text(text_1, get(exporting) ? "Exporting..." : "📤 Export JSON");
|
||
});
|
||
delegated("click", div_1, () => set(showExport, false));
|
||
delegated("click", div_2, (e) => e.stopPropagation());
|
||
delegated("click", button_2, handleExport);
|
||
delegated("click", button_3, () => set(showExport, false));
|
||
append($$anchor, div_1);
|
||
};
|
||
if_block(node, ($$render) => {
|
||
if (get(showExport)) $$render(consequent);
|
||
});
|
||
var node_1 = sibling(node, 2);
|
||
var consequent_5 = ($$anchor) => {
|
||
var div_4 = root_2$1();
|
||
var div_5 = child(div_4);
|
||
var node_2 = sibling(child(div_5), 2);
|
||
var consequent_1 = ($$anchor) => {
|
||
var div_6 = root_3$1();
|
||
var text_2 = child(div_6, true);
|
||
reset(div_6);
|
||
template_effect(() => set_text(text_2, get(importError)));
|
||
append($$anchor, div_6);
|
||
};
|
||
if_block(node_2, ($$render) => {
|
||
if (get(importError)) $$render(consequent_1);
|
||
});
|
||
var node_3 = sibling(node_2, 2);
|
||
var consequent_3 = ($$anchor) => {
|
||
var div_7 = root_4$1();
|
||
var text_3 = child(div_7);
|
||
var node_4 = sibling(text_3);
|
||
var consequent_2 = ($$anchor) => {
|
||
var text_4 = text();
|
||
template_effect(() => set_text(text_4, `(${get(importResult).skipped ?? ""} skipped)`));
|
||
append($$anchor, text_4);
|
||
};
|
||
if_block(node_4, ($$render) => {
|
||
if (get(importResult).skipped > 0) $$render(consequent_2);
|
||
});
|
||
reset(div_7);
|
||
template_effect(() => set_text(text_3, `✓ Imported ${get(importResult).imported.entries ?? ""} entries and ${get(importResult).imported.groups ?? ""} groups `));
|
||
append($$anchor, div_7);
|
||
};
|
||
var consequent_4 = ($$anchor) => {
|
||
var fragment_1 = root_6$1();
|
||
var div_8 = sibling(first_child(fragment_1), 2);
|
||
var input = sibling(child(div_8), 2);
|
||
remove_input_defaults(input);
|
||
reset(div_8);
|
||
var div_9 = sibling(div_8, 2);
|
||
var label = child(div_9);
|
||
var input_1 = child(label);
|
||
remove_input_defaults(input_1);
|
||
input_1.value = input_1.__value = "merge";
|
||
next(2);
|
||
reset(label);
|
||
var label_1 = sibling(label, 2);
|
||
var input_2 = child(label_1);
|
||
remove_input_defaults(input_2);
|
||
input_2.value = input_2.__value = "replace";
|
||
next(2);
|
||
reset(label_1);
|
||
reset(div_9);
|
||
var div_10 = sibling(div_9, 2);
|
||
var button_4 = child(div_10);
|
||
var text_5 = child(button_4, true);
|
||
reset(button_4);
|
||
var button_5 = sibling(button_4, 2);
|
||
reset(div_10);
|
||
template_effect(() => {
|
||
button_4.disabled = get(importing);
|
||
set_text(text_5, get(importing) ? "Importing..." : "📥 Import");
|
||
});
|
||
bind_value(input, () => get(sourcePassword), ($$value) => set(sourcePassword, $$value));
|
||
bind_group(binding_group, [], input_1, () => get(importMode), ($$value) => set(importMode, $$value));
|
||
bind_group(binding_group, [], input_2, () => get(importMode), ($$value) => set(importMode, $$value));
|
||
delegated("click", button_4, handleImportSubmit);
|
||
delegated("click", button_5, () => {
|
||
set(parsedFileData, null);
|
||
set(sourcePassword, "");
|
||
});
|
||
append($$anchor, fragment_1);
|
||
};
|
||
var alternate = ($$anchor) => {
|
||
var fragment_2 = root_7();
|
||
var div_11 = sibling(first_child(fragment_2), 2);
|
||
var label_2 = child(div_11);
|
||
var input_3 = child(label_2);
|
||
remove_input_defaults(input_3);
|
||
input_3.value = input_3.__value = "merge";
|
||
next(2);
|
||
reset(label_2);
|
||
var label_3 = sibling(label_2, 2);
|
||
var input_4 = child(label_3);
|
||
remove_input_defaults(input_4);
|
||
input_4.value = input_4.__value = "replace";
|
||
next(2);
|
||
reset(label_3);
|
||
reset(div_11);
|
||
var div_12 = sibling(div_11, 2);
|
||
var input_5 = sibling(child(div_12), 2);
|
||
reset(div_12);
|
||
template_effect(() => input_5.disabled = get(importing));
|
||
bind_group(binding_group, [], input_3, () => get(importMode), ($$value) => set(importMode, $$value));
|
||
bind_group(binding_group, [], input_4, () => get(importMode), ($$value) => set(importMode, $$value));
|
||
delegated("change", input_5, handleFileSelect);
|
||
append($$anchor, fragment_2);
|
||
};
|
||
if_block(node_3, ($$render) => {
|
||
if (get(importResult)) $$render(consequent_3);
|
||
else if (get(parsedFileData)) $$render(consequent_4, 1);
|
||
else $$render(alternate, -1);
|
||
});
|
||
var div_13 = sibling(node_3, 2);
|
||
var button_6 = child(div_13);
|
||
reset(div_13);
|
||
reset(div_5);
|
||
reset(div_4);
|
||
delegated("click", div_4, () => set(showImport, false));
|
||
delegated("click", div_5, (e) => e.stopPropagation());
|
||
delegated("click", button_6, () => {
|
||
set(showImport, false);
|
||
set(importResult, null);
|
||
set(importError, "");
|
||
});
|
||
append($$anchor, div_4);
|
||
};
|
||
if_block(node_1, ($$render) => {
|
||
if (get(showImport)) $$render(consequent_5);
|
||
});
|
||
reset(div);
|
||
delegated("click", button, () => set(showExport, true));
|
||
delegated("click", button_1, () => set(showImport, true));
|
||
append($$anchor, div);
|
||
pop();
|
||
}
|
||
delegate(["click", "change"]);
|
||
//#endregion
|
||
//#region src/components/MainLayout.svelte
|
||
var root_1$1 = /* @__PURE__ */ from_html(`<button class="sidebar-overlay svelte-1ybayt" aria-label="Close menu"></button>`);
|
||
var root_2 = /* @__PURE__ */ from_html(`<button class="btn btn-ghost btn-sm">← Back</button>`);
|
||
var root_3 = /* @__PURE__ */ from_html(`<h1 class="svelte-1ybayt">All Entries</h1>`);
|
||
var root_4 = /* @__PURE__ */ from_html(`<h1 class="svelte-1ybayt">Entry Details</h1>`);
|
||
var root_5 = /* @__PURE__ */ from_html(`<h1 class="svelte-1ybayt"> </h1>`);
|
||
var root_6 = /* @__PURE__ */ from_html(`<button class="btn btn-primary btn-sm">+ New Entry</button>`);
|
||
var root = /* @__PURE__ */ from_html(`<div class="app-shell svelte-1ybayt"><div class="mobile-header svelte-1ybayt"><button class="btn btn-ghost btn-sm">☰ Menu</button> <span class="mobile-title svelte-1ybayt">Password Vault</span> <button class="btn btn-ghost btn-sm" title="Lock">🔒</button></div> <!> <aside><!></aside> <main class="main-content svelte-1ybayt"><div class="top-bar svelte-1ybayt"><!> <div class="top-bar-title svelte-1ybayt"><!></div> <div class="top-bar-actions svelte-1ybayt"><!> <!> <button class="btn btn-ghost btn-sm" title="Lock vault">🔒</button></div></div> <div class="content-area svelte-1ybayt"><!></div></main></div>`);
|
||
function MainLayout($$anchor, $$props) {
|
||
push($$props, true);
|
||
let sidebarOpen = /* @__PURE__ */ state(false);
|
||
let viewMode = /* @__PURE__ */ state("list");
|
||
let selectedEntryId = /* @__PURE__ */ state(null);
|
||
function goList() {
|
||
set(viewMode, "list");
|
||
set(selectedEntryId, null);
|
||
set(sidebarOpen, false);
|
||
}
|
||
function goDetail(entryId) {
|
||
set(selectedEntryId, entryId, true);
|
||
set(viewMode, "detail");
|
||
set(sidebarOpen, false);
|
||
}
|
||
function goForm(entryId = null) {
|
||
set(selectedEntryId, entryId, true);
|
||
set(viewMode, "form");
|
||
set(sidebarOpen, false);
|
||
}
|
||
function handleBack() {
|
||
if (get(viewMode) === "form") goDetail(get(selectedEntryId));
|
||
else goList();
|
||
}
|
||
function handleLock() {
|
||
app$1.lockVault();
|
||
}
|
||
var div = root();
|
||
var div_1 = child(div);
|
||
var button = child(div_1);
|
||
var button_1 = sibling(button, 4);
|
||
reset(div_1);
|
||
var node = sibling(div_1, 2);
|
||
var consequent = ($$anchor) => {
|
||
var button_2 = root_1$1();
|
||
delegated("click", button_2, () => set(sidebarOpen, false));
|
||
append($$anchor, button_2);
|
||
};
|
||
if_block(node, ($$render) => {
|
||
if (get(sidebarOpen)) $$render(consequent);
|
||
});
|
||
var aside = sibling(node, 2);
|
||
Sidebar(child(aside), { $$events: {
|
||
back: handleBack,
|
||
goList
|
||
} });
|
||
reset(aside);
|
||
var main = sibling(aside, 2);
|
||
var div_2 = child(main);
|
||
var node_2 = child(div_2);
|
||
var consequent_1 = ($$anchor) => {
|
||
var button_3 = root_2();
|
||
delegated("click", button_3, handleBack);
|
||
append($$anchor, button_3);
|
||
};
|
||
if_block(node_2, ($$render) => {
|
||
if (get(viewMode) !== "list") $$render(consequent_1);
|
||
});
|
||
var div_3 = sibling(node_2, 2);
|
||
var node_3 = child(div_3);
|
||
var consequent_2 = ($$anchor) => {
|
||
append($$anchor, root_3());
|
||
};
|
||
var consequent_3 = ($$anchor) => {
|
||
append($$anchor, root_4());
|
||
};
|
||
var consequent_4 = ($$anchor) => {
|
||
var h1_2 = root_5();
|
||
var text = child(h1_2, true);
|
||
reset(h1_2);
|
||
template_effect(() => set_text(text, get(selectedEntryId) ? "Edit Entry" : "New Entry"));
|
||
append($$anchor, h1_2);
|
||
};
|
||
if_block(node_3, ($$render) => {
|
||
if (get(viewMode) === "list") $$render(consequent_2);
|
||
else if (get(viewMode) === "detail") $$render(consequent_3, 1);
|
||
else if (get(viewMode) === "form") $$render(consequent_4, 2);
|
||
});
|
||
reset(div_3);
|
||
var div_4 = sibling(div_3, 2);
|
||
var node_4 = child(div_4);
|
||
var consequent_5 = ($$anchor) => {
|
||
var button_4 = root_6();
|
||
delegated("click", button_4, () => goForm(null));
|
||
append($$anchor, button_4);
|
||
};
|
||
if_block(node_4, ($$render) => {
|
||
if (get(viewMode) === "list") $$render(consequent_5);
|
||
});
|
||
var node_5 = sibling(node_4, 2);
|
||
ImportExport(node_5, {});
|
||
var button_5 = sibling(node_5, 2);
|
||
reset(div_4);
|
||
reset(div_2);
|
||
var div_5 = sibling(div_2, 2);
|
||
var node_6 = child(div_5);
|
||
var consequent_6 = ($$anchor) => {
|
||
EntryList($$anchor, {
|
||
onSelect: goDetail,
|
||
onAdd: () => goForm(null)
|
||
});
|
||
};
|
||
var consequent_7 = ($$anchor) => {
|
||
EntryDetail($$anchor, {
|
||
get entryId() {
|
||
return get(selectedEntryId);
|
||
},
|
||
onEdit: () => goForm(get(selectedEntryId)),
|
||
onBack: goList
|
||
});
|
||
};
|
||
var consequent_8 = ($$anchor) => {
|
||
EntryForm($$anchor, {
|
||
get entryId() {
|
||
return get(selectedEntryId);
|
||
},
|
||
onSave: goList,
|
||
onCancel: handleBack
|
||
});
|
||
};
|
||
if_block(node_6, ($$render) => {
|
||
if (get(viewMode) === "list") $$render(consequent_6);
|
||
else if (get(viewMode) === "detail" && get(selectedEntryId)) $$render(consequent_7, 1);
|
||
else if (get(viewMode) === "form") $$render(consequent_8, 2);
|
||
});
|
||
reset(div_5);
|
||
reset(main);
|
||
reset(div);
|
||
template_effect(() => set_class(aside, 1, `sidebar ${get(sidebarOpen) ? "open" : ""}`, "svelte-1ybayt"));
|
||
delegated("click", button, () => set(sidebarOpen, !get(sidebarOpen)));
|
||
delegated("click", button_1, handleLock);
|
||
delegated("click", button_5, handleLock);
|
||
append($$anchor, div);
|
||
pop();
|
||
}
|
||
delegate(["click"]);
|
||
//#endregion
|
||
//#region src/App.svelte
|
||
var root_1 = /* @__PURE__ */ from_html(`<meta charset="UTF-8"/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/>`, 1);
|
||
function App($$anchor, $$props) {
|
||
push($$props, false);
|
||
init();
|
||
var fragment_1 = comment();
|
||
head("1n46o8q", ($$anchor) => {
|
||
var fragment = root_1();
|
||
next(2);
|
||
append($$anchor, fragment);
|
||
});
|
||
var node = first_child(fragment_1);
|
||
var consequent = ($$anchor) => {
|
||
MainLayout($$anchor, {});
|
||
};
|
||
var alternate = ($$anchor) => {
|
||
LockScreen($$anchor, {});
|
||
};
|
||
if_block(node, ($$render) => {
|
||
if (app$1.isUnlocked) $$render(consequent);
|
||
else $$render(alternate, -1);
|
||
});
|
||
append($$anchor, fragment_1);
|
||
pop();
|
||
}
|
||
mount(App, { target: document.getElementById("app") });
|
||
//#endregion</script>
|
||
<style rel="stylesheet" crossorigin>/* ===== CSS Reset & Base ===== */
|
||
*, *::before, *::after {
|
||
box-sizing: border-box;
|
||
margin: 0;
|
||
padding: 0;
|
||
}
|
||
|
||
:root {
|
||
--color-bg: #0f1117;
|
||
--color-surface: #1a1d27;
|
||
--color-surface-hover: #242836;
|
||
--color-border: #2e3345;
|
||
--color-text: #e4e6f0;
|
||
--color-text-muted: #8b8fa3;
|
||
--color-primary: #6c63ff;
|
||
--color-primary-hover: #5a52d9;
|
||
--color-danger: #e5484d;
|
||
--color-danger-hover: #c93a3f;
|
||
--color-success: #34d399;
|
||
--color-warning: #fbbf24;
|
||
--color-input-bg: #161822;
|
||
--color-sidebar: #13151d;
|
||
--radius-sm: 4px;
|
||
--radius-md: 8px;
|
||
--radius-lg: 12px;
|
||
--shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
||
--transition: 150ms ease;
|
||
}
|
||
|
||
html {
|
||
font-size: 16px;
|
||
-webkit-font-smoothing: antialiased;
|
||
-moz-osx-font-smoothing: grayscale;
|
||
}
|
||
|
||
body {
|
||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||
background-color: var(--color-bg);
|
||
color: var(--color-text);
|
||
line-height: 1.5;
|
||
min-height: 100vh;
|
||
}
|
||
|
||
#app {
|
||
min-height: 100vh;
|
||
}
|
||
|
||
/* ===== Typography ===== */
|
||
h1 { font-size: 1.5rem; font-weight: 600; }
|
||
h2 { font-size: 1.25rem; font-weight: 600; }
|
||
h3 { font-size: 1.1rem; font-weight: 600; }
|
||
|
||
/* ===== Buttons ===== */
|
||
.btn {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
padding: 8px 16px;
|
||
border: none;
|
||
border-radius: var(--radius-md);
|
||
font-size: 0.875rem;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
transition: background-color var(--transition), opacity var(--transition);
|
||
text-decoration: none;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.btn:disabled {
|
||
opacity: 0.5;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
.btn-primary {
|
||
background-color: var(--color-primary);
|
||
color: #fff;
|
||
}
|
||
|
||
.btn-primary:hover:not(:disabled) {
|
||
background-color: var(--color-primary-hover);
|
||
}
|
||
|
||
.btn-danger {
|
||
background-color: var(--color-danger);
|
||
color: #fff;
|
||
}
|
||
|
||
.btn-danger:hover:not(:disabled) {
|
||
background-color: var(--color-danger-hover);
|
||
}
|
||
|
||
.btn-ghost {
|
||
background: transparent;
|
||
color: var(--color-text-muted);
|
||
border: 1px solid var(--color-border);
|
||
}
|
||
|
||
.btn-ghost:hover:not(:disabled) {
|
||
background-color: var(--color-surface-hover);
|
||
color: var(--color-text);
|
||
}
|
||
|
||
.btn-sm {
|
||
padding: 4px 10px;
|
||
font-size: 0.8rem;
|
||
}
|
||
|
||
/* ===== Inputs ===== */
|
||
input[type="text"],
|
||
input[type="password"],
|
||
input[type="url"],
|
||
input[type="email"],
|
||
input[type="number"],
|
||
textarea,
|
||
select {
|
||
width: 100%;
|
||
padding: 10px 12px;
|
||
background-color: var(--color-input-bg);
|
||
border: 1px solid var(--color-border);
|
||
border-radius: var(--radius-md);
|
||
color: var(--color-text);
|
||
font-size: 0.875rem;
|
||
font-family: inherit;
|
||
transition: border-color var(--transition);
|
||
outline: none;
|
||
}
|
||
|
||
input:focus,
|
||
textarea:focus,
|
||
select:focus {
|
||
border-color: var(--color-primary);
|
||
}
|
||
|
||
input::placeholder,
|
||
textarea::placeholder {
|
||
color: var(--color-text-muted);
|
||
}
|
||
|
||
textarea {
|
||
resize: vertical;
|
||
min-height: 80px;
|
||
}
|
||
|
||
label {
|
||
display: block;
|
||
font-size: 0.8rem;
|
||
font-weight: 500;
|
||
color: var(--color-text-muted);
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.form-group {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
/* ===== Utility ===== */
|
||
.text-muted { color: var(--color-text-muted); }
|
||
.text-sm { font-size: 0.8rem; }
|
||
.text-xs { font-size: 0.75rem; }
|
||
.mt-1 { margin-top: 4px; }
|
||
.mt-2 { margin-top: 8px; }
|
||
.mt-3 { margin-top: 12px; }
|
||
.mt-4 { margin-top: 16px; }
|
||
.mb-2 { margin-bottom: 8px; }
|
||
.mb-4 { margin-bottom: 16px; }
|
||
.flex { display: flex; }
|
||
.flex-col { flex-direction: column; }
|
||
.items-center { align-items: center; }
|
||
.justify-between { justify-content: space-between; }
|
||
.gap-1 { gap: 4px; }
|
||
.gap-2 { gap: 8px; }
|
||
.gap-3 { gap: 12px; }
|
||
.gap-4 { gap: 16px; }
|
||
.w-full { width: 100%; }
|
||
.truncate {
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.lock-screen.svelte-7sq1ct {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
min-height: 100vh;
|
||
padding: 1rem;
|
||
}
|
||
|
||
.lock-card.svelte-7sq1ct {
|
||
width: 100%;
|
||
max-width: 400px;
|
||
padding: 2.5rem 2rem;
|
||
background: var(--color-surface);
|
||
border: 1px solid var(--color-border);
|
||
border-radius: var(--radius-lg);
|
||
box-shadow: var(--shadow);
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 1rem;
|
||
}
|
||
|
||
.lock-icon.svelte-7sq1ct {
|
||
font-size: 3rem;
|
||
line-height: 1;
|
||
}
|
||
|
||
h1.svelte-7sq1ct {
|
||
font-size: 1.5rem;
|
||
text-align: center;
|
||
}
|
||
|
||
.subtitle.svelte-7sq1ct {
|
||
color: var(--color-text-muted);
|
||
font-size: 0.9rem;
|
||
text-align: center;
|
||
}
|
||
|
||
.lock-form.svelte-7sq1ct {
|
||
width: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.error-banner.svelte-7sq1ct {
|
||
width: 100%;
|
||
padding: 10px 14px;
|
||
background: rgba(229, 72, 77, 0.15);
|
||
border: 1px solid rgba(229, 72, 77, 0.4);
|
||
border-radius: var(--radius-md);
|
||
color: var(--color-danger);
|
||
font-size: 0.85rem;
|
||
text-align: center;
|
||
}
|
||
|
||
.hint.svelte-7sq1ct {
|
||
font-size: 0.75rem;
|
||
color: var(--color-text-muted);
|
||
text-align: center;
|
||
line-height: 1.4;
|
||
margin-top: 0.5rem;
|
||
}
|
||
|
||
.sidebar-content.svelte-181dlmc {
|
||
display: flex;
|
||
flex-direction: column;
|
||
height: 100%;
|
||
}
|
||
|
||
.sidebar-header.svelte-181dlmc {
|
||
padding: 16px;
|
||
border-bottom: 1px solid var(--color-border);
|
||
}
|
||
|
||
.sidebar-header.svelte-181dlmc h2:where(.svelte-181dlmc) {
|
||
font-size: 1rem;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.search-box.svelte-181dlmc {
|
||
padding: 12px 16px;
|
||
}
|
||
|
||
.search-box.svelte-181dlmc input:where(.svelte-181dlmc) {
|
||
padding: 8px 10px;
|
||
font-size: 0.85rem;
|
||
}
|
||
|
||
.groups-nav.svelte-181dlmc {
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
padding: 8px;
|
||
}
|
||
|
||
.group-row.svelte-181dlmc {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.group-item.svelte-181dlmc {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
flex: 1;
|
||
min-width: 0;
|
||
padding: 8px 12px;
|
||
border: none;
|
||
border-radius: var(--radius-md);
|
||
background: transparent;
|
||
color: var(--color-text-muted);
|
||
font-size: 0.875rem;
|
||
cursor: pointer;
|
||
transition: background-color 150ms, color 150ms;
|
||
text-align: left;
|
||
}
|
||
|
||
.group-item.svelte-181dlmc:hover {
|
||
background: var(--color-surface-hover);
|
||
color: var(--color-text);
|
||
}
|
||
|
||
.group-item.active.svelte-181dlmc {
|
||
background: rgba(108, 99, 255, 0.15);
|
||
color: var(--color-primary);
|
||
}
|
||
|
||
.group-wrapper.drop-target.svelte-181dlmc .group-item:where(.svelte-181dlmc),
|
||
.group-row.drop-target.svelte-181dlmc .group-item:where(.svelte-181dlmc) {
|
||
background: rgba(108, 99, 255, 0.3);
|
||
color: var(--color-primary);
|
||
}
|
||
|
||
.group-wrapper.drop-target.svelte-181dlmc,
|
||
.group-row.drop-target.svelte-181dlmc {
|
||
background: rgba(108, 99, 255, 0.12);
|
||
border: 2px dashed var(--color-primary);
|
||
border-radius: var(--radius-md);
|
||
box-shadow: 0 0 12px rgba(108, 99, 255, 0.3);
|
||
}
|
||
|
||
.group-wrapper.svelte-181dlmc {
|
||
border-radius: var(--radius-md);
|
||
transition: background-color 150ms;
|
||
}
|
||
|
||
.group-icon.svelte-181dlmc {
|
||
font-size: 1rem;
|
||
}
|
||
|
||
.group-color.svelte-181dlmc {
|
||
width: 10px;
|
||
height: 10px;
|
||
border-radius: 50%;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.group-name.svelte-181dlmc {
|
||
flex: 1;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.group-actions.svelte-181dlmc {
|
||
display: flex;
|
||
gap: 2px;
|
||
padding-right: 4px;
|
||
opacity: 0;
|
||
transition: opacity 150ms;
|
||
}
|
||
|
||
.group-row.svelte-181dlmc:hover .group-actions:where(.svelte-181dlmc) {
|
||
opacity: 1;
|
||
}
|
||
|
||
.group-action-btn.svelte-181dlmc {
|
||
background: none;
|
||
border: none;
|
||
cursor: pointer;
|
||
font-size: 0.75rem;
|
||
padding: 4px;
|
||
border-radius: var(--radius-sm);
|
||
transition: background-color 150ms;
|
||
}
|
||
|
||
.group-action-btn.svelte-181dlmc:hover {
|
||
background: var(--color-surface-hover);
|
||
}
|
||
|
||
.sidebar-footer.svelte-181dlmc {
|
||
padding: 12px 16px;
|
||
border-top: 1px solid var(--color-border);
|
||
}
|
||
|
||
.drop-indicator.svelte-181dlmc {
|
||
position: fixed;
|
||
bottom: 20px;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
padding: 8px 16px;
|
||
background: var(--color-primary);
|
||
color: #fff;
|
||
border-radius: var(--radius-md);
|
||
font-size: 0.8rem;
|
||
font-weight: 500;
|
||
z-index: 100;
|
||
pointer-events: none;
|
||
animation: svelte-181dlmc-fadeIn 150ms ease;
|
||
}
|
||
|
||
@keyframes svelte-181dlmc-fadeIn {
|
||
from { opacity: 0; transform: translateX(-50%) translateY(10px); }
|
||
to { opacity: 1; transform: translateX(-50%) translateY(0); }
|
||
}
|
||
|
||
/* Modal */
|
||
.modal-overlay.svelte-181dlmc {
|
||
position: fixed;
|
||
inset: 0;
|
||
background: rgba(0, 0, 0, 0.6);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 200;
|
||
padding: 1rem;
|
||
}
|
||
|
||
.modal.svelte-181dlmc {
|
||
background: var(--color-surface);
|
||
border: 1px solid var(--color-border);
|
||
border-radius: var(--radius-lg);
|
||
padding: 24px;
|
||
max-width: 380px;
|
||
width: 100%;
|
||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||
}
|
||
|
||
.modal.svelte-181dlmc h3:where(.svelte-181dlmc) {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.modal.svelte-181dlmc p:where(.svelte-181dlmc) {
|
||
color: var(--color-text-muted);
|
||
font-size: 0.9rem;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.modal-actions.svelte-181dlmc {
|
||
display: flex;
|
||
gap: 8px;
|
||
}
|
||
|
||
.error-banner.svelte-181dlmc {
|
||
padding: 8px 12px;
|
||
background: rgba(229, 72, 77, 0.15);
|
||
border: 1px solid rgba(229, 72, 77, 0.4);
|
||
border-radius: var(--radius-md);
|
||
color: var(--color-danger);
|
||
font-size: 0.85rem;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
/* Color picker */
|
||
.color-picker.svelte-181dlmc {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 6px;
|
||
}
|
||
|
||
.color-swatch.svelte-181dlmc {
|
||
width: 28px;
|
||
height: 28px;
|
||
border-radius: 50%;
|
||
border: 2px solid transparent;
|
||
cursor: pointer;
|
||
transition: transform 150ms, border-color 150ms;
|
||
}
|
||
|
||
.color-swatch.svelte-181dlmc:hover {
|
||
transform: scale(1.15);
|
||
}
|
||
|
||
.color-swatch.selected.svelte-181dlmc {
|
||
border-color: #fff;
|
||
transform: scale(1.15);
|
||
}
|
||
|
||
.loading.svelte-13s7gu4, .empty-state.svelte-13s7gu4 {
|
||
text-align: center;
|
||
padding: 3rem 1rem;
|
||
color: var(--color-text-muted);
|
||
}
|
||
|
||
.error-banner.svelte-13s7gu4 {
|
||
padding: 12px 16px;
|
||
background: rgba(229, 72, 77, 0.15);
|
||
border: 1px solid rgba(229, 72, 77, 0.4);
|
||
border-radius: var(--radius-md);
|
||
color: var(--color-danger);
|
||
font-size: 0.85rem;
|
||
}
|
||
|
||
.empty-icon.svelte-13s7gu4 {
|
||
font-size: 3rem;
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.empty-text.svelte-13s7gu4 {
|
||
font-size: 1.1rem;
|
||
font-weight: 500;
|
||
color: var(--color-text);
|
||
}
|
||
|
||
.empty-hint.svelte-13s7gu4 {
|
||
font-size: 0.85rem;
|
||
color: var(--color-text-muted);
|
||
}
|
||
|
||
.results-info.svelte-13s7gu4 {
|
||
padding: 8px 0;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.entries-table.svelte-13s7gu4 {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
}
|
||
|
||
.entries-table.svelte-13s7gu4 th:where(.svelte-13s7gu4) {
|
||
text-align: left;
|
||
padding: 8px 12px;
|
||
font-size: 0.75rem;
|
||
font-weight: 600;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.05em;
|
||
color: var(--color-text-muted);
|
||
border-bottom: 1px solid var(--color-border);
|
||
}
|
||
|
||
.entry-row.svelte-13s7gu4 {
|
||
cursor: grab;
|
||
transition: background-color 150ms;
|
||
}
|
||
|
||
.entry-row.svelte-13s7gu4:hover {
|
||
background: var(--color-surface-hover);
|
||
}
|
||
|
||
.entry-row.dragging.svelte-13s7gu4 {
|
||
opacity: 0.4;
|
||
}
|
||
|
||
.entry-row.svelte-13s7gu4:active {
|
||
cursor: grabbing;
|
||
}
|
||
|
||
.entry-row.svelte-13s7gu4 td:where(.svelte-13s7gu4) {
|
||
padding: 10px 12px;
|
||
font-size: 0.875rem;
|
||
border-bottom: 1px solid var(--color-border);
|
||
}
|
||
|
||
.drag-handle.svelte-13s7gu4 {
|
||
color: var(--color-text-muted);
|
||
margin-right: 6px;
|
||
user-select: none;
|
||
opacity: 0.5;
|
||
transition: opacity 150ms;
|
||
}
|
||
|
||
.entry-row.svelte-13s7gu4:hover .drag-handle:where(.svelte-13s7gu4) {
|
||
opacity: 1;
|
||
}
|
||
|
||
.entry-title.svelte-13s7gu4 {
|
||
font-weight: 500;
|
||
}
|
||
|
||
.entry-username.svelte-13s7gu4 {
|
||
color: var(--color-text-muted);
|
||
}
|
||
|
||
.entry-url.svelte-13s7gu4 {
|
||
color: var(--color-text-muted);
|
||
max-width: 200px;
|
||
}
|
||
|
||
@media (max-width: 600px) {
|
||
.entries-table.svelte-13s7gu4 th:where(.svelte-13s7gu4):nth-child(3),
|
||
.entry-row.svelte-13s7gu4 td:where(.svelte-13s7gu4):nth-child(3) {
|
||
display: none;
|
||
}
|
||
}
|
||
|
||
.loading.svelte-dssgjx, .empty-state.svelte-dssgjx {
|
||
text-align: center;
|
||
padding: 3rem;
|
||
color: var(--color-text-muted);
|
||
}
|
||
|
||
.error-banner.svelte-dssgjx {
|
||
padding: 12px 16px;
|
||
background: rgba(229, 72, 77, 0.15);
|
||
border: 1px solid rgba(229, 72, 77, 0.4);
|
||
border-radius: var(--radius-md);
|
||
color: var(--color-danger);
|
||
font-size: 0.85rem;
|
||
}
|
||
|
||
.toast.svelte-dssgjx {
|
||
position: fixed;
|
||
bottom: 20px;
|
||
right: 20px;
|
||
padding: 10px 16px;
|
||
background: var(--color-surface);
|
||
border: 1px solid var(--color-border);
|
||
border-radius: var(--radius-md);
|
||
font-size: 0.85rem;
|
||
color: var(--color-success);
|
||
box-shadow: var(--shadow);
|
||
z-index: 1000;
|
||
animation: svelte-dssgjx-slideIn 200ms ease;
|
||
}
|
||
|
||
@keyframes svelte-dssgjx-slideIn {
|
||
from { transform: translateY(20px); opacity: 0; }
|
||
to { transform: translateY(0); opacity: 1; }
|
||
}
|
||
|
||
.detail-card.svelte-dssgjx {
|
||
background: var(--color-surface);
|
||
border: 1px solid var(--color-border);
|
||
border-radius: var(--radius-lg);
|
||
padding: 24px;
|
||
max-width: 600px;
|
||
}
|
||
|
||
.detail-header.svelte-dssgjx {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 24px;
|
||
padding-bottom: 16px;
|
||
border-bottom: 1px solid var(--color-border);
|
||
gap: 12px;
|
||
}
|
||
|
||
.detail-header.svelte-dssgjx h2:where(.svelte-dssgjx) {
|
||
font-size: 1.25rem;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.header-actions.svelte-dssgjx {
|
||
display: flex;
|
||
gap: 8px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.detail-fields.svelte-dssgjx {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 16px;
|
||
}
|
||
|
||
.field-label.svelte-dssgjx {
|
||
font-size: 0.75rem;
|
||
font-weight: 600;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.05em;
|
||
color: var(--color-text-muted);
|
||
margin-bottom: 4px;
|
||
display: block;
|
||
}
|
||
|
||
.field-value.svelte-dssgjx {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
font-size: 0.95rem;
|
||
word-break: break-all;
|
||
}
|
||
|
||
.field-value.notes.svelte-dssgjx {
|
||
white-space: pre-wrap;
|
||
}
|
||
|
||
.field-value.svelte-dssgjx a:where(.svelte-dssgjx) {
|
||
color: var(--color-primary);
|
||
text-decoration: none;
|
||
}
|
||
|
||
.field-value.svelte-dssgjx a:where(.svelte-dssgjx):hover {
|
||
text-decoration: underline;
|
||
}
|
||
|
||
.copy-btn.svelte-dssgjx {
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.detail-meta.svelte-dssgjx {
|
||
display: flex;
|
||
gap: 16px;
|
||
margin-top: 24px;
|
||
padding-top: 16px;
|
||
border-top: 1px solid var(--color-border);
|
||
}
|
||
|
||
/* Modal */
|
||
.modal-overlay.svelte-dssgjx {
|
||
position: fixed;
|
||
inset: 0;
|
||
background: rgba(0, 0, 0, 0.6);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 200;
|
||
padding: 1rem;
|
||
}
|
||
|
||
.modal.svelte-dssgjx {
|
||
background: var(--color-surface);
|
||
border: 1px solid var(--color-border);
|
||
border-radius: var(--radius-lg);
|
||
padding: 24px;
|
||
max-width: 400px;
|
||
width: 100%;
|
||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||
}
|
||
|
||
.modal.svelte-dssgjx h3:where(.svelte-dssgjx) {
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.modal.svelte-dssgjx p:where(.svelte-dssgjx) {
|
||
color: var(--color-text-muted);
|
||
font-size: 0.9rem;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.modal-actions.svelte-dssgjx {
|
||
display: flex;
|
||
gap: 8px;
|
||
}
|
||
|
||
@media (max-width: 600px) {
|
||
.header-actions.svelte-dssgjx {
|
||
display: none;
|
||
}
|
||
}
|
||
|
||
.loading.svelte-pafazm {
|
||
text-align: center;
|
||
padding: 3rem;
|
||
color: var(--color-text-muted);
|
||
}
|
||
|
||
.error-banner.svelte-pafazm {
|
||
padding: 12px 16px;
|
||
background: rgba(229, 72, 77, 0.15);
|
||
border: 1px solid rgba(229, 72, 77, 0.4);
|
||
border-radius: var(--radius-md);
|
||
color: var(--color-danger);
|
||
font-size: 0.85rem;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.form-card.svelte-pafazm {
|
||
background: var(--color-surface);
|
||
border: 1px solid var(--color-border);
|
||
border-radius: var(--radius-lg);
|
||
padding: 24px;
|
||
max-width: 500px;
|
||
}
|
||
|
||
.validation-errors.svelte-pafazm {
|
||
margin-bottom: 16px;
|
||
padding: 12px;
|
||
background: rgba(251, 191, 36, 0.1);
|
||
border: 1px solid rgba(251, 191, 36, 0.3);
|
||
border-radius: var(--radius-md);
|
||
}
|
||
|
||
.validation-error.svelte-pafazm {
|
||
font-size: 0.85rem;
|
||
color: var(--color-warning);
|
||
}
|
||
|
||
.password-input-group.svelte-pafazm {
|
||
display: flex;
|
||
gap: 8px;
|
||
}
|
||
|
||
.password-input-group.svelte-pafazm input:where(.svelte-pafazm) {
|
||
flex: 1;
|
||
}
|
||
|
||
.form-actions.svelte-pafazm {
|
||
display: flex;
|
||
gap: 8px;
|
||
margin-top: 20px;
|
||
}
|
||
|
||
.modal-overlay.svelte-17di1i9 {
|
||
position: fixed;
|
||
inset: 0;
|
||
background: rgba(0, 0, 0, 0.6);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 200;
|
||
padding: 1rem;
|
||
}
|
||
|
||
.modal.svelte-17di1i9 {
|
||
background: var(--color-surface);
|
||
border: 1px solid var(--color-border);
|
||
border-radius: var(--radius-lg);
|
||
padding: 24px;
|
||
max-width: 420px;
|
||
width: 100%;
|
||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||
}
|
||
|
||
.modal.svelte-17di1i9 h3:where(.svelte-17di1i9) {
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.modal.svelte-17di1i9 p:where(.svelte-17di1i9) {
|
||
color: var(--color-text-muted);
|
||
font-size: 0.9rem;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.modal-actions.svelte-17di1i9 {
|
||
display: flex;
|
||
gap: 8px;
|
||
margin-top: 16px;
|
||
}
|
||
|
||
.error-banner.svelte-17di1i9 {
|
||
padding: 10px 14px;
|
||
background: rgba(229, 72, 77, 0.15);
|
||
border: 1px solid rgba(229, 72, 77, 0.4);
|
||
border-radius: var(--radius-md);
|
||
color: var(--color-danger);
|
||
font-size: 0.85rem;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.success-banner.svelte-17di1i9 {
|
||
padding: 10px 14px;
|
||
background: rgba(52, 211, 153, 0.15);
|
||
border: 1px solid rgba(52, 211, 153, 0.4);
|
||
border-radius: var(--radius-md);
|
||
color: var(--color-success);
|
||
font-size: 0.85rem;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.import-mode.svelte-17di1i9 {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8px;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.radio-label.svelte-17di1i9 {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
padding: 8px 12px;
|
||
border: 1px solid var(--color-border);
|
||
border-radius: var(--radius-md);
|
||
cursor: pointer;
|
||
transition: border-color 150ms, background-color 150ms;
|
||
}
|
||
|
||
.radio-label.svelte-17di1i9:hover {
|
||
border-color: var(--color-primary);
|
||
background: var(--color-surface-hover);
|
||
}
|
||
|
||
.radio-label.svelte-17di1i9 input[type="radio"]:where(.svelte-17di1i9) {
|
||
accent-color: var(--color-primary);
|
||
cursor: pointer;
|
||
}
|
||
|
||
.radio-label.svelte-17di1i9 span:where(.svelte-17di1i9) {
|
||
font-size: 0.85rem;
|
||
}
|
||
|
||
.file-label.svelte-17di1i9 {
|
||
font-size: 0.8rem;
|
||
font-weight: 500;
|
||
color: var(--color-text-muted);
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
input[type="file"].svelte-17di1i9 {
|
||
font-size: 0.85rem;
|
||
padding: 8px;
|
||
}
|
||
|
||
.form-group.svelte-17di1i9 {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.form-group.svelte-17di1i9 input[type="password"]:where(.svelte-17di1i9) {
|
||
width: 100%;
|
||
padding: 8px 12px;
|
||
font-size: 0.85rem;
|
||
border: 1px solid var(--color-border);
|
||
border-radius: var(--radius-md);
|
||
background: var(--color-surface);
|
||
color: var(--color-text);
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.form-group.svelte-17di1i9 input[type="password"]:where(.svelte-17di1i9):focus {
|
||
outline: none;
|
||
border-color: var(--color-primary);
|
||
}
|
||
|
||
.app-shell.svelte-1ybayt {
|
||
display: flex;
|
||
min-height: 100vh;
|
||
}
|
||
|
||
/* Mobile header */
|
||
.mobile-header.svelte-1ybayt {
|
||
display: none;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 10px 16px;
|
||
background: var(--color-surface);
|
||
border-bottom: 1px solid var(--color-border);
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 100;
|
||
}
|
||
|
||
.mobile-title.svelte-1ybayt {
|
||
font-weight: 600;
|
||
font-size: 0.95rem;
|
||
}
|
||
|
||
/* Sidebar */
|
||
.sidebar.svelte-1ybayt {
|
||
width: 260px;
|
||
min-width: 260px;
|
||
background: var(--color-sidebar);
|
||
border-right: 1px solid var(--color-border);
|
||
height: 100vh;
|
||
position: sticky;
|
||
top: 0;
|
||
overflow-y: auto;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
/* Main content */
|
||
.main-content.svelte-1ybayt {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
min-width: 0;
|
||
}
|
||
|
||
.top-bar.svelte-1ybayt {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
padding: 12px 20px;
|
||
background: var(--color-surface);
|
||
border-bottom: 1px solid var(--color-border);
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 10;
|
||
}
|
||
|
||
.top-bar-title.svelte-1ybayt {
|
||
flex: 1;
|
||
min-width: 0;
|
||
}
|
||
|
||
.top-bar-title.svelte-1ybayt h1:where(.svelte-1ybayt) {
|
||
font-size: 1.1rem;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.top-bar-actions.svelte-1ybayt {
|
||
display: flex;
|
||
gap: 8px;
|
||
align-items: center;
|
||
}
|
||
|
||
.content-area.svelte-1ybayt {
|
||
flex: 1;
|
||
padding: 20px;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
/* Sidebar overlay (mobile) */
|
||
.sidebar-overlay.svelte-1ybayt {
|
||
display: none;
|
||
position: fixed;
|
||
inset: 0;
|
||
background: rgba(0, 0, 0, 0.5);
|
||
z-index: 49;
|
||
border: none;
|
||
cursor: pointer;
|
||
padding: 0;
|
||
margin: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
/* Responsive */
|
||
@media (max-width: 768px) {
|
||
.mobile-header.svelte-1ybayt {
|
||
display: flex;
|
||
}
|
||
|
||
.sidebar.svelte-1ybayt {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
bottom: 0;
|
||
z-index: 50;
|
||
transform: translateX(-100%);
|
||
transition: transform 200ms ease;
|
||
}
|
||
|
||
.sidebar.open.svelte-1ybayt {
|
||
transform: translateX(0);
|
||
}
|
||
|
||
.sidebar-overlay.svelte-1ybayt {
|
||
display: block;
|
||
}
|
||
|
||
.content-area.svelte-1ybayt {
|
||
padding: 12px;
|
||
}
|
||
|
||
.top-bar.svelte-1ybayt {
|
||
padding: 10px 12px;
|
||
}
|
||
}
|
||
/*$vite$:1*/</style>
|
||
</head>
|
||
<body>
|
||
<div id="app"></div>
|
||
</body>
|
||
</html>
|