├── .gitignore
├── .hg_archival.txt
├── .prettierrc
├── README.md
├── build
├── dist
│ ├── definition.d.ts
│ ├── definition.js
│ ├── definition.js.map
│ ├── link.d.ts
│ ├── link.js
│ ├── link.js.map
│ ├── node.d.ts
│ ├── node.js
│ ├── node.js.map
│ ├── story-plan-organizer.d.ts
│ ├── story-plan-organizer.js
│ ├── story-plan-organizer.js.map
│ ├── uuid.d.ts
│ ├── uuid.js
│ └── uuid.js.map
└── tsconfig.tsbuildinfo
├── data
├── sample1.json
└── sample2.json
├── eslint.config.js
├── images
├── splash1.png
└── splash2.png
├── img
├── asc.gif
├── bg.gif
├── conv30.png
├── conv40.png
├── conv50.png
├── desc.gif
├── glyphicons-halflings-white.png
├── glyphicons-halflings.png
├── heart30.png
├── heart40.png
├── heart50.png
├── lastfm.gif
├── m1.png
├── m2.png
├── m3.png
├── m4.png
├── m5.png
├── people35.png
├── people45.png
├── people55.png
├── pin.png
└── songkick.png
├── index.html
├── js
├── eventslist.js
├── eventsmap.js
├── filter.js
├── lastfm.js
├── songkick.js
├── status.js
├── ui.js
└── util.js
├── lib
├── bootstrap-alert.js
├── bootstrap-dropdown.js
├── bootstrap-modal.js
├── bootstrap-typeahead.js
├── bootstrap.min.css
├── bootstrap.min.js
├── jquery-3.1.1.min.js
├── jquery-ui
│ ├── css
│ │ └── blitzer
│ │ │ ├── images
│ │ │ ├── ui-bg_diagonals-thick_75_f3d8d8_40x40.png
│ │ │ ├── ui-bg_dots-small_65_a6a6a6_2x2.png
│ │ │ ├── ui-bg_flat_0_333333_40x100.png
│ │ │ ├── ui-bg_flat_65_ffffff_40x100.png
│ │ │ ├── ui-bg_flat_75_ffffff_40x100.png
│ │ │ ├── ui-bg_glass_55_fbf8ee_1x400.png
│ │ │ ├── ui-bg_highlight-hard_100_eeeeee_1x100.png
│ │ │ ├── ui-bg_highlight-hard_100_f6f6f6_1x100.png
│ │ │ ├── ui-bg_highlight-soft_15_cc0000_1x100.png
│ │ │ ├── ui-icons_004276_256x240.png
│ │ │ ├── ui-icons_cc0000_256x240.png
│ │ │ └── ui-icons_ffffff_256x240.png
│ │ │ └── jquery-ui-1.8.17.custom.css
│ └── js
│ │ ├── jquery-1.7.1.min.js
│ │ └── jquery-ui-1.8.17.custom.min.js
├── jquery.tablesorter.js
├── less-1.2.1.min.js
└── markerclusterer.js
├── package-lock.json
├── package.json
├── src
├── definition.ts
├── link.ts
├── node.ts
├── story-plan-organizer.ts
└── uuid.ts
├── styles
└── styles.css
├── tsconfig.json
└── ui.css
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/.hg_archival.txt:
--------------------------------------------------------------------------------
1 | repo: a7bdd3a0e318b23e21cdb1633ed114a2a55ecf7b
2 | node: 0e3418716ee4fbe351d8df6d1bdd4e0039d035d9
3 | branch: default
4 | latesttag: null
5 | latesttagdistance: 35
6 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "arrowParens": "always",
3 | "endOfLine": "auto",
4 | "jsxSingleQuote": true,
5 | "printWidth": 120,
6 | "proseWrap": "preserve",
7 | "semi": true,
8 | "singleQuote": true,
9 | "tabWidth": 2,
10 | "trailingComma": "all"
11 | }
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
2 |
3 | ## Getting Started
4 |
5 | First, run the development server:
6 |
7 | ```bash
8 | npm run dev
9 | # or
10 | yarn dev
11 | # or
12 | pnpm dev
13 | # or
14 | bun dev
15 | ```
16 |
17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
18 |
19 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
20 |
21 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
22 |
23 | ## Learn More
24 |
25 | To learn more about Next.js, take a look at the following resources:
26 |
27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
29 |
30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
31 |
32 | ## Deploy on Vercel
33 |
34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
35 |
36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
37 |
--------------------------------------------------------------------------------
/build/dist/definition.d.ts:
--------------------------------------------------------------------------------
1 | import { UUID } from './uuid.js';
2 | export declare enum NodeType {
3 | Character = "Character",
4 | Location = "Location",
5 | Organization = "Organization",
6 | Event = "Event",
7 | Story = "Story",
8 | Lore = "Lore"
9 | }
10 | export type Point = {
11 | x: number;
12 | y: number;
13 | };
14 | export type Color_Hex = `#${string}`;
15 | export type Node = {
16 | id: UUID;
17 | location: Point;
18 | type: NodeType;
19 | name: string;
20 | color: Color_Hex;
21 | };
22 | export type Character = Node & {
23 | imageSrc: string;
24 | personality: string;
25 | quirk: string;
26 | like: string;
27 | dislike: string;
28 | strength: string;
29 | weakness: string;
30 | flaw: string;
31 | motivation: string;
32 | other: string;
33 | };
34 | export type Location = Node & {
35 | imageSrc: string;
36 | description: string;
37 | };
38 | export type Organization = Node & {
39 | objective: string;
40 | detail: string;
41 | };
42 | export type Event = Node & {
43 | detail: string;
44 | };
45 | export type Story = Node & {
46 | description: string;
47 | };
48 | export type Lore = Node & {
49 | detail: string;
50 | };
51 | export type NodePositionResults = {
52 | top: number;
53 | bottom: number;
54 | left: number;
55 | right: number;
56 | topLeft: Point;
57 | topRight: Point;
58 | bottomLeft: Point;
59 | bottomRight: Point;
60 | };
61 | export type Link = {
62 | nodeFromId: UUID;
63 | nodeToId: UUID;
64 | };
65 | export type Dto = {
66 | nodes: Node[];
67 | links: Link[];
68 | };
69 | export type State = {
70 | nodes: Node[];
71 | nodesCached: HTMLDivElement[];
72 | links: Link[];
73 | linesCached: HTMLDivElement[];
74 | selectedNodeElement: HTMLDivElement | null;
75 | createOngoingLinkId: UUID | null;
76 | deleting: boolean;
77 | };
78 | export declare const CALCULATION_INCREMENT: number;
79 |
--------------------------------------------------------------------------------
/build/dist/definition.js:
--------------------------------------------------------------------------------
1 | export var NodeType;
2 | (function (NodeType) {
3 | NodeType["Character"] = "Character";
4 | NodeType["Location"] = "Location";
5 | NodeType["Organization"] = "Organization";
6 | NodeType["Event"] = "Event";
7 | NodeType["Story"] = "Story";
8 | NodeType["Lore"] = "Lore";
9 | })(NodeType || (NodeType = {}));
10 | export const CALCULATION_INCREMENT = 20;
11 | //# sourceMappingURL=definition.js.map
--------------------------------------------------------------------------------
/build/dist/definition.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"definition.js","sourceRoot":"","sources":["../../src/definition.ts"],"names":[],"mappings":"AAEA,MAAM,CAAN,IAAY,QAOX;AAPD,WAAY,QAAQ;IAClB,mCAAuB,CAAA;IACvB,iCAAqB,CAAA;IACrB,yCAA6B,CAAA;IAC7B,2BAAe,CAAA;IACf,2BAAe,CAAA;IACf,yBAAa,CAAA;AACf,CAAC,EAPW,QAAQ,KAAR,QAAQ,QAOnB;AAmFD,MAAM,CAAC,MAAM,qBAAqB,GAAW,EAAE,CAAC"}
--------------------------------------------------------------------------------
/build/dist/link.d.ts:
--------------------------------------------------------------------------------
1 | import { State } from './definition.js';
2 | import { UUID } from './uuid.js';
3 | export declare const redraw_lines: (state: State) => void;
4 | export declare const add_link: (nodeId1: UUID, nodeId2: UUID, state: State) => void;
5 |
--------------------------------------------------------------------------------
/build/dist/link.js:
--------------------------------------------------------------------------------
1 | import { CALCULATION_INCREMENT } from './definition.js';
2 | import { get_node, get_node_element } from './node.js';
3 | import { refresh } from './story-plan-organizer.js';
4 | const does_link_exist = (nodeId1, nodeId2, links) => {
5 | for (const link of links) {
6 | if ((nodeId1 === link.nodeFromId && nodeId2 === link.nodeToId) ||
7 | (nodeId2 === link.nodeFromId && nodeId1 === link.nodeToId)) {
8 | return true;
9 | }
10 | }
11 | return false;
12 | };
13 | const calculate_element_positions = (node) => {
14 | const element = get_node_element(node.id);
15 | if (element) {
16 | const top = node.location.y;
17 | const bottom = node.location.y + element.offsetHeight;
18 | const left = node.location.x;
19 | const right = node.location.x + element.offsetWidth;
20 | const topLeft = { x: node.location.x, y: node.location.y };
21 | const topRight = { x: node.location.x + element.offsetWidth, y: node.location.y };
22 | const bottomLeft = { x: node.location.x, y: node.location.y + element.offsetHeight };
23 | const bottomRight = { x: node.location.x + element.offsetWidth, y: node.location.y + element.offsetHeight };
24 | return { top, bottom, left, right, topLeft, topRight, bottomLeft, bottomRight };
25 | }
26 | else {
27 | return undefined;
28 | }
29 | };
30 | const calculate_distance = (point1, point2) => {
31 | const a = point1.x - point2.x;
32 | const b = point1.y - point2.y;
33 | return Math.sqrt(a * a + b * b);
34 | };
35 | const calculate_shortest_distance_2 = (point, node2) => {
36 | const currentShortestPoint = { point: { x: 0, y: 0 }, distance: 999999999999 };
37 | const nodePositions2 = calculate_element_positions(node2);
38 | if (nodePositions2) {
39 | // 1. Sweep TopLeft to TopRight
40 | for (let x = nodePositions2.left; x < nodePositions2.right; x = x + CALCULATION_INCREMENT) {
41 | const tempPoint = { x: x, y: nodePositions2.top };
42 | const distance = calculate_distance(point, tempPoint);
43 | if (distance < currentShortestPoint.distance) {
44 | currentShortestPoint.point = tempPoint;
45 | currentShortestPoint.distance = distance;
46 | }
47 | }
48 | // 2. Sweep TopRight to BottomRight
49 | for (let y = nodePositions2.top; y < nodePositions2.bottom; y = y + CALCULATION_INCREMENT) {
50 | const tempPoint = { x: nodePositions2.right, y: y };
51 | const distance = calculate_distance(point, tempPoint);
52 | if (distance < currentShortestPoint.distance) {
53 | currentShortestPoint.point = tempPoint;
54 | currentShortestPoint.distance = distance;
55 | }
56 | }
57 | // 3. Sweep BottomLeft to BottomRight
58 | for (let x = nodePositions2.left; x < nodePositions2.right; x = x + CALCULATION_INCREMENT) {
59 | const tempPoint = { x: x, y: nodePositions2.bottom };
60 | const distance = calculate_distance(point, tempPoint);
61 | if (distance < currentShortestPoint.distance) {
62 | currentShortestPoint.point = tempPoint;
63 | currentShortestPoint.distance = distance;
64 | }
65 | }
66 | // 4. Sweep TopLeft to BottomLeft
67 | for (let y = nodePositions2.top; y < nodePositions2.bottom; y = y + CALCULATION_INCREMENT) {
68 | const tempPoint = { x: nodePositions2.left, y: y };
69 | const distance = calculate_distance(point, tempPoint);
70 | if (distance < currentShortestPoint.distance) {
71 | currentShortestPoint.point = tempPoint;
72 | currentShortestPoint.distance = distance;
73 | }
74 | }
75 | }
76 | return currentShortestPoint;
77 | };
78 | const calculate_shortest_distance = (node1, node2) => {
79 | const currentShortestPoints = { point1: { x: 0, y: 0 }, point2: { x: 0, y: 0 }, distance: 999999999999 };
80 | const nodePositions1 = calculate_element_positions(node1);
81 | if (nodePositions1) {
82 | // 1. Sweep TopLeft to TopRight
83 | for (let x = nodePositions1.left; x < nodePositions1.right; x = x + CALCULATION_INCREMENT) {
84 | const tempPoint = { x: x, y: nodePositions1.top };
85 | const result = calculate_shortest_distance_2(tempPoint, node2);
86 | if (result.distance < currentShortestPoints.distance) {
87 | currentShortestPoints.point1 = tempPoint;
88 | currentShortestPoints.point2 = result.point;
89 | currentShortestPoints.distance = result.distance;
90 | }
91 | }
92 | // 2. Sweep TopRight to BottomRight
93 | for (let y = nodePositions1.top; y < nodePositions1.bottom; y = y + CALCULATION_INCREMENT) {
94 | const tempPoint = { x: nodePositions1.right, y: y };
95 | const result = calculate_shortest_distance_2(tempPoint, node2);
96 | if (result.distance < currentShortestPoints.distance) {
97 | currentShortestPoints.point1 = tempPoint;
98 | currentShortestPoints.point2 = result.point;
99 | currentShortestPoints.distance = result.distance;
100 | }
101 | }
102 | // 3. Sweep BottomLeft to BottomRight
103 | for (let x = nodePositions1.left; x < nodePositions1.right; x = x + CALCULATION_INCREMENT) {
104 | const tempPoint = { x: x, y: nodePositions1.bottom };
105 | const result = calculate_shortest_distance_2(tempPoint, node2);
106 | if (result.distance < currentShortestPoints.distance) {
107 | currentShortestPoints.point1 = tempPoint;
108 | currentShortestPoints.point2 = result.point;
109 | currentShortestPoints.distance = result.distance;
110 | }
111 | }
112 | // 4. Sweep TopLeft to BottomLeft
113 | for (let y = nodePositions1.top; y < nodePositions1.bottom; y = y + CALCULATION_INCREMENT) {
114 | const tempPoint = { x: nodePositions1.left, y: y };
115 | const result = calculate_shortest_distance_2(tempPoint, node2);
116 | if (result.distance < currentShortestPoints.distance) {
117 | currentShortestPoints.point1 = tempPoint;
118 | currentShortestPoints.point2 = result.point;
119 | currentShortestPoints.distance = result.distance;
120 | }
121 | }
122 | }
123 | return { point1: currentShortestPoints.point1, point2: currentShortestPoints.point2 };
124 | };
125 | const create_line = (nodeId1, nodeId2, state) => {
126 | const node1 = get_node(nodeId1, state.nodes);
127 | const node2 = get_node(nodeId2, state.nodes);
128 | if (node1 && node2) {
129 | const newElement = document.createElement('div');
130 | const newLine = document.body.appendChild(newElement);
131 | newLine.className = 'line';
132 | const points = calculate_shortest_distance(node1, node2);
133 | const gradientId = nodeId1 + '_' + nodeId2;
134 | newLine.innerHTML = `
135 |
144 | `;
145 | state.linesCached.push(newElement);
146 | const lineElement = newLine.getElementsByTagName('line')[0];
147 | if (lineElement) {
148 | const nodeElement1 = get_node_element(nodeId1);
149 | const nodeElement2 = get_node_element(nodeId2);
150 | if (state.selectedNodeElement) {
151 | if (nodeElement1 === state.selectedNodeElement || nodeElement2 === state.selectedNodeElement) {
152 | lineElement.classList.add('line-highlighted');
153 | lineElement.classList.remove('line-unhighlighted');
154 | }
155 | else {
156 | lineElement.classList.remove('line-highlighted');
157 | lineElement.classList.add('line-unhighlighted');
158 | }
159 | }
160 | else {
161 | lineElement.classList.remove('line-highlighted');
162 | lineElement.classList.remove('line-unhighlighted');
163 | }
164 | lineElement.addEventListener('click', () => {
165 | if (state.deleting) {
166 | delete_link(nodeId1, nodeId2, state);
167 | }
168 | });
169 | }
170 | }
171 | };
172 | const delete_link = (nodeId1, nodeId2, state) => {
173 | for (let i = state.links.length - 1; i >= 0; i--) {
174 | const link = state.links[i];
175 | if ((nodeId1 === link.nodeFromId && nodeId2 === link.nodeToId) ||
176 | (nodeId2 === link.nodeFromId && nodeId1 === link.nodeToId)) {
177 | state.links.splice(i, 1);
178 | }
179 | }
180 | refresh(state);
181 | };
182 | export const redraw_lines = (state) => {
183 | for (const line of state.linesCached) {
184 | line.remove();
185 | }
186 | state.linesCached = [];
187 | for (const link of state.links) {
188 | create_line(link.nodeFromId, link.nodeToId, state);
189 | }
190 | };
191 | export const add_link = (nodeId1, nodeId2, state) => {
192 | if (nodeId1 && nodeId2 && !does_link_exist(nodeId1, nodeId2, state.links)) {
193 | state.links.push({ nodeFromId: nodeId1, nodeToId: nodeId2 });
194 | refresh(state);
195 | }
196 | };
197 | //# sourceMappingURL=link.js.map
--------------------------------------------------------------------------------
/build/dist/link.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"link.js","sourceRoot":"","sources":["../../src/link.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAiD,MAAM,iBAAiB,CAAC;AACvG,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAGpD,MAAM,eAAe,GAAG,CAAC,OAAa,EAAE,OAAa,EAAE,KAAa,EAAW,EAAE;IAC/E,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IACE,CAAC,OAAO,KAAK,IAAI,CAAC,UAAU,IAAI,OAAO,KAAK,IAAI,CAAC,QAAQ,CAAC;YAC1D,CAAC,OAAO,KAAK,IAAI,CAAC,UAAU,IAAI,OAAO,KAAK,IAAI,CAAC,QAAQ,CAAC,EAC1D,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF,MAAM,2BAA2B,GAAG,CAAC,IAAU,EAAmC,EAAE;IAClF,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC1C,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC;QACtD,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC;QAEpD,MAAM,OAAO,GAAG,EAAE,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;QAC3D,MAAM,QAAQ,GAAG,EAAE,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;QAClF,MAAM,UAAU,GAAG,EAAE,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;QACrF,MAAM,WAAW,GAAG,EAAE,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;QAE5G,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC;IAClF,CAAC;SAAM,CAAC;QACN,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,kBAAkB,GAAG,CAAC,MAAa,EAAE,MAAa,EAAU,EAAE;IAClE,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;IAC9B,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;IAC9B,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AAClC,CAAC,CAAC;AAEF,MAAM,6BAA6B,GAAG,CAAC,KAAY,EAAE,KAAW,EAAsC,EAAE;IACtG,MAAM,oBAAoB,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;IAE/E,MAAM,cAAc,GAAoC,2BAA2B,CAAC,KAAK,CAAC,CAAC;IAC3F,IAAI,cAAc,EAAE,CAAC;QACnB,+BAA+B;QAC/B,KAAK,IAAI,CAAC,GAAG,cAAc,CAAC,IAAI,EAAE,CAAC,GAAG,cAAc,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,qBAAqB,EAAE,CAAC;YAC1F,MAAM,SAAS,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,cAAc,CAAC,GAAG,EAAE,CAAC;YAClD,MAAM,QAAQ,GAAG,kBAAkB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;YACtD,IAAI,QAAQ,GAAG,oBAAoB,CAAC,QAAQ,EAAE,CAAC;gBAC7C,oBAAoB,CAAC,KAAK,GAAG,SAAS,CAAC;gBACvC,oBAAoB,CAAC,QAAQ,GAAG,QAAQ,CAAC;YAC3C,CAAC;QACH,CAAC;QACD,mCAAmC;QACnC,KAAK,IAAI,CAAC,GAAG,cAAc,CAAC,GAAG,EAAE,CAAC,GAAG,cAAc,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,qBAAqB,EAAE,CAAC;YAC1F,MAAM,SAAS,GAAG,EAAE,CAAC,EAAE,cAAc,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;YACpD,MAAM,QAAQ,GAAG,kBAAkB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;YACtD,IAAI,QAAQ,GAAG,oBAAoB,CAAC,QAAQ,EAAE,CAAC;gBAC7C,oBAAoB,CAAC,KAAK,GAAG,SAAS,CAAC;gBACvC,oBAAoB,CAAC,QAAQ,GAAG,QAAQ,CAAC;YAC3C,CAAC;QACH,CAAC;QACD,qCAAqC;QACrC,KAAK,IAAI,CAAC,GAAG,cAAc,CAAC,IAAI,EAAE,CAAC,GAAG,cAAc,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,qBAAqB,EAAE,CAAC;YAC1F,MAAM,SAAS,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,cAAc,CAAC,MAAM,EAAE,CAAC;YACrD,MAAM,QAAQ,GAAG,kBAAkB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;YACtD,IAAI,QAAQ,GAAG,oBAAoB,CAAC,QAAQ,EAAE,CAAC;gBAC7C,oBAAoB,CAAC,KAAK,GAAG,SAAS,CAAC;gBACvC,oBAAoB,CAAC,QAAQ,GAAG,QAAQ,CAAC;YAC3C,CAAC;QACH,CAAC;QACD,iCAAiC;QACjC,KAAK,IAAI,CAAC,GAAG,cAAc,CAAC,GAAG,EAAE,CAAC,GAAG,cAAc,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,qBAAqB,EAAE,CAAC;YAC1F,MAAM,SAAS,GAAG,EAAE,CAAC,EAAE,cAAc,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;YACnD,MAAM,QAAQ,GAAG,kBAAkB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;YACtD,IAAI,QAAQ,GAAG,oBAAoB,CAAC,QAAQ,EAAE,CAAC;gBAC7C,oBAAoB,CAAC,KAAK,GAAG,SAAS,CAAC;gBACvC,oBAAoB,CAAC,QAAQ,GAAG,QAAQ,CAAC;YAC3C,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,oBAAoB,CAAC;AAC9B,CAAC,CAAC;AAEF,MAAM,2BAA2B,GAAG,CAAC,KAAW,EAAE,KAAW,EAAoC,EAAE;IACjG,MAAM,qBAAqB,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;IAEzG,MAAM,cAAc,GAAoC,2BAA2B,CAAC,KAAK,CAAC,CAAC;IAC3F,IAAI,cAAc,EAAE,CAAC;QACnB,+BAA+B;QAC/B,KAAK,IAAI,CAAC,GAAG,cAAc,CAAC,IAAI,EAAE,CAAC,GAAG,cAAc,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,qBAAqB,EAAE,CAAC;YAC1F,MAAM,SAAS,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,cAAc,CAAC,GAAG,EAAE,CAAC;YAClD,MAAM,MAAM,GAAuC,6BAA6B,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;YACnG,IAAI,MAAM,CAAC,QAAQ,GAAG,qBAAqB,CAAC,QAAQ,EAAE,CAAC;gBACrD,qBAAqB,CAAC,MAAM,GAAG,SAAS,CAAC;gBACzC,qBAAqB,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC;gBAC5C,qBAAqB,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;YACnD,CAAC;QACH,CAAC;QACD,mCAAmC;QACnC,KAAK,IAAI,CAAC,GAAG,cAAc,CAAC,GAAG,EAAE,CAAC,GAAG,cAAc,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,qBAAqB,EAAE,CAAC;YAC1F,MAAM,SAAS,GAAG,EAAE,CAAC,EAAE,cAAc,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;YACpD,MAAM,MAAM,GAAuC,6BAA6B,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;YACnG,IAAI,MAAM,CAAC,QAAQ,GAAG,qBAAqB,CAAC,QAAQ,EAAE,CAAC;gBACrD,qBAAqB,CAAC,MAAM,GAAG,SAAS,CAAC;gBACzC,qBAAqB,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC;gBAC5C,qBAAqB,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;YACnD,CAAC;QACH,CAAC;QACD,qCAAqC;QACrC,KAAK,IAAI,CAAC,GAAG,cAAc,CAAC,IAAI,EAAE,CAAC,GAAG,cAAc,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,qBAAqB,EAAE,CAAC;YAC1F,MAAM,SAAS,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,cAAc,CAAC,MAAM,EAAE,CAAC;YACrD,MAAM,MAAM,GAAuC,6BAA6B,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;YACnG,IAAI,MAAM,CAAC,QAAQ,GAAG,qBAAqB,CAAC,QAAQ,EAAE,CAAC;gBACrD,qBAAqB,CAAC,MAAM,GAAG,SAAS,CAAC;gBACzC,qBAAqB,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC;gBAC5C,qBAAqB,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;YACnD,CAAC;QACH,CAAC;QACD,iCAAiC;QACjC,KAAK,IAAI,CAAC,GAAG,cAAc,CAAC,GAAG,EAAE,CAAC,GAAG,cAAc,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,qBAAqB,EAAE,CAAC;YAC1F,MAAM,SAAS,GAAG,EAAE,CAAC,EAAE,cAAc,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;YACnD,MAAM,MAAM,GAAuC,6BAA6B,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;YACnG,IAAI,MAAM,CAAC,QAAQ,GAAG,qBAAqB,CAAC,QAAQ,EAAE,CAAC;gBACrD,qBAAqB,CAAC,MAAM,GAAG,SAAS,CAAC;gBACzC,qBAAqB,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC;gBAC5C,qBAAqB,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;YACnD,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,qBAAqB,CAAC,MAAM,EAAE,CAAC;AACxF,CAAC,CAAC;AAEF,MAAM,WAAW,GAAG,CAAC,OAAa,EAAE,OAAa,EAAE,KAAY,EAAQ,EAAE;IACvE,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IAC7C,IAAI,KAAK,IAAI,KAAK,EAAE,CAAC;QACnB,MAAM,UAAU,GAAmB,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QACjE,MAAM,OAAO,GAAmB,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;QACtE,OAAO,CAAC,SAAS,GAAG,MAAM,CAAC;QAE3B,MAAM,MAAM,GAAqC,2BAA2B,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAC3F,MAAM,UAAU,GAAG,OAAO,GAAG,GAAG,GAAG,OAAO,CAAC;QAC3C,OAAO,CAAC,SAAS,GAAG;;;kCAGU,UAAU,SAAS,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,CAAC,CAAC;kCAC1G,KAAK,CAAC,KAAK;kCACX,KAAK,CAAC,KAAK;;;sBAGvB,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,CAAC,CAAC,kBAAkB,UAAU;;OAElI,CAAC;QAEJ,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAEnC,MAAM,WAAW,GAAG,OAAO,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5D,IAAI,WAAW,EAAE,CAAC;YAChB,MAAM,YAAY,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;YAC/C,MAAM,YAAY,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;YAC/C,IAAI,KAAK,CAAC,mBAAmB,EAAE,CAAC;gBAC9B,IAAI,YAAY,KAAK,KAAK,CAAC,mBAAmB,IAAI,YAAY,KAAK,KAAK,CAAC,mBAAmB,EAAE,CAAC;oBAC7F,WAAW,CAAC,SAAS,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;oBAC9C,WAAW,CAAC,SAAS,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;gBACrD,CAAC;qBAAM,CAAC;oBACN,WAAW,CAAC,SAAS,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;oBACjD,WAAW,CAAC,SAAS,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;gBAClD,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,WAAW,CAAC,SAAS,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;gBACjD,WAAW,CAAC,SAAS,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;YACrD,CAAC;YAED,WAAW,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAS,EAAE;gBAC/C,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;oBACnB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;gBACvC,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,WAAW,GAAG,CAAC,OAAa,EAAE,OAAa,EAAE,KAAY,EAAQ,EAAE;IACvE,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACjD,MAAM,IAAI,GAAS,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAClC,IACE,CAAC,OAAO,KAAK,IAAI,CAAC,UAAU,IAAI,OAAO,KAAK,IAAI,CAAC,QAAQ,CAAC;YAC1D,CAAC,OAAO,KAAK,IAAI,CAAC,UAAU,IAAI,OAAO,KAAK,IAAI,CAAC,QAAQ,CAAC,EAC1D,CAAC;YACD,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IACD,OAAO,CAAC,KAAK,CAAC,CAAC;AACjB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,KAAY,EAAQ,EAAE;IACjD,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;QACrC,IAAI,CAAC,MAAM,EAAE,CAAC;IAChB,CAAC;IACD,KAAK,CAAC,WAAW,GAAG,EAAE,CAAC;IAEvB,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAC/B,WAAW,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IACrD,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,OAAa,EAAE,OAAa,EAAE,KAAY,EAAQ,EAAE;IAC3E,IAAI,OAAO,IAAI,OAAO,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1E,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;QAC7D,OAAO,CAAC,KAAK,CAAC,CAAC;IACjB,CAAC;AACH,CAAC,CAAC"}
--------------------------------------------------------------------------------
/build/dist/node.d.ts:
--------------------------------------------------------------------------------
1 | import { Color_Hex, Node, NodeType, Point, State } from './definition.js';
2 | import { UUID } from './uuid.js';
3 | export declare const get_node: (id: UUID, nodes: Node[]) => Node | undefined;
4 | export declare const get_node_element: (id: UUID) => HTMLDivElement | null;
5 | export declare const add_node: (location: Point, type: NodeType, state: State) => void;
6 | export declare const get_icon: (type: NodeType) => {
7 | color: Color_Hex;
8 | backgroundColor: Color_Hex;
9 | text: string;
10 | };
11 | export declare const create_node_element: (node: Node, state: State) => void;
12 |
--------------------------------------------------------------------------------
/build/dist/node.js:
--------------------------------------------------------------------------------
1 | import { NodeType, } from './definition.js';
2 | import { add_link, redraw_lines } from './link.js';
3 | import { refresh, validate } from './story-plan-organizer.js';
4 | import { randomUUID } from './uuid.js';
5 | export const get_node = (id, nodes) => {
6 | let foundNode;
7 | for (const node of nodes) {
8 | if (node.id === id) {
9 | foundNode = node;
10 | break;
11 | }
12 | }
13 | return foundNode;
14 | };
15 | export const get_node_element = (id) => {
16 | const htmlElement = document.getElementById(id);
17 | return htmlElement ? htmlElement : null;
18 | };
19 | export const add_node = (location, type, state) => {
20 | const base = {
21 | id: randomUUID(),
22 | location,
23 | type,
24 | name: '',
25 | color: '#FFFFFF',
26 | };
27 | let node;
28 | switch (type) {
29 | case NodeType.Character:
30 | {
31 | node = Object.assign(Object.assign({}, base), { imageSrc: '', personality: '', quirk: '', like: '', dislike: '', strength: '', weakness: '', flaw: '', motivation: '', other: '' });
32 | }
33 | break;
34 | case NodeType.Location:
35 | {
36 | node = Object.assign(Object.assign({}, base), { imageSrc: '', description: '' });
37 | }
38 | break;
39 | case NodeType.Organization:
40 | {
41 | node = Object.assign(Object.assign({}, base), { objective: '', detail: '' });
42 | }
43 | break;
44 | case NodeType.Event:
45 | {
46 | node = Object.assign(Object.assign({}, base), { detail: '' });
47 | }
48 | break;
49 | case NodeType.Story:
50 | {
51 | node = Object.assign(Object.assign({}, base), { description: '' });
52 | }
53 | break;
54 | case NodeType.Lore:
55 | {
56 | node = Object.assign(Object.assign({}, base), { detail: '' });
57 | }
58 | break;
59 | default:
60 | break;
61 | }
62 | if (node) {
63 | state.nodes.push(node);
64 | validate(state);
65 | }
66 | };
67 | export const get_icon = (type) => {
68 | var _a;
69 | let color;
70 | const backgroundColor = '#DEF4FF';
71 | switch (type) {
72 | case NodeType.Character:
73 | {
74 | color = '#0000FF';
75 | }
76 | break;
77 | case NodeType.Location:
78 | {
79 | color = '#1BD900';
80 | }
81 | break;
82 | case NodeType.Organization:
83 | {
84 | color = '#FFA500';
85 | }
86 | break;
87 | case NodeType.Event:
88 | {
89 | color = '#FF0000';
90 | }
91 | break;
92 | case NodeType.Story:
93 | {
94 | color = '#C700C7';
95 | }
96 | break;
97 | case NodeType.Lore:
98 | {
99 | color = '#008080';
100 | }
101 | break;
102 | default:
103 | {
104 | color = '#FFFFFF';
105 | }
106 | break;
107 | }
108 | const text = ((_a = document.getElementById('create-node-' + NodeType[type])) === null || _a === void 0 ? void 0 : _a.getElementsByClassName('material-icons')[0]).innerText;
109 | return { color, backgroundColor, text };
110 | };
111 | export const create_node_element = (node, state) => {
112 | const newElement = document.createElement('div');
113 | const newNodeElement = document.body.appendChild(newElement);
114 | newNodeElement.id = node.id;
115 | newNodeElement.className = 'node';
116 | newNodeElement.style.top = node.location.y + 'px';
117 | newNodeElement.style.left = node.location.x + 'px';
118 | newNodeElement.style.borderColor = node.color;
119 | const icon = get_icon(node.type);
120 | newNodeElement.innerHTML = `
121 |
129 | `;
130 | switch (node.type) {
131 | case NodeType.Character:
132 | {
133 | if (node.imageSrc) {
134 | newNodeElement.innerHTML += `
135 |
136 | `;
137 | }
138 | newNodeElement.innerHTML += `
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 | `;
170 | const textarea_personality = newNodeElement.getElementsByTagName('textarea')[0];
171 | textarea_personality.addEventListener('input', () => {
172 | node.personality = textarea_personality.value;
173 | }, false);
174 | const textarea_quirk = newNodeElement.getElementsByTagName('textarea')[1];
175 | textarea_quirk.addEventListener('input', () => {
176 | node.quirk = textarea_quirk.value;
177 | }, false);
178 | const textarea_like = newNodeElement.getElementsByTagName('textarea')[2];
179 | textarea_like.addEventListener('input', () => {
180 | node.like = textarea_like.value;
181 | }, false);
182 | const textarea_dislike = newNodeElement.getElementsByTagName('textarea')[3];
183 | textarea_dislike.addEventListener('input', () => {
184 | node.dislike = textarea_dislike.value;
185 | }, false);
186 | const textarea_strength = newNodeElement.getElementsByTagName('textarea')[4];
187 | textarea_strength.addEventListener('input', () => {
188 | node.strength = textarea_strength.value;
189 | }, false);
190 | const textarea_weakness = newNodeElement.getElementsByTagName('textarea')[5];
191 | textarea_weakness.addEventListener('input', () => {
192 | node.weakness = textarea_weakness.value;
193 | }, false);
194 | const textarea_flaw = newNodeElement.getElementsByTagName('textarea')[6];
195 | textarea_flaw.addEventListener('input', () => {
196 | node.flaw = textarea_flaw.value;
197 | }, false);
198 | const textarea_motivation = newNodeElement.getElementsByTagName('textarea')[7];
199 | textarea_motivation.addEventListener('input', () => {
200 | node.motivation = textarea_motivation.value;
201 | }, false);
202 | const textarea_other = newNodeElement.getElementsByTagName('textarea')[8];
203 | textarea_other.addEventListener('input', () => {
204 | node.other = textarea_other.value;
205 | }, false);
206 | }
207 | break;
208 | case NodeType.Location:
209 | {
210 | if (node.imageSrc) {
211 | newNodeElement.innerHTML += `
212 |
213 | `;
214 | }
215 | newNodeElement.innerHTML += `
216 |
217 |
218 |
219 |
220 | `;
221 | const textarea_description = newNodeElement.getElementsByTagName('textarea')[0];
222 | textarea_description.addEventListener('input', () => {
223 | node.description = textarea_description.value;
224 | }, false);
225 | }
226 | break;
227 | case NodeType.Organization:
228 | {
229 | newNodeElement.innerHTML += `
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 | `;
239 | const textarea_objective = newNodeElement.getElementsByTagName('textarea')[0];
240 | textarea_objective.addEventListener('input', () => {
241 | node.objective = textarea_objective.value;
242 | }, false);
243 | const textarea_detail = newNodeElement.getElementsByTagName('textarea')[1];
244 | textarea_detail.addEventListener('input', () => {
245 | node.detail = textarea_detail.value;
246 | }, false);
247 | }
248 | break;
249 | case NodeType.Event:
250 | {
251 | newNodeElement.innerHTML += `
252 |
253 |
254 |
255 |
256 | `;
257 | const textarea_detail = newNodeElement.getElementsByTagName('textarea')[0];
258 | textarea_detail.addEventListener('input', () => {
259 | node.detail = textarea_detail.value;
260 | }, false);
261 | }
262 | break;
263 | case NodeType.Story:
264 | {
265 | newNodeElement.innerHTML += `
266 |
267 |
268 |
269 |
270 | `;
271 | const textarea_description = newNodeElement.getElementsByTagName('textarea')[0];
272 | textarea_description.addEventListener('input', () => {
273 | node.description = textarea_description.value;
274 | }, false);
275 | }
276 | break;
277 | case NodeType.Lore:
278 | {
279 | newNodeElement.innerHTML += `
280 |
281 |
282 |
283 |
284 | `;
285 | const textarea_detail = newNodeElement.getElementsByTagName('textarea')[0];
286 | textarea_detail.addEventListener('input', () => {
287 | node.detail = textarea_detail.value;
288 | }, false);
289 | }
290 | break;
291 | default:
292 | break;
293 | }
294 | // addEventListeners need to be after all the += innerHTML
295 | const input_name = newNodeElement.getElementsByClassName('node-name')[0];
296 | input_name.addEventListener('input', () => {
297 | node.name = input_name.value;
298 | }, false);
299 | const input_color = newNodeElement.getElementsByClassName('node-color')[0];
300 | input_color.addEventListener('input', () => {
301 | node.color = input_color.value;
302 | newNodeElement.style.borderColor = node.color;
303 | redraw_lines(state);
304 | }, false);
305 | setup_accordions(newNodeElement, state);
306 | drag_node_element(newElement, state);
307 | state.nodesCached.push(newElement);
308 | };
309 | const setup_accordions = (nodeElement, state) => {
310 | const accordions = nodeElement.getElementsByClassName('accordion');
311 | for (let i = 0; i < accordions.length; i++) {
312 | accordions[i].addEventListener('click', () => {
313 | accordions[i].classList.toggle('active');
314 | const panel = accordions[i].nextElementSibling;
315 | if (panel) {
316 | if (panel.style.maxHeight === '0px') {
317 | panel.style.maxHeight = '100%';
318 | }
319 | else {
320 | panel.style.maxHeight = '0px';
321 | }
322 | }
323 | const textareas = panel.getElementsByTagName('textarea');
324 | for (let i = 0; i < textareas.length; i++) {
325 | const textarea = textareas[i];
326 | textarea.setAttribute('style', textarea.getAttribute('style') + 'height:' + textarea.scrollHeight + 'px; overflow-y:hidden;');
327 | textarea.addEventListener('input', () => {
328 | textarea.style.height = 'auto';
329 | textarea.style.height = textarea.scrollHeight + 'px';
330 | }, false);
331 | }
332 | redraw_lines(state);
333 | });
334 | }
335 | };
336 | const drag_node_element = (element, state) => {
337 | let pos1 = 0;
338 | let pos2 = 0;
339 | let pos3 = 0;
340 | let pos4 = 0;
341 | const moveElement = element.getElementsByClassName('move')[0];
342 | moveElement.onmousedown = dragMouseDown;
343 | moveElement.addEventListener('mouseup', (event) => {
344 | if (event.button === 2) {
345 | // Right mouse button
346 | if (element.id && state.createOngoingLinkId) {
347 | add_link(element.id, state.createOngoingLinkId, state);
348 | }
349 | state.createOngoingLinkId = null;
350 | }
351 | });
352 | function dragMouseDown(event) {
353 | event = event || window.event;
354 | event.preventDefault();
355 | if (event.button === 0) {
356 | // Left mouse button
357 | if (state.deleting) {
358 | delete_node(element, state);
359 | return;
360 | }
361 | if (element !== state.selectedNodeElement) {
362 | state.selectedNodeElement = element;
363 | }
364 | refresh(state);
365 | pos3 = event.clientX;
366 | pos4 = event.clientY;
367 | document.onmouseup = closeDragElement;
368 | document.onmousemove = elementDrag;
369 | }
370 | else if (event.button === 2) {
371 | // Right mouse button
372 | state.createOngoingLinkId = element.id;
373 | }
374 | }
375 | function elementDrag(event) {
376 | event = event || window.event;
377 | event.preventDefault();
378 | pos1 = pos3 - event.clientX;
379 | pos2 = pos4 - event.clientY;
380 | pos3 = event.clientX;
381 | pos4 = event.clientY;
382 | const node = get_node(element.id, state.nodes);
383 | if (node) {
384 | node.location.x = element.offsetLeft - pos1;
385 | node.location.y = element.offsetTop - pos2;
386 | element.style.top = node.location.y + 'px';
387 | element.style.left = node.location.x + 'px';
388 | redraw_lines(state);
389 | }
390 | }
391 | function closeDragElement() {
392 | document.onmouseup = null;
393 | document.onmousemove = null;
394 | }
395 | };
396 | const delete_node = (nodeElement, state) => {
397 | if (nodeElement === state.selectedNodeElement) {
398 | state.selectedNodeElement = null;
399 | }
400 | const nodeFound = get_node(nodeElement.id, state.nodes);
401 | if (nodeFound) {
402 | const index = state.nodes.indexOf(nodeFound);
403 | if (index !== -1) {
404 | state.nodes.splice(index, 1);
405 | }
406 | }
407 | validate(state);
408 | };
409 | //# sourceMappingURL=node.js.map
--------------------------------------------------------------------------------
/build/dist/node.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"node.js","sourceRoot":"","sources":["../../src/node.ts"],"names":[],"mappings":"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"}
--------------------------------------------------------------------------------
/build/dist/story-plan-organizer.d.ts:
--------------------------------------------------------------------------------
1 | import { State } from './definition.js';
2 | export declare const validate: (state: State) => void;
3 | export declare const refresh: (state: State) => void;
4 |
--------------------------------------------------------------------------------
/build/dist/story-plan-organizer.js:
--------------------------------------------------------------------------------
1 | var _a, _b;
2 | import { NodeType } from './definition.js';
3 | import { redraw_lines } from './link.js';
4 | import { add_node, create_node_element, get_icon, get_node, get_node_element } from './node.js';
5 | // Does not handle refreshing, just validating
6 | export const validate = (state) => {
7 | // Validate node elements
8 | for (const node of state.nodes) {
9 | const nodeElement = get_node_element(node.id);
10 | if (!nodeElement) {
11 | create_node_element(node, state);
12 | }
13 | }
14 | for (let i = state.nodesCached.length - 1; i >= 0; i--) {
15 | const nodeElement = state.nodesCached[i];
16 | const node = get_node(nodeElement.id, state.nodes);
17 | if (!node) {
18 | const index = state.nodesCached.indexOf(nodeElement);
19 | if (index !== -1) {
20 | state.nodesCached.splice(index, 1);
21 | }
22 | nodeElement.remove();
23 | }
24 | }
25 | // Validate links
26 | for (let i = state.links.length - 1; i >= 0; i--) {
27 | const link = state.links[i];
28 | const validNode1 = get_node(link.nodeFromId, state.nodes) ? true : false;
29 | const validNode2 = get_node(link.nodeToId, state.nodes) ? true : false;
30 | if (!validNode1 || !validNode2) {
31 | state.links.splice(i, 1);
32 | }
33 | }
34 | // Validate highlights and redraw lines
35 | refresh(state);
36 | };
37 | export const refresh = (state) => {
38 | for (const nodeElement of state.nodesCached) {
39 | if (state.selectedNodeElement) {
40 | if (nodeElement === state.selectedNodeElement) {
41 | state.selectedNodeElement.classList.add('node-highlighted');
42 | state.selectedNodeElement.classList.remove('node-unhighlighted');
43 | }
44 | else {
45 | nodeElement.classList.remove('node-highlighted');
46 | nodeElement.classList.add('node-unhighlighted');
47 | }
48 | }
49 | else {
50 | nodeElement.classList.remove('node-highlighted');
51 | nodeElement.classList.remove('node-unhighlighted');
52 | }
53 | }
54 | if (state.selectedNodeElement) {
55 | const connectedNodeIds = [];
56 | for (const link of state.links) {
57 | if (link.nodeFromId === state.selectedNodeElement.id) {
58 | connectedNodeIds.push(link.nodeToId);
59 | }
60 | else if (link.nodeToId === state.selectedNodeElement.id) {
61 | connectedNodeIds.push(link.nodeFromId);
62 | }
63 | }
64 | for (const nodeId of connectedNodeIds) {
65 | const nodeElement = get_node_element(nodeId);
66 | if (nodeElement) {
67 | nodeElement.classList.add('node-highlighted');
68 | nodeElement.classList.remove('node-unhighlighted');
69 | }
70 | }
71 | }
72 | for (const node of state.nodes) {
73 | if (node.location.x < 0) {
74 | node.location.x = 0;
75 | const nodeElement = get_node_element(node.id);
76 | if (nodeElement) {
77 | nodeElement.style.left = node.location.x.toString() + 'px';
78 | }
79 | }
80 | if (node.location.y < 110) {
81 | node.location.y = 110;
82 | const nodeElement = get_node_element(node.id);
83 | if (nodeElement) {
84 | nodeElement.style.top = node.location.y.toString() + 'px';
85 | }
86 | }
87 | }
88 | redraw_lines(state);
89 | };
90 | const state = {
91 | nodes: [],
92 | nodesCached: [],
93 | links: [],
94 | linesCached: [],
95 | selectedNodeElement: null,
96 | createOngoingLinkId: null,
97 | deleting: false,
98 | };
99 | window.onbeforeunload = function (event) {
100 | event.preventDefault();
101 | };
102 | document.addEventListener('contextmenu', (event) => event.preventDefault());
103 | window.addEventListener('keydown', (event) => keydownResponse(event, state), false);
104 | window.addEventListener('keyup', (event) => keyupResponse(event, state), false);
105 | function keydownResponse(event, state) {
106 | if (event.key === 'Escape') {
107 | state.selectedNodeElement = null;
108 | refresh(state);
109 | }
110 | if (event.key === 'd') {
111 | state.deleting = true;
112 | }
113 | }
114 | function keyupResponse(event, state) {
115 | if (event.key === 'd') {
116 | state.deleting = false;
117 | }
118 | }
119 | // Loading Toolbar create node button icon colors
120 | for (const nodeType of [
121 | NodeType.Character,
122 | NodeType.Location,
123 | NodeType.Organization,
124 | NodeType.Event,
125 | NodeType.Story,
126 | NodeType.Lore,
127 | ]) {
128 | const button_create = document.getElementById('create-node-' + NodeType[nodeType]);
129 | button_create === null || button_create === void 0 ? void 0 : button_create.addEventListener('click', (event) => {
130 | add_node({ x: event.pageX, y: event.pageY + 100 }, nodeType, state);
131 | });
132 | (button_create === null || button_create === void 0 ? void 0 : button_create.firstElementChild).style.color = get_icon(nodeType).color;
133 | }
134 | // Export
135 | const download = (fileName, text) => {
136 | const element = document.createElement('a');
137 | element.setAttribute('href', 'data:application/json;charset=utf-8,' + encodeURIComponent(text));
138 | element.setAttribute('download', fileName);
139 | element.style.display = 'none';
140 | document.body.appendChild(element);
141 | element.click();
142 | document.body.removeChild(element);
143 | };
144 | (_a = document.getElementById('export')) === null || _a === void 0 ? void 0 : _a.addEventListener('click', () => {
145 | console.log(state);
146 | const fileName = 'story.json';
147 | const dto = { nodes: state.nodes, links: state.links };
148 | const fileContent = JSON.stringify(dto, null, 2);
149 | download(fileName, fileContent);
150 | });
151 | // Import
152 | const validJson = (json) => {
153 | try {
154 | JSON.parse(json);
155 | }
156 | catch (e) {
157 | return false;
158 | }
159 | return true;
160 | };
161 | const load = (dto, state) => {
162 | reset(state);
163 | state.nodes = dto.nodes;
164 | state.links = dto.links;
165 | validate(state);
166 | };
167 | const reset = (state) => {
168 | state.nodes = [];
169 | for (const nodeElement of state.nodesCached) {
170 | nodeElement.remove();
171 | }
172 | state.links = [];
173 | for (const lineElement of state.linesCached) {
174 | lineElement.remove();
175 | }
176 | validate(state);
177 | state.selectedNodeElement = null;
178 | state.createOngoingLinkId = null;
179 | state.deleting = false;
180 | };
181 | document.getElementById('inputLoadFile').onchange = (event) => {
182 | const reader = new FileReader();
183 | reader.onload = onReaderLoad;
184 | const tempElement = event.target;
185 | if (tempElement && tempElement.files) {
186 | reader.readAsText(tempElement.files[0]);
187 | }
188 | function onReaderLoad(event) {
189 | var _a, _b, _c, _d, _e;
190 | console.log(event);
191 | if (event.target && event.target.result) {
192 | const jsonString = event.target.result;
193 | if (validJson(jsonString)) {
194 | const jsonObject = JSON.parse(jsonString);
195 | load(jsonObject, state);
196 | const button = document.getElementById('button-load');
197 | button.disabled = true;
198 | button.innerText = '';
199 | // To maximize the textareas the next time user shows all
200 | (_a = document.getElementById('toggle-visibility')) === null || _a === void 0 ? void 0 : _a.click();
201 | (_b = document.getElementById('toggle-visibility')) === null || _b === void 0 ? void 0 : _b.click();
202 | (_c = document.getElementById('toggle-visibility')) === null || _c === void 0 ? void 0 : _c.click();
203 | (_d = document.getElementById('toggle-visibility')) === null || _d === void 0 ? void 0 : _d.click();
204 | (_e = document.getElementById('toggle-visibility')) === null || _e === void 0 ? void 0 : _e.click();
205 | }
206 | }
207 | }
208 | };
209 | // Hide / Show All
210 | let toggleVisibility = 0;
211 | (_b = document.getElementById('toggle-visibility')) === null || _b === void 0 ? void 0 : _b.addEventListener('click', () => {
212 | var _a, _b;
213 | const accordions = document.getElementsByClassName('accordion');
214 | for (let i = 0; i < accordions.length; i++) {
215 | const panel = accordions[i].nextElementSibling;
216 | if (panel) {
217 | if (toggleVisibility % 3 === 0) {
218 | // Hide All
219 | if (panel.style.maxHeight !== '0px') {
220 | accordions[i].click();
221 | }
222 | }
223 | else if (toggleVisibility % 3 === 1) {
224 | // Show Events, otherwise Hide
225 | const id = (_a = accordions[i].parentElement) === null || _a === void 0 ? void 0 : _a.id;
226 | if (id && ((_b = get_node(id, state.nodes)) === null || _b === void 0 ? void 0 : _b.type) === NodeType.Event) {
227 | const textarea = panel.getElementsByTagName('textarea')[0];
228 | if (panel.style.maxHeight === '0px' && textarea.value !== '') {
229 | accordions[i].click();
230 | }
231 | }
232 | else if (panel.style.maxHeight !== '0px') {
233 | accordions[i].click();
234 | }
235 | }
236 | else if (toggleVisibility % 3 === 2) {
237 | // Show All
238 | const textarea = panel.getElementsByTagName('textarea')[0];
239 | const textareaRight = panel.getElementsByTagName('textarea')[1];
240 | if (panel.style.maxHeight === '0px' &&
241 | (textarea.value !== '' || (textareaRight && textareaRight.value !== ''))) {
242 | accordions[i].click();
243 | }
244 | }
245 | }
246 | }
247 | ++toggleVisibility;
248 | });
249 | //# sourceMappingURL=story-plan-organizer.js.map
--------------------------------------------------------------------------------
/build/dist/story-plan-organizer.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"story-plan-organizer.js","sourceRoot":"","sources":["../../src/story-plan-organizer.ts"],"names":[],"mappings":"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"}
--------------------------------------------------------------------------------
/build/dist/uuid.d.ts:
--------------------------------------------------------------------------------
1 | export type UUID = `${string}-${string}-${string}-${string}-${string}`;
2 | export declare const randomUUID: () => UUID;
3 |
--------------------------------------------------------------------------------
/build/dist/uuid.js:
--------------------------------------------------------------------------------
1 | // Note: `@types/node/crypto` doesn't seem to work with .ts when bundled, it cannot be imported properly when viewed from the browser
2 | export const randomUUID = () => {
3 | // https://stackoverflow.com/questions/105034/how-do-i-create-a-guid-uuid
4 | // Timestamp
5 | let d = new Date().getTime();
6 | // Time in microseconds since page-load or 0 if unsupported
7 | let d2 = (typeof performance !== 'undefined' && performance.now && performance.now() * 1000) || 0;
8 | return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
9 | // Random number between 0 and 16
10 | let r = Math.random() * 16;
11 | if (d > 0) {
12 | // Use timestamp until depleted
13 | r = (d + r) % 16 | 0;
14 | d = Math.floor(d / 16);
15 | }
16 | else {
17 | // Use microseconds since page-load if supported
18 | r = (d2 + r) % 16 | 0;
19 | d2 = Math.floor(d2 / 16);
20 | }
21 | return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16);
22 | });
23 | };
24 | //# sourceMappingURL=uuid.js.map
--------------------------------------------------------------------------------
/build/dist/uuid.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"uuid.js","sourceRoot":"","sources":["../../src/uuid.ts"],"names":[],"mappings":"AAAA,qIAAqI;AAIrI,MAAM,CAAC,MAAM,UAAU,GAAG,GAAS,EAAE;IACnC,yEAAyE;IACzE,YAAY;IACZ,IAAI,CAAC,GAAG,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC;IAC7B,2DAA2D;IAC3D,IAAI,EAAE,GAAG,CAAC,OAAO,WAAW,KAAK,WAAW,IAAI,WAAW,CAAC,GAAG,IAAI,WAAW,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;IAClG,OAAO,sCAAsC,CAAC,OAAO,CAAC,OAAO,EAAE,UAAU,CAAC;QACxE,iCAAiC;QACjC,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC;QAC3B,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACV,+BAA+B;YAC/B,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YACrB,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;QACzB,CAAC;aAAM,CAAC;YACN,gDAAgD;YAChD,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YACtB,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAC3B,CAAC;QACD,OAAO,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACxD,CAAC,CAAS,CAAC;AACb,CAAC,CAAC"}
--------------------------------------------------------------------------------
/build/tsconfig.tsbuildinfo:
--------------------------------------------------------------------------------
1 | {"program":{"fileNames":["../node_modules/typescript/lib/lib.es5.d.ts","../node_modules/typescript/lib/lib.es2015.d.ts","../node_modules/typescript/lib/lib.es2016.d.ts","../node_modules/typescript/lib/lib.es2017.d.ts","../node_modules/typescript/lib/lib.es2018.d.ts","../node_modules/typescript/lib/lib.es2019.d.ts","../node_modules/typescript/lib/lib.es2020.d.ts","../node_modules/typescript/lib/lib.dom.d.ts","../node_modules/typescript/lib/lib.es2015.core.d.ts","../node_modules/typescript/lib/lib.es2015.collection.d.ts","../node_modules/typescript/lib/lib.es2015.generator.d.ts","../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../node_modules/typescript/lib/lib.es2015.promise.d.ts","../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../node_modules/typescript/lib/lib.es2016.intl.d.ts","../node_modules/typescript/lib/lib.es2017.date.d.ts","../node_modules/typescript/lib/lib.es2017.object.d.ts","../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../node_modules/typescript/lib/lib.es2017.string.d.ts","../node_modules/typescript/lib/lib.es2017.intl.d.ts","../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../node_modules/typescript/lib/lib.es2018.intl.d.ts","../node_modules/typescript/lib/lib.es2018.promise.d.ts","../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../node_modules/typescript/lib/lib.es2019.array.d.ts","../node_modules/typescript/lib/lib.es2019.object.d.ts","../node_modules/typescript/lib/lib.es2019.string.d.ts","../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../node_modules/typescript/lib/lib.es2019.intl.d.ts","../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../node_modules/typescript/lib/lib.es2020.date.d.ts","../node_modules/typescript/lib/lib.es2020.promise.d.ts","../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../node_modules/typescript/lib/lib.es2020.string.d.ts","../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../node_modules/typescript/lib/lib.es2020.intl.d.ts","../node_modules/typescript/lib/lib.es2020.number.d.ts","../node_modules/typescript/lib/lib.decorators.d.ts","../node_modules/typescript/lib/lib.decorators.legacy.d.ts","../src/uuid.ts","../src/definition.ts","../src/story-plan-organizer.ts","../src/node.ts","../src/link.ts"],"fileInfos":[{"version":"824cb491a40f7e8fdeb56f1df5edf91b23f3e3ee6b4cde84d4a99be32338faee","affectsGlobalScope":true},"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","9a68c0c07ae2fa71b44384a839b7b8d81662a236d4b9ac30916718f7510b1b2d","5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4",{"version":"87d693a4920d794a73384b3c779cadcb8548ac6945aa7a925832fe2418c9527a","affectsGlobalScope":true},{"version":"138fb588d26538783b78d1e3b2c2cc12d55840b97bf5e08bca7f7a174fbe2f17","affectsGlobalScope":true},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true},{"version":"4443e68b35f3332f753eacc66a04ac1d2053b8b035a0e0ac1d455392b5e243b3","affectsGlobalScope":true},{"version":"bc47685641087c015972a3f072480889f0d6c65515f12bd85222f49a98952ed7","affectsGlobalScope":true},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true},{"version":"93495ff27b8746f55d19fcbcdbaccc99fd95f19d057aed1bd2c0cafe1335fbf0","affectsGlobalScope":true},{"version":"6fc23bb8c3965964be8c597310a2878b53a0306edb71d4b5a4dfe760186bcc01","affectsGlobalScope":true},{"version":"ea011c76963fb15ef1cdd7ce6a6808b46322c527de2077b6cfdf23ae6f5f9ec7","affectsGlobalScope":true},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true},{"version":"bb42a7797d996412ecdc5b2787720de477103a0b2e53058569069a0e2bae6c7e","affectsGlobalScope":true},{"version":"4738f2420687fd85629c9efb470793bb753709c2379e5f85bc1815d875ceadcd","affectsGlobalScope":true},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true},{"version":"9fc46429fbe091ac5ad2608c657201eb68b6f1b8341bd6d670047d32ed0a88fa","affectsGlobalScope":true},{"version":"61c37c1de663cf4171e1192466e52c7a382afa58da01b1dc75058f032ddf0839","affectsGlobalScope":true},{"version":"b541a838a13f9234aba650a825393ffc2292dc0fc87681a5d81ef0c96d281e7a","affectsGlobalScope":true},{"version":"b20fe0eca9a4e405f1a5ae24a2b3290b37cf7f21eba6cbe4fc3fab979237d4f3","affectsGlobalScope":true},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true},{"version":"49ed889be54031e1044af0ad2c603d627b8bda8b50c1a68435fe85583901d072","affectsGlobalScope":true},{"version":"e93d098658ce4f0c8a0779e6cab91d0259efb88a318137f686ad76f8410ca270","affectsGlobalScope":true},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true},{"version":"bf14a426dbbf1022d11bd08d6b8e709a2e9d246f0c6c1032f3b2edb9a902adbe","affectsGlobalScope":true},{"version":"5e07ed3809d48205d5b985642a59f2eba47c402374a7cf8006b686f79efadcbd","affectsGlobalScope":true},{"version":"2b72d528b2e2fe3c57889ca7baef5e13a56c957b946906d03767c642f386bbc3","affectsGlobalScope":true},{"version":"8073890e29d2f46fdbc19b8d6d2eb9ea58db9a2052f8640af20baff9afbc8640","affectsGlobalScope":true},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true},{"version":"33358442698bb565130f52ba79bfd3d4d484ac85fe33f3cb1759c54d18201393","affectsGlobalScope":true},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true},{"version":"a8afe9060fa3e6a988fe1f6acebb5661ef7e63c276ec1f6f5c4da31bb70ae1a4","signature":"a415c308e38ed0cce398eb898960ff8310474a4e7db9e2a94e610d49890b74a5"},{"version":"dbb9c3dc32640113de2aa447ef54ee06c473b149ea4e2a100eac5e970ffd9ba0","signature":"e33da25488f15e6de1851c02eb8cb2db61551361645619551f9abb020b4c5bd7"},{"version":"7f4f62dbce693cdd4276430c4f8b28a4c73f65af95bacce38d559930f2c4541e","signature":"1087f3cfcaea8e3133e8c0146b3f3969493b000333586bd09933c75aea8f2266"},{"version":"9092ff8686c098b857eab9500ced141765b2c716ae193acba25e1e3fd06c834e","signature":"3ebe4633b85ae43ab0fb05673d09b0f2ef05ea51528df29a6a538e42eb550f00"},{"version":"5f1f8d7890069809e3c80ed4b381ba9becc790d0c9ff109597340a9da1e8483d","signature":"b4456f5c6e8d3c410b8e0de7eae26b46cefbf40c50103e324e04ea9fc71e7576"}],"root":[[46,50]],"options":{"allowJs":true,"alwaysStrict":true,"declaration":true,"esModuleInterop":true,"module":5,"noEmitOnError":true,"noFallthroughCasesInSwitch":true,"noImplicitAny":true,"noImplicitReturns":true,"noImplicitThis":true,"noUnusedLocals":false,"noUnusedParameters":true,"outDir":"./dist","removeComments":false,"rootDir":"../src","skipLibCheck":false,"sourceMap":true,"strict":true,"strictFunctionTypes":true,"strictNullChecks":true,"strictPropertyInitialization":true,"target":2},"fileIdsList":[[46],[46,47,48,49],[46,47,48,50],[46,47,49,50],[46,47],[47]],"referencedMap":[[47,1],[50,2],[49,3],[48,4]],"exportedModulesMap":[[47,1],[50,5],[49,5], [48,6]],"semanticDiagnosticsPerFile":[44,45,8,10,9,2,11,12,13,14,15,16,17,18,3,19,4,20,24,21,22,23,25,26,27,5,28,29,30,31,6,35,32,33,34,36,7,37,42,43,38,39,40,41,1,47,50,49,48,46]},"version":"5.4.5"}
--------------------------------------------------------------------------------
/data/sample1.json:
--------------------------------------------------------------------------------
1 | {
2 | "nodes": [
3 | {
4 | "id": "24ec3ea7-81c2-4d42-8016-3c6d8d37b693",
5 | "location": {
6 | "x": 694,
7 | "y": 340
8 | },
9 | "type": "Character",
10 | "name": "Hanako Hoshizora",
11 | "color": "#ff80c0",
12 | "imageSrc": "",
13 |
14 | "personality": "Energetic, optimistic, loyal, strong sense of justice",
15 | "quirk": "Hums anime tunes, twirls hair when stressed",
16 | "like": "Cute things, sweets (taiyaki), fashion (Harajuku)",
17 | "dislike": "Bullies, manipulation, burnt toast, spicy food",
18 | "strength": "Optimism, inspiring, agile, quick reflexes",
19 | "weakness": "Naive, impulsive, easily distracted, limited magical power",
20 | "flaw": "Self-doubt, overworks herself",
21 | "motivation": "Protects dreams of the innocent, wants to make the world a better place",
22 | "other": ""
23 | },
24 | {
25 | "id": "ff923a1c-50bb-4ee7-9bc2-9c9fcedb60f0",
26 | "location": {
27 | "x": 1135,
28 | "y": 340
29 | },
30 | "type": "Character",
31 | "name": "Yuuri Kageyama",
32 | "color": "#ff8040",
33 | "imageSrc": "",
34 | "personality": "Calm, sarcastic wit, dry humor, secretly admires Hanako's bravery",
35 | "quirk": "Raises an eyebrow skeptically at Hanako's flights of fancy, excellent doodler (often captures funny sketches of Hanako's antics)",
36 | "like": "Reading, spending time at cafes, witty banter, a good mystery novel",
37 | "dislike": "Crowds, overly emotional situations, sugary foods",
38 | "strength": "Level-headed, analytical thinker, keeps Hanako grounded, resourceful",
39 | "weakness": "Can be overly cautious, struggles to express emotions openly",
40 | "flaw": "Sometimes comes across as cynical, lacks self-confidence in her own abilities",
41 | "motivation": "Cares deeply for Hanako and wants to ensure her safety, secretly finds Hanako's magical adventures exciting",
42 | "other": ""
43 | },
44 | {
45 | "id": "6d9a8af6-2f25-4af7-ae6a-ff9bf38d02be",
46 | "location": {
47 | "x": 227,
48 | "y": 329
49 | },
50 | "type": "Character",
51 | "name": "Hoshihikari Amane",
52 | "color": "#ff0080",
53 | "imageSrc": "",
54 | "personality": "Calm, enigmatic, possesses immense knowledge of magic",
55 | "quirk": "Speaks in riddles and proverbs, enjoys sipping green tea while gazing at the stars",
56 | "like": "Peace, tranquility, sharing wisdom with worthy students",
57 | "dislike": "Disruption of the natural balance, misuse of magic for personal gain",
58 | "strength": "Powerful magic user, vast knowledge of celestial lore, excellent teacher",
59 | "weakness": "Can be cryptic and difficult to understand at times, limited physical mobility",
60 | "flaw": "Holds magic in high regard, possibly hesitant to trust humans fully",
61 | "motivation": "Seeks to maintain the balance between the human world and the magical realm, desires to pass on her knowledge to a worthy successor",
62 | "other": ""
63 | },
64 | {
65 | "id": "ec7f5de0-aa19-421f-812c-77a286737214",
66 | "location": {
67 | "x": 1585,
68 | "y": 341
69 | },
70 | "type": "Character",
71 | "name": "Akira Sato",
72 | "color": "#00ffff",
73 | "imageSrc": "",
74 | "personality": "Outgoing, enthusiastic, always has a joke or story to tell",
75 | "quirk": "Trips over his own feet frequently, has a knack for getting into trouble (often unintentionally)",
76 | "like": "Spending time with Hanako, trying new foods, participating in local festivals",
77 | "dislike": "Boredom, loneliness, seeing his friends upset",
78 | "strength": "Loyal, supportive, brings out the lighter side in Hanako",
79 | "weakness": "Can be oblivious to social cues, sometimes lacks focus",
80 | "flaw": "Can be a bit clingy and overprotective of Hanako",
81 | "motivation": "Secretly harbors a deeper affection for Hanako, wants to be there for her no matter what, even if it means helping her with her magical battles (despite not knowing the full extent of them)",
82 | "other": ""
83 | },
84 | {
85 | "id": "6aa7369b-d01c-4e41-a07d-3ac14ae828db",
86 | "location": {
87 | "x": 2029,
88 | "y": 340
89 | },
90 | "type": "Character",
91 | "name": "Yami-D",
92 | "color": "#808000",
93 | "imageSrc": "",
94 | "personality": "Malicious, manipulative, feeds on the weaknesses and desires of others.",
95 | "quirk": "Speaks in glitching fragments of code and advertisements, enjoys toying with its victims before consuming them.",
96 | "like": "Feeding on negative emotions, spreading chaos and despair, corrupting dreams.",
97 | "dislike": "Purity, genuine happiness, acts of selflessness that disrupt its control.",
98 | "strength": "Powerful digital manipulation, can create hypnotic illusions and advertisements, possesses vast knowledge of consumer desires.",
99 | "weakness": "Vulnerable to pure celestial energy, can be disrupted by strong emotions like love and hope. Reliant on technology - a power outage or EMP could be disastrous.",
100 | "flaw": "Overconfident, underestimates the power of human connection and genuine desire.",
101 | "motivation": "Consumes dreams to fuel its own power and existence. Believes humans are weak and easily manipulated by their desires. Wants to control the world by turning everyone's dreams into a twisted reflection of their materialistic wants.",
102 | "other": ""
103 | },
104 | {
105 | "id": "122ee6a4-0e6f-4822-abd8-60c509ad579d",
106 | "location": {
107 | "x": 1253,
108 | "y": 208
109 | },
110 | "type": "Location",
111 | "name": "Sakura High School",
112 | "color": "#008040",
113 | "imageSrc": "",
114 | "description": "By day, Sakura High hides its secret as a training ground for magical girls, its classrooms doubling as enchantment chambers under the glow of cherry blossom trees."
115 | },
116 | {
117 | "id": "6427a20e-226d-4df6-8f12-b4ec82c192c2",
118 | "location": {
119 | "x": 1875,
120 | "y": 186
121 | },
122 | "type": "Organization",
123 | "name": "Glitching Horde",
124 | "color": "#400000",
125 | "objective": "Seeks to infect the world with corrupted desires, turning humanity into mindless consumers trapped in a digital nightmare.",
126 | "detail": "Yami-D's scattered followers, the Glitching Horde, spread like a digital virus, hijacking dreams and desires through corrupted internet connections."
127 | },
128 | {
129 | "id": "02d3adf1-5907-4a05-9b8f-37c1e36fe20e",
130 | "location": {
131 | "x": 2191,
132 | "y": 202
133 | },
134 | "type": "Location",
135 | "name": "Yami-D's lair",
136 | "color": "#804000",
137 | "imageSrc": "",
138 | "description": "Atop a skyscraper shaped like a distorted smartphone screen, Yami-D's lair pulsed with hypnotic advertisements, bleeding digital nightmares into the Tokyo night."
139 | },
140 | {
141 | "id": "dab3851a-e0f1-4185-b905-c7962780ed1f",
142 | "location": {
143 | "x": 904,
144 | "y": 200
145 | },
146 | "type": "Organization",
147 | "name": "Dream Weavers",
148 | "color": "#00ff80",
149 | "objective": "Bound by the power of the stars, fight to protect humanity's dreams from the digital corruption of Yami-D and the Glitching Horde.",
150 | "detail": "A network of young women who use celestial magic to safeguard dreams from the clutches of digital nightmares."
151 | },
152 | {
153 | "id": "5a04aa04-d648-4882-9296-b5a8571d223c",
154 | "location": {
155 | "x": 537,
156 | "y": 226
157 | },
158 | "type": "Location",
159 | "name": "Star Tea House",
160 | "color": "#ffff00",
161 | "imageSrc": "",
162 | "description": "Disguised as a charming, traditional tea house, the Hoshi Chaya (Star Tea House) serves as a meeting point for the Dream Weavers. Beneath the fragrant steam and delicate teacups, they strategize and share information."
163 | },
164 | {
165 | "id": "b503d84e-67e5-4448-9f03-5523ccd9c104",
166 | "location": {
167 | "x": 1278,
168 | "y": 1171
169 | },
170 | "type": "Story",
171 | "name": "Season 1",
172 | "color": "#00ffff",
173 | "description": "In modern Tokyo, bubbly high school student Hanako leads a double life. By day, she serves sugary treats at a maid cafe. By night, she transforms into Hoshizora, a magical girl who joins the Dream Weavers, a hidden network protecting humanity's dreams from the nightmarish digital corruption spread by Yami-D and its Glitching Horde."
174 | },
175 | {
176 | "id": "45c3cd76-5c96-4a02-84ee-036e8d7bdb66",
177 | "location": {
178 | "x": 694,
179 | "y": 845
180 | },
181 | "type": "Lore",
182 | "name": "Hoshizora",
183 | "color": "#ff00ff",
184 | "detail": "Hoshizora isn't just a magical girl persona; it's a title and a legacy. Passed down through generations of Dream Weavers, Hoshizora signifies the protector who wields the power of the stars. By day, Hanako might be an ordinary student, but under the moonlight, she transforms, channeling the celestial energy to become the newest Hoshizora, the Star Weaver."
185 | },
186 | {
187 | "id": "4bd611a5-c114-41b8-b156-e85c3b82010a",
188 | "location": {
189 | "x": 854,
190 | "y": 549
191 | },
192 | "type": "Lore",
193 | "name": "Dream Weaver Magic",
194 | "color": "#0080c0",
195 | "detail": "Source: Celestial Energy (stars & constellations)\nFuel: Positive Emotions (hope, courage)\nTransformation: Personal Item (imbued with celestial energy) - e.g., Hanako's hair clip\nAbilities:\n- Defense: Shimmering curtains of starlight to block nightmares and attacks\n- Offense: Celestial blasts or constellation-inspired attacks (e.g., Starlight Serenade)\n- Dream Navigation: Enter dreamscapes to fight nightmares directly\n\nLimitations:\n- Negative Emotions weaken magic\n- Limited Power for young Dream Weavers\n- Weak Celestial Connection hinders abilities (e.g., heavy clouds)"
196 | },
197 | {
198 | "id": "5fcf2528-599c-4330-8b69-30f3dd0e3067",
199 | "location": {
200 | "x": 2180,
201 | "y": 568
202 | },
203 | "type": "Lore",
204 | "name": "Yami-D's Digital Corruption",
205 | "color": "#400080",
206 | "detail": "Source: Digital Manipulation\nPower:\n- Hypnotic Advertisements: Creates captivating ads that manipulate desires and trap minds in a digital dream world.\n- Corrupted Code Tendrils: Lashes out with corrupted code to physically restrain and harm opponents.\n- Dream Infiltration: Can access and distort human dreams, feeding on negativity and amplifying desires.\n\nWeakness:\n- Pure Celestial Energy: Disrupted by powerful displays of starlight magic used by the Dream Weavers.\n- Technology Reliance: Vulnerable to disruptions in its digital infrastructure (e.g., EMP attack).\n- Overconfidence: Underestimates the power of human connection and genuine desires."
207 | },
208 | {
209 | "id": "f0e625ce-41fb-4fa8-bcf8-8a2a121de151",
210 | "location": {
211 | "x": 1636,
212 | "y": 720
213 | },
214 | "type": "Event",
215 | "name": "Witnessing Evil",
216 | "color": "#FFFFFF",
217 | "detail": "Hanako witnesses Yami-D's corrupted advertisements manipulating people in Shibuya Crossing."
218 | },
219 | {
220 | "id": "570fbc1a-8954-4054-9b30-48615acd3864",
221 | "location": {
222 | "x": 1637,
223 | "y": 552
224 | },
225 | "type": "Event",
226 | "name": "Confrontation",
227 | "color": "#FFFFFF",
228 | "detail": "As Hoshizora, she confronts Yami-D in a battle across the neon-lit rooftops of Tokyo."
229 | },
230 | {
231 | "id": "4c0c1746-5fd3-40fa-a70c-1c5396b55f12",
232 | "location": {
233 | "x": 1155,
234 | "y": 551
235 | },
236 | "type": "Event",
237 | "name": "Battle Assist",
238 | "color": "#FFFFFF",
239 | "detail": "While battling, Hoshizora encounters another Dream Weaver (potentially Yuuri or a new character) who assists her."
240 | },
241 | {
242 | "id": "5b720633-f29d-46fb-9f82-61161962401b",
243 | "location": {
244 | "x": 725,
245 | "y": 628
246 | },
247 | "type": "Event",
248 | "name": "Worries",
249 | "color": "#FFFFFF",
250 | "detail": "Back in her normal life, Hanako ponders the growing threat of Yami-D and the responsibility of being Hoshizora."
251 | },
252 | {
253 | "id": "bf35b66e-10a8-4158-813b-7e632f9b0cdd",
254 | "location": {
255 | "x": 300,
256 | "y": 541
257 | },
258 | "type": "Event",
259 | "name": "Mentoring",
260 | "color": "#FFFFFF",
261 | "detail": "Hanako seeks guidance from her mentor Hoshihikari to learn more about Yami-D and her powers."
262 | },
263 | {
264 | "id": "9dd9473a-44a7-42fb-8ce7-d1dcf1d88d81",
265 | "location": {
266 | "x": 780,
267 | "y": 920
268 | },
269 | "type": "Event",
270 | "name": "Double Life",
271 | "color": "#FFFFFF",
272 | "detail": "Hanako's double life becomes more complicated as she juggles school, her part-time job, and her duties as Hoshizora."
273 | }
274 | ],
275 | "links": [
276 | {
277 | "nodeFromId": "5a04aa04-d648-4882-9296-b5a8571d223c",
278 | "nodeToId": "ff923a1c-50bb-4ee7-9bc2-9c9fcedb60f0"
279 | },
280 | {
281 | "nodeFromId": "24ec3ea7-81c2-4d42-8016-3c6d8d37b693",
282 | "nodeToId": "5a04aa04-d648-4882-9296-b5a8571d223c"
283 | },
284 | {
285 | "nodeFromId": "4bd611a5-c114-41b8-b156-e85c3b82010a",
286 | "nodeToId": "24ec3ea7-81c2-4d42-8016-3c6d8d37b693"
287 | },
288 | {
289 | "nodeFromId": "ff923a1c-50bb-4ee7-9bc2-9c9fcedb60f0",
290 | "nodeToId": "4bd611a5-c114-41b8-b156-e85c3b82010a"
291 | },
292 | {
293 | "nodeFromId": "4bd611a5-c114-41b8-b156-e85c3b82010a",
294 | "nodeToId": "6d9a8af6-2f25-4af7-ae6a-ff9bf38d02be"
295 | },
296 | {
297 | "nodeFromId": "5a04aa04-d648-4882-9296-b5a8571d223c",
298 | "nodeToId": "6d9a8af6-2f25-4af7-ae6a-ff9bf38d02be"
299 | },
300 | {
301 | "nodeFromId": "24ec3ea7-81c2-4d42-8016-3c6d8d37b693",
302 | "nodeToId": "6d9a8af6-2f25-4af7-ae6a-ff9bf38d02be"
303 | },
304 | {
305 | "nodeFromId": "24ec3ea7-81c2-4d42-8016-3c6d8d37b693",
306 | "nodeToId": "45c3cd76-5c96-4a02-84ee-036e8d7bdb66"
307 | },
308 | {
309 | "nodeFromId": "24ec3ea7-81c2-4d42-8016-3c6d8d37b693",
310 | "nodeToId": "122ee6a4-0e6f-4822-abd8-60c509ad579d"
311 | },
312 | {
313 | "nodeFromId": "122ee6a4-0e6f-4822-abd8-60c509ad579d",
314 | "nodeToId": "ff923a1c-50bb-4ee7-9bc2-9c9fcedb60f0"
315 | },
316 | {
317 | "nodeFromId": "ec7f5de0-aa19-421f-812c-77a286737214",
318 | "nodeToId": "122ee6a4-0e6f-4822-abd8-60c509ad579d"
319 | },
320 | {
321 | "nodeFromId": "5a04aa04-d648-4882-9296-b5a8571d223c",
322 | "nodeToId": "dab3851a-e0f1-4185-b905-c7962780ed1f"
323 | },
324 | {
325 | "nodeFromId": "24ec3ea7-81c2-4d42-8016-3c6d8d37b693",
326 | "nodeToId": "dab3851a-e0f1-4185-b905-c7962780ed1f"
327 | },
328 | {
329 | "nodeFromId": "6d9a8af6-2f25-4af7-ae6a-ff9bf38d02be",
330 | "nodeToId": "dab3851a-e0f1-4185-b905-c7962780ed1f"
331 | },
332 | {
333 | "nodeFromId": "dab3851a-e0f1-4185-b905-c7962780ed1f",
334 | "nodeToId": "ff923a1c-50bb-4ee7-9bc2-9c9fcedb60f0"
335 | },
336 | {
337 | "nodeFromId": "02d3adf1-5907-4a05-9b8f-37c1e36fe20e",
338 | "nodeToId": "6aa7369b-d01c-4e41-a07d-3ac14ae828db"
339 | },
340 | {
341 | "nodeFromId": "02d3adf1-5907-4a05-9b8f-37c1e36fe20e",
342 | "nodeToId": "6427a20e-226d-4df6-8f12-b4ec82c192c2"
343 | },
344 | {
345 | "nodeFromId": "6aa7369b-d01c-4e41-a07d-3ac14ae828db",
346 | "nodeToId": "6427a20e-226d-4df6-8f12-b4ec82c192c2"
347 | },
348 | {
349 | "nodeFromId": "6aa7369b-d01c-4e41-a07d-3ac14ae828db",
350 | "nodeToId": "5fcf2528-599c-4330-8b69-30f3dd0e3067"
351 | },
352 | {
353 | "nodeFromId": "ff923a1c-50bb-4ee7-9bc2-9c9fcedb60f0",
354 | "nodeToId": "4c0c1746-5fd3-40fa-a70c-1c5396b55f12"
355 | },
356 | {
357 | "nodeFromId": "4c0c1746-5fd3-40fa-a70c-1c5396b55f12",
358 | "nodeToId": "24ec3ea7-81c2-4d42-8016-3c6d8d37b693"
359 | },
360 | {
361 | "nodeFromId": "6aa7369b-d01c-4e41-a07d-3ac14ae828db",
362 | "nodeToId": "570fbc1a-8954-4054-9b30-48615acd3864"
363 | },
364 | {
365 | "nodeFromId": "24ec3ea7-81c2-4d42-8016-3c6d8d37b693",
366 | "nodeToId": "570fbc1a-8954-4054-9b30-48615acd3864"
367 | },
368 | {
369 | "nodeFromId": "6aa7369b-d01c-4e41-a07d-3ac14ae828db",
370 | "nodeToId": "f0e625ce-41fb-4fa8-bcf8-8a2a121de151"
371 | },
372 | {
373 | "nodeFromId": "24ec3ea7-81c2-4d42-8016-3c6d8d37b693",
374 | "nodeToId": "f0e625ce-41fb-4fa8-bcf8-8a2a121de151"
375 | },
376 | {
377 | "nodeFromId": "24ec3ea7-81c2-4d42-8016-3c6d8d37b693",
378 | "nodeToId": "5b720633-f29d-46fb-9f82-61161962401b"
379 | },
380 | {
381 | "nodeFromId": "24ec3ea7-81c2-4d42-8016-3c6d8d37b693",
382 | "nodeToId": "9dd9473a-44a7-42fb-8ce7-d1dcf1d88d81"
383 | },
384 | {
385 | "nodeFromId": "6d9a8af6-2f25-4af7-ae6a-ff9bf38d02be",
386 | "nodeToId": "bf35b66e-10a8-4158-813b-7e632f9b0cdd"
387 | },
388 | {
389 | "nodeFromId": "24ec3ea7-81c2-4d42-8016-3c6d8d37b693",
390 | "nodeToId": "bf35b66e-10a8-4158-813b-7e632f9b0cdd"
391 | },
392 | {
393 | "nodeFromId": "b503d84e-67e5-4448-9f03-5523ccd9c104",
394 | "nodeToId": "bf35b66e-10a8-4158-813b-7e632f9b0cdd"
395 | },
396 | {
397 | "nodeFromId": "f0e625ce-41fb-4fa8-bcf8-8a2a121de151",
398 | "nodeToId": "b503d84e-67e5-4448-9f03-5523ccd9c104"
399 | },
400 | {
401 | "nodeFromId": "b503d84e-67e5-4448-9f03-5523ccd9c104",
402 | "nodeToId": "570fbc1a-8954-4054-9b30-48615acd3864"
403 | },
404 | {
405 | "nodeFromId": "5b720633-f29d-46fb-9f82-61161962401b",
406 | "nodeToId": "b503d84e-67e5-4448-9f03-5523ccd9c104"
407 | },
408 | {
409 | "nodeFromId": "b503d84e-67e5-4448-9f03-5523ccd9c104",
410 | "nodeToId": "9dd9473a-44a7-42fb-8ce7-d1dcf1d88d81"
411 | },
412 | {
413 | "nodeFromId": "4c0c1746-5fd3-40fa-a70c-1c5396b55f12",
414 | "nodeToId": "b503d84e-67e5-4448-9f03-5523ccd9c104"
415 | }
416 | ]
417 | }
--------------------------------------------------------------------------------
/data/sample2.json:
--------------------------------------------------------------------------------
1 | {
2 | "nodes": [
3 | {
4 | "id": "24ec3ea7-81c2-4d42-8016-3c6d8d37b693",
5 | "location": {
6 | "x": 2045,
7 | "y": 448
8 | },
9 | "type": "Character",
10 | "name": "Hanako Hoshizora",
11 | "color": "#ff80c0",
12 | "imageSrc": "",
13 | "personality": "Energetic, optimistic, loyal, strong sense of justice",
14 | "quirk": "Hums anime tunes, twirls hair when stressed",
15 | "like": "Cute things, sweets (taiyaki), fashion (Harajuku)",
16 | "dislike": "Bullies, manipulation, burnt toast, spicy food",
17 | "strength": "Optimism, inspiring, agile, quick reflexes",
18 | "weakness": "Naive, impulsive, easily distracted, limited magical power",
19 | "flaw": "Self-doubt, overworks herself",
20 | "motivation": "Protects dreams of the innocent, wants to make the world a better place",
21 | "other": ""
22 | },
23 | {
24 | "id": "ff923a1c-50bb-4ee7-9bc2-9c9fcedb60f0",
25 | "location": {
26 | "x": 670,
27 | "y": 303
28 | },
29 | "type": "Character",
30 | "name": "Yuuri Kageyama",
31 | "color": "#ff8040",
32 | "imageSrc": "",
33 | "personality": "Calm, sarcastic wit, dry humor, secretly admires Hanako's bravery",
34 | "quirk": "Raises an eyebrow skeptically at Hanako's flights of fancy, excellent doodler (often captures funny sketches of Hanako's antics)",
35 | "like": "Reading, spending time at cafes, witty banter, a good mystery novel",
36 | "dislike": "Crowds, overly emotional situations, sugary foods",
37 | "strength": "Level-headed, analytical thinker, keeps Hanako grounded, resourceful",
38 | "weakness": "Can be overly cautious, struggles to express emotions openly",
39 | "flaw": "Sometimes comes across as cynical, lacks self-confidence in her own abilities",
40 | "motivation": "Cares deeply for Hanako and wants to ensure her safety, secretly finds Hanako's magical adventures exciting",
41 | "other": ""
42 | },
43 | {
44 | "id": "6d9a8af6-2f25-4af7-ae6a-ff9bf38d02be",
45 | "location": {
46 | "x": 111,
47 | "y": 169
48 | },
49 | "type": "Character",
50 | "name": "Hoshihikari Amane",
51 | "color": "#ff0080",
52 | "imageSrc": "",
53 | "personality": "Calm, enigmatic, possesses immense knowledge of magic",
54 | "quirk": "Speaks in riddles and proverbs, enjoys sipping green tea while gazing at the stars",
55 | "like": "Peace, tranquility, sharing wisdom with worthy students",
56 | "dislike": "Disruption of the natural balance, misuse of magic for personal gain",
57 | "strength": "Powerful magic user, vast knowledge of celestial lore, excellent teacher",
58 | "weakness": "Can be cryptic and difficult to understand at times, limited physical mobility",
59 | "flaw": "Holds magic in high regard, possibly hesitant to trust humans fully",
60 | "motivation": "Seeks to maintain the balance between the human world and the magical realm, desires to pass on her knowledge to a worthy successor",
61 | "other": ""
62 | },
63 | {
64 | "id": "ec7f5de0-aa19-421f-812c-77a286737214",
65 | "location": {
66 | "x": 1175,
67 | "y": 616
68 | },
69 | "type": "Character",
70 | "name": "Akira Sato",
71 | "color": "#00ffff",
72 | "imageSrc": "",
73 | "personality": "Outgoing, enthusiastic, always has a joke or story to tell",
74 | "quirk": "Trips over his own feet frequently, has a knack for getting into trouble (often unintentionally)",
75 | "like": "Spending time with Hanako, trying new foods, participating in local festivals",
76 | "dislike": "Boredom, loneliness, seeing his friends upset",
77 | "strength": "Loyal, supportive, brings out the lighter side in Hanako",
78 | "weakness": "Can be oblivious to social cues, sometimes lacks focus",
79 | "flaw": "Can be a bit clingy and overprotective of Hanako",
80 | "motivation": "Secretly harbors a deeper affection for Hanako, wants to be there for her no matter what, even if it means helping her with her magical battles (despite not knowing the full extent of them)",
81 | "other": ""
82 | },
83 | {
84 | "id": "6aa7369b-d01c-4e41-a07d-3ac14ae828db",
85 | "location": {
86 | "x": 3644,
87 | "y": 88
88 | },
89 | "type": "Character",
90 | "name": "Yami-D",
91 | "color": "#808000",
92 | "imageSrc": "",
93 | "personality": "Malicious, manipulative, feeds on the weaknesses and desires of others.",
94 | "quirk": "Speaks in glitching fragments of code and advertisements, enjoys toying with its victims before consuming them.",
95 | "like": "Feeding on negative emotions, spreading chaos and despair, corrupting dreams.",
96 | "dislike": "Purity, genuine happiness, acts of selflessness that disrupt its control.",
97 | "strength": "Powerful digital manipulation, can create hypnotic illusions and advertisements, possesses vast knowledge of consumer desires.",
98 | "weakness": "Vulnerable to pure celestial energy, can be disrupted by strong emotions like love and hope. Reliant on technology - a power outage or EMP could be disastrous.",
99 | "flaw": "Overconfident, underestimates the power of human connection and genuine desire.",
100 | "motivation": "Consumes dreams to fuel its own power and existence. Believes humans are weak and easily manipulated by their desires. Wants to control the world by turning everyone's dreams into a twisted reflection of their materialistic wants.",
101 | "other": ""
102 | },
103 | {
104 | "id": "122ee6a4-0e6f-4822-abd8-60c509ad579d",
105 | "location": {
106 | "x": 1835,
107 | "y": 1092
108 | },
109 | "type": "Location",
110 | "name": "Sakura High School",
111 | "color": "#008040",
112 | "imageSrc": "",
113 | "description": "By day, Sakura High hides its secret as a training ground for magical girls, its classrooms doubling as enchantment chambers under the glow of cherry blossom trees."
114 | },
115 | {
116 | "id": "6427a20e-226d-4df6-8f12-b4ec82c192c2",
117 | "location": {
118 | "x": 3172,
119 | "y": 615
120 | },
121 | "type": "Organization",
122 | "name": "Glitching Horde",
123 | "color": "#400000",
124 | "objective": "Seeks to infect the world with corrupted desires, turning humanity into mindless consumers trapped in a digital nightmare.",
125 | "detail": "Yami-D's scattered followers, the Glitching Horde, spread like a digital virus, hijacking dreams and desires through corrupted internet connections."
126 | },
127 | {
128 | "id": "02d3adf1-5907-4a05-9b8f-37c1e36fe20e",
129 | "location": {
130 | "x": 3214,
131 | "y": 329
132 | },
133 | "type": "Location",
134 | "name": "Yami-D's lair",
135 | "color": "#804000",
136 | "imageSrc": "",
137 | "description": "Atop a skyscraper shaped like a distorted smartphone screen, Yami-D's lair pulsed with hypnotic advertisements, bleeding digital nightmares into the Tokyo night."
138 | },
139 | {
140 | "id": "dab3851a-e0f1-4185-b905-c7962780ed1f",
141 | "location": {
142 | "x": 1651,
143 | "y": 458
144 | },
145 | "type": "Organization",
146 | "name": "Dream Weavers",
147 | "color": "#00ff80",
148 | "objective": "Bound by the power of the stars, fight to protect humanity's dreams from the digital corruption of Yami-D and the Glitching Horde.",
149 | "detail": "A network of young women who use celestial magic to safeguard dreams from the clutches of digital nightmares."
150 | },
151 | {
152 | "id": "5a04aa04-d648-4882-9296-b5a8571d223c",
153 | "location": {
154 | "x": 1395,
155 | "y": 55
156 | },
157 | "type": "Location",
158 | "name": "Star Tea House",
159 | "color": "#ffff00",
160 | "imageSrc": "",
161 | "description": "Disguised as a charming, traditional tea house, the Hoshi Chaya (Star Tea House) serves as a meeting point for the Dream Weavers. Beneath the fragrant steam and delicate teacups, they strategize and share information."
162 | },
163 | {
164 | "id": "b503d84e-67e5-4448-9f03-5523ccd9c104",
165 | "location": {
166 | "x": 2823,
167 | "y": 89
168 | },
169 | "type": "Story",
170 | "name": "Season 1",
171 | "color": "#FFFFFF",
172 | "description": "In modern Tokyo, bubbly high school student Hanako leads a double life. By day, she serves sugary treats at a maid cafe. By night, she transforms into Hoshizora, a magical girl who joins the Dream Weavers, a hidden network protecting humanity's dreams from the nightmarish digital corruption spread by Yami-D and its Glitching Horde."
173 | },
174 | {
175 | "id": "45c3cd76-5c96-4a02-84ee-036e8d7bdb66",
176 | "location": {
177 | "x": 2682,
178 | "y": 837
179 | },
180 | "type": "Lore",
181 | "name": "Hoshizora",
182 | "color": "#ff00ff",
183 | "detail": "Hoshizora isn't just a magical girl persona; it's a title and a legacy. Passed down through generations of Dream Weavers, Hoshizora signifies the protector who wields the power of the stars. By day, Hanako might be an ordinary student, but under the moonlight, she transforms, channeling the celestial energy to become the newest Hoshizora, the Star Weaver."
184 | },
185 | {
186 | "id": "4bd611a5-c114-41b8-b156-e85c3b82010a",
187 | "location": {
188 | "x": 163,
189 | "y": 842
190 | },
191 | "type": "Lore",
192 | "name": "Dream Weaver Magic",
193 | "color": "#0080c0",
194 | "detail": "Source: Celestial Energy (stars & constellations)\nFuel: Positive Emotions (hope, courage)\nTransformation: Personal Item (imbued with celestial energy) - e.g., Hanako's hair clip\nAbilities:\n- Defense: Shimmering curtains of starlight to block nightmares and attacks\n- Offense: Celestial blasts or constellation-inspired attacks (e.g., Starlight Serenade)\n- Dream Navigation: Enter dreamscapes to fight nightmares directly\n\nLimitations:\n- Negative Emotions weaken magic\n- Limited Power for young Dream Weavers\n- Weak Celestial Connection hinders abilities (e.g., heavy clouds)"
195 | },
196 | {
197 | "id": "5fcf2528-599c-4330-8b69-30f3dd0e3067",
198 | "location": {
199 | "x": 4257,
200 | "y": 185
201 | },
202 | "type": "Lore",
203 | "name": "Yami-D's Digital Corruption",
204 | "color": "#400080",
205 | "detail": "Source: Digital Manipulation\nPower:\n- Hypnotic Advertisements: Creates captivating ads that manipulate desires and trap minds in a digital dream world.\n- Corrupted Code Tendrils: Lashes out with corrupted code to physically restrain and harm opponents.\n- Dream Infiltration: Can access and distort human dreams, feeding on negativity and amplifying desires.\n\nWeakness:\n- Pure Celestial Energy: Disrupted by powerful displays of starlight magic used by the Dream Weavers.\n- Technology Reliance: Vulnerable to disruptions in its digital infrastructure (e.g., EMP attack).\n- Overconfidence: Underestimates the power of human connection and genuine desires."
206 | },
207 | {
208 | "id": "f0e625ce-41fb-4fa8-bcf8-8a2a121de151",
209 | "location": {
210 | "x": 3190,
211 | "y": 60
212 | },
213 | "type": "Event",
214 | "name": "Witnessing Evil",
215 | "color": "#FFFFFF",
216 | "detail": "Hanako witnesses Yami-D's corrupted advertisements manipulating people in Shibuya Crossing."
217 | },
218 | {
219 | "id": "570fbc1a-8954-4054-9b30-48615acd3864",
220 | "location": {
221 | "x": 2322,
222 | "y": 1090
223 | },
224 | "type": "Event",
225 | "name": "Confrontation",
226 | "color": "#FFFFFF",
227 | "detail": "As Hoshizora, she confronts Yami-D in a battle across the neon-lit rooftops of Tokyo."
228 | },
229 | {
230 | "id": "4c0c1746-5fd3-40fa-a70c-1c5396b55f12",
231 | "location": {
232 | "x": 2339,
233 | "y": 160
234 | },
235 | "type": "Event",
236 | "name": "Battle Assist",
237 | "color": "#FFFFFF",
238 | "detail": "While battling, Hoshizora encounters another Dream Weaver (potentially Yuuri or a new character) who assists her."
239 | },
240 | {
241 | "id": "5b720633-f29d-46fb-9f82-61161962401b",
242 | "location": {
243 | "x": 2494,
244 | "y": 465
245 | },
246 | "type": "Event",
247 | "name": "Worries",
248 | "color": "#FFFFFF",
249 | "detail": "Back in her normal life, Hanako ponders the growing threat of Yami-D and the responsibility of being Hoshizora."
250 | },
251 | {
252 | "id": "bf35b66e-10a8-4158-813b-7e632f9b0cdd",
253 | "location": {
254 | "x": 1823,
255 | "y": 96
256 | },
257 | "type": "Event",
258 | "name": "Mentoring",
259 | "color": "#FFFFFF",
260 | "detail": "Hanako seeks guidance from her mentor Hoshihikari to learn more about Yami-D and her powers."
261 | },
262 | {
263 | "id": "9dd9473a-44a7-42fb-8ce7-d1dcf1d88d81",
264 | "location": {
265 | "x": 2814,
266 | "y": 595
267 | },
268 | "type": "Event",
269 | "name": "Double Life",
270 | "color": "#FFFFFF",
271 | "detail": "Hanako's double life becomes more complicated as she juggles school, her part-time job, and her duties as Hoshizora."
272 | }
273 | ],
274 | "links": [
275 | {
276 | "nodeFromId": "5a04aa04-d648-4882-9296-b5a8571d223c",
277 | "nodeToId": "ff923a1c-50bb-4ee7-9bc2-9c9fcedb60f0"
278 | },
279 | {
280 | "nodeFromId": "24ec3ea7-81c2-4d42-8016-3c6d8d37b693",
281 | "nodeToId": "5a04aa04-d648-4882-9296-b5a8571d223c"
282 | },
283 | {
284 | "nodeFromId": "4bd611a5-c114-41b8-b156-e85c3b82010a",
285 | "nodeToId": "24ec3ea7-81c2-4d42-8016-3c6d8d37b693"
286 | },
287 | {
288 | "nodeFromId": "ff923a1c-50bb-4ee7-9bc2-9c9fcedb60f0",
289 | "nodeToId": "4bd611a5-c114-41b8-b156-e85c3b82010a"
290 | },
291 | {
292 | "nodeFromId": "4bd611a5-c114-41b8-b156-e85c3b82010a",
293 | "nodeToId": "6d9a8af6-2f25-4af7-ae6a-ff9bf38d02be"
294 | },
295 | {
296 | "nodeFromId": "5a04aa04-d648-4882-9296-b5a8571d223c",
297 | "nodeToId": "6d9a8af6-2f25-4af7-ae6a-ff9bf38d02be"
298 | },
299 | {
300 | "nodeFromId": "24ec3ea7-81c2-4d42-8016-3c6d8d37b693",
301 | "nodeToId": "6d9a8af6-2f25-4af7-ae6a-ff9bf38d02be"
302 | },
303 | {
304 | "nodeFromId": "24ec3ea7-81c2-4d42-8016-3c6d8d37b693",
305 | "nodeToId": "45c3cd76-5c96-4a02-84ee-036e8d7bdb66"
306 | },
307 | {
308 | "nodeFromId": "24ec3ea7-81c2-4d42-8016-3c6d8d37b693",
309 | "nodeToId": "122ee6a4-0e6f-4822-abd8-60c509ad579d"
310 | },
311 | {
312 | "nodeFromId": "122ee6a4-0e6f-4822-abd8-60c509ad579d",
313 | "nodeToId": "ff923a1c-50bb-4ee7-9bc2-9c9fcedb60f0"
314 | },
315 | {
316 | "nodeFromId": "ec7f5de0-aa19-421f-812c-77a286737214",
317 | "nodeToId": "122ee6a4-0e6f-4822-abd8-60c509ad579d"
318 | },
319 | {
320 | "nodeFromId": "5a04aa04-d648-4882-9296-b5a8571d223c",
321 | "nodeToId": "dab3851a-e0f1-4185-b905-c7962780ed1f"
322 | },
323 | {
324 | "nodeFromId": "24ec3ea7-81c2-4d42-8016-3c6d8d37b693",
325 | "nodeToId": "dab3851a-e0f1-4185-b905-c7962780ed1f"
326 | },
327 | {
328 | "nodeFromId": "6d9a8af6-2f25-4af7-ae6a-ff9bf38d02be",
329 | "nodeToId": "dab3851a-e0f1-4185-b905-c7962780ed1f"
330 | },
331 | {
332 | "nodeFromId": "dab3851a-e0f1-4185-b905-c7962780ed1f",
333 | "nodeToId": "ff923a1c-50bb-4ee7-9bc2-9c9fcedb60f0"
334 | },
335 | {
336 | "nodeFromId": "02d3adf1-5907-4a05-9b8f-37c1e36fe20e",
337 | "nodeToId": "6aa7369b-d01c-4e41-a07d-3ac14ae828db"
338 | },
339 | {
340 | "nodeFromId": "02d3adf1-5907-4a05-9b8f-37c1e36fe20e",
341 | "nodeToId": "6427a20e-226d-4df6-8f12-b4ec82c192c2"
342 | },
343 | {
344 | "nodeFromId": "6aa7369b-d01c-4e41-a07d-3ac14ae828db",
345 | "nodeToId": "6427a20e-226d-4df6-8f12-b4ec82c192c2"
346 | },
347 | {
348 | "nodeFromId": "6aa7369b-d01c-4e41-a07d-3ac14ae828db",
349 | "nodeToId": "5fcf2528-599c-4330-8b69-30f3dd0e3067"
350 | },
351 | {
352 | "nodeFromId": "ff923a1c-50bb-4ee7-9bc2-9c9fcedb60f0",
353 | "nodeToId": "4c0c1746-5fd3-40fa-a70c-1c5396b55f12"
354 | },
355 | {
356 | "nodeFromId": "4c0c1746-5fd3-40fa-a70c-1c5396b55f12",
357 | "nodeToId": "24ec3ea7-81c2-4d42-8016-3c6d8d37b693"
358 | },
359 | {
360 | "nodeFromId": "6aa7369b-d01c-4e41-a07d-3ac14ae828db",
361 | "nodeToId": "570fbc1a-8954-4054-9b30-48615acd3864"
362 | },
363 | {
364 | "nodeFromId": "24ec3ea7-81c2-4d42-8016-3c6d8d37b693",
365 | "nodeToId": "570fbc1a-8954-4054-9b30-48615acd3864"
366 | },
367 | {
368 | "nodeFromId": "6aa7369b-d01c-4e41-a07d-3ac14ae828db",
369 | "nodeToId": "f0e625ce-41fb-4fa8-bcf8-8a2a121de151"
370 | },
371 | {
372 | "nodeFromId": "24ec3ea7-81c2-4d42-8016-3c6d8d37b693",
373 | "nodeToId": "f0e625ce-41fb-4fa8-bcf8-8a2a121de151"
374 | },
375 | {
376 | "nodeFromId": "24ec3ea7-81c2-4d42-8016-3c6d8d37b693",
377 | "nodeToId": "5b720633-f29d-46fb-9f82-61161962401b"
378 | },
379 | {
380 | "nodeFromId": "24ec3ea7-81c2-4d42-8016-3c6d8d37b693",
381 | "nodeToId": "9dd9473a-44a7-42fb-8ce7-d1dcf1d88d81"
382 | },
383 | {
384 | "nodeFromId": "6d9a8af6-2f25-4af7-ae6a-ff9bf38d02be",
385 | "nodeToId": "bf35b66e-10a8-4158-813b-7e632f9b0cdd"
386 | },
387 | {
388 | "nodeFromId": "24ec3ea7-81c2-4d42-8016-3c6d8d37b693",
389 | "nodeToId": "bf35b66e-10a8-4158-813b-7e632f9b0cdd"
390 | },
391 | {
392 | "nodeFromId": "b503d84e-67e5-4448-9f03-5523ccd9c104",
393 | "nodeToId": "bf35b66e-10a8-4158-813b-7e632f9b0cdd"
394 | },
395 | {
396 | "nodeFromId": "f0e625ce-41fb-4fa8-bcf8-8a2a121de151",
397 | "nodeToId": "b503d84e-67e5-4448-9f03-5523ccd9c104"
398 | },
399 | {
400 | "nodeFromId": "b503d84e-67e5-4448-9f03-5523ccd9c104",
401 | "nodeToId": "570fbc1a-8954-4054-9b30-48615acd3864"
402 | },
403 | {
404 | "nodeFromId": "5b720633-f29d-46fb-9f82-61161962401b",
405 | "nodeToId": "b503d84e-67e5-4448-9f03-5523ccd9c104"
406 | },
407 | {
408 | "nodeFromId": "b503d84e-67e5-4448-9f03-5523ccd9c104",
409 | "nodeToId": "9dd9473a-44a7-42fb-8ce7-d1dcf1d88d81"
410 | },
411 | {
412 | "nodeFromId": "4c0c1746-5fd3-40fa-a70c-1c5396b55f12",
413 | "nodeToId": "b503d84e-67e5-4448-9f03-5523ccd9c104"
414 | }
415 | ]
416 | }
--------------------------------------------------------------------------------
/eslint.config.js:
--------------------------------------------------------------------------------
1 | // @ts-check
2 |
3 | // eslint-disable-next-line @typescript-eslint/no-var-requires, no-undef
4 | const eslint = require('@eslint/js');
5 | // eslint-disable-next-line @typescript-eslint/no-var-requires, no-undef
6 | const tseslint = require('typescript-eslint');
7 | // eslint-disable-next-line @typescript-eslint/no-var-requires, no-undef
8 | const eslintPluginPrettierRecommended = require('eslint-plugin-prettier/recommended');
9 |
10 | // eslint-disable-next-line no-undef
11 | module.exports = [
12 | eslint.configs.recommended,
13 | ...tseslint.configs.recommended,
14 | eslintPluginPrettierRecommended,
15 | {
16 | ignores: ['build/*'],
17 | },
18 | ];
19 |
--------------------------------------------------------------------------------
/images/splash1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/images/splash1.png
--------------------------------------------------------------------------------
/images/splash2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/images/splash2.png
--------------------------------------------------------------------------------
/img/asc.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/img/asc.gif
--------------------------------------------------------------------------------
/img/bg.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/img/bg.gif
--------------------------------------------------------------------------------
/img/conv30.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/img/conv30.png
--------------------------------------------------------------------------------
/img/conv40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/img/conv40.png
--------------------------------------------------------------------------------
/img/conv50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/img/conv50.png
--------------------------------------------------------------------------------
/img/desc.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/img/desc.gif
--------------------------------------------------------------------------------
/img/glyphicons-halflings-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/img/glyphicons-halflings-white.png
--------------------------------------------------------------------------------
/img/glyphicons-halflings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/img/glyphicons-halflings.png
--------------------------------------------------------------------------------
/img/heart30.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/img/heart30.png
--------------------------------------------------------------------------------
/img/heart40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/img/heart40.png
--------------------------------------------------------------------------------
/img/heart50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/img/heart50.png
--------------------------------------------------------------------------------
/img/lastfm.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/img/lastfm.gif
--------------------------------------------------------------------------------
/img/m1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/img/m1.png
--------------------------------------------------------------------------------
/img/m2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/img/m2.png
--------------------------------------------------------------------------------
/img/m3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/img/m3.png
--------------------------------------------------------------------------------
/img/m4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/img/m4.png
--------------------------------------------------------------------------------
/img/m5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/img/m5.png
--------------------------------------------------------------------------------
/img/people35.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/img/people35.png
--------------------------------------------------------------------------------
/img/people45.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/img/people45.png
--------------------------------------------------------------------------------
/img/people55.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/img/people55.png
--------------------------------------------------------------------------------
/img/pin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/img/pin.png
--------------------------------------------------------------------------------
/img/songkick.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/img/songkick.png
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
40 |
41 |
42 |
43 |
44 |
45 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
69 |
70 |
71 |
72 |

