├── .gitignore
├── .prettierrc
├── .vscode
└── settings.json
├── DOC.md
├── LICENSE
├── package-lock.json
├── package.json
├── readme.md
├── src
├── css
│ ├── accordion.css
│ ├── cascaded-menu.css
│ ├── console.css
│ ├── construct-doc.css
│ ├── cursor.css
│ ├── doc-box.css
│ ├── draft-mode.css
│ ├── editor.css
│ ├── hole.css
│ ├── index.css
│ ├── messages.css
│ ├── notification.css
│ ├── suggestion-menu.css
│ ├── toolbox.css
│ └── tooltip.css
├── docs
│ ├── add-var.json
│ ├── add.json
│ ├── and.json
│ ├── assign-add.json
│ ├── assign-div.json
│ ├── assign-mult.json
│ ├── assign-sub.json
│ ├── assign.json
│ ├── break.json
│ ├── choice.json
│ ├── comp-eq.json
│ ├── comp-gt.json
│ ├── comp-gte.json
│ ├── comp-lt.json
│ ├── comp-lte.json
│ ├── comp-ne.json
│ ├── div.json
│ ├── elif.json
│ ├── else.json
│ ├── f-str-item.json
│ ├── f-str.json
│ ├── false.json
│ ├── find.json
│ ├── floor-div.json
│ ├── for.json
│ ├── if.json
│ ├── import.json
│ ├── in.json
│ ├── input.json
│ ├── join.json
│ ├── len.json
│ ├── list-append.json
│ ├── list-element-assign.json
│ ├── list-index.json
│ ├── list-item.json
│ ├── list-literal.json
│ ├── mod.json
│ ├── mult.json
│ ├── not-in.json
│ ├── not.json
│ ├── num.json
│ ├── or.json
│ ├── print.json
│ ├── randint.json
│ ├── range.json
│ ├── replace.json
│ ├── split.json
│ ├── str.json
│ ├── sub.json
│ ├── to-int.json
│ ├── to-str.json
│ ├── true.json
│ └── while.json
├── editor
│ ├── accordion.ts
│ ├── action-executor.ts
│ ├── action-filter.ts
│ ├── consts.ts
│ ├── cursor.ts
│ ├── data-types.ts
│ ├── doc-box.ts
│ ├── draft.ts
│ ├── editor.ts
│ ├── event-router.ts
│ ├── event-stack.ts
│ ├── focus.ts
│ ├── hole.ts
│ ├── toolbox.ts
│ └── validator.ts
├── index.html
├── index.ts
├── logger
│ ├── analytics.ts
│ ├── requests.ts
│ └── user.ts
├── messages
│ ├── error-msg-generator.ts
│ ├── message-controller.ts
│ ├── messages.ts
│ └── notifications.ts
├── pyodide-js
│ ├── load-pyodide.js
│ └── pyodide-controller.js
├── pyodide-ts
│ └── pyodide-ui.ts
├── suggestions
│ ├── construct-doc.ts
│ └── suggestions-controller.ts
├── syntax-tree
│ ├── ast.ts
│ ├── body.ts
│ ├── callback.ts
│ ├── consts.ts
│ ├── module.ts
│ ├── scope.ts
│ ├── tree-array.ts
│ ├── type-checker.ts
│ └── variable-controller.ts
└── utilities
│ ├── text-enhance.ts
│ └── util.ts
├── tsconfig.json
└── webpack.config.js
/.gitignore:
--------------------------------------------------------------------------------
1 | dist/
2 | node_modules/
3 | lib
4 | logs
5 | *.log
6 | npm-debug.log*
7 | .env
8 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "tabWidth": 4,
3 | "useTabs": false,
4 | "printWidth": 120
5 | }
6 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "cSpell.words": ["elif", "randint", "consts", "pyodide", "builtins"],
3 | "editor.formatOnSave": true,
4 | "editor.codeActionsOnSave": {
5 | "source.organizeImports": true
6 | },
7 | "editor.tabSize": 4
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nova-editor",
3 | "version": "1.0.0",
4 | "description": "A new text-based environment that helps beginners transition into conventional text-based programming environments.",
5 | "keywords": [
6 | "programming",
7 | "cs-education",
8 | "novice",
9 | "beginner",
10 | "editor"
11 | ],
12 | "author": "Majeed Kazemitaabar, Viktar Chyhir",
13 | "license": "GPL-3.0",
14 | "scripts": {
15 | "start": "webpack serve --config webpack.config.js --open",
16 | "build": "node node_modules/webpack/bin/webpack.js --progress"
17 | },
18 | "dependencies": {
19 | "axios": "^0.24.0",
20 | "fuse.js": "^6.4.6",
21 | "monaco-editor": "^0.25.2"
22 | },
23 | "devDependencies": {
24 | "@webpack-cli/serve": "^1.5.1",
25 | "css-loader": "^5.2.6",
26 | "file-loader": "^6.2.0",
27 | "html-webpack-plugin": "^5.3.2",
28 | "monaco-editor-webpack-plugin": "^4.0.0",
29 | "style-loader": "^3.0.0",
30 | "terser-webpack-plugin": "^5.1.4",
31 | "ts-loader": "^9.2.3",
32 | "typescript": "^4.4.2",
33 | "webpack": "^5.43.0",
34 | "webpack-cli": "^4.7.2",
35 | "webpack-dev-server": "^3.11.3"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # CodeStruct
2 | A new text-based environment that helps beginners transition into conventional text-based programming environments.
3 |
4 | Features:
5 | - avoids syntax errors
6 | - enables structured text-based editing
7 | - provides learning moments on invalid attempts
8 | - provides hints and visual descriptions
9 |
10 | Authoring code with CodeStruct:
11 | - Cursor-aware Toolbox
12 | - Suggestion Menus and Autocomplete
13 | - Draft Mode Editing
14 |
--------------------------------------------------------------------------------
/src/css/accordion.css:
--------------------------------------------------------------------------------
1 | .accordion-group-container {
2 | }
3 |
4 | .accordion-row {
5 | border-radius: 4px;
6 | margin: 8px;
7 | background-color: #fff;
8 | overflow: hidden;
9 | box-shadow: 0px 1px 3px 1px #167faa;
10 | }
11 |
12 | .accordion-row .header-container {
13 | display: flex;
14 | justify-content: space-between;
15 | font-size: 14px;
16 | cursor: pointer;
17 |
18 | transition: 0.15s ease-in-out;
19 | -webkit-transition: 0.15s ease-in-out;
20 | -moz-transition: 0.15s ease-in-out;
21 | -o-transition: 0.15s ease-in-out;
22 | -ms-transition: 0.15s ease-in-out;
23 | }
24 |
25 | .accordion-row .header-container:hover {
26 | background-color: #ccc;
27 | }
28 |
29 | .accordion-row .header-container:hover .expand-collapse-button svg {
30 | background-color: #aebbcf;
31 | color: #00f;
32 | }
33 |
34 | .accordion-row .row-icon {
35 | display: flex;
36 | margin-left: 5px;
37 | align-items: center;
38 | }
39 | .accordion-row .row-type {
40 | margin-left: 5px;
41 | margin-top: 4px;
42 | }
43 | .accordion-row .row-title {
44 | margin-left: 5px;
45 | color: #000;
46 | font-weight: bold;
47 | }
48 | .accordion-row .row-chevron-right-icon {
49 | display: flex;
50 | margin-left: 5px;
51 | }
52 | .accordion-row .expand-collapse-button {
53 | display: flex;
54 | }
55 |
56 | .accordion-row .expand-collapse-button svg {
57 | cursor: pointer;
58 | margin: 2px;
59 | cursor: pointer;
60 | border-radius: 99px;
61 | color: #000;
62 |
63 | transition: 0.15s ease-in-out;
64 | -webkit-transition: 0.15s ease-in-out;
65 | -moz-transition: 0.15s ease-in-out;
66 | -o-transition: 0.15s ease-in-out;
67 | -ms-transition: 0.15s ease-in-out;
68 | }
69 |
70 | .accordion-row .content-container {
71 | overflow: hidden;
72 | }
73 |
74 | .accordion-row .header-container .type-container {
75 | background-color: #670093;
76 | padding-right: 8px;
77 | display: flex;
78 | flex-direction: row;
79 | align-content: center;
80 | height: 100%;
81 | }
82 | .accordion-row .header-container .text-container {
83 | display: flex;
84 | flex-direction: row;
85 | align-items: center;
86 | }
87 |
88 | .accordion-row .header-container .bg-learn {
89 | background-color: #9c27b0;
90 | }
91 | .accordion-row .header-container .bg-try {
92 | background-color: #45a249;
93 | }
94 | .accordion-row .header-container .bg-hint {
95 | background-color: #cc451b;
96 | }
97 |
98 | .accordion-row .chevron {
99 | color: #000;
100 | padding: 10px;
101 |
102 | transition: background-color 0.15s ease-in-out;
103 | -webkit-transition: background-color 0.15s ease-in-out;
104 | -moz-transition: background-color 0.15s ease-in-out;
105 | -o-transition: background-color 0.15s ease-in-out;
106 | -ms-transition: background-color 0.15s ease-in-out;
107 | }
108 |
109 | .accordion-row .chevron:hover {
110 | color: #00f;
111 | }
112 |
--------------------------------------------------------------------------------
/src/css/cascaded-menu.css:
--------------------------------------------------------------------------------
1 | .cascadedMenuMainDiv::-webkit-scrollbar {
2 | background: #ccc;
3 | margin: 5px;
4 | width: 8px;
5 | }
6 |
7 | .cascadedMenuMainDiv::-webkit-scrollbar-track {
8 | background: #ebebeb;
9 | }
10 |
11 | .cascadedMenuMainDiv::-webkit-scrollbar-thumb {
12 | border: none;
13 | background-color: #d1d1d1;
14 | border-radius: 0px;
15 | }
16 |
17 | .cascadedMenuMainDiv {
18 | opacity: 0;
19 |
20 | min-width: 375px;
21 | z-index: 10;
22 | position: absolute;
23 | background-color: white;
24 | box-shadow: 0px 8px 16px 0px rgb(0 0 0 / 20%);
25 |
26 | border-radius: 6px;
27 |
28 | overflow-y: auto;
29 |
30 | transition: opacity 0.1s ease-in-out;
31 | -webkit-transition: opacity 0.1s ease-in-out;
32 | -moz-transition: opacity 0.1s ease-in-out;
33 | -o-transition: opacity 0.1s ease-in-out;
34 | -ms-transition: opacity 0.1s ease-in-out;
35 | }
36 |
37 | .cascadedMenuItem {
38 | cursor: pointer;
39 | }
40 |
41 | .cascadedMenuMainDiv .cascadedMenuItem :not(:hover) {
42 | background-color: white;
43 | }
44 |
45 | .cascadedMenuContent {
46 | padding-left: 9px;
47 | }
48 |
49 | .cascadedMenuContent .inline-var-id {
50 | color: #aa5bc8;
51 | border-radius: 4px;
52 | padding: 1px 4px;
53 | border: solid 1px #bbb;
54 | }
55 |
56 | .cascadedMenuOptionTooltip {
57 | display: inline;
58 | align-self: center;
59 | font-size: 14px;
60 | color: #16b3c1;
61 | margin-right: 10px;
62 | }
63 |
64 | .valid-option-tooltip {
65 | font-weight: bold;
66 | }
67 |
68 | .hoverable:hover .cascadedMenuMainDiv {
69 | display: block;
70 | }
71 |
72 | .cascaded-menu-header {
73 | border-bottom: solid 1px #ccc;
74 | margin-bottom: 5px;
75 | height: 35px;
76 | width: 100%;
77 | display: flex;
78 | flex-direction: row;
79 | align-items: center;
80 | background-color: #006a93;
81 | color: #fff;
82 | }
83 |
84 | .cascaded-menu-header h3 {
85 | font-weight: bold;
86 | font-size: 18px;
87 | margin: 8px 10px 8px 10px;
88 | }
89 |
90 | .cascaded-menu-header .identifier {
91 | font-weight: bold;
92 | background-color: #9850b3;
93 | padding: 0px 8px 0px 8px;
94 | border-radius: 3px;
95 | color: #fff;
96 | }
97 |
98 | .cascadedMenuContent .button {
99 | font-size: 15px;
100 | padding: 6px 10px;
101 |
102 | white-space: nowrap;
103 | box-shadow: 0px 1px 5px 2px #ddd;
104 |
105 | transition: 0.15s ease-in-out;
106 | -webkit-transition: 0.15s ease-in-out;
107 | -moz-transition: 0.15s ease-in-out;
108 | -o-transition: 0.15s ease-in-out;
109 | -ms-transition: 0.15s ease-in-out;
110 |
111 | -webkit-user-select: none; /* Safari */
112 | -moz-user-select: none; /* Firefox */
113 | -ms-user-select: none; /* IE10+/Edge */
114 | user-select: none; /* Standard */
115 | }
116 |
117 | .cascadedMenuContent .button:hover {
118 | box-shadow: 0px 1px 5px 2px #ccc;
119 | }
120 |
121 | .cascadedMenuContent .var-button-container {
122 | display: inline-flex;
123 | }
124 |
125 | .cascadedMenuContent .button-id {
126 | color: #aa5bc8;
127 | }
128 |
129 | .var-more-actions-button {
130 | border: solid 1px #007acc;
131 | padding: 3px 6px;
132 | border-radius: 5px;
133 | color: #007acc;
134 | font-size: 13px;
135 |
136 | transition: background-color 0.15s ease-in-out;
137 | -webkit-transition: background-color 0.15s ease-in-out;
138 | -moz-transition: background-color 0.15s ease-in-out;
139 | -o-transition: background-color 0.15s ease-in-out;
140 | -ms-transition: background-color 0.15s ease-in-out;
141 |
142 | cursor: pointer;
143 |
144 | margin-right: 5px;
145 | }
146 |
147 | .var-more-actions-button:hover {
148 | background-color: #007acc;
149 | color: #fff;
150 | }
151 |
--------------------------------------------------------------------------------
/src/css/console.css:
--------------------------------------------------------------------------------
1 | #console {
2 | font-family: Consolas, "Courier New", monospace;
3 |
4 | flex-shrink: 0;
5 | flex-grow: 0;
6 | flex-basis: 30%;
7 | height: 30%;
8 | width: 100%;
9 |
10 | display: flex;
11 | flex-flow: column;
12 |
13 | background-color: #ccc;
14 | box-shadow: 10px 0px 20px 0px #ccc;
15 | }
16 |
17 | .run-code-btn {
18 | justify-self: start;
19 | background-color: rgb(24 200 120);
20 | color: #fff !important;
21 | }
22 |
23 | .run-code-button-container {
24 | margin: 10px 0px 0px 20px;
25 | }
26 |
27 | .run-code-button-container .disabled {
28 | background-color: #888;
29 | cursor: not-allowed;
30 | }
31 |
32 | #outputDiv {
33 | color: #000;
34 | font-size: 14px;
35 | font-weight: bold;
36 |
37 | overflow-y: auto;
38 | border-top: solid #bcbcbc 1px;
39 |
40 | margin-top: 10px;
41 | padding-left: 20px;
42 | padding: 8px 0 8px 20px;
43 | }
44 |
45 | .consoleTxt {
46 | font-weight: 10pt;
47 | }
48 |
49 | .consoleErrTxt {
50 | color: red;
51 | }
52 |
53 | .consoleWarnTxt {
54 | color: orange;
55 | }
56 |
57 | .clear-output-btn {
58 | box-shadow: none;
59 | border: solid #4f4f4f 0.5px;
60 | }
61 |
62 | .console-button {
63 | color: #000;
64 | cursor: pointer;
65 | border-radius: 4px;
66 |
67 | display: inline-block;
68 | align-items: center;
69 | justify-content: center;
70 |
71 | opacity: 1;
72 |
73 | height: -webkit-fit-content;
74 | height: -moz-fit-content;
75 | height: fit-content;
76 |
77 | margin-right: 10px;
78 | box-shadow: rgb(0 0 0 / 20%) 0px 3px 1px -2px, rgb(0 0 0 / 14%) 0px 2px 2px 0px, rgb(0 0 0 / 12%) 0px 1px 5px 0px;
79 |
80 | font-size: 14px;
81 | font-weight: bold;
82 |
83 | padding: 8px 10px;
84 |
85 | width: -webkit-fit-content;
86 | width: -moz-fit-content;
87 | width: fit-content;
88 |
89 | transition: 0.2s ease-in-out;
90 | -webkit-transition: 0.2s ease-in-out;
91 | -moz-transition: 0.2s ease-in-out;
92 | -o-transition: 0.2s ease-in-out;
93 | -ms-transition: 0.2s ease-in-out;
94 | }
95 |
96 | .run-code-btn:hover {
97 | background-color: rgb(21 173 110);
98 | box-shadow: rgb(0 0 0 / 20%) 0px 2px 4px -1px, rgb(0 0 0 / 14%) 0px 4px 5px 0px, rgb(0 0 0 / 12%) 0px 1px 10px 0px;
99 | }
100 |
101 | .clear-output-btn:hover {
102 | background-color: #4f4f4f;
103 | color: #fff;
104 | }
105 |
106 | #outputDiv::-webkit-scrollbar {
107 | background: #ccc;
108 | margin: 5px;
109 | width: 8px;
110 | }
111 |
112 | #outputDiv::-webkit-scrollbar-track {
113 | background: #c1c1c1;
114 | }
115 |
116 | #outputDiv::-webkit-scrollbar-thumb {
117 | border: none;
118 | background-color: #8c8c8c;
119 | border-radius: 0px;
120 | }
121 |
--------------------------------------------------------------------------------
/src/css/construct-doc.css:
--------------------------------------------------------------------------------
1 | .docParent {
2 | position: absolute;
3 | left: 200px;
4 | top: 200px;
5 |
6 | max-width: 50%;
7 | max-height: 30%;
8 | min-width: 40%;
9 | min-height: 20%;
10 | width: fit-content;
11 | height: fit-content;
12 | overflow-y: scroll;
13 |
14 | border-style: solid;
15 | border-width: 2px;
16 | border-color: grey;
17 |
18 | background-color: rgb(197, 197, 197);
19 |
20 | padding: 2px 2px 2px 2px;
21 |
22 | overflow-y: scroll;
23 | scrollbar-width: none; /* Firefox */
24 | -ms-overflow-style: none; /* Internet Explorer 10+ */
25 | }
26 | .docParent::-webkit-scrollbar {
27 | width: 0;
28 | height: 0;
29 | }
30 |
31 | .docTitle {
32 | padding: 2px;
33 | margin: 0px;
34 | border-bottom: solid 1px;
35 | border-color: black;
36 | }
37 |
38 | .docBody {
39 | padding-left: 1px;
40 | padding-right: 1px;
41 | padding-top: 1px;
42 | padding-bottom: 1px;
43 | font-size: 10pt;
44 | }
45 |
46 | .docImageParent {
47 | display: grid;
48 | grid-template-columns: 50% 50%;
49 | grid-template-rows: auto;
50 | column-gap: 10px;
51 | row-gap: 15px;
52 | margin-top: 10px;
53 |
54 | padding-right: 10px;
55 | padding-top: 2px;
56 | padding-bottom: 1px;
57 | }
58 |
59 | .docImage {
60 | max-width: 100%;
61 | max-height: 100%;
62 | min-width: 100%;
63 | min-height: 100%;
64 | }
65 |
--------------------------------------------------------------------------------
/src/css/cursor.css:
--------------------------------------------------------------------------------
1 | .custom-selection-cursor {
2 | position: absolute;
3 | background: #a4e2ff94;
4 | mix-blend-mode: multiply;
5 |
6 | transition: 0.1s ease-in;
7 | pointer-events: none;
8 | z-index: 5;
9 | border-radius: 8.5px;
10 |
11 | /* this should match the border-width of hole in hole.css */
12 | padding: 1px;
13 | }
14 |
--------------------------------------------------------------------------------
/src/css/doc-box.css:
--------------------------------------------------------------------------------
1 | .doc-box-container {
2 | position: absolute;
3 | box-shadow: 0px 0px 20px 0px #5d5d5d;
4 | width: 400px;
5 | height: 330px;
6 | left: calc(50% - 150px);
7 | top: calc(50% - 125px);
8 | background-color: #fff;
9 | border-radius: 7px;
10 | overflow: hidden;
11 | resize: both;
12 |
13 | font-family: Consolas, "Courier New", monospace;
14 | }
15 |
16 | .focused-header {
17 | background-color: #6699aa !important;
18 | }
19 |
20 | .doc-box-header {
21 | height: 25px;
22 | display: flex;
23 | flex-direction: row;
24 | align-items: center;
25 |
26 | background-color: #6699aa70;
27 |
28 | transition: background-color 0.15s ease-in-out;
29 | -webkit-transition: background-color 0.15s ease-in-out;
30 | -moz-transition: background-color 0.15s ease-in-out;
31 | -o-transition: background-color 0.15s ease-in-out;
32 | -ms-transition: background-color 0.15s ease-in-out;
33 |
34 | cursor: grab;
35 | }
36 |
37 | .doc-box-header:hover {
38 | background-color: #578;
39 | }
40 |
41 | .doc-title {
42 | color: #fff;
43 | font-size: 16px;
44 | margin: 0 0 0 15px;
45 | }
46 |
47 | .close-button {
48 | margin-left: auto;
49 | margin-top: 1px;
50 | font-weight: bold;
51 | color: #fff;
52 | font-size: 27px;
53 |
54 | transition: background-color 0.15s ease-in-out;
55 | -webkit-transition: background-color 0.15s ease-in-out;
56 | -moz-transition: background-color 0.15s ease-in-out;
57 | -o-transition: background-color 0.15s ease-in-out;
58 | -ms-transition: background-color 0.15s ease-in-out;
59 |
60 | cursor: pointer;
61 | padding: 0px 10px;
62 | }
63 |
64 | .close-button:hover {
65 | color: #000;
66 | }
67 |
68 | .doc-body {
69 | overflow-y: auto;
70 | width: calc(100% - 30px);
71 | height: calc(100% - 25px);
72 | padding: 0 15px 0 15px;
73 | font-family: monospace;
74 | font-size: 15px;
75 | }
76 |
77 | .doc-editor {
78 | width: 100%;
79 | border: solid 1px #eee;
80 | }
81 |
82 | .doc-body::-webkit-scrollbar {
83 | background: #ccc;
84 | margin: 5px;
85 | width: 8px;
86 | }
87 |
88 | .doc-body::-webkit-scrollbar-track {
89 | background: #ebebeb;
90 | }
91 |
92 | .doc-body::-webkit-scrollbar-thumb {
93 | border: none;
94 | background-color: #b8ccd1;
95 | border-radius: 0px;
96 | }
97 |
98 | div.doc-body p span.italics {
99 | font-style: italic;
100 | }
101 |
102 | div.doc-body p span.code {
103 | background-color: #ddd;
104 | border-radius: 3px;
105 | padding: 1px 5px;
106 | font-weight: bold;
107 | }
108 |
109 | div.doc-body p span.bold {
110 | font-weight: bold;
111 | }
112 |
113 | div.doc-body > div.doc-editor:nth-last-child(1) {
114 | margin-bottom: 7%;
115 | }
116 |
117 | .doc-editor-container {
118 | border-top: solid 1px #ccc;
119 | }
120 |
121 | .console-output::-webkit-scrollbar {
122 | background: #ccc;
123 | margin: 5px;
124 | width: 8px;
125 | }
126 |
127 | .console-output::-webkit-scrollbar-track {
128 | background: #c1c1c1;
129 | }
130 |
131 | .console-output::-webkit-scrollbar-thumb {
132 | border: none;
133 | background-color: #8c8c8c;
134 | border-radius: 0px;
135 | }
136 |
137 | .doc-example-console {
138 | background-color: #ccc;
139 | font-size: 14px;
140 | font-weight: bold;
141 | }
142 |
143 | .doc-example-console p {
144 | padding: 0;
145 | margin: 0;
146 | }
147 |
148 | .doc-editor-header {
149 | background-color: #17a564;
150 | color: #fff;
151 | font-weight: bold;
152 | padding: 4px 8px;
153 | font-size: 14px;
154 | }
155 |
156 | .doc-example-btn {
157 | padding: 5px 10px !important;
158 | font-size: 12px !important;
159 | }
160 |
161 | .reset-editor-btn {
162 | visibility: hidden;
163 | }
164 |
165 | .block-vs-text-table-container {
166 | border-radius: 5px;
167 | box-shadow: 0 0 5px 1px #888;
168 | }
169 |
170 | .block-vs-text-table-header {
171 | height: 20px;
172 | background-color: #d9e7ee;
173 | display: flex;
174 | flex-direction: row;
175 | justify-content: space-between;
176 | align-items: center;
177 | padding: 5px 15px;
178 | font-size: 12px;
179 | font-weight: bold;
180 | }
181 |
182 | .image-container {
183 | flex-direction: row;
184 | justify-content: space-between;
185 | display: flex;
186 | align-items: start;
187 | padding: 15px;
188 | }
189 |
190 | .image-container img {
191 | width: 48%;
192 | }
193 |
194 | .console-output {
195 | height: 100px;
196 | max-height: 0px;
197 | overflow-y: scroll;
198 |
199 | color: #000;
200 |
201 | transition: max-height 0.2s ease-in-out;
202 | -webkit-transition: max-height 0.2s ease-in-out;
203 | -moz-transition: max-height 0.2s ease-in-out;
204 | -o-transition: max-height 0.2s ease-in-out;
205 | -ms-transition: max-height 0.2s ease-in-out;
206 | }
207 |
208 | .console-output-open {
209 | padding: 5px;
210 | max-height: 100px;
211 | }
212 |
213 | .doc-example-console-button-container {
214 | border-bottom: solid 1px#bbb;
215 | padding: 5px;
216 | }
217 |
--------------------------------------------------------------------------------
/src/css/draft-mode.css:
--------------------------------------------------------------------------------
1 | .draftModeLine {
2 | background-color: rgba(255, 0, 0, 0.3);
3 | position: absolute;
4 | pointer-events: none;
5 | border-radius: 5px;
6 | }
7 |
8 | .draftModeLine.fixed {
9 | background-color: rgba(30, 255, 0, 0.3);
10 | }
11 |
--------------------------------------------------------------------------------
/src/css/editor.css:
--------------------------------------------------------------------------------
1 | #editorArea {
2 | width: 100%;
3 | height: 100%;
4 | display: flex;
5 | flex-direction: column;
6 | }
7 |
8 | #editor {
9 | width: 100%;
10 | flex-shrink: 0;
11 | flex-grow: 0;
12 | flex-basis: 70%;
13 | height: 70%;
14 | }
15 |
16 | #editor .monaco-editor.no-user-select.showUnused.showDeprecated.vs {
17 | height: 100%;
18 | }
19 |
20 | #editor .monaco-editor,
21 | #editor .monaco-editor-background,
22 | #editor .monaco-editor .inputarea.ime-input {
23 | background-color: rgba(0, 0, 0, 0) !important;
24 | }
25 |
26 | #editor .monaco-editor-background {
27 | /* background-color: var(--main-bg-color) !important; */
28 | background-color: rgba(0, 0, 0, 0) !important;
29 | }
30 |
31 | #editor .monaco-editor .margin {
32 | /* background-color: var(--main-bg-color) !important; */
33 | background-color: rgba(0, 0, 0, 0) !important;
34 | }
35 |
36 | #editor .monaco-editor .view-overlays .current-line {
37 | display: none;
38 | }
39 |
40 | #editor .execution-decoration {
41 | left: 45px !important;
42 |
43 | width: 8px !important;
44 | height: 8px !important;
45 |
46 | border-radius: 50%;
47 | border: 1px solid #bfbebe;
48 | background-color: #00000008 !important;
49 |
50 | margin-top: 10%;
51 |
52 | display: none;
53 | }
54 |
55 | #editor .monaco-editor .line-numbers {
56 | color: black !important;
57 | opacity: 0.2;
58 | font-size: 12px !important;
59 | margin-top: 2px !important;
60 | transition: 1s;
61 | transition-property: opacity;
62 | margin-left: -10px;
63 | }
64 |
65 | #editor .monaco-editor .line-numbers:hover {
66 | opacity: 1 !important;
67 | }
68 |
69 | #editor .line-selected {
70 | font-weight: 800 !important;
71 | opacity: 1 !important;
72 | }
73 |
74 | #editor .cigr {
75 | box-shadow: 0.5px 0 0 0 rgba(0, 0, 0, 0) inset !important;
76 | }
77 |
78 | #editor .cigra {
79 | box-shadow: 0.5px 0 0 0 rgba(0, 0, 0, 0) inset !important;
80 | }
81 |
82 | #editor .monaco-editor .margin-view-overlays .codicon-chevron-down {
83 | font-size: 80%;
84 | }
85 |
86 | #editor .monaco-editor .margin-view-overlays .codicon-folding-collapsed,
87 | #editor .monaco-editor .margin-view-overlays .codicon-folding-expanded {
88 | font-size: 80% !important;
89 | }
90 |
91 | #editor .cdr.bracket-match {
92 | opacity: 0.5;
93 | border: none !important;
94 | outline: none !important;
95 | border-radius: 3px;
96 | padding: 2px;
97 | background: none !important;
98 | }
99 |
100 | #editor .monaco-editor .cursors-layer .cursor {
101 | background-color: black !important;
102 | transition-property: top, left;
103 | transition: 0.1s;
104 | opacity: 0.5;
105 | height: 20px !important;
106 | margin-top: 11px !important;
107 | margin-left: 2px !important;
108 | }
109 |
110 | #editor .monaco-editor .scroll-decoration {
111 | box-shadow: none !important;
112 | }
113 |
114 | #editor .monaco-scrollable-element {
115 | overflow: visible !important;
116 | }
117 |
118 | #editor .monaco-editor .view-overlays .current-line {
119 | border: none !important;
120 | }
121 |
122 | #editor .monaco-editor .selected-text {
123 | background: none !important;
124 | }
125 |
--------------------------------------------------------------------------------
/src/css/hole.css:
--------------------------------------------------------------------------------
1 | .hole {
2 | position: absolute;
3 | pointer-events: none;
4 |
5 | /* box-shadow: 0px 0px 3px 1px #00000029 inset; */
6 | border: solid 1px #00000029;
7 | transition-property: background;
8 | transition-duration: 0.2s;
9 |
10 | border-radius: 5px;
11 | }
12 |
13 | .editableHole {
14 | /* box-shadow: 0px 0px 3px 1px #398dfab6 inset; */
15 | border: solid 1px #398dfab6;
16 | }
17 |
18 | .validVarIdentifierHole {
19 | background-color: rgba(58, 223, 58, 0.3);
20 | }
21 |
22 | .draftVarIdentifierHole {
23 | background-color: rgb(255, 255, 230, 0.6);
24 | }
25 |
26 | .expression-hole {
27 | border-radius: 15px !important;
28 | }
29 |
30 | .text-editable-expr-hole {
31 | border-radius: 15px !important;
32 | border-style: dashed !important;
33 | }
34 |
35 | .empty-operator-hole {
36 | border-radius: 0 !important;
37 | }
38 |
39 | .identifier-hole {
40 | border-radius: 0 !important;
41 | border-style: dashed !important;
42 | }
43 |
44 | .errorTooltipHole {
45 | position: relative;
46 | top: 5px;
47 | }
48 |
--------------------------------------------------------------------------------
/src/css/index.css:
--------------------------------------------------------------------------------
1 | @import url("doc-box.css");
2 | @import url("editor.css");
3 | @import url("toolbox.css");
4 | @import url("cursor.css");
5 | @import url("hole.css");
6 | @import url("messages.css");
7 | @import url("suggestion-menu.css");
8 | @import url("construct-doc.css");
9 | @import url("draft-mode.css");
10 | @import url("cascaded-menu.css");
11 | @import url("console.css");
12 | @import url("notification.css");
13 | @import url("tooltip.css");
14 | @import url("accordion.css");
15 |
16 | @import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,300;0,400;0,600;0,700;1,300;1,400;1,600&display=swap");
17 |
18 | html {
19 | height: 100%;
20 | }
21 |
22 | body {
23 | margin: 0px;
24 | width: 100%;
25 | height: 100%;
26 | overflow: hidden;
27 | font-family: Source Sans Pro;
28 | }
29 |
30 | #editor-container {
31 | display: flex;
32 | height: 100%;
33 | }
34 |
35 | .button {
36 | color: #0d0c22;
37 | cursor: pointer;
38 | border-radius: 4px;
39 | display: flex;
40 | align-items: center;
41 | justify-content: center;
42 | opacity: 1;
43 | height: -webkit-fit-content;
44 | height: -moz-fit-content;
45 | height: fit-content;
46 | margin-right: 10px;
47 | font-size: 14px;
48 | padding: 10px 14px;
49 | width: -webkit-fit-content;
50 | width: -moz-fit-content;
51 | width: fit-content;
52 | border: solid 2px #fff;
53 | }
54 |
55 | .button.button-invalid {
56 | opacity: 0.4;
57 | cursor: not-allowed;
58 | border: solid 2px #c5c5c5;
59 | }
60 |
61 | .button.button-valid {
62 | font-weight: bold;
63 | }
64 |
65 | .button.button-draft-mode {
66 | background-color: rgb(255 254 195);
67 | }
68 |
--------------------------------------------------------------------------------
/src/css/messages.css:
--------------------------------------------------------------------------------
1 | .codeVisual {
2 | display: block;
3 | position: absolute;
4 | pointer-events: none;
5 | z-index: -999;
6 | }
7 |
8 | .codeVisual.highlight {
9 | border-radius: 5px;
10 |
11 | background-color: rgba(255, 255, 255, 0);
12 |
13 | transition: background-color 0.3s ease-in-out;
14 | -webkit-transition: background-color 0.3s ease-in-out;
15 | -moz-transition: background-color 0.3s ease-in-out;
16 | -o-transition: background-color 0.3s ease-in-out;
17 | -ms-transition: background-color 0.3s ease-in-out;
18 | }
19 |
20 | .scope-header-highlight {
21 | display: block;
22 | position: absolute;
23 | pointer-events: none;
24 | z-index: -999;
25 |
26 | border-top-left-radius: 6px;
27 | border-bottom-left-radius: 6px;
28 | border-top-right-radius: 6px;
29 | }
30 |
31 | .scope-body-highlight {
32 | display: block;
33 | position: absolute;
34 | pointer-events: none;
35 | z-index: -999;
36 |
37 | border-bottom-left-radius: 6px;
38 | border-bottom-right-radius: 6px;
39 | }
40 |
41 | .codeVisual.textBox {
42 | font-family: Consolas, "Courier New", monospace;
43 | color: #000;
44 | font-size: 14px;
45 |
46 | box-shadow: 0 0 7px 1px #888;
47 | background-color: #c5d2d9;
48 | overflow-y: scroll;
49 | overflow-wrap: break-word;
50 | scrollbar-width: none;
51 |
52 | max-width: 40vw;
53 | width: 40vw;
54 | height: fit-content;
55 | max-height: 40vh;
56 |
57 | display: block;
58 | height: fit-content;
59 |
60 | border-radius: 5px;
61 |
62 | pointer-events: all;
63 | z-index: 999;
64 | }
65 |
66 | .codeVisual.textBox::-webkit-scrollbar {
67 | display: none;
68 | }
69 |
70 | .codeVisual .text-container-style {
71 | margin-bottom: 5px;
72 | line-height: 18px;
73 | }
74 |
75 | .codeVisual .msg-content-container {
76 | padding: 8px;
77 | }
78 |
79 | .codeVisual.popUp {
80 | background-color: rgb(253, 198, 115);
81 | color: black;
82 | position: absolute;
83 | width: 125px;
84 | height: fit-content;
85 | max-height: 30%;
86 | }
87 |
88 | .identifier {
89 | color: blueviolet;
90 | font-weight: bold;
91 | }
92 |
93 | .type {
94 | font-weight: bold;
95 | background-color: #99a7ad;
96 | padding: 1px 5px 1px 5px;
97 | border-radius: 3px;
98 | }
99 |
100 | .keyword {
101 | color: blue;
102 | font-weight: 500;
103 | }
104 |
105 | .other {
106 | font-weight: 600;
107 | }
108 |
109 | .emph {
110 | font-weight: 700;
111 | }
112 |
113 | .codeVisual.textBox .button {
114 | display: inline-flex;
115 | margin: 7px 7px 0 0;
116 | font-size: 13px;
117 | box-shadow: 0 0 3px 1px #aaa;
118 |
119 | background-color: #ffffff;
120 | height: 17px;
121 | padding: 3px 8px 3px 8px;
122 | align-content: center;
123 | }
124 |
125 | .hover-msg-header {
126 | width: 100%;
127 | height: 20px;
128 | background-color: rgb(130 155 169);
129 | color: white;
130 | display: flex;
131 | flex-direction: row;
132 | align-items: center;
133 | padding-left: 8px;
134 | }
135 |
--------------------------------------------------------------------------------
/src/css/notification.css:
--------------------------------------------------------------------------------
1 | .notification-container {
2 | padding: 10px;
3 | border-radius: 6px;
4 | position: fixed;
5 | bottom: calc(30% + 25px);
6 | right: 25px;
7 | width: 450px;
8 | z-index: 9999;
9 | background-color: rgb(102 65 173 / 50%);
10 | font-family: Consolas, "Courier New", monospace;
11 |
12 | opacity: 0;
13 | transform: scale(0.75);
14 | }
15 |
16 | .notification-container .message {
17 | font-size: 17px;
18 | }
19 |
20 | .notification-container .message .code {
21 | background-color: #64a;
22 | border-radius: 4px;
23 | padding: 3px 5px;
24 | color: #fff;
25 | font-weight: bold;
26 | }
27 |
28 | .animate {
29 | transition: all 0.2s ease-in-out;
30 | opacity: 1;
31 | transform: scale(1);
32 | }
33 |
34 | .key-animation-container {
35 | margin-top: 10px;
36 | }
37 |
38 | .key-animation-container .key-span {
39 | display: inline-block;
40 | margin-right: 8px;
41 | padding: 5px 5px;
42 | border-radius: 4px;
43 | background-color: #0ff;
44 | font-size: 20px;
45 | font-weight: bold;
46 | }
47 |
48 | expr-hole {
49 | border-radius: 2px;
50 | margin: 0px 3px;
51 | min-width: 21px;
52 | height: 10px;
53 | display: inline-block;
54 | }
55 |
56 | id-hole {
57 | height: 10px;
58 | width: 8px;
59 | display: inline-block;
60 | }
61 |
--------------------------------------------------------------------------------
/src/css/suggestion-menu.css:
--------------------------------------------------------------------------------
1 | .suggestionMenuParent {
2 | display: flex;
3 | flex-direction: column;
4 | position: absolute;
5 | width: fit-content;
6 | max-width: 50%;
7 | min-width: 2%;
8 |
9 | overflow-y: scroll;
10 | scrollbar-width: none; /* Firefox */
11 | -ms-overflow-style: none; /* Internet Explorer 10+ */
12 | }
13 | .suggestionMenuParent::-webkit-scrollbar {
14 | width: 0;
15 | height: 0;
16 | }
17 |
18 | .suggestionMenuParent hole1 {
19 | border-radius: 5px;
20 | box-shadow: 0px 0px 1px 1px #0000005e inset;
21 | display: inline-block;
22 |
23 | position: relative;
24 | top: 2px;
25 | margin: 0px 2px;
26 | height: 16px;
27 | min-width: 16px;
28 | }
29 |
30 | .suggestionMenuParent hole2 {
31 | border-radius: 5px;
32 | box-shadow: 0px 0px 1px 1px #0000005e inset;
33 | display: inline-block;
34 |
35 | position: relative;
36 | top: 2px;
37 | margin: 0px 2px;
38 | box-shadow: none;
39 | border: dashed 1px #777;
40 | min-width: 9px;
41 | height: 13px;
42 | border-radius: 0;
43 | }
44 |
45 | .suggestionOptionParent {
46 | padding-left: 2px;
47 | padding-top: 2px;
48 | padding-bottom: 2px;
49 | padding-right: 2px;
50 | background-color: rgba(215, 215, 215, 0.7);
51 | cursor: pointer;
52 |
53 | height: fit-content;
54 |
55 | font-family: Consolas, "Courier New", monospace;
56 | font-weight: normal;
57 | font-feature-settings: "liga" 0, "calt" 0;
58 | }
59 |
60 | :hover.suggestionOptionParent {
61 | background-color: rgba(176, 202, 243, 0.9);
62 | }
63 |
64 | .suggestionOptionText {
65 | color: black;
66 | width: fit-content;
67 | font-size: 18px;
68 | line-height: 22px;
69 | letter-spacing: -0.5px;
70 | float: left;
71 | }
72 |
73 | .suggestionOptionExtraInfo {
74 | float: right;
75 | margin-left: 30px;
76 | margin-right: 5px;
77 | color: #555;
78 | position: relative;
79 | top: 2px;
80 | }
81 |
82 | .highlighted-text {
83 | background-color: #cc00ef;
84 | color: #fff;
85 | font-weight: bold;
86 |
87 | padding: 0 5px;
88 | border-radius: 3px;
89 | }
90 |
91 | .matchingText {
92 | color: #cc00ef;
93 | font-weight: bold;
94 | }
95 |
96 | .selectedSuggestionOptionParent {
97 | background-color: rgba(93, 149, 240, 0.9) !important;
98 | }
99 |
100 | .draftModeOptionElementClass {
101 | background-color: rgba(230, 233, 202, 0.7);
102 | }
103 |
104 | .optionArrowImage {
105 | grid-column-start: 2;
106 | grid-column-end: 2;
107 | grid-row-start: 1;
108 | grid-row-end: 1;
109 |
110 | width: 8px;
111 | height: 10px;
112 | align-self: center;
113 | justify-self: end;
114 | }
115 |
116 | .categoryHeading {
117 | font-weight: bold;
118 | }
119 |
120 | .categoryOption {
121 | padding-left: 10px;
122 | }
123 |
--------------------------------------------------------------------------------
/src/css/toolbox.css:
--------------------------------------------------------------------------------
1 | #toolbox-container {
2 | display: flex;
3 | flex-direction: column;
4 |
5 | box-shadow: 20px -50px 50px -15px #ccc;
6 |
7 | min-width: 375px;
8 |
9 | font-family: Consolas, "Courier New", monospace;
10 | }
11 |
12 | #editor-toolbox {
13 | display: flex;
14 | flex-direction: column;
15 |
16 | overflow-x: hidden;
17 | overflow-y: scroll;
18 |
19 | border-left: solid 1px #ddd;
20 |
21 | height: calc(100% - 75px);
22 | }
23 |
24 | #editor-toolbox .button {
25 | font-size: 15px;
26 | padding: 6px 10px;
27 |
28 | white-space: nowrap;
29 | box-shadow: 0px 1px 5px 2px #ddd;
30 |
31 | transition: 0.15s ease-in-out;
32 | -webkit-transition: 0.15s ease-in-out;
33 | -moz-transition: 0.15s ease-in-out;
34 | -o-transition: 0.15s ease-in-out;
35 | -ms-transition: 0.15s ease-in-out;
36 |
37 | -webkit-user-select: none; /* Safari */
38 | -moz-user-select: none; /* Firefox */
39 | -ms-user-select: none; /* IE10+/Edge */
40 | user-select: none; /* Standard */
41 | }
42 |
43 | #editor-toolbox .button:hover {
44 | box-shadow: 0px 1px 5px 2px #ccc;
45 | }
46 |
47 | hole1 {
48 | min-width: 25px;
49 | height: 15px;
50 | border-radius: 10px;
51 | box-shadow: 0px 0px 1px 1px #0000005e inset;
52 | margin: 0px 3px;
53 | display: inline-block;
54 | }
55 |
56 | hole2 {
57 | margin: 0px 3px;
58 | display: inline-block;
59 | box-shadow: none;
60 | border: dashed 1px #c7c7c7;
61 | min-width: 12px;
62 | height: 16px;
63 | }
64 |
65 | #user-variables {
66 | height: calc(100% - 25px);
67 | overflow-y: auto;
68 | }
69 |
70 | .var-button {
71 | font-size: 16px;
72 | padding: 3px 14px;
73 | white-space: nowrap;
74 | box-shadow: 0px 1px 5px 2px #ddd;
75 | transition: 0.15s ease-in-out;
76 | -webkit-transition: 0.15s ease-in-out;
77 | font-weight: bold;
78 | background-color: #b200c4;
79 | border-radius: 25px;
80 | cursor: pointer;
81 | color: #fff;
82 | }
83 |
84 | .var-button:hover {
85 | box-shadow: 0px 1px 5px 2px #b200c499;
86 | }
87 |
88 | .var-container-wrapper {
89 | display: flex;
90 | margin-left: 5px;
91 | }
92 |
93 | .var-button-container {
94 | display: flex;
95 | align-items: center;
96 | justify-content: space-between;
97 |
98 | padding: 5px 0;
99 | border-radius: 6px;
100 |
101 | box-shadow: 0 0 0 0 #5de1a5;
102 |
103 | transition: 0.5s ease-in-out;
104 | -webkit-transition: 0.5s ease-in-out;
105 | -moz-transition: 0.5s ease-in-out;
106 | -o-transition: 0.5s ease-in-out;
107 | -ms-transition: 0.5s ease-in-out;
108 | }
109 |
110 | .glowing {
111 | box-shadow: 0 0 10px 6px #5de1a5;
112 | background-color: #c6f5e0;
113 | }
114 |
115 | #editor-toolbox .group {
116 | justify-items: start;
117 | margin: 0 0 20px 10px;
118 | }
119 |
120 | #editor-toolbox .group > p {
121 | grid-column: 1 / span 2;
122 | grid-row: 1 / span 1;
123 | font-weight: bold;
124 | font-size: 20px;
125 |
126 | margin: 5px 0 5px 0;
127 | }
128 |
129 | #editor-toolbox::-webkit-scrollbar {
130 | background: #ccc;
131 | margin: 5px;
132 | width: 8px;
133 | }
134 |
135 | #editor-toolbox::-webkit-scrollbar-track {
136 | background: #ebebeb;
137 | }
138 |
139 | #editor-toolbox::-webkit-scrollbar-thumb {
140 | border: none;
141 | background-color: #b8ccd1;
142 | border-radius: 0px;
143 | }
144 |
145 | #user-variables::-webkit-scrollbar {
146 | background: #ccc;
147 | margin: 5px;
148 | width: 8px;
149 | }
150 |
151 | #user-variables::-webkit-scrollbar-track {
152 | background: #ebebeb;
153 | }
154 |
155 | #user-variables::-webkit-scrollbar-thumb {
156 | border: none;
157 | background-color: #b8ccd1;
158 | border-radius: 0px;
159 | }
160 |
161 | #toolbox-menu {
162 | float: left;
163 | }
164 |
165 | #toolbox-menu .menu-button {
166 | border-radius: 3px;
167 | padding: 5px 10px 5px 10px;
168 | cursor: pointer;
169 | color: #26265a;
170 | font-size: 16px;
171 |
172 | transition: 0.15s ease-in-out;
173 | -webkit-transition: 0.15s ease-in-out;
174 | -moz-transition: 0.15s ease-in-out;
175 | -o-transition: 0.15s ease-in-out;
176 | -ms-transition: 0.15s ease-in-out;
177 | }
178 |
179 | #toolbox-menu .menu-button:hover {
180 | background-color: #e0efff;
181 | font-weight: bold;
182 | }
183 |
184 | #static-toolbox {
185 | height: 70%;
186 | }
187 |
188 | #dynamic-toolbox {
189 | height: 30%;
190 | }
191 |
192 | .box-header {
193 | height: 25px;
194 | background-color: #69a;
195 | color: #fff;
196 |
197 | display: flex;
198 | flex-direction: column;
199 | justify-content: center;
200 | }
201 |
202 | .box-header h2 {
203 | display: block;
204 | margin-block-end: 0px;
205 | margin-block-start: 0px;
206 | font-size: 18px;
207 | font-weight: bold;
208 | margin-left: 10px;
209 | }
210 |
211 | #vars-button-grid {
212 | margin: 5px;
213 | }
214 |
215 | .learn-button {
216 | position: relative;
217 | border-radius: 5px;
218 | border: solid 1px #fff;
219 | padding: 0px 10px;
220 | margin-right: 10px;
221 | font-size: 14px;
222 | color: #006a93;
223 | display: inline-flex;
224 | flex-direction: column;
225 | justify-content: center;
226 | font-weight: bold;
227 | align-items: center;
228 | box-shadow: 0 0 6px 1px rgb(0 71 99);
229 | font-family: Consolas, "Courier New", monospace;
230 | height: 20px;
231 | cursor: pointer;
232 | background-color: #fff;
233 |
234 | transition: background-color 0.15s ease-in-out;
235 | -webkit-transition: background-color 0.15s ease-in-out;
236 | -moz-transition: background-color 0.15s ease-in-out;
237 | -o-transition: background-color 0.15s ease-in-out;
238 | -ms-transition: background-color 0.15s ease-in-out;
239 | }
240 |
241 | .tooltip-container {
242 | font-family: Consolas, "Courier New", monospace;
243 | position: fixed;
244 | display: none;
245 | color: #fff;
246 | border-radius: 10px;
247 | width: 500px;
248 | overflow: hidden;
249 | background: rgb(0 162 225);
250 | box-shadow: 0px 8px 16px 0px rgb(0 0 0 / 20%);
251 | opacity: 0;
252 |
253 | transition: opacity 0.1s ease-in-out;
254 | -webkit-transition: opacity 0.1s ease-in-out;
255 | -moz-transition: opacity 0.1s ease-in-out;
256 | -o-transition: opacity 0.1s ease-in-out;
257 | -ms-transition: opacity 0.1s ease-in-out;
258 | }
259 |
260 | .tooltip-container .tooltip-top {
261 | background-color: rgb(0 106 147);
262 | font-size: 14px;
263 | }
264 |
265 | .tooltip-container .tooltip-header {
266 | display: flex;
267 | flex-direction: row;
268 | align-items: center;
269 | justify-content: space-between;
270 | }
271 |
272 | .tooltip-container .tooltip-header h4 {
273 | font-weight: bold;
274 | font-size: 16px;
275 | margin: 0;
276 | padding: 10px;
277 | }
278 |
279 | .tooltip-container .tooltip-text {
280 | font-size: 14px;
281 | padding: 0 10px 10px;
282 | margin: 0;
283 | }
284 |
285 | .tooltip-container .error-text {
286 | padding: 5px 10px;
287 | color: #000;
288 | background-color: rgb(255 200 200);
289 | box-shadow: 0px 0px 10px 0px rgb(0 65 72);
290 | }
291 |
292 | .tooltip-container .warning-text {
293 | padding: 5px 10px;
294 | color: #000;
295 | background-color: rgb(255 255 205);
296 | box-shadow: 0px 0px 10px 0px rgb(0 65 72);
297 | }
298 |
299 | .tooltip-container .return-type-text {
300 | padding: 5px 10px;
301 | background-color: rgb(0 133 147);
302 | box-shadow: 0px 0px 10px 0px rgb(0 65 72);
303 | }
304 |
305 | .tooltip-container .return-type-text .return-type {
306 | padding: 0 5px;
307 | border-radius: 3px;
308 | background-color: #8d97a3;
309 | color: #000;
310 | font-weight: bold;
311 | }
312 |
313 | .tooltip-container .learn-button:hover {
314 | background-color: rgb(0 106 147);
315 | color: #fff;
316 | }
317 |
318 | .tooltip-container .use-cases-container {
319 | max-height: 300px;
320 | overflow-y: scroll;
321 | background-color: #fff;
322 | padding-bottom: 10px;
323 | }
324 |
325 | .tooltip-container .spacing {
326 | height: 5px;
327 | }
328 |
329 | .tooltip-container .use-cases-container::-webkit-scrollbar {
330 | background: #ccc;
331 | margin: 5px;
332 | width: 8px;
333 | }
334 |
335 | .tooltip-container .use-cases-container::-webkit-scrollbar-track {
336 | background: #ebebeb;
337 | }
338 |
339 | .tooltip-container .use-cases-container::-webkit-scrollbar-thumb {
340 | border: none;
341 | background-color: #b8ccd1;
342 | border-radius: 0px;
343 | }
344 |
345 | .tooltip-container .quick-tip {
346 | border-top: solid 1px #ccc;
347 | padding: 5px;
348 | color: #000;
349 | font-size: 14px;
350 | }
351 |
352 | .tooltip-container .quick-tip .quick-tip-text {
353 | font-size: 13px;
354 | color: #000;
355 | }
356 |
357 | .tooltip-container .quick-tip .quick-tip-title {
358 | font-size: 13px;
359 | color: #fff;
360 | background-color: #00aeae;
361 | padding: 1px 4px;
362 | border-radius: 3px;
363 | margin-right: 5px;
364 | font-weight: bold;
365 | }
366 |
367 | .tooltip-container .single-use-case-container {
368 | color: #000;
369 | font-weight: bold;
370 | border-top: solid 1px #ccc;
371 | }
372 |
373 | .tooltip-container .single-use-case-container .use-case-title {
374 | padding: 5px 5px 5px 10px;
375 | font-weight: bold;
376 | font-size: 13px;
377 | cursor: pointer;
378 | display: flex;
379 | justify-content: space-between;
380 |
381 | transition: background-color 0.15s ease-in-out;
382 | -webkit-transition: background-color 0.15s ease-in-out;
383 | -moz-transition: background-color 0.15s ease-in-out;
384 | -o-transition: background-color 0.15s ease-in-out;
385 | -ms-transition: background-color 0.15s ease-in-out;
386 | }
387 |
388 | .tooltip-container .single-use-case-container .use-case-title:hover {
389 | background-color: #cfe3eb !important;
390 | }
391 |
392 | .tooltip-container .single-use-case-container .use-case-title .use-case-title-header {
393 | /* margin-top: 4px; */
394 | }
395 |
396 | .tooltip-container .single-use-case-container .use-case-learn-button {
397 | color: #000000;
398 | cursor: pointer;
399 | border-radius: 4px;
400 | font-size: 14px;
401 | padding: 3px 10px;
402 | border: solid 1px #006a938c;
403 | background-color: #006a931f;
404 |
405 | transition: background-color 0.2s ease-in-out;
406 | -webkit-transition: background-color 0.2s ease-in-out;
407 | -moz-transition: background-color 0.2s ease-in-out;
408 | -o-transition: background-color 0.2s ease-in-out;
409 | -ms-transition: background-color 0.2s ease-in-out;
410 |
411 | transition: opacity 0.4 ease-in-out;
412 | -webkit-transition: opacity 0.4 ease-in-out;
413 | -moz-transition: opacity 0.4 ease-in-out;
414 | -o-transition: opacity 0.4 ease-in-out;
415 | -ms-transition: opacity 0.4 ease-in-out;
416 | }
417 |
418 | .tooltip-container .single-use-case-container .use-case-learn-button:hover {
419 | background-color: #006a9338;
420 | }
421 |
422 | .tooltip-container .slider-container {
423 | font-family: Consolas, "Courier New", monospace;
424 |
425 | transition: max-height 0.15s ease-in-out;
426 | -webkit-transition: max-height 0.15s ease-in-out;
427 | -moz-transition: max-height 0.15s ease-in-out;
428 | -o-transition: max-height 0.15s ease-in-out;
429 | -ms-transition: max-height 0.15s ease-in-out;
430 | }
431 |
432 | .tooltip-container .slider-container .range-slider {
433 | display: inline-block;
434 | flex-grow: 1;
435 | }
436 |
437 | .tooltip-container .slider-container .slider-btn {
438 | display: inline-block;
439 | cursor: pointer;
440 | -webkit-user-select: none;
441 | -moz-user-select: none;
442 | -ms-user-select: none;
443 | user-select: none;
444 | background-color: #7017ff;
445 | margin: 0 10px 0;
446 | padding: 5px 10px;
447 | border-radius: 5px;
448 | font-weight: bold;
449 | box-shadow: rgb(0 0 0 / 20%) 0px 3px 1px -2px, rgb(0 0 0 / 14%) 0px 2px 2px 0px, rgb(0 0 0 / 12%) 0px 1px 5px 0px;
450 | color: #fff;
451 | }
452 |
453 | .tooltip-container .slider-container .slider-image {
454 | width: 470px;
455 | display: block;
456 | }
457 |
458 | .tooltip-container .slider-container .labels-container {
459 | display: flex;
460 | font-size: 14px;
461 | justify-content: center;
462 | }
463 |
464 | .tooltip-container .slider-container .slider-label {
465 | border: solid 2px #00719e;
466 | margin: 10px 0 10px 10px;
467 | padding: 3px 7px;
468 | border-radius: 5px;
469 | background-color: #0a82b1;
470 | color: #ffffff;
471 | }
472 |
473 | .tooltip-container .slider-container .explanation-container {
474 | margin: 5px;
475 | padding: 3px 7px;
476 | border-radius: 5px;
477 | background-color: #7017ff;
478 | color: #ffffff;
479 | position: relative;
480 | }
481 |
482 | .tooltip-container .slider-container .explanation-container::after {
483 | content: "";
484 | position: absolute;
485 | bottom: 98%;
486 | left: 49%;
487 | margin-left: -5px;
488 | border-width: 7px;
489 | border-style: solid;
490 | border-color: transparent transparent #7017ff transparent;
491 | }
492 |
493 | .tooltip-container .slider-container .buttons-container {
494 | display: flex;
495 | margin-bottom: 5px;
496 | }
497 |
498 | .statement-button {
499 | border-bottom: solid #fff0 3.5px;
500 |
501 | transition: border 0.15s ease-in-out;
502 | -webkit-transition: border 0.15s ease-in-out;
503 | -moz-transition: border 0.15s ease-in-out;
504 | -o-transition: border 0.15s ease-in-out;
505 | -ms-transition: border 0.15s ease-in-out;
506 | }
507 |
508 | .statement-button:hover {
509 | border-bottom: solid #05c8ac 3.5px !important;
510 | }
511 |
512 | .expression-button {
513 | border: solid #fff0 3px;
514 | padding-left: 10px !important;
515 | padding-right: 10px !important;
516 | border-radius: 25px !important;
517 |
518 | transition: border 0.15s ease-in-out;
519 | -webkit-transition: border 0.15s ease-in-out;
520 | -moz-transition: border 0.15s ease-in-out;
521 | -o-transition: border 0.15s ease-in-out;
522 | -ms-transition: border 0.15s ease-in-out;
523 | }
524 |
525 | .expression-button:hover {
526 | border: solid #05c8ac 3px !important;
527 | }
528 |
529 | .modifier-button {
530 | border-left: solid #fff0 3.5px;
531 |
532 | transition: border 0.15s ease-in-out;
533 | -webkit-transition: border 0.15s ease-in-out;
534 | -moz-transition: border 0.15s ease-in-out;
535 | -o-transition: border 0.15s ease-in-out;
536 | -ms-transition: border 0.15s ease-in-out;
537 | }
538 |
539 | .modifier-button:hover {
540 | border-left: solid #05c8ac 3.5px !important;
541 | }
542 |
543 | .var-type-text {
544 | align-self: center;
545 | font-size: 14px;
546 | margin-left: 10px;
547 | }
548 |
549 | .search-box {
550 | height: 30px;
551 | width: calc(100% - 20px);
552 | margin: 10px;
553 | box-shadow: 0px 0px 6px 1px #ccc inset;
554 | border: 1px solid #ccc;
555 | border-radius: 6px;
556 | padding: 7px;
557 | font-family: Consolas, "Courier New", monospace;
558 |
559 | transition: box-shadow 0.15s ease-in-out;
560 | -webkit-transition: box-shadow 0.15s ease-in-out;
561 | -moz-transition: box-shadow 0.15s ease-in-out;
562 | -o-transition: box-shadow 0.15s ease-in-out;
563 | -ms-transition: box-shadow 0.15s ease-in-out;
564 | }
565 |
566 | .search-box:hover {
567 | box-shadow: 0px 0px 6px 1px #aaa inset;
568 | font-weight: bold;
569 | }
570 |
571 | .search-box:focus-visible {
572 | border: 1px solid #bbb;
573 | outline: none;
574 | font-weight: bold;
575 | }
576 |
577 | .def-vars-type-title-span {
578 | font-style: italic;
579 | }
580 |
581 | .def-vars-type-span {
582 | font-style: normal;
583 | font-weight: bold;
584 | color: #006bff;
585 | }
586 |
587 | .defined-var-container {
588 | border-bottom: solid #ccc 1px;
589 | flex-direction: column;
590 | display: flex;
591 | }
592 |
593 | .immediate-tooltip {
594 | display: inline-block;
595 | box-shadow: 0px 1px 5px 2px #ddd;
596 | padding: 3px 8px;
597 | border-radius: 2px;
598 | margin-left: 6px;
599 | }
600 |
601 | .immediate-tooltips-container {
602 | font-size: 13px;
603 | }
604 |
605 | .cascaded-menu-extra-container {
606 | background-color: #008593;
607 | padding: 10px;
608 | }
609 |
610 | .cascaded-menu-extra-item {
611 | border-radius: 4px;
612 | border: solid 1px #ddd;
613 | padding: 5px 10px;
614 | color: #fff;
615 | }
616 |
617 | .cascaded-menu-extra-item:not(:last-child) {
618 | margin-bottom: 5px;
619 | }
620 |
621 | .cascaded-menu-extra-item .code {
622 | color: #0f0fff;
623 | border-radius: 4px;
624 | padding: 0px 6px;
625 | background-color: #fff;
626 | font-weight: bold;
627 | }
628 |
629 | .cascaded-menu-extra-item .inline-var {
630 | color: #aa5bc8;
631 | }
632 |
--------------------------------------------------------------------------------
/src/css/tooltip.css:
--------------------------------------------------------------------------------
1 | .tooltip-top-container {
2 | width: 100%;
3 | background-color: black;
4 | color: #fff;
5 | text-align: center;
6 | border-radius: 6px;
7 | padding: 5px 0;
8 | position: absolute;
9 | z-index: 1;
10 | top: 150%;
11 | left: 50%;
12 | margin-left: -60px;
13 | }
14 |
15 | .tooltip-top-container::after {
16 | content: "";
17 | position: absolute;
18 | bottom: 100%;
19 | left: 50%;
20 | margin-left: -5px;
21 | border-width: 5px;
22 | border-style: solid;
23 | border-color: transparent transparent black transparent;
24 | }
25 |
26 | .tooltip-left-container {
27 | width: 100%;
28 | background-color: black;
29 | color: #fff;
30 | text-align: center;
31 | border-radius: 6px;
32 | padding: 5px 0;
33 | position: absolute;
34 | z-index: 1;
35 | top: -5px;
36 | left: 110%;
37 | }
38 |
39 | .tooltip-left-container::after {
40 | content: "";
41 | position: absolute;
42 | top: 50%;
43 | right: 100%;
44 | margin-top: -5px;
45 | border-width: 5px;
46 | border-style: solid;
47 | border-color: transparent black transparent transparent;
48 | }
49 |
--------------------------------------------------------------------------------
/src/docs/add-var.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Create/Reassign Variable",
3 | "tooltip": {
4 | "title": "Create Variable Assignment",
5 | "body": "Allows to store a value and give it a name to reference it by later."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-declare-print-var",
11 | "example": "name = \"John\"\nprint(name)"
12 | },
13 | {
14 | "type": "quick",
15 | "text": "A variable is created the moment you first assign a value to it."
16 | },
17 | {
18 | "type": "bullet-point",
19 | "title": "variable naming",
20 | "bullets": [
21 | "Variable names can only contain letters, numbers, and underscores",
22 | "Variable names are case-sensitive (\"x\" and \"X\" are different)",
23 | "A variable name must start with a letter or the underscore character",
24 | "A variable name cannot start with a number"
25 | ]
26 | }
27 | ],
28 | "search-queries": ["create new variable", "variable", "var"]
29 | }
30 |
--------------------------------------------------------------------------------
/src/docs/add.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "add",
3 | "tooltip": {
4 | "title": "Insert Addition",
5 | "body": "Adds the values to the left and right of the operator."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-sum-numbers",
11 | "example": "a = 2\nb = 5\nprint((a + b))"
12 | },
13 | {
14 | "type": "executable",
15 | "id": "ex-sum-strings",
16 | "example": "a = \"hello\"\nb = \"world\"\nprint((a + \" \" + b))"
17 | }
18 | ],
19 | "search-queries": ["add", "sum"]
20 | }
21 |
--------------------------------------------------------------------------------
/src/docs/and.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "and",
3 | "tooltip": {
4 | "title": "And Operator",
5 | "body": "Used to combine conditional expressions. Results in True if both the left and right expressions are True; returns False otherwise."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-and-four-cases",
11 | "example": "if (true and true):\n\tprint(true)\n\nif (true and false):\n\tprint(\"not true\")\n\nif (false and true):\n\tprint(\"still not true\")\n\nif (false and false):\n\tprint(\"also false\")"
12 | },
13 | {
14 | "type": "executable",
15 | "id": "ex-gt-and-gt",
16 | "example": "a = 5\nb = 7\nc=2\n\nif ((a > c) and (b > c)):\n\tprint(\"Both expressions are true.\")"
17 | }
18 | ],
19 | "search-queries": ["and", "both", "and operator"]
20 | }
21 |
--------------------------------------------------------------------------------
/src/docs/assign-add.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Add to Variable",
3 | "tooltip": {
4 | "title": "Add Value to Variable",
5 | "body": "Adds the value on the right-hand side of the += sign to the specified variable and stores the result in the variable."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-var-sum-by-val",
11 | "example": "a = 2\na += 2\nprint(a)"
12 | }
13 | ],
14 | "search-queries": ["add to variable"]
15 | }
16 |
--------------------------------------------------------------------------------
/src/docs/assign-div.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Divide a Variable",
3 | "tooltip": {
4 | "title": "Divide Variable by Value",
5 | "body": "Divides the variable by the value given on the right-hand side of the /= sign and stores the result back in the variable."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-var-divide-by-value",
11 | "example": "a = 10\na /= 2\nprint(a)"
12 | }
13 | ],
14 | "search-queries": ["divide variable"]
15 | }
16 |
--------------------------------------------------------------------------------
/src/docs/assign-mult.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Multiply a Variable",
3 | "tooltip": {
4 | "title": "Multiply Variable by Value",
5 | "body": "Multiplies the variable by the value on the right-hand side of the *= sign and stores the result back in the variable."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-var-mul-by-val",
11 | "example": "a = 5\na *= 2\nprint(a)"
12 | }
13 | ],
14 | "search-queries": ["multiply variable"]
15 | }
16 |
--------------------------------------------------------------------------------
/src/docs/assign-sub.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Subtract from Variable",
3 | "tooltip": {
4 | "title": "Subtract Value from Variable",
5 | "body": "Subtracts the value on the right-hand side of the -= sign from the specified variable and stores the result back in the variable."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-var-sub-by-val",
11 | "example": "a = 5\na -= 2\nprint(a)"
12 | }
13 | ],
14 | "search-queries": ["subtract from variable", "deduct from variable"]
15 | }
16 |
--------------------------------------------------------------------------------
/src/docs/assign.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Assign to Variable",
3 | "tooltip": {
4 | "title": "Update Value of Variable",
5 | "body": "Allows assigning a new value to an existing variable."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-assign-val-var-twice",
11 | "example": "a = 123\nprint(a)\na=321\nprint(a)"
12 | }
13 | ],
14 | "search-queries": ["set", "assign", "assign variable", "set variable", "update value variable"]
15 | }
16 |
--------------------------------------------------------------------------------
/src/docs/break.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Break out of loops",
3 | "tooltip": {
4 | "title": "Insert Break inside Loop",
5 | "body": "Stops the innermost running loop (for, while) and breaks out of it."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-break-out-range",
11 | "example": "for i in range(0, 50):\n\tif i == 25:\n\t\tbreak\n\tprint(i)"
12 | },
13 | {
14 | "type": "use-case",
15 | "title": "break out of a while loop on some condition",
16 | "path": "https://cdn.majeed.cc/pydoc/images/use-cases/3-break/",
17 | "max": 30,
18 | "extension": "PNG",
19 | "prefix": "Slide",
20 | "id": "break-while-on-condition",
21 | "explanations": [
22 | { "slide": 5, "text": "variable i is defined and set to 0" },
23 | { "slide": 6, "text": "should repeat the while statements if i < 10" },
24 | { "slide": 7, "text": "i is 0 and less than 10 -> should repeat" },
25 | { "slide": 9, "text": "i is 0, so i + 1 is 1" },
26 | { "slide": 11, "text": "i becomes 1" },
27 | { "slide": 12, "text": "should enter the if statements if i equals 3" },
28 | { "slide": 13, "text": "i is 1 so shouldn't enter the if" },
29 | { "slide": 16, "text": "i is 1, so i + 1 is 2" },
30 | { "slide": 14, "text": "should continue repeating because i is 1" },
31 | { "slide": 18, "text": "i becomes 2" },
32 | { "slide": 20, "text": "i is not equal to 3" },
33 | { "slide": 21, "text": "should continue repeating because i is 2" },
34 | { "slide": 23, "text": "i is 2, so i + 1 is 3" },
35 | { "slide": 25, "text": "i becomes 3" },
36 | { "slide": 27, "text": "is equal to 3 -> should enter if" },
37 | { "slide": 28, "text": "break out of the current loop" },
38 | { "slide": 29, "text": "won't check the while condition as we used break" },
39 | { "slide": 30, "text": "will print 'done'" }
40 | ]
41 | }
42 | ],
43 | "search-queries": ["exit", "loop", "break"]
44 | }
45 |
--------------------------------------------------------------------------------
/src/docs/choice.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "choice(choices: list[any])",
3 | "tooltip": {
4 | "title": "Insert Choice from List",
5 | "body": "Randomly selects and returns an item from the given list. Needs to be imported from the random module."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-choice",
11 | "example": "from random import choice\n\nif choice([1, 2, 3, 4, 5, 6]) == 6:\n\tprint(\"Rolled Six!\")"
12 | }
13 | ],
14 | "search-queries": ["choice", "random choice", "choose randomly from list", "select randomly from array"]
15 | }
16 |
--------------------------------------------------------------------------------
/src/docs/comp-eq.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Is Equal?",
3 | "tooltip": {
4 | "title": "Is Equal?",
5 | "body": "Compares two values. Returns True if they are equal; returns False otherwise."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-is-eq-1",
11 | "example": "a = 2\nb = 3\nif a == c:\n\tprint(\"a is equal to c\")\n\nif b == a:\n\tprint(\"This will not print because the condition is false.\")"
12 | },
13 | {
14 | "type": "executable",
15 | "id": "ex-is-eq-2",
16 | "example": "a = 5\nb = 5\nwhile a == b:\n\ta += 1\nprint(a)\nprint(a)"
17 | }
18 | ],
19 | "search-queries": ["compare equal", "check equal", "are equal"]
20 | }
21 |
--------------------------------------------------------------------------------
/src/docs/comp-gt.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Is Greater Than?",
3 | "tooltip": {
4 | "title": "Is Greater Than?",
5 | "body": "Compares two values. Returns True if the left value is greater than the right value."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-gt-1",
11 | "example": "a = 2\nb = 3\nif b > a:\n\tprint(\"b is greater than a\")\n\nif a > b:\n\tprint(\"a is greater to b\")"
12 | },
13 | {
14 | "type": "executable",
15 | "id": "ex-gt-2",
16 | "example": "a = 1\nb = 5\nwhile b > a:\n\ta += 1\nprint(a)\nprint(a)"
17 | }
18 | ],
19 | "search-queries": ["compare greater than", "compare", "check greater than"]
20 | }
21 |
--------------------------------------------------------------------------------
/src/docs/comp-gte.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "is greater than or equal?",
3 | "tooltip": {
4 | "title": "Is Greater Than or Equal?",
5 | "body": "Compares two values. Returns True if the left value is greater than or equal to the right value."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-gte-1",
11 | "example": "a = 2\nb = 3\n c = 2\n if b >= a:\n\tprint(\"b is greater than a\")\n\nif c >= a:\n\tprint(\"c is equal to a\")"
12 | },
13 | {
14 | "type": "executable",
15 | "id": "ex-gt-1",
16 | "example": "a = 1\nb = 5\nwhile b >= a:\n\ta += 1\nprint(a)\nprint(a)"
17 | }
18 | ],
19 | "search-queries": ["compare greater than or equal", "compare", "check greater than or equal"]
20 | }
21 |
--------------------------------------------------------------------------------
/src/docs/comp-lt.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Is Less Than?",
3 | "tooltip": {
4 | "title": "Is Less Than?",
5 | "body": "Compares two values. Returns True if the left value is less than the right value."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-lt-1",
11 | "example": "a = 2\nb = 3\nif a < b:\n\tprint(\"a is less than b\")\n\nif c < a:\n\tprint(\"This will not print because the condition is false.\")"
12 | },
13 | {
14 | "type": "executable",
15 | "id": "ex-lt-2",
16 | "example": "a = 1\nb = 5\nwhile a < b:\n\ta += 1\nprint(a)\nprint(a)"
17 | }
18 | ],
19 | "search-queries": ["compare", "compare less than", "check less than"]
20 | }
21 |
--------------------------------------------------------------------------------
/src/docs/comp-lte.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "is less than or equal?",
3 | "tooltip": {
4 | "title": "Is Less Than or Equal?",
5 | "body": "Compares two values. Returns True if the left value is less than or equal to the right value."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-leq-1",
11 | "example": "a = 2\nb = 3\n c = 2\n if a <= b:\n\tprint(\"a is less than b\")\n\nif c <= a:\n\tprint(\"c is equal to a\")"
12 | },
13 | {
14 | "type": "executable",
15 | "id": "ex-leq-2",
16 | "example": "a = 1\nb = 5\nwhile a <= b:\n\ta += 1\nprint(a)\nprint(a)"
17 | }
18 | ],
19 | "search-queries": ["less than or equal", "compare", "compare less than or equal", "check"]
20 | }
21 |
--------------------------------------------------------------------------------
/src/docs/comp-ne.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Is Not Equal?",
3 | "tooltip": {
4 | "title": "Is Not Equal?",
5 | "body": "Compares two values. Returns True if they are not equal; returns False otherwise."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-not-equal-1",
11 | "example": "a = 2\nb = 3\nif a != b:\n\tprint(\"a is not equal to b\")\n\nif c != a:\n\tprint(\"This will not print because the condition is false.\")"
12 | },
13 | {
14 | "type": "executable",
15 | "id": "ex-not-equal-2",
16 | "example": "a = 1\nb = 5\nwhile a != b:\n\ta += 1\nprint(a)\nprint(a)"
17 | }
18 | ],
19 | "search-queries": ["not equal", "compare not equal", "not equal to", "are not equal"]
20 | }
21 |
--------------------------------------------------------------------------------
/src/docs/div.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "divide",
3 | "tooltip": {
4 | "title": "Insert Division",
5 | "body": "Divides the values to the left of the operator by the right value."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-div-two-vars",
11 | "example": "a = 2\nb = 10\nprint((b / a))"
12 | }
13 | ],
14 | "search-queries": ["divide", "division", "divide numbers"]
15 | }
16 |
--------------------------------------------------------------------------------
/src/docs/elif.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "elif statement",
3 | "tooltip": {
4 | "title": "Insert Elif Statement",
5 | "body": "Short for else-if; adds another case to an existing if statement. The `elif` will only run when previous `if` or `elif` statement is false"
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-elif-1",
11 | "example": "a = 3\nif a > 10:\n\tprint(\"a is larger than 10\")\nelif a < 10:\n\tprint(\"a is smaller than 10\")"
12 | },
13 | {
14 | "type": "executable",
15 | "id": "ex-elif-2",
16 | "example": "a = 5\nif a > 3:\n\tprint(3)\nelif a > 4:\n\tprint(4)\nelif a == 5:\n\tprint(5)\nelif a > 6:\n\tprint(6)"
17 | },
18 | {
19 | "type": "use-case",
20 | "title": "using elif after an if statement",
21 | "path": "https://cdn.majeed.cc/pydoc/images/use-cases/7-if-single-elif/",
22 | "max": 11,
23 | "extension": "PNG",
24 | "prefix": "Slide",
25 | "id": "elif-after-if"
26 | },
27 | {
28 | "type": "use-case",
29 | "title": "using elif after another elif statement",
30 | "path": "https://cdn.majeed.cc/pydoc/images/use-cases/7-if-double-elif/",
31 | "max": 13,
32 | "extension": "PNG",
33 | "prefix": "Slide",
34 | "id": "elif-after-elif"
35 | }
36 | ],
37 | "search-queries": ["else if", "else", "else condition", "choose", "path", "elif"]
38 | }
39 |
--------------------------------------------------------------------------------
/src/docs/else.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "else statement",
3 | "tooltip": {
4 | "title": "Insert Else Statement",
5 | "body": "Can be used after an if or an elif statement. will execute its block of code when the if and the elif statements were not true"
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-else-1",
11 | "example": "a = 2\nif a > 3:\n\tprint(3)\nelif a > 4:\n\tprint(4)\nelif a == 5:\n\tprint(5)\nelif a > 6:\n\tprint(6)\nelse:\n\tprint(\"None of the above are true.\")"
12 | }
13 | ],
14 | "search-queries": ["else", "otherwise", "if"]
15 | }
16 |
--------------------------------------------------------------------------------
/src/docs/f-str-item.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "formatted text item",
3 | "tooltip": {
4 | "title": "Formatted Text Item",
5 | "body": "Converts the item to its textual value. Can only be used inside a formatted text (f'')."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-f-str-item",
11 | "example": "age = 16\nname = \"Alex\"\nprint(f'My name is {name} and I am {age} years old')"
12 | }
13 | ],
14 | "search-queries": ["formatted string item", "formatted text item"]
15 | }
16 |
--------------------------------------------------------------------------------
/src/docs/f-str.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "formatted text",
3 | "tooltip": {
4 | "title": "Insert Formattable Text",
5 | "body": "Inserts an editable, formattable text; used along with the {} operator to include non-static values and variables inside the text."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-f-str-1",
11 | "example": "age = 16\nname = \"Alex\"\nprint(f'My name is {name} and I am {age} years old')"
12 | }
13 | ],
14 | "search-queries": ["formatted string", "formatted text"]
15 | }
16 |
--------------------------------------------------------------------------------
/src/docs/false.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "false",
3 | "tooltip": {
4 | "title": "Insert False",
5 | "body": "Inserts a False boolean value."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-false",
11 | "example": "if False :\n\tprint(\"will not print\")\n\nif True :\n\tprint(\"will print\")"
12 | }
13 | ],
14 | "search-queries": ["false", "boolean"]
15 | }
16 |
--------------------------------------------------------------------------------
/src/docs/find.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "find(txt: text)",
3 | "tooltip": {
4 | "title": "Call Find Method",
5 | "body": "Finds the first occurrence of the input's textual value in the text."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-find-1",
11 | "example": "name = \"Zimmer\"\nindexOfE = name.find(\"e\")\nprint(indexOfE)"
12 | }
13 | ],
14 | "search-queries": ["search text", "find text", "find string"]
15 | }
16 |
--------------------------------------------------------------------------------
/src/docs/floor-div.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "floor division",
3 | "tooltip": {
4 | "title": "Insert Floor Division",
5 | "body": "Performs integer division (remainder is discarded and always result is always rounded down) between the values to the left and right of the operator."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-floor-div",
11 | "example": "a = 2\nb = 7\nprint((b / a))"
12 | }
13 | ],
14 | "search-queries": ["divide numbers", "divide integer", "divide floor"]
15 | }
16 |
--------------------------------------------------------------------------------
/src/docs/for.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "for loop",
3 | "tooltip": {
4 | "title": "loop through a sequence of elements",
5 | "body": "executes a set of statements for each element in a sequence (like a `range`, a `list`, or a `string`). "
6 | },
7 | "tips": [
8 | {
9 | "type": "quick",
10 | "title": "for loop inputs",
11 | "text": "for loops have two inputs: a variable name, and a sequence of items. the created variable is used to hold the current item, and the sequence is the list of items to go through."
12 | },
13 | {
14 | "type": "quick",
15 | "title": "for loop as a counter",
16 | "text": "for loops can be used with the `range` function to work like a counter"
17 | },
18 | {
19 | "type": "executable",
20 | "title": "using a for loop to go through a list",
21 | "id": "ex-for-list-items",
22 | "example": "lst = [\"cat\", \"dog\", \"mouse\", \"parrot\"]\nfor animal in lst:\n\tprint(animal)"
23 | },
24 | {
25 | "type": "use-case",
26 | "title": "go through a list of items",
27 | "path": "https://cdn.majeed.cc/pydoc/images/use-cases/2-for-loop-list/",
28 | "max": 25,
29 | "extension": "PNG",
30 | "prefix": "Slide",
31 | "id": "loop-list-items"
32 | },
33 | {
34 | "type": "use-case",
35 | "title": "go through a sequence of numbers",
36 | "path": "https://cdn.majeed.cc/pydoc/images/use-cases/3-for-loop-range/",
37 | "max": 21,
38 | "extension": "PNG",
39 | "prefix": "Slide",
40 | "id": "loop-sequence-nums"
41 | },
42 | {
43 | "type": "use-case",
44 | "title": "go through a list of items using indices",
45 | "path": "https://cdn.majeed.cc/pydoc/images/use-cases/4-for-loop-range-list/",
46 | "max": 30,
47 | "extension": "PNG",
48 | "prefix": "Slide",
49 | "id": "loop-list-items-using-indices"
50 | },
51 | {
52 | "type": "use-case",
53 | "title": "go through every character of a string",
54 | "path": "https://cdn.majeed.cc/pydoc/images/use-cases/5-for-loop-string/",
55 | "max": 21,
56 | "extension": "PNG",
57 | "prefix": "Slide",
58 | "id": "loop-chars-of-str"
59 | }
60 | ],
61 | "search-queries": ["for", "loop", "repeat", "go through", "iterate", "list"]
62 | }
63 |
--------------------------------------------------------------------------------
/src/docs/if.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "if statement",
3 | "tooltip": {
4 | "title": "Insert If Statement",
5 | "body": "Will only execute the indented block of code below it when the condition is true"
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-if-1",
11 | "example": "a = 3\nif a < 10:\n\tprint(\"Success!\")"
12 | },
13 | {
14 | "type": "executable",
15 | "id": "ex-if-2",
16 | "example": "a = 3\nif a > 10:\n\tprint(\"Success!\")"
17 | },
18 | {
19 | "type": "use-case",
20 | "title": "check the value of a variable",
21 | "path": "https://cdn.majeed.cc/pydoc/images/use-cases/6-if/",
22 | "max": 13,
23 | "extension": "PNG",
24 | "prefix": "Slide",
25 | "id": "check-val-variable"
26 | }
27 | ],
28 | "search-queries": ["if", "condition", "conditional", "choose", "path"]
29 | }
30 |
--------------------------------------------------------------------------------
/src/docs/import.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Import Module",
3 | "tooltip": {
4 | "title": "Imports A Function",
5 | "body": "Loads a particular function from a module."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-import-randint-and-choice",
11 | "example": "from random import randint\nfrom random import choice"
12 | },
13 | {
14 | "type": "executable",
15 | "id": "ex-import-randint-use",
16 | "example": "from random import randint\nprint(randint(1, 6))"
17 | }
18 | ],
19 | "search-queries": ["import module", "import random"]
20 | }
21 |
--------------------------------------------------------------------------------
/src/docs/in.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Inside?",
3 | "tooltip": {
4 | "title": "Inside?",
5 | "body": "Returns True if the left item is inside the right item; returns False otherwise."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-in-list",
11 | "example": "from random import randint\na = randint(1, 10)\nb = [1, 2, 3, 4, 5]\nif a in b:\n\tprint(\"a is inside b\")\n\nif a not in b:\n\tprint(\"a is not inside b\")"
12 | }
13 | ],
14 | "search-queries": ["in list", "inside list", "is inside list", "check inside list", "check list includes"]
15 | }
16 |
--------------------------------------------------------------------------------
/src/docs/input.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "input(prompt: text)",
3 | "tooltip": {
4 | "title": "Ask User for Textual Input",
5 | "body": "Displays a message that prompts the user to enter some text. The entered text will be returned."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-input-1",
11 | "example": "name = input(\"Hi! What’s your name?\")\nprint(name)"
12 | }
13 | ],
14 | "search-queries": ["input", "prompt", "text", "user", "ask input", "ask user"]
15 | }
16 |
--------------------------------------------------------------------------------
/src/docs/join.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "join(elements: list[text])",
3 | "tooltip": {
4 | "title": "Call Join Method",
5 | "body": "Uses this text as a separator to join a list of values together into a new text."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-join-1",
11 | "example": "names = [\"Anna\", \"John\", \"Peter\"]\njoinedNames = \"-\".join(names)\nprint(joinedNames)"
12 | }
13 | ],
14 | "search-queries": ["join string", "join text"]
15 | }
16 |
--------------------------------------------------------------------------------
/src/docs/len.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "len(iterable: list/text)",
3 | "tooltip": {
4 | "title": "Get Length of List or Text",
5 | "body": "Returns the number of items in an object, or the number of characters in a text."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-len-1",
11 | "example": "greeting = \"Hello World!\"\na = len(greeting)\nprint(a)"
12 | },
13 | {
14 | "type": "executable",
15 | "id": "ex-len-2",
16 | "example": "items = [1, 2, 3]\na = len(items)\nprint(a)"
17 | }
18 | ],
19 | "search-queries": ["length of list", "length of string", "length of text"]
20 | }
21 |
--------------------------------------------------------------------------------
/src/docs/list-append.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "append(element: object)",
3 | "tooltip": {
4 | "title": "Append Element to List",
5 | "body": "Appends (adds to the end of) a new element to the list."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-append-1",
11 | "example": "a = [1, 2, 3]\na.append(4)\nprint(a)"
12 | },
13 | {
14 | "type": "executable",
15 | "id": "ex-append-2",
16 | "example": "print([1, 2, 3].append(4))"
17 | }
18 | ],
19 | "search-queries": [
20 | "add to list",
21 | "append to list",
22 | "insert into list",
23 | "add to end list",
24 | "append to end list",
25 | "insert end list"
26 | ]
27 | }
28 |
--------------------------------------------------------------------------------
/src/docs/list-element-assign.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "List Element Assignment",
3 | "tooltip": {
4 | "title": "",
5 | "body": ""
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-list-el-assign-1",
11 | "example": "a = [1, 2, 3]\na[2] = 4\nprint(a)"
12 | },
13 | {
14 | "type": "executable",
15 | "id": "ex-list-el-assign-2",
16 | "example": "a = [1, 2, 3]\na[1] = \"cat\"\nprint(a)"
17 | }
18 | ],
19 | "search-queries": [
20 | "assign element at index",
21 | "change value list index",
22 | "update item at index",
23 | "set value list index"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/src/docs/list-index.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "List Element Access",
3 | "tooltip": {
4 | "title": "Access List Element",
5 | "body": "Adds a list accessor to a list (or a text) to access an element of the list at the provided index."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-list-index-1",
11 | "example": "a = [1, 2, 3]\nprint(a[0])"
12 | },
13 | {
14 | "type": "executable",
15 | "id": "ex-list-index-2",
16 | "example": "a = [1, 2, 3]\nif a[1] == 2:\n\tprint(\"The second element of the list is equal to 2.\")"
17 | }
18 | ],
19 | "search-queries": ["access list item", "access list element", "access list element at index"]
20 | }
21 |
--------------------------------------------------------------------------------
/src/docs/list-item.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "List Item",
3 | "tooltip": {
4 | "title": "Insert List Element",
5 | "body": "Inserts a new empty element inside a list."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-list-item",
11 | "example": "a = []\nb = [1, 2]\nc = [1, 2, 3]"
12 | }
13 | ],
14 | "search-queries": ["comma", "list item"]
15 | }
16 |
--------------------------------------------------------------------------------
/src/docs/list-literal.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "List",
3 | "tooltip": {
4 | "title": "Insert Editable List",
5 | "body": "Inserts an empty list. Press comma before or after each item to add a new empty item."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-list-1",
11 | "example": "a = []\nprint(a) # a is an empty list\na = [1, 2, 3]\nprint(a) # a is a list with three items"
12 | },
13 | {
14 | "type": "executable",
15 | "id": "ex-list-1",
16 | "example": "a = [\"cat\", \"dog\", \"parrot\"]\nb = [1, \"cat\", true]\nc = [1, [1, \"dog\"], \"cat\", [true]]"
17 | }
18 | ],
19 | "search-queries": ["empty list", "create empty list", "create list", "array", "create empty array"]
20 | }
21 |
--------------------------------------------------------------------------------
/src/docs/mod.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "modulo",
3 | "tooltip": {
4 | "title": "Insert Modulo",
5 | "body": "Calculates the remainder of the division between the values to the left and right of the operator."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-modulo",
11 | "example": "print((29 % 5)) # prints 4\nprint((28 % 5)) # prints 3\nprint((27 % 5)) # prints 2\nprint((26 % 5)) # prints 1\nprint((25 % 5)) # prints 0"
12 | }
13 | ],
14 | "search-queries": ["modulo", "remainder"]
15 | }
16 |
--------------------------------------------------------------------------------
/src/docs/mult.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "multiply",
3 | "tooltip": {
4 | "title": "Insert Multiplication",
5 | "body": "Multiplies the values to the left and right of the operator."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-mul-vars",
11 | "example": "a = 2\nb = 5\nprint((b * a))"
12 | }
13 | ],
14 | "search-queries": ["multiply numbers", "multiply"]
15 | }
16 |
--------------------------------------------------------------------------------
/src/docs/not-in.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Not Inside?",
3 | "tooltip": {
4 | "title": "Not Inside?",
5 | "body": "Returns True if the left item is not inside the right item; returns False otherwise."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-not-inside-rand-list",
11 | "example": "from random import randint\na = randint(1, 10)\nb = [1, 2, 3, 4, 5]\nif a in b:\n\tprint(\"a is inside b\")\n\nif a not in b:\n\tprint(\"a is not inside b\")"
12 | }
13 | ],
14 | "search-queries": ["not in", "not inside list", "not within list", "does not include"]
15 | }
16 |
--------------------------------------------------------------------------------
/src/docs/not.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "not",
3 | "tooltip": {
4 | "title": "Not Operator",
5 | "body": "Flips the truth value of an expression. True becomes False, and False becomes True."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-not",
11 | "example": "a = 2\nb = 2\nif not (a == b):\n\tprint(\"Will not print.\")\n\nif not (b != a):\n\tprint(\"b is equal to a\")"
12 | }
13 | ],
14 | "search-queries": ["negate", "not", "logical", "boolean", "opposite"]
15 | }
16 |
--------------------------------------------------------------------------------
/src/docs/num.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "123",
3 | "tooltip": {
4 | "title": "Insert a Number",
5 | "body": "Inserts a number and edit its value."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-num",
11 | "example": "age = 21\nprint(age)\nprint(21)"
12 | }
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/src/docs/or.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "or",
3 | "tooltip": {
4 | "title": "Or Operator",
5 | "body": "Used to combine conditional expressions. Results in True as long as at least one of the left and right expressions is True; returns False otherwise."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-or-1",
11 | "example": "if (true or true):\n\tprint(true)\n\nif (true or false):\n\tprint(\"true\")\n\nif (false or true):\n\tprint(\"still true\")\n\nif (false or false):\n\tprint(\"false\")"
12 | },
13 | {
14 | "type": "executable",
15 | "id": "ex-or-2",
16 | "example": "a = 5\nb = 7\nc=2\n\nif ((a > c) and (b < c)):\n\tprint(\"Only the first expression is true.\")"
17 | }
18 | ],
19 | "search-queries": ["conditional", "or", "logical", "boolean", "one of"]
20 | }
21 |
--------------------------------------------------------------------------------
/src/docs/print.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "print(message: any)",
3 | "tooltip": {
4 | "title": "Display Text in Console",
5 | "body": "Displays the textual value of its input in the console."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-print-num-str",
11 | "example": "print(123)\nprint(\"Hello World!\")"
12 | },
13 | {
14 | "type": "executable",
15 | "id": "ex-print-var",
16 | "example": "a = \"abc\"\nprint(a)"
17 | }
18 | ],
19 | "search-queries": ["output", "say", "print", "print output", "console", "write", "see output"]
20 | }
21 |
--------------------------------------------------------------------------------
/src/docs/randint.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "randint(min: number, max: number)",
3 | "tooltip": {
4 | "title": "Generate a Random Number",
5 | "body": "Returns a randomly generated number from the given range. Needs to be imported from the random module."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-randint",
11 | "example": "a = randint(0, 10)\nprint(a)"
12 | }
13 | ],
14 | "search-queries": ["random number", "random integer", "randint", "random between"]
15 | }
16 |
--------------------------------------------------------------------------------
/src/docs/range.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "range(end: number)",
3 | "tooltip": {
4 | "title": "Create Iterable Sequence",
5 | "body": "Generates a sequence of numbers from 0 to the provided input. Usually used with a for loop."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-range",
11 | "example": "for i in range(10):\n\tprint(i)"
12 | }
13 | ],
14 | "search-queries": ["range", "sequence", "iterate", "for loop"]
15 | }
16 |
--------------------------------------------------------------------------------
/src/docs/replace.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "replace(old: text, new: text)",
3 | "tooltip": {
4 | "title": "Call Replace Method",
5 | "body": "Replaces all occurrences of the first input with the value of the second input in the text."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-replace",
11 | "example": "name = \"John\"\nname = name.replace(\"oh\", \"a\")\nprint(name)"
12 | }
13 | ],
14 | "search-queries": ["replace", "replace text", "replace string"]
15 | }
16 |
--------------------------------------------------------------------------------
/src/docs/split.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "split(separator: text)",
3 | "tooltip": {
4 | "title": "Call Split Method",
5 | "body": "Splits the text into a list of components based on the input (as a separator)."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-split",
11 | "example": "name = \"Split-this-text-on-hyphen\"\nsplitName = name.split(\"-\")\nprint(splitName)"
12 | }
13 | ],
14 | "search-queries": ["split", "split text", "split string"]
15 | }
16 |
--------------------------------------------------------------------------------
/src/docs/str.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "text",
3 | "tooltip": {
4 | "title": "Insert a Text",
5 | "body": "Inserts an editable text that is wrapped by double quotes."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-assign-str",
11 | "example": "fruit = \"apple\"\nprint(fruit)\nprint(\"apple\")"
12 | }
13 | ],
14 | "search-queries": ["create text", "create string", "empty string", "empty text"]
15 | }
16 |
--------------------------------------------------------------------------------
/src/docs/sub.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "subtract",
3 | "tooltip": {
4 | "title": "Insert Subtraction",
5 | "body": "Subtracts the value to the right of the operator from the value to the left."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-sub-vars",
11 | "example": "a = 20\nb = 10\nprint((a - b))"
12 | }
13 | ],
14 | "search-queries": ["subtract numbers", "subtraction", "deduct"]
15 | }
16 |
--------------------------------------------------------------------------------
/src/docs/to-int.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "int(object: string)",
3 | "tooltip": {
4 | "title": "Converts Text to Number",
5 | "body": "Converts a number text to an actual number. Extremely useful when trying to input numbers from the user."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-int-cast",
11 | "example": "a = \"2\"\nb = \"5\"\ntext_add = a + b\nnumber_add = int(a) + int(b)"
12 | }
13 | ],
14 | "search-queries": ["integer cast", "number convert", "convert to number", "convert to integer"]
15 | }
16 |
--------------------------------------------------------------------------------
/src/docs/to-str.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "str(object: any)",
3 | "body": [
4 | {
5 | "paragraph": "Converts the passed object to a text object. Useful when comparing values of different types and one of them is a text value. This type of conversion is called a cast because it is temporary."
6 | },
7 | { "example": "a = 2\nc = \"2\"\nprint(str(a) == c)" },
8 | {
9 | "paragraph": "In the above example you would not be able to compare a to c before performing the conversion."
10 | }
11 | ],
12 | "tooltip": {
13 | "title": "Converts Anything to Text",
14 | "body": "Converts the passed object to its textual representation."
15 | },
16 | "tips": [
17 | {
18 | "type": "executable",
19 | "id": "ex-str-cast",
20 | "example": "a = 2\nc = \"2\"\nprint(str(a) == c)"
21 | }
22 | ],
23 | "search-queries": ["string cast", "text convert", "convert to string", "convert to text"]
24 | }
25 |
--------------------------------------------------------------------------------
/src/docs/true.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "true",
3 | "tooltip": {
4 | "title": "Insert True",
5 | "body": "Inserts a True boolean value."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "id": "ex-true",
11 | "example": "if True :\n\tprint(\"will print\")\n\nif False :\n\tprint(\"will not print\")"
12 | }
13 | ],
14 | "search-queries": ["true", "boolean"]
15 | }
16 |
--------------------------------------------------------------------------------
/src/docs/while.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "while loop",
3 | "tooltip": {
4 | "title": "repeatedly execute code while true",
5 | "body": "repeatedly executes the code block inside the while loop as long as the condition remains `True`."
6 | },
7 | "tips": [
8 | {
9 | "type": "executable",
10 | "title": "infinite loop",
11 | "id": "ex-while-1",
12 | "example": "while True :\n\tprint(\"an infinite loop\")"
13 | },
14 | {
15 | "type": "executable",
16 | "title": "count from 0 to 10",
17 | "id": "ex-while-2",
18 | "example": "i = 0\nwhile i < 10:\n\tprint(i)\n\ti = i + 1"
19 | },
20 | {
21 | "type": "quick",
22 | "title": "compare to scratch's repeat until block",
23 | "text": "the `while` loop in Python compared to the `repeat until` block in Scratch: the `while` loop in Python repeats code as long as the condition is `True`, and stops when the condition becomes `False`. However, the `repeat until` block in Scratch repeats code as long as the condition is `False`, and stops when the condition becomes `True`."
24 | },
25 | {
26 | "type": "use-case",
27 | "title": "repeatedly increment a variable",
28 | "path": "https://cdn.majeed.cc/pydoc/images/use-cases/1-while-counter/",
29 | "max": 30,
30 | "prefix": "Slide",
31 | "extension": "PNG",
32 | "id": "while-increment-var",
33 | "explanations": [
34 | { "slide": 7, "text": "i is less than 3 so the condition holds true" },
35 | { "slide": 28, "text": "i is no longer less than 3 so the condition is false" },
36 | { "slide": 29, "text": "should execute the next line after the while loop" }
37 | ]
38 | }
39 | ],
40 | "search-queries": [
41 | "while",
42 | "repeat",
43 | "repeat while",
44 | "repeat until",
45 | "loop",
46 | "condition",
47 | "conditional",
48 | "repeat condition"
49 | ]
50 | }
51 |
--------------------------------------------------------------------------------
/src/editor/accordion.ts:
--------------------------------------------------------------------------------
1 | import { LogEvent, Logger, LogType } from "./../logger/analytics";
2 | export enum TooltipType {
3 | StepByStepExample = "step-by-step-example",
4 | UsageHint = "usage-hint",
5 | RunnableExample = "runnable-example",
6 | }
7 |
8 | export class AccordionRow {
9 | private accordion: Accordion;
10 | private isOpen: boolean = false;
11 | private chevronElement: HTMLElement;
12 | private contentContainer: HTMLDivElement;
13 | element: HTMLDivElement;
14 | id: string;
15 | usageTime: number = 0;
16 | type: TooltipType;
17 |
18 | constructor(
19 | accordion: Accordion,
20 | id: string,
21 | type: TooltipType,
22 | title: string,
23 | content: HTMLDivElement,
24 | onClick: () => void = () => {}
25 | ) {
26 | this.type = type;
27 | this.id = id;
28 | this.accordion = accordion;
29 |
30 | this.element = document.createElement("div");
31 | this.element.classList.add("accordion-row");
32 |
33 | const headerContainer = document.createElement("div");
34 | headerContainer.classList.add("header-container");
35 |
36 | this.contentContainer = document.createElement("div");
37 | this.contentContainer.classList.add("content-container");
38 | this.contentContainer.style.maxHeight = "0px";
39 | this.contentContainer.appendChild(content);
40 |
41 | this.element.appendChild(headerContainer);
42 | this.element.appendChild(this.contentContainer);
43 |
44 | const textContainer = document.createElement("div");
45 | textContainer.classList.add("text-container");
46 |
47 | const typeContainer = document.createElement("div");
48 | typeContainer.classList.add("type-container");
49 |
50 | const icon = document.createElement("i");
51 | icon.classList.add("row-icon");
52 | let typeText = "";
53 |
54 | switch (type) {
55 | case TooltipType.StepByStepExample: {
56 | icon.innerHTML = zapIconSVG;
57 | typeText = "learn";
58 | typeContainer.classList.add("bg-learn");
59 |
60 | break;
61 | }
62 |
63 | case TooltipType.UsageHint: {
64 | icon.innerHTML = lightBulbIconSVG;
65 | typeText = "hint";
66 | typeContainer.classList.add("bg-hint");
67 |
68 | break;
69 | }
70 |
71 | case TooltipType.RunnableExample: {
72 | icon.innerHTML = playIconSVG;
73 | typeText = "try";
74 | typeContainer.classList.add("bg-try");
75 |
76 | break;
77 | }
78 | }
79 |
80 | const typeElement = document.createElement("span");
81 | typeElement.classList.add("row-type");
82 | typeElement.innerHTML = typeText;
83 |
84 | const titleElement = document.createElement("span");
85 | titleElement.classList.add("row-title");
86 | titleElement.innerHTML = title;
87 |
88 | const chevronRightIcon = document.createElement("i");
89 | chevronRightIcon.classList.add("row-chevron-right-icon");
90 | chevronRightIcon.innerHTML = chevronRightIconSVG;
91 |
92 | typeContainer.appendChild(icon);
93 | typeContainer.appendChild(typeElement);
94 | textContainer.appendChild(typeContainer);
95 | textContainer.appendChild(titleElement);
96 |
97 | this.chevronElement = document.createElement("i");
98 | this.chevronElement.classList.add("expand-collapse-button");
99 | this.chevronElement.innerHTML = chevronDownIconSVG;
100 |
101 | headerContainer.addEventListener("click", () => {
102 | if (this.isOpen) {
103 | this.close();
104 |
105 | this.sendUsageDuration();
106 | } else {
107 | this.open();
108 | onClick();
109 |
110 | this.usageTime = Date.now();
111 | }
112 | });
113 |
114 | headerContainer.appendChild(textContainer);
115 | headerContainer.appendChild(this.chevronElement);
116 | }
117 |
118 | sendUsageDuration = () => {
119 | const duration = Date.now() - this.usageTime;
120 |
121 | if (duration > 1500) {
122 | Logger.Instance().queueEvent(new LogEvent(LogType.TooltipItemUsage, { type: this.type, duration }));
123 |
124 | this.usageTime = 0;
125 | }
126 | };
127 |
128 | open() {
129 | this.contentContainer.style.maxHeight = this.contentContainer.scrollHeight + "px";
130 |
131 | setTimeout(() => {
132 | this.contentContainer.style.maxHeight = "1000px";
133 | }, 350);
134 |
135 | this.chevronElement.innerHTML = chevronUpIconSVG;
136 |
137 | this.accordion.rows.forEach((row) => {
138 | if (row !== this) {
139 | row.close();
140 | }
141 | });
142 |
143 | this.isOpen = true;
144 | }
145 |
146 | close() {
147 | this.contentContainer.style.maxHeight = "0px";
148 | this.chevronElement.innerHTML = chevronDownIconSVG;
149 |
150 | this.isOpen = false;
151 | }
152 |
153 | onRemove() {
154 | this.sendUsageDuration();
155 | }
156 | }
157 |
158 | export class Accordion {
159 | rows = new Array();
160 | private id: string;
161 | container: HTMLDivElement;
162 |
163 | constructor(id: string) {
164 | this.id = id;
165 |
166 | this.container = document.createElement("div");
167 | this.container.classList.add("accordion-group-container");
168 | }
169 |
170 | addRow(type: TooltipType, title: string, content: HTMLDivElement, onClick: () => void = () => {}) {
171 | const id = this.id + "-" + this.rows.length;
172 | const row = new AccordionRow(this, id, type, title, content, onClick);
173 | this.rows.push(row);
174 | this.container.appendChild(row.element);
175 | }
176 |
177 | onRemove() {
178 | if (this?.rows) {
179 | this.rows.forEach((row) => {
180 | row.onRemove();
181 | });
182 | }
183 | }
184 | }
185 |
186 | const playIconSVG = ``;
187 | const lightBulbIconSVG = ``;
188 | const zapIconSVG = ``;
189 | const chevronUpIconSVG = ``;
190 | const chevronDownIconSVG = ``;
191 | const chevronRightIconSVG = ``;
192 |
--------------------------------------------------------------------------------
/src/editor/action-filter.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Expression,
3 | ForStatement,
4 | ListComma,
5 | Modifier,
6 | Statement,
7 | TypedEmptyExpr,
8 | ValueOperationExpr,
9 | VarAssignmentStmt,
10 | VariableReferenceExpr,
11 | VarOperationStmt,
12 | } from "../syntax-tree/ast";
13 | import { InsertionType, TypeConversionRecord } from "../syntax-tree/consts";
14 | import { Module } from "../syntax-tree/module";
15 | import { Reference } from "../syntax-tree/scope";
16 | import { getUserFriendlyType } from "../utilities/util";
17 | import { ActionExecutor } from "./action-executor";
18 | import { Actions, InsertActionType } from "./consts";
19 | import { EventRouter } from "./event-router";
20 | import { Context } from "./focus";
21 | import { Validator } from "./validator";
22 |
23 | export class ActionFilter {
24 | module: Module;
25 |
26 | constructor(module: Module) {
27 | this.module = module;
28 | }
29 |
30 | validateInsertions(): Map {
31 | const context = this.module.focus.getContext();
32 | const validOptionMap: Map = new Map();
33 | //need to know InsertionType in case we want to make any visual changes to those options in the suggestion menu
34 |
35 | // loop over all code-constructs and call their validateContext() + typeValidation() => insertionType
36 | // we are assuming that the action executor will calculate the insertionType again in the exectue() function
37 | for (const action of Actions.instance().actionsList) {
38 | validOptionMap.set(
39 | action.optionName,
40 | EditCodeAction.createDynamicEditCodeAction(
41 | action.optionName,
42 | action.cssId,
43 | action.getCodeFunction,
44 | action.insertActionType,
45 | action.insertData,
46 | action.validateAction(this.module.validator, context),
47 | action.terminatingChars,
48 | action.matchString,
49 | action.matchRegex,
50 | action.insertableTerminatingCharRegex
51 | )
52 | );
53 | }
54 |
55 | return validOptionMap;
56 | }
57 |
58 | validateEdits(): Map {
59 | // console.warn("validateEdits() is not implemented.");
60 |
61 | return new Map();
62 | }
63 |
64 | validateVariableInsertions(): Map {
65 | const context = this.module.focus.getContext();
66 | const validOptionMap: Map = new Map(); //