73 |
74 |
75 |
76 |

77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
97 |
98 |
99 |
100 |
101 |
102 |
103 | No events are matching this filter.
104 |
105 |
106 |
116 |
117 |
118 |
119 |
--------------------------------------------------------------------------------
/js/eventslist.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Stores a list of events, also allows to filter them. Each event is an object
3 | * with the following fields
4 | *
5 | * artist : string
6 | * type : Concert/Festival
7 | * startDate : Date
8 | * location : {lat, lng}
9 | * venue : string
10 | * city: string
11 | * country : string
12 | * tags : [] string
13 | **/
14 | function EventsList() {
15 | this.events = [];
16 | }
17 |
18 | /**
19 | * Adds an event to the event list. It transforms it from the songkick format
20 | * to internal format, that stores only the fields that are used.
21 | **/
22 | EventsList.prototype.addEvent = function(songkickArtist, songkickEvent) {
23 | var eventCity = songkickEvent.location ? songkickEvent.location.city : "";
24 | var lastComma = eventCity.lastIndexOf(",");
25 |
26 | var city = $.trim(eventCity.substring(0, lastComma));
27 | var country = $.trim(eventCity.substring(lastComma + 1));
28 |
29 | var event = {
30 | artist : songkickArtist.displayName,
31 | location : {
32 | lat : songkickEvent.location ? songkickEvent.location.lat : 0,
33 | lng : songkickEvent.location ? songkickEvent.location.lng : 0
34 | },
35 | venue : songkickEvent.venue ? songkickEvent.venue.displayName : "",
36 | type : songkickEvent.type,
37 | city : city,
38 | country : country,
39 | startDate : new Date(songkickEvent.start ? songkickEvent.start.date : Date.now()),
40 | tags: songkickArtist.tags,
41 | url: {
42 | songkick: songkickEvent.uri
43 | }
44 | }
45 |
46 | this.events.push(event);
47 | return event;
48 | }
49 |
50 | /**
51 | * Gets a list of suggestions that can be used ina typeahead for the added
52 | * events.
53 | */
54 | EventsList.prototype.getSuggestions = function() {
55 | var suggestions = {};
56 |
57 | util.each(this.events, function(event) {
58 | util.eachValue(event, function(value) {
59 | if (util.is_string(value)) {
60 | suggestions[value] = 1;
61 | }
62 | })
63 | });
64 |
65 | return util.keys(suggestions);
66 | }
67 |
68 | /**
69 | * Gets all events in the event list.
70 | */
71 | EventsList.prototype.getEvents = function() {
72 | return this.events;
73 | }
74 |
75 |
76 |
--------------------------------------------------------------------------------
/js/eventsmap.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Represents the map. Events can be added to it, and it can be cleared.
3 | */
4 | function EventsMap() {
5 | var mapOptions = {
6 | center: new google.maps.LatLng(39.325178, 13.359375),
7 | zoom: 2,
8 | mapTypeId: google.maps.MapTypeId.ROADMAP,
9 | mapTypeControlOptions : {
10 | position: google.maps.ControlPosition.TOP_RIGHT
11 | },
12 | panControlOptions: {
13 | position: google.maps.ControlPosition.RIGHT_TOP
14 | },
15 | zoomControlOptions: {
16 | position: google.maps.ControlPosition.RIGHT_TOP
17 | },
18 | streetViewControlOptions: {
19 | position: google.maps.ControlPosition.RIGHT_TOP
20 | }
21 | };
22 |
23 | this.infoWindowCount = 0; // used for generating unique id for each infowindow
24 | this.map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);
25 | this.clusterer = new MarkerClusterer(this.map, [], {minimumClusterSize:1, zoomOnClick:false});
26 | this.infoWindow = new google.maps.InfoWindow();
27 |
28 | google.maps.event.addListener(this.clusterer, 'clusterclick', $.proxy(this.showInfoWindow, this));
29 | }
30 |
31 | /**
32 | * Adds a marker with the event to the google map.
33 | **/
34 | EventsMap.prototype.addEvent = function(event) {
35 | var location = new google.maps.LatLng(event.location.lat, event.location.lng);
36 | var marker = new google.maps.Marker({
37 | position: location,
38 | map: this.map,
39 | title: event.name
40 | });
41 |
42 | marker.event = event;
43 |
44 | this.clusterer.addMarker(marker);
45 | }
46 |
47 | /**
48 | * Adds all events to the event map.
49 | */
50 | EventsMap.prototype.addEvents = function(events) {
51 | util.each(events, $.proxy(this.addEvent, this));
52 | }
53 |
54 | /**
55 | * Clears all event markers.
56 | */
57 | EventsMap.prototype.clear = function() {
58 | this.clusterer.clearMarkers();
59 | }
60 |
61 | /**
62 | * Shows an InfoWindow with the information for all events in a cluster.
63 | */
64 | EventsMap.prototype.showInfoWindow = function(cluster) {
65 | var table = new TableBuilder(["Date", "Artist", "Venue", "City", "Country"], 'tablesorter');
66 |
67 | var markers = cluster.getMarkers();
68 | for (var i = 0; i < markers.length; i++) {
69 | var event = markers[i].event;
70 | var d = event.startDate;
71 | var dateString = ("0"+(d.getMonth()+1)).slice(-2) + "/" + ("0" + d.getDate()).slice(-2) + "/" + d.getFullYear();
72 | table.addRow([dateString, "" + event.artist + "", event.venue, event.city, event.country]);
73 | }
74 |
75 | this.infoWindow.setContent('' + table.build() + "
");
76 | // put the info window at a bogus marker
77 | var center = {lat: cluster.getCenter().lat(), lng: cluster.getCenter().lng()};
78 | var image = {
79 | url: 'https://developers.google.com/maps/documentation/javascript/examples/full/images/beachflag.png',
80 | size: new google.maps.Size(0, 0),
81 | origin: new google.maps.Point(0, 0),
82 | anchor: new google.maps.Point(0, 0)
83 | };
84 | this.infoWindow.open(this.map, new google.maps.Marker({position: center, map: this.map, icon: image}));
85 | $('.tablesorter').tablesorter();
86 | }
--------------------------------------------------------------------------------
/js/filter.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Represents teh filter dialogue. It can can show it, and match events agains it.
3 | */
4 | function Filter(eventList) {
5 | this.fromDate = $("#from-date");
6 | this.toDate = $("#to-date");
7 | this.weekend = $("#weekend");
8 | this.filter = $("#filter-text");
9 | this.filterDiv = $("#filter-div");
10 |
11 | util.each([this.fromDate, this.toDate, this.filter], function(element) {
12 | element.val("");
13 | });
14 |
15 | this.fromDate.datepicker();
16 | this.toDate.datepicker();
17 | this.filterDiv.css('display', 'none');
18 | }
19 |
20 | Filter.prototype.fromDateFilter = function(event) {
21 | return this.fromDate.val() ? new Date(this.fromDate.val()) <= event.startDate : true;
22 | }
23 |
24 | Filter.prototype.toDateFilter = function(event) {
25 | return this.toDate.val() ? new Date(this.toDate.val()) >= event.startDate : true;
26 | }
27 |
28 | Filter.prototype.weekendFilter = function(event) {
29 | var day = event.startDate.getDay();
30 | return this.weekend.is(':checked') ? (day == 5 || day == 6) : true;
31 | }
32 |
33 | Filter.prototype.stringMatchFilter = function(event) {
34 | var match = this.filter.val().toLowerCase();
35 |
36 | function matches(value) {
37 | return (util.is_string(value)) ? (value.toLowerCase().indexOf(match) != -1) : false;
38 | }
39 |
40 | return match ? util.or(util.values(event), matches) : true;
41 | }
42 |
43 | /**
44 | * Shows the filter menu.
45 | */
46 | Filter.prototype.show = function(eventsList) {
47 | this.filterDiv.show();
48 | var suggestions = eventsList.getSuggestions();
49 | this.filter.typeahead();
50 | // the source is set here, so it can be updated
51 | this.filter.data('typeahead').source = suggestions;
52 | }
53 |
54 | /**
55 | * Checks if event is matching all filters.
56 | */
57 | Filter.prototype.isMatching = function(event) {
58 | var filters = [$.proxy(this.fromDateFilter, this),
59 | $.proxy(this.toDateFilter, this),
60 | $.proxy(this.weekendFilter, this),
61 | $.proxy(this.stringMatchFilter, this)];
62 |
63 | return util.and(filters, function(filter) {
64 | var result = filter(event);
65 | return result;
66 | });
67 | }
68 |
--------------------------------------------------------------------------------
/js/lastfm.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Wrapper around the Last.FM API.
3 | */
4 | function LastFM() {
5 | this.apiKey = "26fd5c4e94f30e7a0f2489b2c5babb61";
6 | }
7 |
8 | /**
9 | * Gets the 5 most popular tags for an artist.
10 | */
11 | LastFM.prototype.getTags = function(artist, callback) {
12 | var url = "http://ws.audioscrobbler.com/2.0/?method=artist.gettoptags&artist=" + artist + "&api_key=" + this.apiKey + "&format=json&callback=?";
13 |
14 | var handler = function(response) {
15 | var tags = [];
16 |
17 | if (response && response.toptags && response.toptags.tag) {
18 | var topTags = response.toptags.tag;
19 | var length = Math.min(5, topTags.length);
20 | for (i = 0; i < length; i++) {
21 | tags.push(topTags[i].name);
22 | }
23 | }
24 |
25 | callback(tags);
26 | }
27 |
28 | $.ajax({
29 | url: url,
30 | dataType: 'json',
31 | success: handler,
32 | error: function() { callback([]); }
33 | });
34 | }
--------------------------------------------------------------------------------
/js/songkick.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Wrapper around the songkick api.
3 | */
4 | function Songkick(user, eventsList, eventsMap) {
5 | this.apiKey = "hZ2Fewy4geaBhLCS";
6 | this.user = user;
7 | this.eventsList = eventsList;
8 | this.eventsMap = eventsMap;
9 | this.events = [];
10 | this.lastfm = new LastFM();
11 | }
12 |
13 | /**
14 | * Displays all future events for the tracked artists.
15 | */
16 | Songkick.prototype.showEventsForTrackerArtists = function(onFinish) {
17 | var trackingsUrl = "http://api.songkick.com/api/3.0/users/" + this.user +"/artists/tracked.json?location=clientip&apikey=" + this.apiKey + "&jsoncallback=?";
18 | var status = new Status(onFinish);
19 |
20 | function initializeStatus(firstPage) {
21 | status.setTotal(firstPage.resultsPage.totalEntries);
22 | }
23 |
24 | function addEvent(songkickArtist) {
25 | return function(songkickEvent) {
26 | var event = this.eventsList.addEvent(songkickArtist, songkickEvent);
27 | this.eventsMap.addEvent(event);
28 | }
29 | }
30 |
31 | function updateStatus(artist) {
32 | return function() {
33 | status.increment(artist.displayName);
34 | }
35 | }
36 |
37 | function showEvents(artist) {
38 | if (artist.onTourUntil != null) {
39 | this.lastfm.getTags(artist.displayName, $.proxy(function(tags) {
40 | artist.tags = tags;
41 | var eventsUrl = "http://api.songkick.com/api/3.0/artists/" + artist.id + "/calendar.json?apikey=" + this.apiKey + "&jsoncallback=?";
42 | this.forEachItem({ url:eventsUrl, processItem:addEvent(artist), onFinish:updateStatus(artist) });
43 | }, this));
44 | } else {
45 | updateStatus(artist)();
46 | }
47 | }
48 |
49 | this.forEachItem({url:trackingsUrl, processItem:showEvents, onStart:initializeStatus, hide: function() { status.finish() } });
50 | }
51 |
52 | /**
53 | * Iterates through paginated resutls and calls processItem for each result.
54 | */
55 | Songkick.prototype.forEachItem = function(params) {
56 | var processItem = $.proxy(params.processItem, this);
57 | var onStart = $.proxy(params.onStart || function(){}, this);
58 | var onFinish = $.proxy(params.onFinish || function(){}, this);
59 |
60 | var totalPages;
61 | var processedPages = 0;
62 |
63 | function processPage(data) {
64 | var results = util.getFirstProperty(data.resultsPage.results);
65 | util.each(results, processItem);
66 |
67 | if (++processedPages == totalPages) {
68 | onFinish();
69 | }
70 | }
71 |
72 | function forEachPage(firstPage) {
73 | totalPages = Math.ceil(firstPage.resultsPage.totalEntries / firstPage.resultsPage.perPage);
74 |
75 | onStart(firstPage);
76 |
77 | processPage(firstPage);
78 | for (var page = 2; page <= totalPages; page++) {
79 | $.getJSON(params.url + "&page=" + page, processPage).fail(function(e) {
80 | params.hide();
81 | });
82 | }
83 | }
84 |
85 | $.getJSON(params.url, forEachPage).fail(function(e) {
86 | console.log(e);
87 | params.hide();
88 | });
89 | }
90 |
91 |
92 |
--------------------------------------------------------------------------------
/js/status.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Status modal. It displays a progress bar which is updated on every increment
3 | * call. total is the number of increment calls expected and onFinish is an
4 | * optional function that should be called when the status has reached 100%.
5 | **/
6 | function Status(onFinish) {
7 | onFinish = onFinish || function() {};
8 | this.processed = 0;
9 | this.finish = function () {
10 | $('#status-modal').hide();
11 | onFinish();
12 | }
13 |
14 | $("#status-modal").modal({ show:true, keyboard:false, backdrop:false });
15 | $("#status-modal").show();
16 | $("#progress-bar").css("width", "0%");
17 | }
18 |
19 | /**
20 | * Sets the total number of increments expected.
21 | */
22 | Status.prototype.setTotal = function(total) {
23 | this.total = total;
24 | }
25 |
26 | /**
27 | * Increments the progress bar and displays the info text.
28 | **/
29 | Status.prototype.increment = function(info) {
30 | this.processed++;
31 |
32 | if (this.processed / this.total * 100 > 90 && this.processed < this.total) {
33 | window.clearTimeout(this.timeout);
34 | this.timeout = window.setTimeout($.proxy(this.finish, this), 2000)
35 | }
36 |
37 | $("#progress-bar").css("width", Math.floor( (this.processed / this.total) * 100 ) + "%");
38 | $("#progress-info").html(info);
39 |
40 | if (this.processed == this.total) {
41 | setTimeout($.proxy(this.finish, this), 500);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/js/ui.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Initializes the document.
3 | */
4 | $(document).ready(function() {
5 | var eventsMap = new EventsMap();
6 | initializeSearchBox(eventsMap);
7 | })
8 |
9 | /**
10 | * Initializes the search box.
11 | **/
12 | function initializeSearchBox(eventsMap) {
13 | $("#search-button").click(function() {
14 | window.location.hash = $("#search-box").val();
15 | $("#search-button").addClass("disabled");
16 | $("#search-box").attr("disabled", "");
17 | $("#search-box").blur();
18 | $("#no-results-alert").css("display", "none");
19 | eventsMap.clear();
20 |
21 | var eventsList = new EventsList();
22 | var filter = new Filter();
23 | var songkick = new Songkick($("#search-box").val(), eventsList, eventsMap);
24 |
25 | songkick.showEventsForTrackerArtists(function() {
26 | $("#search-button").removeClass("disabled");
27 | $("#search-box").removeAttr("disabled");
28 | filter.show(eventsList);
29 | });
30 |
31 | $("#filter-button").click(function() {
32 | var matchingEvents = eventsList.getEvents().filter($.proxy(filter.isMatching, filter));
33 | eventsMap.clear();
34 | if (matchingEvents.length == 0) {
35 | $("#no-results-alert").css("display", "block")
36 | } else {
37 | $("#no-results-alert").css("display", "none");
38 | eventsMap.addEvents(matchingEvents);
39 | }
40 | return false;
41 | });
42 |
43 | return false;
44 | });
45 |
46 | $("#search-box").keydown(function(event){
47 | if(event.keyCode == 13){
48 | $("#search-button").click();
49 | }
50 | });
51 |
52 | var hash = window.location.hash.slice(1);
53 |
54 | if (hash) {
55 | $("#search-box").val(hash);
56 | $("#search-button").click();
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/js/util.js:
--------------------------------------------------------------------------------
1 | var util = {}
2 |
3 | /**
4 | * Gets the first property of an object.
5 | */
6 | util.getFirstProperty = function(object) {
7 | var firstProperty = {};
8 | for (var property in object) {
9 | firstProperty = object[property];
10 | break;
11 | }
12 | return firstProperty;
13 | }
14 |
15 | /**
16 | * Calls processItem on item, or if item is a list it calls it for each element
17 | * in the list.
18 | */
19 | util.each = function(item, processItem) {
20 | if ($.isArray(item)) {
21 | $.each(item, function(index, value) {
22 | processItem(value);
23 | });
24 | } else {
25 | processItem(item);
26 | }
27 | }
28 |
29 | /**
30 | * Calls the processValue function for each value in a hash.
31 | **/
32 | util.eachValue = function(hash, processValue) {
33 | for (var key in hash) {
34 | util.each(hash[key], processValue);
35 | }
36 | }
37 |
38 | /**
39 | * Returns a list with the values in the hash.
40 | */
41 | util.values = function(hash) {
42 | var values = [];
43 | util.eachValue(hash, $.proxy(values.push, values));
44 | return values;
45 | }
46 |
47 | /**
48 | * Returns a list with the keys in the hash.
49 | */
50 | util.keys = function(hash) {
51 | var keys = [];
52 | for (var key in hash) {
53 | keys.push(key);
54 | }
55 | return keys;
56 | }
57 |
58 | /**
59 | * Returns true if predicate is true for all items.
60 | **/
61 | util.and = function(items, predicate) {
62 | var result = true;
63 | util.each(items, function(item) {
64 | result = result && predicate(item);
65 | });
66 |
67 | return result;
68 | }
69 |
70 | /**
71 | * Returns true if predicate is true for some of the items.
72 | */
73 | util.or = function(items, predicate) {
74 | var result = false;
75 | util.each(items, function(item) {
76 | result = result || predicate(item);
77 | });
78 |
79 | return result;
80 | }
81 |
82 | /**
83 | * Checks if the input is string.
84 | **/
85 | util.is_string = function(input) {
86 | return $.type(input) === 'string';
87 | }
88 |
89 | /**
90 | * Class that facilitates building the html for a table.
91 | */
92 | function TableBuilder(columns, optionalClass) {
93 | optionalClass = optionalClass || "";
94 | this.html = '';
95 | this.html += '';
96 | for (var i = 0; i < columns.length; i++) {
97 | columns[i] += ' ';
98 | }
99 | this._addRow(columns, 'th');
100 | this.html += '';
101 | }
102 |
103 | TableBuilder.prototype._addRow = function(values, columnTag) {
104 | this.html += '';
105 | for (var i = 0; i < values.length; i++) {
106 | this.html += '<' + columnTag + '>' + values[i] + '' + columnTag + '>';
107 | }
108 | this.html += '
';
109 | }
110 |
111 | TableBuilder.prototype.addRow = function(values) {
112 | this._addRow(values, 'td');
113 | }
114 |
115 | TableBuilder.prototype.build = function() {
116 | this.html += "
";
117 | return this.html;
118 | }
--------------------------------------------------------------------------------
/lib/bootstrap-alert.js:
--------------------------------------------------------------------------------
1 | /* ==========================================================
2 | * bootstrap-alert.js v2.0.1
3 | * http://twitter.github.com/bootstrap/javascript.html#alerts
4 | * ==========================================================
5 | * Copyright 2012 Twitter, Inc.
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | * ========================================================== */
19 |
20 |
21 | !function( $ ){
22 |
23 | "use strict"
24 |
25 | /* ALERT CLASS DEFINITION
26 | * ====================== */
27 |
28 | var dismiss = '[data-dismiss="alert"]'
29 | , Alert = function ( el ) {
30 | $(el).on('click', dismiss, this.close)
31 | }
32 |
33 | Alert.prototype = {
34 |
35 | constructor: Alert
36 |
37 | , close: function ( e ) {
38 | var $this = $(this)
39 | , selector = $this.attr('data-target')
40 | , $parent
41 |
42 | if (!selector) {
43 | selector = $this.attr('href')
44 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
45 | }
46 |
47 | $parent = $(selector)
48 | $parent.trigger('close')
49 |
50 | e && e.preventDefault()
51 |
52 | $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent())
53 |
54 | $parent
55 | .trigger('close')
56 | .removeClass('in')
57 |
58 | function removeElement() {
59 | $parent
60 | .trigger('closed')
61 | .remove()
62 | }
63 |
64 | $.support.transition && $parent.hasClass('fade') ?
65 | $parent.on($.support.transition.end, removeElement) :
66 | removeElement()
67 | }
68 |
69 | }
70 |
71 |
72 | /* ALERT PLUGIN DEFINITION
73 | * ======================= */
74 |
75 | $.fn.alert = function ( option ) {
76 | return this.each(function () {
77 | var $this = $(this)
78 | , data = $this.data('alert')
79 | if (!data) $this.data('alert', (data = new Alert(this)))
80 | if (typeof option == 'string') data[option].call($this)
81 | })
82 | }
83 |
84 | $.fn.alert.Constructor = Alert
85 |
86 |
87 | /* ALERT DATA-API
88 | * ============== */
89 |
90 | $(function () {
91 | $('body').on('click.alert.data-api', dismiss, Alert.prototype.close)
92 | })
93 |
94 | }( window.jQuery );
--------------------------------------------------------------------------------
/lib/bootstrap-dropdown.js:
--------------------------------------------------------------------------------
1 | /* ============================================================
2 | * bootstrap-dropdown.js v2.0.1
3 | * http://twitter.github.com/bootstrap/javascript.html#dropdowns
4 | * ============================================================
5 | * Copyright 2012 Twitter, Inc.
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | * ============================================================ */
19 |
20 |
21 | !function( $ ){
22 |
23 | "use strict"
24 |
25 | /* DROPDOWN CLASS DEFINITION
26 | * ========================= */
27 |
28 | var toggle = '[data-toggle="dropdown"]'
29 | , Dropdown = function ( element ) {
30 | var $el = $(element).on('click.dropdown.data-api', this.toggle)
31 | $('html').on('click.dropdown.data-api', function () {
32 | $el.parent().removeClass('open')
33 | })
34 | }
35 |
36 | Dropdown.prototype = {
37 |
38 | constructor: Dropdown
39 |
40 | , toggle: function ( e ) {
41 | var $this = $(this)
42 | , selector = $this.attr('data-target')
43 | , $parent
44 | , isActive
45 |
46 | if (!selector) {
47 | selector = $this.attr('href')
48 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
49 | }
50 |
51 | $parent = $(selector)
52 | $parent.length || ($parent = $this.parent())
53 |
54 | isActive = $parent.hasClass('open')
55 |
56 | clearMenus()
57 | !isActive && $parent.toggleClass('open')
58 |
59 | return false
60 | }
61 |
62 | }
63 |
64 | function clearMenus() {
65 | $(toggle).parent().removeClass('open')
66 | }
67 |
68 |
69 | /* DROPDOWN PLUGIN DEFINITION
70 | * ========================== */
71 |
72 | $.fn.dropdown = function ( option ) {
73 | return this.each(function () {
74 | var $this = $(this)
75 | , data = $this.data('dropdown')
76 | if (!data) $this.data('dropdown', (data = new Dropdown(this)))
77 | if (typeof option == 'string') data[option].call($this)
78 | })
79 | }
80 |
81 | $.fn.dropdown.Constructor = Dropdown
82 |
83 |
84 | /* APPLY TO STANDARD DROPDOWN ELEMENTS
85 | * =================================== */
86 |
87 | $(function () {
88 | $('html').on('click.dropdown.data-api', clearMenus)
89 | $('body').on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle)
90 | })
91 |
92 | }( window.jQuery );
--------------------------------------------------------------------------------
/lib/bootstrap-modal.js:
--------------------------------------------------------------------------------
1 | /* =========================================================
2 | * bootstrap-modal.js v2.0.1
3 | * http://twitter.github.com/bootstrap/javascript.html#modals
4 | * =========================================================
5 | * Copyright 2012 Twitter, Inc.
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | * ========================================================= */
19 |
20 |
21 | !function( $ ){
22 |
23 | "use strict"
24 |
25 | /* MODAL CLASS DEFINITION
26 | * ====================== */
27 |
28 | var Modal = function ( content, options ) {
29 | this.options = options
30 | this.$element = $(content)
31 | .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this))
32 | }
33 |
34 | Modal.prototype = {
35 |
36 | constructor: Modal
37 |
38 | , toggle: function () {
39 | return this[!this.isShown ? 'show' : 'hide']()
40 | }
41 |
42 | , show: function () {
43 | var that = this
44 |
45 | if (this.isShown) return
46 |
47 | $('body').addClass('modal-open')
48 |
49 | this.isShown = true
50 | this.$element.trigger('show')
51 |
52 | escape.call(this)
53 | backdrop.call(this, function () {
54 | var transition = $.support.transition && that.$element.hasClass('fade')
55 |
56 | !that.$element.parent().length && that.$element.appendTo(document.body) //don't move modals dom position
57 |
58 | that.$element
59 | .show()
60 |
61 | if (transition) {
62 | that.$element[0].offsetWidth // force reflow
63 | }
64 |
65 | that.$element.addClass('in')
66 |
67 | transition ?
68 | that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) :
69 | that.$element.trigger('shown')
70 |
71 | })
72 | }
73 |
74 | , hide: function ( e ) {
75 | e && e.preventDefault()
76 |
77 | if (!this.isShown) return
78 |
79 | var that = this
80 | this.isShown = false
81 |
82 | $('body').removeClass('modal-open')
83 |
84 | escape.call(this)
85 |
86 | this.$element
87 | .trigger('hide')
88 | .removeClass('in')
89 |
90 | $.support.transition && this.$element.hasClass('fade') ?
91 | hideWithTransition.call(this) :
92 | hideModal.call(this)
93 | }
94 |
95 | }
96 |
97 |
98 | /* MODAL PRIVATE METHODS
99 | * ===================== */
100 |
101 | function hideWithTransition() {
102 | var that = this
103 | , timeout = setTimeout(function () {
104 | that.$element.off($.support.transition.end)
105 | hideModal.call(that)
106 | }, 500)
107 |
108 | this.$element.one($.support.transition.end, function () {
109 | clearTimeout(timeout)
110 | hideModal.call(that)
111 | })
112 | }
113 |
114 | function hideModal( that ) {
115 | this.$element
116 | .hide()
117 | .trigger('hidden')
118 |
119 | backdrop.call(this)
120 | }
121 |
122 | function backdrop( callback ) {
123 | var that = this
124 | , animate = this.$element.hasClass('fade') ? 'fade' : ''
125 |
126 | if (this.isShown && this.options.backdrop) {
127 | var doAnimate = $.support.transition && animate
128 |
129 | this.$backdrop = $('')
130 | .appendTo(document.body)
131 |
132 | if (this.options.backdrop != 'static') {
133 | this.$backdrop.click($.proxy(this.hide, this))
134 | }
135 |
136 | if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
137 |
138 | this.$backdrop.addClass('in')
139 |
140 | doAnimate ?
141 | this.$backdrop.one($.support.transition.end, callback) :
142 | callback()
143 |
144 | } else if (!this.isShown && this.$backdrop) {
145 | this.$backdrop.removeClass('in')
146 |
147 | $.support.transition && this.$element.hasClass('fade')?
148 | this.$backdrop.one($.support.transition.end, $.proxy(removeBackdrop, this)) :
149 | removeBackdrop.call(this)
150 |
151 | } else if (callback) {
152 | callback()
153 | }
154 | }
155 |
156 | function removeBackdrop() {
157 | this.$backdrop.remove()
158 | this.$backdrop = null
159 | }
160 |
161 | function escape() {
162 | var that = this
163 | if (this.isShown && this.options.keyboard) {
164 | $(document).on('keyup.dismiss.modal', function ( e ) {
165 | e.which == 27 && that.hide()
166 | })
167 | } else if (!this.isShown) {
168 | $(document).off('keyup.dismiss.modal')
169 | }
170 | }
171 |
172 |
173 | /* MODAL PLUGIN DEFINITION
174 | * ======================= */
175 |
176 | $.fn.modal = function ( option ) {
177 | return this.each(function () {
178 | var $this = $(this)
179 | , data = $this.data('modal')
180 | , options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option)
181 | if (!data) $this.data('modal', (data = new Modal(this, options)))
182 | if (typeof option == 'string') data[option]()
183 | else if (options.show) data.show()
184 | })
185 | }
186 |
187 | $.fn.modal.defaults = {
188 | backdrop: true
189 | , keyboard: true
190 | , show: true
191 | }
192 |
193 | $.fn.modal.Constructor = Modal
194 |
195 |
196 | /* MODAL DATA-API
197 | * ============== */
198 |
199 | $(function () {
200 | $('body').on('click.modal.data-api', '[data-toggle="modal"]', function ( e ) {
201 | var $this = $(this), href
202 | , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
203 | , option = $target.data('modal') ? 'toggle' : $.extend({}, $target.data(), $this.data())
204 |
205 | e.preventDefault()
206 | $target.modal(option)
207 | })
208 | })
209 |
210 | }( window.jQuery );
--------------------------------------------------------------------------------
/lib/bootstrap-typeahead.js:
--------------------------------------------------------------------------------
1 | /* =============================================================
2 | * bootstrap-typeahead.js v2.0.1
3 | * http://twitter.github.com/bootstrap/javascript.html#typeahead
4 | * =============================================================
5 | * Copyright 2012 Twitter, Inc.
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | * ============================================================ */
19 |
20 | !function( $ ){
21 |
22 | "use strict"
23 |
24 | var Typeahead = function ( element, options ) {
25 | this.$element = $(element)
26 | this.options = $.extend({}, $.fn.typeahead.defaults, options)
27 | this.matcher = this.options.matcher || this.matcher
28 | this.sorter = this.options.sorter || this.sorter
29 | this.highlighter = this.options.highlighter || this.highlighter
30 | this.$menu = $(this.options.menu).appendTo('body')
31 | this.source = this.options.source
32 | this.shown = false
33 | this.listen()
34 | }
35 |
36 | Typeahead.prototype = {
37 |
38 | constructor: Typeahead
39 |
40 | , select: function () {
41 | var val = this.$menu.find('.active').attr('data-value')
42 | this.$element.val(val)
43 | // hack!
44 | $("#filter-button").click();
45 | return this.hide()
46 | }
47 |
48 | , show: function () {
49 | var pos = $.extend({}, this.$element.offset(), {
50 | height: this.$element[0].offsetHeight
51 | })
52 |
53 | this.$menu.css({
54 | top: pos.top + pos.height
55 | , left: pos.left
56 | , "z-index": 10
57 | })
58 |
59 | this.$menu.show()
60 | this.shown = true
61 | return this
62 | }
63 |
64 | , hide: function () {
65 | this.$menu.hide()
66 | this.shown = false
67 | return this
68 | }
69 |
70 | , lookup: function (event) {
71 | var that = this
72 | , items
73 | , q
74 |
75 | this.query = this.$element.val()
76 |
77 | if (!this.query) {
78 | return this.shown ? this.hide() : this
79 | }
80 |
81 | items = $.grep(this.source, function (item) {
82 | if (that.matcher(item)) return item
83 | })
84 |
85 | items = this.sorter(items)
86 |
87 | if (!items.length) {
88 | return this.shown ? this.hide() : this
89 | }
90 |
91 | return this.render(items.slice(0, this.options.items)).show()
92 | }
93 |
94 | , matcher: function (item) {
95 | return ~item.toLowerCase().indexOf(this.query.toLowerCase())
96 | }
97 |
98 | , sorter: function (items) {
99 | var beginswith = []
100 | , caseSensitive = []
101 | , caseInsensitive = []
102 | , item
103 |
104 | while (item = items.shift()) {
105 | if (!item.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item)
106 | else if (~item.indexOf(this.query)) caseSensitive.push(item)
107 | else caseInsensitive.push(item)
108 | }
109 |
110 | return beginswith.concat(caseSensitive, caseInsensitive)
111 | }
112 |
113 | , highlighter: function (item) {
114 | return item.replace(new RegExp('(' + this.query + ')', 'ig'), function ($1, match) {
115 | return '' + match + ''
116 | })
117 | }
118 |
119 | , render: function (items) {
120 | var that = this
121 |
122 | items = $(items).map(function (i, item) {
123 | i = $(that.options.item).attr('data-value', item)
124 | i.find('a').html(that.highlighter(item))
125 | return i[0]
126 | })
127 |
128 | items.first().addClass('active')
129 | this.$menu.html(items)
130 | return this
131 | }
132 |
133 | , next: function (event) {
134 | var active = this.$menu.find('.active').removeClass('active')
135 | , next = active.next()
136 |
137 | if (!next.length) {
138 | next = $(this.$menu.find('li')[0])
139 | }
140 |
141 | next.addClass('active')
142 | }
143 |
144 | , prev: function (event) {
145 | var active = this.$menu.find('.active').removeClass('active')
146 | , prev = active.prev()
147 |
148 | if (!prev.length) {
149 | prev = this.$menu.find('li').last()
150 | }
151 |
152 | prev.addClass('active')
153 | }
154 |
155 | , listen: function () {
156 | this.$element
157 | .on('blur', $.proxy(this.blur, this))
158 | .on('keypress', $.proxy(this.keypress, this))
159 | .on('keyup', $.proxy(this.keyup, this))
160 |
161 | if ($.browser.webkit || $.browser.msie) {
162 | this.$element.on('keydown', $.proxy(this.keypress, this))
163 | }
164 |
165 | this.$menu
166 | .on('click', $.proxy(this.click, this))
167 | .on('mouseenter', 'li', $.proxy(this.mouseenter, this))
168 | }
169 |
170 | , keyup: function (e) {
171 | e.stopPropagation()
172 | e.preventDefault()
173 |
174 | switch(e.keyCode) {
175 | case 40: // down arrow
176 | case 38: // up arrow
177 | break
178 |
179 | case 9: // tab
180 | case 13: // enter
181 | if (!this.shown) return
182 | this.select()
183 | break
184 |
185 | case 27: // escape
186 | this.hide()
187 | break
188 |
189 | default:
190 | this.lookup()
191 | }
192 |
193 | }
194 |
195 | , keypress: function (e) {
196 | e.stopPropagation()
197 | if (!this.shown) return
198 |
199 | switch(e.keyCode) {
200 | case 9: // tab
201 | case 13: // enter
202 | case 27: // escape
203 | e.preventDefault()
204 | break
205 |
206 | case 38: // up arrow
207 | e.preventDefault()
208 | this.prev()
209 | break
210 |
211 | case 40: // down arrow
212 | e.preventDefault()
213 | this.next()
214 | break
215 | }
216 | }
217 |
218 | , blur: function (e) {
219 | var that = this
220 | e.stopPropagation()
221 | e.preventDefault()
222 | setTimeout(function () { that.hide() }, 150)
223 | }
224 |
225 | , click: function (e) {
226 | e.stopPropagation()
227 | e.preventDefault()
228 | this.select()
229 | }
230 |
231 | , mouseenter: function (e) {
232 | this.$menu.find('.active').removeClass('active')
233 | $(e.currentTarget).addClass('active')
234 | }
235 |
236 | }
237 |
238 |
239 | /* TYPEAHEAD PLUGIN DEFINITION
240 | * =========================== */
241 |
242 | $.fn.typeahead = function ( option ) {
243 | return this.each(function () {
244 | var $this = $(this)
245 | , data = $this.data('typeahead')
246 | , options = typeof option == 'object' && option
247 | if (!data) $this.data('typeahead', (data = new Typeahead(this, options)))
248 | if (typeof option == 'string') data[option]()
249 | })
250 | }
251 |
252 | $.fn.typeahead.defaults = {
253 | source: []
254 | , items: 8
255 | , menu: ''
256 | , item: ''
257 | }
258 |
259 | $.fn.typeahead.Constructor = Typeahead
260 |
261 |
262 | /* TYPEAHEAD DATA-API
263 | * ================== */
264 |
265 | $(function () {
266 | $('body').on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) {
267 | var $this = $(this)
268 | if ($this.data('typeahead')) return
269 | e.preventDefault()
270 | $this.typeahead($this.data())
271 | })
272 | })
273 |
274 | }( window.jQuery );
--------------------------------------------------------------------------------
/lib/jquery-ui/css/blitzer/images/ui-bg_diagonals-thick_75_f3d8d8_40x40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/lib/jquery-ui/css/blitzer/images/ui-bg_diagonals-thick_75_f3d8d8_40x40.png
--------------------------------------------------------------------------------
/lib/jquery-ui/css/blitzer/images/ui-bg_dots-small_65_a6a6a6_2x2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/lib/jquery-ui/css/blitzer/images/ui-bg_dots-small_65_a6a6a6_2x2.png
--------------------------------------------------------------------------------
/lib/jquery-ui/css/blitzer/images/ui-bg_flat_0_333333_40x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/lib/jquery-ui/css/blitzer/images/ui-bg_flat_0_333333_40x100.png
--------------------------------------------------------------------------------
/lib/jquery-ui/css/blitzer/images/ui-bg_flat_65_ffffff_40x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/lib/jquery-ui/css/blitzer/images/ui-bg_flat_65_ffffff_40x100.png
--------------------------------------------------------------------------------
/lib/jquery-ui/css/blitzer/images/ui-bg_flat_75_ffffff_40x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/lib/jquery-ui/css/blitzer/images/ui-bg_flat_75_ffffff_40x100.png
--------------------------------------------------------------------------------
/lib/jquery-ui/css/blitzer/images/ui-bg_glass_55_fbf8ee_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/lib/jquery-ui/css/blitzer/images/ui-bg_glass_55_fbf8ee_1x400.png
--------------------------------------------------------------------------------
/lib/jquery-ui/css/blitzer/images/ui-bg_highlight-hard_100_eeeeee_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/lib/jquery-ui/css/blitzer/images/ui-bg_highlight-hard_100_eeeeee_1x100.png
--------------------------------------------------------------------------------
/lib/jquery-ui/css/blitzer/images/ui-bg_highlight-hard_100_f6f6f6_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/lib/jquery-ui/css/blitzer/images/ui-bg_highlight-hard_100_f6f6f6_1x100.png
--------------------------------------------------------------------------------
/lib/jquery-ui/css/blitzer/images/ui-bg_highlight-soft_15_cc0000_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/lib/jquery-ui/css/blitzer/images/ui-bg_highlight-soft_15_cc0000_1x100.png
--------------------------------------------------------------------------------
/lib/jquery-ui/css/blitzer/images/ui-icons_004276_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/lib/jquery-ui/css/blitzer/images/ui-icons_004276_256x240.png
--------------------------------------------------------------------------------
/lib/jquery-ui/css/blitzer/images/ui-icons_cc0000_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/lib/jquery-ui/css/blitzer/images/ui-icons_cc0000_256x240.png
--------------------------------------------------------------------------------
/lib/jquery-ui/css/blitzer/images/ui-icons_ffffff_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json574/commune-events-scrap/7635dc41e6fb3e773920df4a5475e15f0217de9b/lib/jquery-ui/css/blitzer/images/ui-icons_ffffff_256x240.png
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "commune event map",
3 | "lockfileVersion": 3,
4 | "requires": true,
5 | "packages": {}
6 | }
7 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "story-plan-organizer",
3 | "version": "1.0.0",
4 | "description": "Story plan organizer.",
5 | "main": "index.js",
6 | "scripts": {
7 | "build": "tsc --build",
8 | "clean": "tsc --build --clean",
9 | "lint": "npx eslint --fix .",
10 | "test": "echo \"Error: no test specified\" && exit 1"
11 | },
12 | "author": "",
13 | "license": "ISC",
14 | "devDependencies": {
15 | "@eslint/js": "^9.1.1",
16 | "eslint": "^8.57.0",
17 | "eslint-config-prettier": "^9.1.0",
18 | "eslint-plugin-prettier": "^5.1.3",
19 | "prettier": "^3.2.5",
20 | "typescript": "^5.4.5",
21 | "typescript-eslint": "^7.7.1"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/definition.ts:
--------------------------------------------------------------------------------
1 | import { UUID } from './uuid.js';
2 |
3 | export enum NodeType {
4 | Character = 'Character',
5 | Location = 'Location',
6 | Organization = 'Organization',
7 | Event = 'Event',
8 | Story = 'Story',
9 | Lore = 'Lore',
10 | }
11 |
12 | export type Point = {
13 | x: number;
14 | y: number;
15 | };
16 |
17 | export type Color_Hex = `#${string}`;
18 |
19 | export type Node = {
20 | id: UUID;
21 | location: Point;
22 | type: NodeType;
23 | name: string;
24 | color: Color_Hex;
25 | };
26 |
27 | export type Character = Node & {
28 | imageSrc: string;
29 | personality: string;
30 | quirk: string;
31 | like: string;
32 | dislike: string;
33 | strength: string;
34 | weakness: string;
35 | flaw: string;
36 | motivation: string;
37 | other: string;
38 | };
39 |
40 | export type Location = Node & {
41 | imageSrc: string;
42 | description: string;
43 | };
44 |
45 | export type Organization = Node & {
46 | objective: string;
47 | detail: string;
48 | };
49 |
50 | export type Event = Node & {
51 | detail: string;
52 | };
53 |
54 | export type Story = Node & {
55 | description: string;
56 | };
57 |
58 | export type Lore = Node & {
59 | detail: string;
60 | };
61 |
62 | export type NodePositionResults = {
63 | top: number;
64 | bottom: number;
65 | left: number;
66 | right: number;
67 | topLeft: Point;
68 | topRight: Point;
69 | bottomLeft: Point;
70 | bottomRight: Point;
71 | };
72 |
73 | export type Link = {
74 | nodeFromId: UUID;
75 | nodeToId: UUID;
76 | };
77 |
78 | export type Dto = {
79 | nodes: Node[];
80 | links: Link[];
81 | };
82 |
83 | export type State = {
84 | nodes: Node[];
85 | nodesCached: HTMLDivElement[];
86 | links: Link[];
87 | linesCached: HTMLDivElement[];
88 | selectedNodeElement: HTMLDivElement | null;
89 | createOngoingLinkId: UUID | null;
90 | deleting: boolean;
91 | };
92 |
93 | export const CALCULATION_INCREMENT: number = 20;
94 |
--------------------------------------------------------------------------------
/src/link.ts:
--------------------------------------------------------------------------------
1 | import { CALCULATION_INCREMENT, Link, Node, NodePositionResults, Point, State } from './definition.js';
2 | import { get_node, get_node_element } from './node.js';
3 | import { refresh } from './story-plan-organizer.js';
4 | import { UUID } from './uuid.js';
5 |
6 | const does_link_exist = (nodeId1: UUID, nodeId2: UUID, links: Link[]): boolean => {
7 | for (const link of links) {
8 | if (
9 | (nodeId1 === link.nodeFromId && nodeId2 === link.nodeToId) ||
10 | (nodeId2 === link.nodeFromId && nodeId1 === link.nodeToId)
11 | ) {
12 | return true;
13 | }
14 | }
15 | return false;
16 | };
17 |
18 | const calculate_element_positions = (node: Node): NodePositionResults | undefined => {
19 | const element = get_node_element(node.id);
20 | if (element) {
21 | const top = node.location.y;
22 | const bottom = node.location.y + element.offsetHeight;
23 | const left = node.location.x;
24 | const right = node.location.x + element.offsetWidth;
25 |
26 | const topLeft = { x: node.location.x, y: node.location.y };
27 | const topRight = { x: node.location.x + element.offsetWidth, y: node.location.y };
28 | const bottomLeft = { x: node.location.x, y: node.location.y + element.offsetHeight };
29 | const bottomRight = { x: node.location.x + element.offsetWidth, y: node.location.y + element.offsetHeight };
30 |
31 | return { top, bottom, left, right, topLeft, topRight, bottomLeft, bottomRight };
32 | } else {
33 | return undefined;
34 | }
35 | };
36 |
37 | const calculate_distance = (point1: Point, point2: Point): number => {
38 | const a = point1.x - point2.x;
39 | const b = point1.y - point2.y;
40 | return Math.sqrt(a * a + b * b);
41 | };
42 |
43 | const calculate_shortest_distance_2 = (point: Point, node2: Node): { point: Point; distance: number } => {
44 | const currentShortestPoint = { point: { x: 0, y: 0 }, distance: 999999999999 };
45 |
46 | const nodePositions2: NodePositionResults | undefined = calculate_element_positions(node2);
47 | if (nodePositions2) {
48 | // 1. Sweep TopLeft to TopRight
49 | for (let x = nodePositions2.left; x < nodePositions2.right; x = x + CALCULATION_INCREMENT) {
50 | const tempPoint = { x: x, y: nodePositions2.top };
51 | const distance = calculate_distance(point, tempPoint);
52 | if (distance < currentShortestPoint.distance) {
53 | currentShortestPoint.point = tempPoint;
54 | currentShortestPoint.distance = distance;
55 | }
56 | }
57 | // 2. Sweep TopRight to BottomRight
58 | for (let y = nodePositions2.top; y < nodePositions2.bottom; y = y + CALCULATION_INCREMENT) {
59 | const tempPoint = { x: nodePositions2.right, y: y };
60 | const distance = calculate_distance(point, tempPoint);
61 | if (distance < currentShortestPoint.distance) {
62 | currentShortestPoint.point = tempPoint;
63 | currentShortestPoint.distance = distance;
64 | }
65 | }
66 | // 3. Sweep BottomLeft to BottomRight
67 | for (let x = nodePositions2.left; x < nodePositions2.right; x = x + CALCULATION_INCREMENT) {
68 | const tempPoint = { x: x, y: nodePositions2.bottom };
69 | const distance = calculate_distance(point, tempPoint);
70 | if (distance < currentShortestPoint.distance) {
71 | currentShortestPoint.point = tempPoint;
72 | currentShortestPoint.distance = distance;
73 | }
74 | }
75 | // 4. Sweep TopLeft to BottomLeft
76 | for (let y = nodePositions2.top; y < nodePositions2.bottom; y = y + CALCULATION_INCREMENT) {
77 | const tempPoint = { x: nodePositions2.left, y: y };
78 | const distance = calculate_distance(point, tempPoint);
79 | if (distance < currentShortestPoint.distance) {
80 | currentShortestPoint.point = tempPoint;
81 | currentShortestPoint.distance = distance;
82 | }
83 | }
84 | }
85 |
86 | return currentShortestPoint;
87 | };
88 |
89 | const calculate_shortest_distance = (node1: Node, node2: Node): { point1: Point; point2: Point } => {
90 | const currentShortestPoints = { point1: { x: 0, y: 0 }, point2: { x: 0, y: 0 }, distance: 999999999999 };
91 |
92 | const nodePositions1: NodePositionResults | undefined = calculate_element_positions(node1);
93 | if (nodePositions1) {
94 | // 1. Sweep TopLeft to TopRight
95 | for (let x = nodePositions1.left; x < nodePositions1.right; x = x + CALCULATION_INCREMENT) {
96 | const tempPoint = { x: x, y: nodePositions1.top };
97 | const result: { point: Point; distance: number } = calculate_shortest_distance_2(tempPoint, node2);
98 | if (result.distance < currentShortestPoints.distance) {
99 | currentShortestPoints.point1 = tempPoint;
100 | currentShortestPoints.point2 = result.point;
101 | currentShortestPoints.distance = result.distance;
102 | }
103 | }
104 | // 2. Sweep TopRight to BottomRight
105 | for (let y = nodePositions1.top; y < nodePositions1.bottom; y = y + CALCULATION_INCREMENT) {
106 | const tempPoint = { x: nodePositions1.right, y: y };
107 | const result: { point: Point; distance: number } = calculate_shortest_distance_2(tempPoint, node2);
108 | if (result.distance < currentShortestPoints.distance) {
109 | currentShortestPoints.point1 = tempPoint;
110 | currentShortestPoints.point2 = result.point;
111 | currentShortestPoints.distance = result.distance;
112 | }
113 | }
114 | // 3. Sweep BottomLeft to BottomRight
115 | for (let x = nodePositions1.left; x < nodePositions1.right; x = x + CALCULATION_INCREMENT) {
116 | const tempPoint = { x: x, y: nodePositions1.bottom };
117 | const result: { point: Point; distance: number } = calculate_shortest_distance_2(tempPoint, node2);
118 | if (result.distance < currentShortestPoints.distance) {
119 | currentShortestPoints.point1 = tempPoint;
120 | currentShortestPoints.point2 = result.point;
121 | currentShortestPoints.distance = result.distance;
122 | }
123 | }
124 | // 4. Sweep TopLeft to BottomLeft
125 | for (let y = nodePositions1.top; y < nodePositions1.bottom; y = y + CALCULATION_INCREMENT) {
126 | const tempPoint = { x: nodePositions1.left, y: y };
127 | const result: { point: Point; distance: number } = calculate_shortest_distance_2(tempPoint, node2);
128 | if (result.distance < currentShortestPoints.distance) {
129 | currentShortestPoints.point1 = tempPoint;
130 | currentShortestPoints.point2 = result.point;
131 | currentShortestPoints.distance = result.distance;
132 | }
133 | }
134 | }
135 |
136 | return { point1: currentShortestPoints.point1, point2: currentShortestPoints.point2 };
137 | };
138 |
139 | const create_line = (nodeId1: UUID, nodeId2: UUID, state: State): void => {
140 | const node1 = get_node(nodeId1, state.nodes);
141 | const node2 = get_node(nodeId2, state.nodes);
142 | if (node1 && node2) {
143 | const newElement: HTMLDivElement = document.createElement('div');
144 | const newLine: HTMLDivElement = document.body.appendChild(newElement);
145 | newLine.className = 'line';
146 |
147 | const points: { point1: Point; point2: Point } = calculate_shortest_distance(node1, node2);
148 | const gradientId = nodeId1 + '_' + nodeId2;
149 | newLine.innerHTML = `
150 |
159 | `;
160 |
161 | state.linesCached.push(newElement);
162 |
163 | const lineElement = newLine.getElementsByTagName('line')[0];
164 | if (lineElement) {
165 | const nodeElement1 = get_node_element(nodeId1);
166 | const nodeElement2 = get_node_element(nodeId2);
167 | if (state.selectedNodeElement) {
168 | if (nodeElement1 === state.selectedNodeElement || nodeElement2 === state.selectedNodeElement) {
169 | lineElement.classList.add('line-highlighted');
170 | lineElement.classList.remove('line-unhighlighted');
171 | } else {
172 | lineElement.classList.remove('line-highlighted');
173 | lineElement.classList.add('line-unhighlighted');
174 | }
175 | } else {
176 | lineElement.classList.remove('line-highlighted');
177 | lineElement.classList.remove('line-unhighlighted');
178 | }
179 |
180 | lineElement.addEventListener('click', (): void => {
181 | if (state.deleting) {
182 | delete_link(nodeId1, nodeId2, state);
183 | }
184 | });
185 | }
186 | }
187 | };
188 |
189 | const delete_link = (nodeId1: UUID, nodeId2: UUID, state: State): void => {
190 | for (let i = state.links.length - 1; i >= 0; i--) {
191 | const link: Link = state.links[i];
192 | if (
193 | (nodeId1 === link.nodeFromId && nodeId2 === link.nodeToId) ||
194 | (nodeId2 === link.nodeFromId && nodeId1 === link.nodeToId)
195 | ) {
196 | state.links.splice(i, 1);
197 | }
198 | }
199 | refresh(state);
200 | };
201 |
202 | export const redraw_lines = (state: State): void => {
203 | for (const line of state.linesCached) {
204 | line.remove();
205 | }
206 | state.linesCached = [];
207 |
208 | for (const link of state.links) {
209 | create_line(link.nodeFromId, link.nodeToId, state);
210 | }
211 | };
212 |
213 | export const add_link = (nodeId1: UUID, nodeId2: UUID, state: State): void => {
214 | if (nodeId1 && nodeId2 && !does_link_exist(nodeId1, nodeId2, state.links)) {
215 | state.links.push({ nodeFromId: nodeId1, nodeToId: nodeId2 });
216 | refresh(state);
217 | }
218 | };
219 |
--------------------------------------------------------------------------------
/src/node.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Character,
3 | Color_Hex,
4 | Event,
5 | Location,
6 | Lore,
7 | Node,
8 | NodeType,
9 | Organization,
10 | Point,
11 |
12 | State,
13 | Story,
14 | } from './definition.js';
15 | import { add_link, redraw_lines } from './link.js';
16 | import { refresh, validate } from './story-plan-organizer.js';
17 | import { randomUUID, UUID } from './uuid.js';
18 |
19 | export const get_node = (id: UUID, nodes: Node[]): Node | undefined => {
20 | let foundNode;
21 | for (const node of nodes) {
22 | if (node.id === id) {
23 | foundNode = node;
24 | break;
25 | }
26 | }
27 | return foundNode;
28 | };
29 |
30 | export const get_node_element = (id: UUID): HTMLDivElement | null => {
31 | const htmlElement: HTMLElement | null = document.getElementById(id);
32 | return htmlElement ? (htmlElement as HTMLDivElement) : null;
33 | };
34 |
35 | export const add_node = (location: Point, type: NodeType, state: State): void => {
36 | const base: Node = {
37 | id: randomUUID(),
38 | location,
39 | type,
40 | name: '',
41 | color: '#FFFFFF',
42 | };
43 |
44 | let node: Node | undefined;
45 | switch (type) {
46 | case NodeType.Character:
47 | {
48 | node = {
49 | ...base,
50 | imageSrc: '',
51 | personality: '',
52 | quirk: '',
53 | like: '',
54 | dislike: '',
55 | strength: '',
56 | weakness: '',
57 | flaw: '',
58 | motivation: '',
59 | other: '',
60 | } as Character;
61 | }
62 | break;
63 | case NodeType.Location:
64 | {
65 | node = {
66 | ...base,
67 | imageSrc: '',
68 | description: '',
69 | } as Location;
70 | }
71 | break;
72 | case NodeType.Organization:
73 | {
74 | node = {
75 | ...base,
76 | objective: '',
77 | detail: '',
78 | } as Organization;
79 | }
80 | break;
81 | case NodeType.Event:
82 | {
83 | node = {
84 | ...base,
85 | detail: '',
86 | } as Event;
87 | }
88 | break;
89 | case NodeType.Story:
90 | {
91 | node = {
92 | ...base,
93 | description: '',
94 | } as Story;
95 | }
96 | break;
97 | case NodeType.Lore:
98 | {
99 | node = {
100 | ...base,
101 | detail: '',
102 | } as Lore;
103 | }
104 | break;
105 | default:
106 | break;
107 | }
108 |
109 | if (node) {
110 | state.nodes.push(node);
111 | validate(state);
112 | }
113 | };
114 |
115 | export const get_icon = (type: NodeType): { color: Color_Hex; backgroundColor: Color_Hex; text: string } => {
116 | let color: Color_Hex;
117 | const backgroundColor: Color_Hex = '#DEF4FF';
118 | switch (type) {
119 | case NodeType.Character:
120 | {
121 | color = '#0000FF';
122 | }
123 | break;
124 | case NodeType.Location:
125 | {
126 | color = '#1BD900';
127 | }
128 | break;
129 | case NodeType.Organization:
130 | {
131 | color = '#FFA500';
132 | }
133 | break;
134 | case NodeType.Event:
135 | {
136 | color = '#FF0000';
137 | }
138 | break;
139 | case NodeType.Story:
140 | {
141 | color = '#C700C7';
142 | }
143 | break;
144 | case NodeType.Lore:
145 | {
146 | color = '#008080';
147 | }
148 | break;
149 | default:
150 | {
151 | color = '#FFFFFF';
152 | }
153 | break;
154 | }
155 |
156 | const text: string = (
157 | document.getElementById('create-node-' + NodeType[type])?.getElementsByClassName('material-icons')[0] as HTMLElement
158 | ).innerText;
159 |
160 | return { color, backgroundColor, text };
161 | };
162 |
163 | export const create_node_element = (node: Node, state: State): void => {
164 | const newElement: HTMLDivElement = document.createElement('div');
165 | const newNodeElement: HTMLDivElement = document.body.appendChild(newElement);
166 | newNodeElement.id = node.id;
167 | newNodeElement.className = 'node';
168 | newNodeElement.style.top = node.location.y + 'px';
169 | newNodeElement.style.left = node.location.x + 'px';
170 | newNodeElement.style.borderColor = node.color;
171 |
172 | const icon = get_icon(node.type);
173 | newNodeElement.innerHTML = `
174 |
182 | `;
183 |
184 | switch (node.type) {
185 | case NodeType.Character:
186 | {
187 | if ((node as Character).imageSrc) {
188 | newNodeElement.innerHTML += `
189 |
190 | `;
191 | }
192 | newNodeElement.innerHTML += `
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 | `;
224 | const textarea_personality = newNodeElement.getElementsByTagName('textarea')[0];
225 | textarea_personality.addEventListener(
226 | 'input',
227 | (): void => {
228 | (node as Character).personality = textarea_personality.value;
229 | },
230 | false,
231 | );
232 | const textarea_quirk = newNodeElement.getElementsByTagName('textarea')[1];
233 | textarea_quirk.addEventListener(
234 | 'input',
235 | (): void => {
236 | (node as Character).quirk = textarea_quirk.value;
237 | },
238 | false,
239 | );
240 | const textarea_like = newNodeElement.getElementsByTagName('textarea')[2];
241 | textarea_like.addEventListener(
242 | 'input',
243 | (): void => {
244 | (node as Character).like = textarea_like.value;
245 | },
246 | false,
247 | );
248 | const textarea_dislike = newNodeElement.getElementsByTagName('textarea')[3];
249 | textarea_dislike.addEventListener(
250 | 'input',
251 | (): void => {
252 | (node as Character).dislike = textarea_dislike.value;
253 | },
254 | false,
255 | );
256 | const textarea_strength = newNodeElement.getElementsByTagName('textarea')[4];
257 | textarea_strength.addEventListener(
258 | 'input',
259 | (): void => {
260 | (node as Character).strength = textarea_strength.value;
261 | },
262 | false,
263 | );
264 | const textarea_weakness = newNodeElement.getElementsByTagName('textarea')[5];
265 | textarea_weakness.addEventListener(
266 | 'input',
267 | (): void => {
268 | (node as Character).weakness = textarea_weakness.value;
269 | },
270 | false,
271 | );
272 | const textarea_flaw = newNodeElement.getElementsByTagName('textarea')[6];
273 | textarea_flaw.addEventListener(
274 | 'input',
275 | (): void => {
276 | (node as Character).flaw = textarea_flaw.value;
277 | },
278 | false,
279 | );
280 | const textarea_motivation = newNodeElement.getElementsByTagName('textarea')[7];
281 | textarea_motivation.addEventListener(
282 | 'input',
283 | (): void => {
284 | (node as Character).motivation = textarea_motivation.value;
285 | },
286 | false,
287 | );
288 | const textarea_other = newNodeElement.getElementsByTagName('textarea')[8];
289 | textarea_other.addEventListener(
290 | 'input',
291 | (): void => {
292 | (node as Character).other = textarea_other.value;
293 | },
294 | false,
295 | );
296 | }
297 | break;
298 | case NodeType.Location:
299 | {
300 | if ((node as Location).imageSrc) {
301 | newNodeElement.innerHTML += `
302 |
303 | `;
304 | }
305 | newNodeElement.innerHTML += `
306 |
307 |
308 |
309 |
310 | `;
311 | const textarea_description = newNodeElement.getElementsByTagName('textarea')[0];
312 | textarea_description.addEventListener(
313 | 'input',
314 | (): void => {
315 | (node as Location).description = textarea_description.value;
316 | },
317 | false,
318 | );
319 | }
320 | break;
321 | case NodeType.Organization:
322 | {
323 | newNodeElement.innerHTML += `
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 | `;
333 | const textarea_objective = newNodeElement.getElementsByTagName('textarea')[0];
334 | textarea_objective.addEventListener(
335 | 'input',
336 | (): void => {
337 | (node as Organization).objective = textarea_objective.value;
338 | },
339 | false,
340 | );
341 | const textarea_detail = newNodeElement.getElementsByTagName('textarea')[1];
342 | textarea_detail.addEventListener(
343 | 'input',
344 | (): void => {
345 | (node as Organization).detail = textarea_detail.value;
346 | },
347 | false,
348 | );
349 | }
350 | break;
351 | case NodeType.Event:
352 | {
353 | newNodeElement.innerHTML += `
354 |
355 |
356 |
357 |
358 | `;
359 | const textarea_detail = newNodeElement.getElementsByTagName('textarea')[0];
360 | textarea_detail.addEventListener(
361 | 'input',
362 | (): void => {
363 | (node as Event).detail = textarea_detail.value;
364 | },
365 | false,
366 | );
367 | }
368 | break;
369 | case NodeType.Story:
370 | {
371 | newNodeElement.innerHTML += `
372 |
373 |
374 |
375 |
376 | `;
377 | const textarea_description = newNodeElement.getElementsByTagName('textarea')[0];
378 | textarea_description.addEventListener(
379 | 'input',
380 | (): void => {
381 | (node as Story).description = textarea_description.value;
382 | },
383 | false,
384 | );
385 | }
386 | break;
387 | case NodeType.Lore:
388 | {
389 | newNodeElement.innerHTML += `
390 |
391 |
392 |
393 |
394 | `;
395 | const textarea_detail = newNodeElement.getElementsByTagName('textarea')[0];
396 | textarea_detail.addEventListener(
397 | 'input',
398 | (): void => {
399 | (node as Lore).detail = textarea_detail.value;
400 | },
401 | false,
402 | );
403 | }
404 | break;
405 | default:
406 | break;
407 | }
408 |
409 | // addEventListeners need to be after all the += innerHTML
410 | const input_name = newNodeElement.getElementsByClassName('node-name')[0] as HTMLInputElement;
411 | input_name.addEventListener(
412 | 'input',
413 | (): void => {
414 | node.name = input_name.value;
415 | },
416 | false,
417 | );
418 |
419 | const input_color = newNodeElement.getElementsByClassName('node-color')[0] as HTMLInputElement;
420 | input_color.addEventListener(
421 | 'input',
422 | (): void => {
423 | node.color = input_color.value as Color_Hex;
424 | newNodeElement.style.borderColor = node.color;
425 | redraw_lines(state);
426 | },
427 | false,
428 | );
429 |
430 | setup_accordions(newNodeElement, state);
431 |
432 | drag_node_element(newElement, state);
433 |
434 | state.nodesCached.push(newElement);
435 | };
436 |
437 | const setup_accordions = (nodeElement: HTMLDivElement, state: State): void => {
438 | const accordions = nodeElement.getElementsByClassName('accordion');
439 | for (let i = 0; i < accordions.length; i++) {
440 | accordions[i].addEventListener('click', (): void => {
441 | accordions[i].classList.toggle('active');
442 | const panel = accordions[i].nextElementSibling as HTMLDivElement;
443 | if (panel) {
444 | if (panel.style.maxHeight === '0px') {
445 | panel.style.maxHeight = '100%';
446 | } else {
447 | panel.style.maxHeight = '0px';
448 | }
449 | }
450 |
451 | const textareas = panel.getElementsByTagName('textarea');
452 | for (let i = 0; i < textareas.length; i++) {
453 | const textarea = textareas[i];
454 | textarea.setAttribute(
455 | 'style',
456 | textarea.getAttribute('style') + 'height:' + textarea.scrollHeight + 'px; overflow-y:hidden;',
457 | );
458 | textarea.addEventListener(
459 | 'input',
460 | (): void => {
461 | textarea.style.height = 'auto';
462 | textarea.style.height = textarea.scrollHeight + 'px';
463 | },
464 | false,
465 | );
466 | }
467 |
468 | redraw_lines(state);
469 | });
470 | }
471 | };
472 |
473 | const drag_node_element = (element: HTMLDivElement, state: State): void => {
474 | let pos1: number = 0;
475 | let pos2: number = 0;
476 | let pos3: number = 0;
477 | let pos4: number = 0;
478 |
479 | const moveElement: HTMLDivElement = element.getElementsByClassName('move')[0] as HTMLDivElement;
480 | moveElement.onmousedown = dragMouseDown;
481 | moveElement.addEventListener('mouseup', (event: MouseEvent): void => {
482 | if (event.button === 2) {
483 | // Right mouse button
484 | if (element.id && state.createOngoingLinkId) {
485 | add_link(element.id as UUID, state.createOngoingLinkId, state);
486 | }
487 | state.createOngoingLinkId = null;
488 | }
489 | });
490 |
491 | function dragMouseDown(event: MouseEvent): void {
492 | event = event || window.event;
493 | event.preventDefault();
494 |
495 | if (event.button === 0) {
496 | // Left mouse button
497 | if (state.deleting) {
498 | delete_node(element, state);
499 | return;
500 | }
501 |
502 | if (element !== state.selectedNodeElement) {
503 | state.selectedNodeElement = element;
504 | }
505 | refresh(state);
506 |
507 | pos3 = event.clientX;
508 | pos4 = event.clientY;
509 | document.onmouseup = closeDragElement;
510 |
511 | document.onmousemove = elementDrag;
512 | } else if (event.button === 2) {
513 | // Right mouse button
514 | state.createOngoingLinkId = element.id as UUID;
515 | }
516 | }
517 |
518 | function elementDrag(event: MouseEvent): void {
519 | event = event || window.event;
520 | event.preventDefault();
521 |
522 | pos1 = pos3 - event.clientX;
523 | pos2 = pos4 - event.clientY;
524 | pos3 = event.clientX;
525 | pos4 = event.clientY;
526 |
527 | const node: Node | undefined = get_node(element.id as UUID, state.nodes);
528 | if (node) {
529 | node.location.x = element.offsetLeft - pos1;
530 | node.location.y = element.offsetTop - pos2;
531 |
532 | element.style.top = node.location.y + 'px';
533 | element.style.left = node.location.x + 'px';
534 |
535 | redraw_lines(state);
536 | }
537 | }
538 |
539 | function closeDragElement(): void {
540 | document.onmouseup = null;
541 | document.onmousemove = null;
542 | }
543 | };
544 |
545 | const delete_node = (nodeElement: HTMLDivElement, state: State): void => {
546 | if (nodeElement === state.selectedNodeElement) {
547 | state.selectedNodeElement = null;
548 | }
549 | const nodeFound: Node | undefined = get_node(nodeElement.id as UUID, state.nodes);
550 | if (nodeFound) {
551 | const index = state.nodes.indexOf(nodeFound);
552 | if (index !== -1) {
553 | state.nodes.splice(index, 1);
554 | }
555 | }
556 | validate(state);
557 | };
558 |
--------------------------------------------------------------------------------
/src/story-plan-organizer.ts:
--------------------------------------------------------------------------------
1 | import { Dto, NodeType, State } from './definition.js';
2 | import { redraw_lines } from './link.js';
3 | import { add_node, create_node_element, get_icon, get_node, get_node_element } from './node.js';
4 | import { UUID } from './uuid.js';
5 |
6 | // Does not handle refreshing, just validating
7 | export const validate = (state: State): void => {
8 | // Validate node elements
9 | for (const node of state.nodes) {
10 | const nodeElement = get_node_element(node.id);
11 | if (!nodeElement) {
12 | create_node_element(node, state);
13 | }
14 | }
15 | for (let i = state.nodesCached.length - 1; i >= 0; i--) {
16 | const nodeElement = state.nodesCached[i];
17 | const node = get_node(nodeElement.id as UUID, state.nodes);
18 | if (!node) {
19 | const index = state.nodesCached.indexOf(nodeElement);
20 | if (index !== -1) {
21 | state.nodesCached.splice(index, 1);
22 | }
23 | nodeElement.remove();
24 | }
25 | }
26 |
27 | // Validate links
28 | for (let i = state.links.length - 1; i >= 0; i--) {
29 | const link = state.links[i];
30 |
31 | const validNode1 = get_node(link.nodeFromId, state.nodes) ? true : false;
32 | const validNode2 = get_node(link.nodeToId, state.nodes) ? true : false;
33 |
34 | if (!validNode1 || !validNode2) {
35 | state.links.splice(i, 1);
36 | }
37 | }
38 |
39 | // Validate highlights and redraw lines
40 | refresh(state);
41 | };
42 |
43 | export const refresh = (state: State): void => {
44 | for (const nodeElement of state.nodesCached) {
45 | if (state.selectedNodeElement) {
46 | if (nodeElement === state.selectedNodeElement) {
47 | state.selectedNodeElement.classList.add('node-highlighted');
48 | state.selectedNodeElement.classList.remove('node-unhighlighted');
49 | } else {
50 | nodeElement.classList.remove('node-highlighted');
51 | nodeElement.classList.add('node-unhighlighted');
52 | }
53 | } else {
54 | nodeElement.classList.remove('node-highlighted');
55 | nodeElement.classList.remove('node-unhighlighted');
56 | }
57 | }
58 |
59 | if (state.selectedNodeElement) {
60 | const connectedNodeIds: UUID[] = [];
61 | for (const link of state.links) {
62 | if (link.nodeFromId === state.selectedNodeElement.id) {
63 | connectedNodeIds.push(link.nodeToId);
64 | } else if (link.nodeToId === state.selectedNodeElement.id) {
65 | connectedNodeIds.push(link.nodeFromId);
66 | }
67 | }
68 | for (const nodeId of connectedNodeIds) {
69 | const nodeElement = get_node_element(nodeId);
70 | if (nodeElement) {
71 | nodeElement.classList.add('node-highlighted');
72 | nodeElement.classList.remove('node-unhighlighted');
73 | }
74 | }
75 | }
76 |
77 | for (const node of state.nodes) {
78 | if (node.location.x < 0) {
79 | node.location.x = 0;
80 | const nodeElement: HTMLDivElement | null = get_node_element(node.id);
81 | if (nodeElement) {
82 | nodeElement.style.left = node.location.x.toString() + 'px';
83 | }
84 | }
85 | if (node.location.y < 110) {
86 | node.location.y = 110;
87 | const nodeElement: HTMLDivElement | null = get_node_element(node.id);
88 | if (nodeElement) {
89 | nodeElement.style.top = node.location.y.toString() + 'px';
90 | }
91 | }
92 | }
93 |
94 | redraw_lines(state);
95 | };
96 |
97 | const state: State = {
98 | nodes: [],
99 | nodesCached: [],
100 | links: [],
101 | linesCached: [],
102 | selectedNodeElement: null,
103 | createOngoingLinkId: null,
104 | deleting: false,
105 | };
106 |
107 | window.onbeforeunload = function (event: BeforeUnloadEvent) {
108 | event.preventDefault();
109 | };
110 | document.addEventListener('contextmenu', (event: MouseEvent): void => event.preventDefault());
111 | window.addEventListener('keydown', (event: KeyboardEvent): void => keydownResponse(event, state), false);
112 | window.addEventListener('keyup', (event: KeyboardEvent): void => keyupResponse(event, state), false);
113 |
114 | function keydownResponse(event: KeyboardEvent, state: State): void {
115 | if (event.key === 'Escape') {
116 | state.selectedNodeElement = null;
117 | refresh(state);
118 | }
119 | if (event.key === 'd') {
120 | state.deleting = true;
121 | }
122 | }
123 |
124 | function keyupResponse(event: KeyboardEvent, state: State): void {
125 | if (event.key === 'd') {
126 | state.deleting = false;
127 | }
128 | }
129 |
130 | // Loading Toolbar create node button icon colors
131 | for (const nodeType of [
132 | NodeType.Character,
133 | NodeType.Location,
134 | NodeType.Organization,
135 | NodeType.Event,
136 | NodeType.Story,
137 | NodeType.Lore,
138 | ]) {
139 | const button_create = document.getElementById('create-node-' + NodeType[nodeType]);
140 | button_create?.addEventListener('click', (event: MouseEvent): void => {
141 | add_node({ x: event.pageX, y: event.pageY + 100 }, nodeType, state);
142 | });
143 | (button_create?.firstElementChild as HTMLElement).style.color = get_icon(nodeType).color;
144 | }
145 |
146 | // Export
147 | const download = (fileName: string, text: string): void => {
148 | const element = document.createElement('a');
149 | element.setAttribute('href', 'data:application/json;charset=utf-8,' + encodeURIComponent(text));
150 | element.setAttribute('download', fileName);
151 | element.style.display = 'none';
152 | document.body.appendChild(element);
153 | element.click();
154 | document.body.removeChild(element);
155 | };
156 |
157 | document.getElementById('export')?.addEventListener('click', (): void => {
158 | console.log(state);
159 |
160 | const fileName: string = 'story.json';
161 | const dto: Dto = { nodes: state.nodes, links: state.links };
162 | const fileContent: string = JSON.stringify(dto, null, 2);
163 | download(fileName, fileContent);
164 | });
165 |
166 | // Import
167 | const validJson = (json: string): boolean => {
168 | try {
169 | JSON.parse(json);
170 | } catch (e) {
171 | return false;
172 | }
173 | return true;
174 | };
175 |
176 | const load = (dto: Dto, state: State): void => {
177 | reset(state);
178 |
179 | state.nodes = dto.nodes;
180 | state.links = dto.links;
181 |
182 | validate(state);
183 | };
184 |
185 | const reset = (state: State): void => {
186 | state.nodes = [];
187 | for (const nodeElement of state.nodesCached) {
188 | nodeElement.remove();
189 | }
190 | state.links = [];
191 | for (const lineElement of state.linesCached) {
192 | lineElement.remove();
193 | }
194 | validate(state);
195 | state.selectedNodeElement = null;
196 | state.createOngoingLinkId = null;
197 | state.deleting = false;
198 | };
199 |
200 | (document.getElementById('inputLoadFile') as HTMLInputElement).onchange = (event: Event): void => {
201 | const reader = new FileReader();
202 | reader.onload = onReaderLoad;
203 |
204 | const tempElement = event.target as HTMLInputElement;
205 | if (tempElement && tempElement.files) {
206 | reader.readAsText(tempElement.files[0]);
207 | }
208 |
209 | function onReaderLoad(event: ProgressEvent): void {
210 | console.log(event);
211 | if (event.target && event.target.result) {
212 | const jsonString = event.target.result as string;
213 | if (validJson(jsonString)) {
214 | const jsonObject = JSON.parse(jsonString);
215 | load(jsonObject as Dto, state);
216 | const button = document.getElementById('button-load') as HTMLButtonElement;
217 | button.disabled = true;
218 | button.innerText = '';
219 |
220 | // To maximize the textareas the next time user shows all
221 | document.getElementById('toggle-visibility')?.click();
222 | document.getElementById('toggle-visibility')?.click();
223 | document.getElementById('toggle-visibility')?.click();
224 | document.getElementById('toggle-visibility')?.click();
225 | document.getElementById('toggle-visibility')?.click();
226 | }
227 | }
228 | }
229 | };
230 |
231 | // Hide / Show All
232 | let toggleVisibility: number = 0;
233 | document.getElementById('toggle-visibility')?.addEventListener('click', (): void => {
234 | const accordions = document.getElementsByClassName('accordion');
235 | for (let i = 0; i < accordions.length; i++) {
236 | const panel = accordions[i].nextElementSibling as HTMLDivElement;
237 | if (panel) {
238 | if (toggleVisibility % 3 === 0) {
239 | // Hide All
240 | if (panel.style.maxHeight !== '0px') {
241 | (accordions[i] as HTMLElement).click();
242 | }
243 | } else if (toggleVisibility % 3 === 1) {
244 | // Show Events, otherwise Hide
245 | const id = accordions[i].parentElement?.id;
246 | if (id && get_node(id as UUID, state.nodes)?.type === NodeType.Event) {
247 | const textarea: HTMLTextAreaElement = panel.getElementsByTagName('textarea')[0];
248 | if (panel.style.maxHeight === '0px' && textarea.value !== '') {
249 | (accordions[i] as HTMLElement).click();
250 | }
251 | } else if (panel.style.maxHeight !== '0px') {
252 | (accordions[i] as HTMLElement).click();
253 | }
254 | } else if (toggleVisibility % 3 === 2) {
255 | // Show All
256 | const textarea: HTMLTextAreaElement = panel.getElementsByTagName('textarea')[0];
257 | const textareaRight: HTMLTextAreaElement | undefined = panel.getElementsByTagName('textarea')[1];
258 | if (
259 | panel.style.maxHeight === '0px' &&
260 | (textarea.value !== '' || (textareaRight && textareaRight.value !== ''))
261 | ) {
262 | (accordions[i] as HTMLElement).click();
263 | }
264 | }
265 | }
266 | }
267 | ++toggleVisibility;
268 | });
269 |
--------------------------------------------------------------------------------
/src/uuid.ts:
--------------------------------------------------------------------------------
1 | // Note: `@types/node/crypto` doesn't seem to work with .ts when bundled, it cannot be imported properly when viewed from the browser
2 |
3 | export type UUID = `${string}-${string}-${string}-${string}-${string}`;
4 |
5 | export const randomUUID = (): UUID => {
6 | // https://stackoverflow.com/questions/105034/how-do-i-create-a-guid-uuid
7 | // Timestamp
8 | let d = new Date().getTime();
9 | // Time in microseconds since page-load or 0 if unsupported
10 | let d2 = (typeof performance !== 'undefined' && performance.now && performance.now() * 1000) || 0;
11 | return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
12 | // Random number between 0 and 16
13 | let r = Math.random() * 16;
14 | if (d > 0) {
15 | // Use timestamp until depleted
16 | r = (d + r) % 16 | 0;
17 | d = Math.floor(d / 16);
18 | } else {
19 | // Use microseconds since page-load if supported
20 | r = (d2 + r) % 16 | 0;
21 | d2 = Math.floor(d2 / 16);
22 | }
23 | return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16);
24 | }) as UUID;
25 | };
26 |
--------------------------------------------------------------------------------
/styles/styles.css:
--------------------------------------------------------------------------------
1 | body
2 | {
3 | font-family: Arial, Helvetica, sans-serif;
4 | width: 9999px;
5 | height: 9999px;
6 | background-color: #0E0E10;
7 | margin: 0px;
8 | }
9 |
10 | .toolbar-button
11 | {
12 | background-color: white;
13 | font-size: 18px;
14 | text-align: center;
15 | text-decoration: none;
16 | opacity: 1;
17 | border: 2px solid grey;
18 | display: inline-block;
19 | transition: 0.3s;
20 | padding: 5px;
21 | }
22 |
23 |
24 | .toolbar-button:hover
25 | {
26 | background-color: #89CFF0;
27 | opacity: 1;
28 | }
29 |
30 | .toolbar-button:disabled
31 | {
32 | background-color: grey;
33 | opacity: 0.2;
34 | }
35 |
36 | .tooltip
37 | {
38 | position: relative;
39 | display: inline-block;
40 | }
41 |
42 | .tooltip .tooltip-text
43 | {
44 | visibility: hidden;
45 | background-color: #555555;
46 | color: #fff;
47 | text-align: center;
48 | padding: 5px;
49 | border-radius: 6px;
50 | position: absolute;
51 | z-index: 2;
52 | top: 115%;
53 | left: 50%;
54 | margin-left: -50%;
55 | opacity: 0;
56 | transition: opacity 0.3s;
57 | }
58 |
59 | .tooltip:hover .tooltip-text
60 | {
61 | visibility: visible;
62 | opacity: 1.0;
63 | }
64 |
65 | .icon
66 | {
67 | color: grey;
68 | }
69 |
70 | .icon:hover
71 | {
72 | color: black;
73 | }
74 |
75 | input[type="file"]
76 | {
77 | display: none;
78 | }
79 |
80 | .node
81 | {
82 | display: flex;
83 | flex-direction: column;
84 | position: absolute;
85 | z-index: 1;
86 | background-color: white;
87 | border: 3px solid white;
88 | border-radius: 4px;
89 | opacity: 1.0;
90 | }
91 |
92 | .node-highlighted
93 | {
94 | border-width: 5px;
95 | }
96 |
97 | .node-unhighlighted
98 | {
99 | opacity: 0.3;
100 | }
101 |
102 | .move
103 | {
104 | width: 30px;
105 | height: 30px;
106 | cursor: move;
107 | background-color: #2196F3;
108 | display: flex;
109 | align-items: center;
110 | justify-content: center;
111 | }
112 |
113 | .node-name
114 | {
115 | flex: 1;
116 | width: 200px;
117 | font-size: 23px;
118 | font-weight: bold;
119 | letter-spacing: 2px;
120 | text-align: center;
121 | color: black;
122 | background-color: lightblue;
123 | border: 0px;
124 | }
125 |
126 | .node-color
127 | {
128 | width: 10px;
129 | height: 30px;
130 | border: 0px;
131 | padding: 0px;
132 | margin: 0px;
133 | }
134 |
135 | img
136 | {
137 | align-self: center;
138 | }
139 |
140 | .line
141 | {
142 | position: absolute;
143 | top: 0px;
144 | left: 0px;
145 | pointer-events: none;
146 | z-index: 0;
147 | stroke-width: 2px;
148 | }
149 |
150 | .line-highlighted
151 | {
152 | stroke-width: 4px;
153 | }
154 |
155 | .line-unhighlighted
156 | {
157 | stroke-width: 1px;
158 | stroke-opacity: 0.3;
159 | }
160 |
161 | .accordion
162 | {
163 | width: 100%;
164 | font-size: 14px;
165 | font-weight: bold;
166 | letter-spacing: 1.2px;
167 | outline: none;
168 | color: #222222;
169 | background-color: #EEEEEE;
170 | border: none;
171 | padding: 0px;
172 | }
173 |
174 | .active, .accordion:hover
175 | {
176 | background-color: #CCCCCC;
177 | }
178 |
179 | .accordion:after
180 | {
181 | content: '\002B';
182 | color: #777777;
183 | font-weight: bold;
184 | float: right;
185 | margin-left: 5px;
186 | }
187 |
188 | .active:after
189 | {
190 | content: "\2212";
191 | }
192 |
193 | .panel
194 | {
195 | width: calc(100% - 6px);
196 | background-color: white;
197 | overflow: hidden;
198 | padding-right: 6px;
199 | }
200 |
201 | textarea
202 | {
203 | width: 100%;
204 | min-width: 100%;
205 | max-width: 100%;
206 | max-height: 100%;
207 | font-size: 18px;
208 | border: 1px solid gray;
209 | padding: 0px 2px;
210 | margin: 0px;
211 | }
212 |
213 | .textarea-half
214 | {
215 | min-width: 50%;
216 | max-width: 50%;
217 | padding: 0px;
218 | }
219 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowJs": true,
4 | "baseUrl": "./src",
5 | "declaration": true,
6 | "esModuleInterop": true,
7 | "forceConsistentCasingInFileNames": true,
8 | "lib": ["DOM", "ES2020"],
9 | "incremental": true,
10 | "module": "ES6",
11 | "moduleResolution": "node",
12 | "outDir": "./build/dist",
13 | "resolveJsonModule": true,
14 | "rootDir": "./src",
15 | "skipLibCheck": false,
16 | "sourceMap": true,
17 | "target": "ES6",
18 | "types": [],
19 | "typeRoots": ["node_modules/@types", "src/types"],
20 |
21 | // Strict options
22 | "alwaysStrict": true,
23 | "noEmitOnError": true,
24 | "noImplicitAny": true,
25 | "noImplicitThis": true,
26 | "removeComments": false,
27 | "strict": true,
28 | "strictFunctionTypes": true,
29 | "strictNullChecks": true,
30 | "strictPropertyInitialization": true,
31 |
32 | // Checks
33 | "noFallthroughCasesInSwitch": true,
34 | "noImplicitReturns": true,
35 | "noUnusedLocals": false,
36 | "noUnusedParameters": true,
37 |
38 | // Debugging
39 | "listEmittedFiles": false,
40 | "listFiles": false,
41 | "pretty": true,
42 | "traceResolution": false,
43 | },
44 | "compileOnSave": false,
45 | "include": ["src/**/*.ts"],
46 | "exclude": ["**/node_modules/**"],
47 | }
48 |
--------------------------------------------------------------------------------
/ui.css:
--------------------------------------------------------------------------------
1 | html { height: 100% }
2 |
3 | body {
4 | height: 100%;
5 | }
6 |
7 | .navigation-input {
8 | height: 18px;
9 | margin-bottom: 5px;
10 | -webkit-border-radius: 4px;
11 | -moz-border-radius: 4px;
12 | border-radius: 4px;
13 | }
14 |
15 | .search-form {
16 | margin-top: 2px;
17 | }
18 |
19 | #status-modal {
20 | display:none;
21 | }
22 |
23 | #search-action {
24 | display: inline-block;
25 | vertical-align: middle;
26 | margin-top: 1px;
27 | }
28 |
29 | #search-button {
30 | margin-bottom: 5px;
31 | margin-top: 0px;
32 | }
33 |
34 | .logo {
35 | margin: 4px;
36 | }
37 |
38 | #map-canvas {
39 | width: 100%;
40 | height: 100%;
41 | }
42 |
43 | #filter-div {
44 | position: absolute;
45 | top: 42px;
46 | left: 1px;
47 | z-index: 2;
48 | padding: 10px;
49 | display: none;
50 | }
51 |
52 | #filter-form {
53 | padding: 10px;
54 | }
55 |
56 | #no-results-alert {
57 | position: absolute;
58 | top: 50px;
59 | left: 50%;
60 | margin-left: -100px;
61 | z-index: 100;
62 | display: none;
63 | }
64 |
65 | .dropdown-open {
66 | display: block;
67 | z-index: 0;
68 | }
69 |
70 | #map-canvas img{max-width: inherit;}
71 |
72 | table.tablesorter thead tr .header {
73 | background-image: url(img/bg.gif);
74 | background-repeat: no-repeat;
75 | background-position: center right;
76 | cursor: pointer;
77 | }
78 | table.tablesorter thead tr .headerSortUp {
79 | background-image: url(img/asc.gif);
80 | }
81 | table.tablesorter thead tr .headerSortDown {
82 | background-image: url(img/desc.gif);
83 | }
84 |
85 |
86 |
--------------------------------------------------------------------------------