janito 1.10.0__py3-none-any.whl → 1.11.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- janito/__init__.py +1 -1
- janito/agent/conversation_api.py +178 -90
- janito/agent/conversation_ui.py +1 -1
- janito/agent/llm_conversation_history.py +12 -0
- janito/agent/templates/profiles/system_prompt_template_base.txt.j2 +19 -4
- janito/agent/tools/__init__.py +2 -0
- janito/agent/tools/create_directory.py +1 -1
- janito/agent/tools/create_file.py +1 -1
- janito/agent/tools/fetch_url.py +1 -1
- janito/agent/tools/find_files.py +26 -13
- janito/agent/tools/get_file_outline/core.py +1 -1
- janito/agent/tools/get_file_outline/python_outline.py +139 -95
- janito/agent/tools/get_lines.py +92 -63
- janito/agent/tools/move_file.py +58 -32
- janito/agent/tools/open_url.py +31 -0
- janito/agent/tools/python_command_runner.py +85 -86
- janito/agent/tools/python_file_runner.py +85 -86
- janito/agent/tools/python_stdin_runner.py +87 -88
- janito/agent/tools/remove_directory.py +1 -1
- janito/agent/tools/remove_file.py +1 -1
- janito/agent/tools/replace_file.py +2 -2
- janito/agent/tools/replace_text_in_file.py +193 -149
- janito/agent/tools/run_bash_command.py +1 -1
- janito/agent/tools/run_powershell_command.py +4 -0
- janito/agent/tools/search_text/__init__.py +1 -0
- janito/agent/tools/search_text/core.py +176 -0
- janito/agent/tools/search_text/match_lines.py +58 -0
- janito/agent/tools/search_text/pattern_utils.py +65 -0
- janito/agent/tools/search_text/traverse_directory.py +132 -0
- janito/agent/tools/validate_file_syntax/core.py +41 -30
- janito/agent/tools/validate_file_syntax/html_validator.py +21 -5
- janito/agent/tools/validate_file_syntax/markdown_validator.py +77 -34
- janito/agent/tools_utils/gitignore_utils.py +25 -2
- janito/agent/tools_utils/utils.py +7 -1
- janito/cli/config_commands.py +112 -109
- janito/shell/main.py +51 -8
- janito/shell/session/config.py +83 -75
- janito/shell/ui/interactive.py +97 -73
- janito/termweb/static/editor.css +32 -29
- janito/termweb/static/editor.css.bak +140 -22
- janito/termweb/static/editor.html +12 -7
- janito/termweb/static/editor.html.bak +16 -11
- janito/termweb/static/editor.js +94 -40
- janito/termweb/static/editor.js.bak +97 -65
- janito/termweb/static/index.html +1 -2
- janito/termweb/static/index.html.bak +1 -1
- janito/termweb/static/termweb.css +1 -22
- janito/termweb/static/termweb.css.bak +6 -4
- janito/termweb/static/termweb.js +0 -6
- janito/termweb/static/termweb.js.bak +1 -2
- {janito-1.10.0.dist-info → janito-1.11.1.dist-info}/METADATA +1 -1
- {janito-1.10.0.dist-info → janito-1.11.1.dist-info}/RECORD +56 -51
- {janito-1.10.0.dist-info → janito-1.11.1.dist-info}/WHEEL +1 -1
- janito/agent/tools/search_text.py +0 -254
- {janito-1.10.0.dist-info → janito-1.11.1.dist-info}/entry_points.txt +0 -0
- {janito-1.10.0.dist-info → janito-1.11.1.dist-info}/licenses/LICENSE +0 -0
- {janito-1.10.0.dist-info → janito-1.11.1.dist-info}/top_level.txt +0 -0
janito/shell/ui/interactive.py
CHANGED
@@ -24,6 +24,92 @@ def print_welcome(console, version=None, continue_id=None):
|
|
24
24
|
)
|
25
25
|
|
26
26
|
|
27
|
+
def format_tokens(n, tag=None):
|
28
|
+
if n is None:
|
29
|
+
return "?"
|
30
|
+
if n < 1000:
|
31
|
+
val = str(n)
|
32
|
+
elif n < 1000000:
|
33
|
+
val = f"{n/1000:.1f}k"
|
34
|
+
else:
|
35
|
+
val = f"{n/1000000:.1f}M"
|
36
|
+
return f"<{tag}>{val}</{tag}>" if tag else val
|
37
|
+
|
38
|
+
|
39
|
+
def assemble_first_line(model_name, role_ref, style_ref):
|
40
|
+
model_part = f" {tr('Model')}: <model>{model_name}</model>" if model_name else ""
|
41
|
+
role_part = ""
|
42
|
+
vanilla_mode = runtime_config.get("vanilla_mode", False)
|
43
|
+
if role_ref and not vanilla_mode:
|
44
|
+
role = role_ref()
|
45
|
+
if role:
|
46
|
+
role_part = f"{tr('Role')}: <role>{role}</role>"
|
47
|
+
style_part = ""
|
48
|
+
if style_ref:
|
49
|
+
style = style_ref()
|
50
|
+
if style:
|
51
|
+
style_part = f"{tr('Style')}: <b>{style}</b>"
|
52
|
+
first_line_parts = []
|
53
|
+
if model_part:
|
54
|
+
first_line_parts.append(model_part)
|
55
|
+
if role_part:
|
56
|
+
first_line_parts.append(role_part)
|
57
|
+
if style_part:
|
58
|
+
first_line_parts.append(style_part)
|
59
|
+
return " | ".join(first_line_parts)
|
60
|
+
|
61
|
+
|
62
|
+
def assemble_second_line(
|
63
|
+
width,
|
64
|
+
last_usage_info_ref,
|
65
|
+
history_ref,
|
66
|
+
messages_ref,
|
67
|
+
session_id,
|
68
|
+
model_name,
|
69
|
+
role_ref,
|
70
|
+
style_ref,
|
71
|
+
):
|
72
|
+
usage = last_usage_info_ref()
|
73
|
+
prompt_tokens = usage.get("prompt_tokens") if usage else None
|
74
|
+
completion_tokens = usage.get("completion_tokens") if usage else None
|
75
|
+
total_tokens = usage.get("total_tokens") if usage else None
|
76
|
+
msg_count = len(history_ref()) if history_ref else len(messages_ref())
|
77
|
+
left = f" {tr('Messages')}: <msg_count>{msg_count}</msg_count>"
|
78
|
+
tokens_part = ""
|
79
|
+
if (
|
80
|
+
prompt_tokens is not None
|
81
|
+
or completion_tokens is not None
|
82
|
+
or total_tokens is not None
|
83
|
+
):
|
84
|
+
tokens_part = (
|
85
|
+
f" | {tr('Tokens')} - {tr('Prompt')}: {format_tokens(prompt_tokens, 'tokens_in')}, "
|
86
|
+
f"{tr('Completion')}: {format_tokens(completion_tokens, 'tokens_out')}, "
|
87
|
+
f"{tr('Total')}: {format_tokens(total_tokens, 'tokens_total')}"
|
88
|
+
)
|
89
|
+
session_part = (
|
90
|
+
f" | Session ID: <session_id>{session_id}</session_id>" if session_id else ""
|
91
|
+
)
|
92
|
+
second_line = f"{left}{tokens_part}{session_part}"
|
93
|
+
total_len = len(left) + len(tokens_part) + len(session_part)
|
94
|
+
first_line = assemble_first_line(model_name, role_ref, style_ref)
|
95
|
+
if first_line:
|
96
|
+
total_len += len(first_line) + 3
|
97
|
+
if total_len < width:
|
98
|
+
padding = " " * (width - total_len)
|
99
|
+
second_line = f"{left}{tokens_part}{session_part}{padding}"
|
100
|
+
return second_line
|
101
|
+
|
102
|
+
|
103
|
+
def assemble_bindings_line():
|
104
|
+
return (
|
105
|
+
f"<b> F12</b>: {tr('Quick Action')} | "
|
106
|
+
f"<b>Ctrl-Y</b>: {tr('Yes')} | "
|
107
|
+
f"<b>Ctrl-N</b>: {tr('No')} | "
|
108
|
+
f"<b>/help</b>: {tr('Help')} | "
|
109
|
+
f"<b>/restart</b>: {tr('Reset Conversation')}"
|
110
|
+
)
|
111
|
+
|
112
|
+
|
27
113
|
def get_toolbar_func(
|
28
114
|
messages_ref,
|
29
115
|
last_usage_info_ref,
|
@@ -37,82 +123,20 @@ def get_toolbar_func(
|
|
37
123
|
):
|
38
124
|
from prompt_toolkit.application.current import get_app
|
39
125
|
|
40
|
-
def format_tokens(n, tag=None):
|
41
|
-
if n is None:
|
42
|
-
return "?"
|
43
|
-
if n < 1000:
|
44
|
-
val = str(n)
|
45
|
-
elif n < 1000000:
|
46
|
-
val = f"{n/1000:.1f}k"
|
47
|
-
else:
|
48
|
-
val = f"{n/1000000:.1f}M"
|
49
|
-
return f"<{tag}>{val}</{tag}>" if tag else val
|
50
|
-
|
51
126
|
def get_toolbar():
|
52
127
|
width = get_app().output.get_size().columns
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
style_part = ""
|
64
|
-
if style_ref:
|
65
|
-
style = style_ref()
|
66
|
-
if style:
|
67
|
-
style_part = f"{tr('Style')}: <b>{style}</b>"
|
68
|
-
usage = last_usage_info_ref()
|
69
|
-
prompt_tokens = usage.get("prompt_tokens") if usage else None
|
70
|
-
completion_tokens = usage.get("completion_tokens") if usage else None
|
71
|
-
total_tokens = usage.get("total_tokens") if usage else None
|
72
|
-
first_line_parts = []
|
73
|
-
if model_part:
|
74
|
-
first_line_parts.append(model_part)
|
75
|
-
|
76
|
-
if role_part:
|
77
|
-
first_line_parts.append(role_part)
|
78
|
-
if style_part:
|
79
|
-
first_line_parts.append(style_part)
|
80
|
-
first_line = " | ".join(first_line_parts)
|
81
|
-
msg_count = len(history_ref()) if history_ref else len(messages_ref())
|
82
|
-
left = f" {tr('Messages')}: <msg_count>{msg_count}</msg_count>"
|
83
|
-
tokens_part = ""
|
84
|
-
if (
|
85
|
-
prompt_tokens is not None
|
86
|
-
or completion_tokens is not None
|
87
|
-
or total_tokens is not None
|
88
|
-
):
|
89
|
-
tokens_part = (
|
90
|
-
f" | {tr('Tokens')} - {tr('Prompt')}: {format_tokens(prompt_tokens, 'tokens_in')}, "
|
91
|
-
f"{tr('Completion')}: {format_tokens(completion_tokens, 'tokens_out')}, "
|
92
|
-
f"{tr('Total')}: {format_tokens(total_tokens, 'tokens_total')}"
|
93
|
-
)
|
94
|
-
# Move /help and /restart tips to key bindings/info line
|
95
|
-
# Compose second/status line (no help_part)
|
96
|
-
session_part = (
|
97
|
-
f" | Session ID: <session_id>{session_id}</session_id>"
|
98
|
-
if session_id
|
99
|
-
else ""
|
100
|
-
)
|
101
|
-
second_line = f"{left}{tokens_part}{session_part}"
|
102
|
-
total_len = len(left) + len(tokens_part) + len(session_part)
|
103
|
-
if first_line:
|
104
|
-
total_len += len(first_line) + 3
|
105
|
-
if total_len < width:
|
106
|
-
padding = " " * (width - total_len)
|
107
|
-
second_line = f"{left}{tokens_part}{session_part}{padding}"
|
108
|
-
# Add key bindings info as an extra line, now including /help and /restart
|
109
|
-
bindings_line = (
|
110
|
-
f"<b> F12</b>: {tr('Quick Action')} | "
|
111
|
-
f"<b>Ctrl-Y</b>: {tr('Yes')} | "
|
112
|
-
f"<b>Ctrl-N</b>: {tr('No')} | "
|
113
|
-
f"<b>/help</b>: {tr('Help')} | "
|
114
|
-
f"<b>/restart</b>: {tr('Reset Conversation')}"
|
128
|
+
first_line = assemble_first_line(model_name, role_ref, style_ref)
|
129
|
+
second_line = assemble_second_line(
|
130
|
+
width,
|
131
|
+
last_usage_info_ref,
|
132
|
+
history_ref,
|
133
|
+
messages_ref,
|
134
|
+
session_id,
|
135
|
+
model_name,
|
136
|
+
role_ref,
|
137
|
+
style_ref,
|
115
138
|
)
|
139
|
+
bindings_line = assemble_bindings_line()
|
116
140
|
if first_line:
|
117
141
|
toolbar_text = first_line + "\n" + second_line + "\n" + bindings_line
|
118
142
|
else:
|
janito/termweb/static/editor.css
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
/* Highlight active line in CodeMirror */
|
2
2
|
.CodeMirror-activeline-background {
|
3
|
-
background: #353b45
|
3
|
+
background: #353b45;
|
4
4
|
}
|
5
5
|
body.light-theme .CodeMirror-activeline-background {
|
6
|
-
background: #e0eaff
|
6
|
+
background: #e0eaff;
|
7
7
|
}
|
8
8
|
html, body {
|
9
9
|
height: 100%;
|
@@ -39,36 +39,22 @@ body.light-theme {
|
|
39
39
|
flex-direction: column;
|
40
40
|
height: 100%;
|
41
41
|
min-height: 0;
|
42
|
-
padding: 0
|
43
|
-
margin: 0
|
44
|
-
}
|
45
|
-
.CodeMirror {
|
46
|
-
flex: 1 1 auto;
|
47
|
-
height: 100% !important;
|
48
|
-
min-height: 0;
|
49
|
-
font-size: 1.1em;
|
50
|
-
background: #282a36;
|
51
|
-
color: #f8f8f2;
|
52
|
-
border-radius: 0;
|
53
|
-
border: none;
|
54
|
-
transition: background 0.2s, color 0.2s;
|
55
|
-
}
|
56
|
-
body.light-theme .CodeMirror {
|
57
|
-
background: #fff;
|
58
|
-
color: #222;
|
42
|
+
padding: 0;
|
43
|
+
margin: 0;
|
59
44
|
}
|
45
|
+
/* Removed custom .CodeMirror background/color to use CodeMirror's theme defaults */
|
60
46
|
.header {
|
61
47
|
background: #222;
|
62
48
|
color: #fff;
|
63
|
-
padding:
|
64
|
-
font-size:
|
49
|
+
padding: 4px 12px;
|
50
|
+
font-size: 0.95em;
|
65
51
|
font-weight: bold;
|
66
52
|
position: relative;
|
67
53
|
transition: background 0.2s, color 0.2s;
|
68
54
|
display: flex;
|
69
55
|
align-items: center;
|
70
56
|
justify-content: flex-end;
|
71
|
-
height:
|
57
|
+
height: 36px;
|
72
58
|
}
|
73
59
|
|
74
60
|
.header-title {
|
@@ -78,20 +64,39 @@ body.light-theme .CodeMirror {
|
|
78
64
|
transform: translate(-50%, -50%);
|
79
65
|
pointer-events: none;
|
80
66
|
font-weight: bold;
|
81
|
-
font-size: 1.
|
67
|
+
font-size: 1.05em;
|
68
|
+
display: flex;
|
69
|
+
align-items: center;
|
70
|
+
gap: 0.5em;
|
71
|
+
}
|
72
|
+
|
73
|
+
.filename-display {
|
74
|
+
font-weight: normal;
|
75
|
+
font-size: 0.98em;
|
76
|
+
color: #bbb;
|
77
|
+
margin-left: 0.5em;
|
78
|
+
pointer-events: auto;
|
79
|
+
text-overflow: ellipsis;
|
80
|
+
white-space: nowrap;
|
81
|
+
overflow: hidden;
|
82
|
+
max-width: 180px;
|
83
|
+
}
|
84
|
+
body.light-theme .filename-display {
|
85
|
+
color: #666;
|
82
86
|
}
|
83
87
|
|
84
88
|
.footer {
|
85
89
|
width: 100%;
|
86
90
|
background: #23272b;
|
87
91
|
color: #fff;
|
88
|
-
padding:
|
92
|
+
padding: 4px 12px;
|
89
93
|
box-sizing: border-box;
|
90
94
|
display: flex;
|
91
95
|
align-items: center;
|
92
96
|
justify-content: flex-start;
|
93
97
|
border-top: 1px solid #333;
|
94
|
-
min-height:
|
98
|
+
min-height: 28px;
|
99
|
+
font-size: 0.95em;
|
95
100
|
}
|
96
101
|
|
97
102
|
.save-btn {
|
@@ -102,7 +107,6 @@ body.light-theme .CodeMirror {
|
|
102
107
|
margin-left: auto;
|
103
108
|
}
|
104
109
|
|
105
|
-
|
106
110
|
.save-btn {
|
107
111
|
background: #4caf50;
|
108
112
|
color: #fff;
|
@@ -117,8 +121,8 @@ body.light-theme .CodeMirror {
|
|
117
121
|
display: flex;
|
118
122
|
align-items: center;
|
119
123
|
justify-content: center;
|
120
|
-
|
121
|
-
|
124
|
+
height: 100%;
|
125
|
+
aspect-ratio: 1/1;
|
122
126
|
font-size: 1.3em;
|
123
127
|
line-height: 1;
|
124
128
|
padding: 0;
|
@@ -139,4 +143,3 @@ body.light-theme .header {
|
|
139
143
|
background: #eaeaea;
|
140
144
|
color: #222;
|
141
145
|
}
|
142
|
-
|
@@ -1,27 +1,145 @@
|
|
1
|
+
/* Highlight active line in CodeMirror */
|
2
|
+
.CodeMirror-activeline-background {
|
3
|
+
background: #353b45;
|
4
|
+
}
|
5
|
+
body.light-theme .CodeMirror-activeline-background {
|
6
|
+
background: #e0eaff;
|
7
|
+
}
|
8
|
+
html, body {
|
9
|
+
height: 100%;
|
10
|
+
margin: 0;
|
11
|
+
padding: 0;
|
12
|
+
}
|
13
|
+
body {
|
14
|
+
display: flex;
|
15
|
+
flex-direction: column;
|
16
|
+
min-height: 100vh;
|
17
|
+
background: #181a1b;
|
18
|
+
color: #eee;
|
19
|
+
transition: background 0.2s, color 0.2s;
|
20
|
+
}
|
21
|
+
body.light-theme {
|
22
|
+
background: #f5f5f5;
|
23
|
+
color: #222;
|
24
|
+
}
|
25
|
+
.main {
|
26
|
+
flex: 1 1 auto;
|
27
|
+
display: flex;
|
28
|
+
flex-direction: column;
|
29
|
+
justify-content: stretch;
|
30
|
+
align-items: stretch;
|
31
|
+
min-height: 0;
|
32
|
+
padding: 0;
|
33
|
+
margin: 0;
|
34
|
+
height: 100%;
|
35
|
+
}
|
36
|
+
.editor-pane {
|
37
|
+
flex: 1 1 auto;
|
38
|
+
display: flex;
|
39
|
+
flex-direction: column;
|
40
|
+
height: 100%;
|
41
|
+
min-height: 0;
|
42
|
+
padding: 0;
|
43
|
+
margin: 0;
|
44
|
+
}
|
45
|
+
/* Removed custom .CodeMirror background/color to use CodeMirror's theme defaults */
|
46
|
+
.header {
|
47
|
+
background: #222;
|
48
|
+
color: #fff;
|
49
|
+
padding: 4px 12px;
|
50
|
+
font-size: 0.95em;
|
51
|
+
font-weight: bold;
|
52
|
+
position: relative;
|
53
|
+
transition: background 0.2s, color 0.2s;
|
54
|
+
display: flex;
|
55
|
+
align-items: center;
|
56
|
+
justify-content: flex-end;
|
57
|
+
height: 36px;
|
58
|
+
}
|
59
|
+
|
60
|
+
.header-title {
|
61
|
+
position: absolute;
|
62
|
+
left: 50%;
|
63
|
+
top: 50%;
|
64
|
+
transform: translate(-50%, -50%);
|
65
|
+
pointer-events: none;
|
66
|
+
font-weight: bold;
|
67
|
+
font-size: 1.05em;
|
68
|
+
display: flex;
|
69
|
+
align-items: center;
|
70
|
+
gap: 0.5em;
|
71
|
+
}
|
72
|
+
|
73
|
+
.filename-display {
|
74
|
+
font-weight: normal;
|
75
|
+
font-size: 0.98em;
|
76
|
+
color: #bbb;
|
77
|
+
margin-left: 0.5em;
|
78
|
+
pointer-events: auto;
|
79
|
+
text-overflow: ellipsis;
|
80
|
+
white-space: nowrap;
|
81
|
+
overflow: hidden;
|
82
|
+
max-width: 180px;
|
83
|
+
}
|
84
|
+
body.light-theme .filename-display {
|
85
|
+
color: #666;
|
86
|
+
}
|
87
|
+
|
88
|
+
.footer {
|
89
|
+
width: 100%;
|
90
|
+
background: #23272b;
|
91
|
+
color: #fff;
|
92
|
+
padding: 4px 12px;
|
93
|
+
box-sizing: border-box;
|
94
|
+
display: flex;
|
95
|
+
align-items: center;
|
96
|
+
justify-content: flex-start;
|
97
|
+
border-top: 1px solid #333;
|
98
|
+
min-height: 28px;
|
99
|
+
font-size: 0.95em;
|
100
|
+
}
|
1
101
|
|
2
102
|
.save-btn {
|
3
|
-
|
4
|
-
|
103
|
+
/* No margin needed, align left in footer */
|
104
|
+
}
|
105
|
+
|
106
|
+
.theme-switcher {
|
107
|
+
margin-left: auto;
|
108
|
+
}
|
109
|
+
|
110
|
+
.save-btn {
|
111
|
+
background: #4caf50;
|
112
|
+
color: #fff;
|
113
|
+
border: none;
|
114
|
+
border-radius: 4px;
|
115
|
+
padding: 6px 14px;
|
116
|
+
cursor: pointer;
|
117
|
+
font-size: 1em;
|
118
|
+
}
|
119
|
+
|
120
|
+
.theme-switcher {
|
121
|
+
display: flex;
|
122
|
+
align-items: center;
|
123
|
+
justify-content: center;
|
124
|
+
width: 36px;
|
125
|
+
height: 36px;
|
126
|
+
font-size: 1.3em;
|
127
|
+
line-height: 1;
|
128
|
+
padding: 0;
|
129
|
+
background: #444;
|
130
|
+
color: #fff;
|
5
131
|
border: none;
|
6
|
-
border-radius:
|
7
|
-
padding: 12px 38px;
|
132
|
+
border-radius: 4px;
|
8
133
|
cursor: pointer;
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
text-shadow: 0 2px 8px #fff8, 0 1px 0 #fff8;
|
21
|
-
}
|
22
|
-
.save-btn:hover, .save-btn:focus {
|
23
|
-
background: linear-gradient(90deg, #00cfff 0%, #00ff99 100%);
|
24
|
-
color: #111;
|
25
|
-
box-shadow: 0 0 24px 6px rgba(0,255,153,0.45), 0 4px 24px 0 rgba(0,207,255,0.28);
|
26
|
-
outline: 3px solid #00ff99;
|
134
|
+
transition: background 0.2s, color 0.2s;
|
135
|
+
}
|
136
|
+
|
137
|
+
body.light-theme .theme-switcher {
|
138
|
+
background: #ddd;
|
139
|
+
color: #222;
|
140
|
+
}
|
141
|
+
|
142
|
+
body.light-theme .header {
|
143
|
+
background: #eaeaea;
|
144
|
+
color: #222;
|
27
145
|
}
|
@@ -4,7 +4,7 @@
|
|
4
4
|
<link rel="icon" type="image/svg+xml" href="/static/termicon.svg">
|
5
5
|
<link rel="shortcut icon" type="image/x-icon" href="/static/favicon.ico">
|
6
6
|
<meta charset="UTF-8">
|
7
|
-
<title>
|
7
|
+
<title>Janito Light Editor</title>
|
8
8
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/codemirror.min.css">
|
9
9
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/theme/dracula.min.css">
|
10
10
|
<link rel="stylesheet" href="/static/termweb.css">
|
@@ -12,27 +12,32 @@
|
|
12
12
|
</head>
|
13
13
|
<body>
|
14
14
|
<div class="header">
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
<div class="header-title">Janito Light Editor</div>
|
16
|
+
<span id="filename-display" class="filename-display"></span>
|
17
|
+
<div style="flex:1 1 auto;"></div>
|
18
|
+
<button class="theme-switcher" id="theme-switcher" title="Alternator tema">
|
19
|
+
<span id="theme-icon" aria-label="Switch theme" style="pointer-events:none;">🌙</span>
|
20
|
+
</button>
|
21
|
+
</div>
|
20
22
|
<div class="footer">
|
21
23
|
<button class="save-btn" id="save-btn">Save</button>
|
22
24
|
</div>
|
23
|
-
<div id="save-popup" style="display:none;position:
|
25
|
+
<div id="save-popup" style="display:none;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);z-index:9999;background:#323b4c;color:#fff;padding:14px 28px;border-radius:8px;box-shadow:0 2px 12px #0007;font-size:1.1em;">Saved!</div>
|
24
26
|
<div class="main">
|
25
27
|
<div class="editor-pane">
|
26
28
|
<textarea id="code" name="code"></textarea>
|
29
|
+
<div id="save-popup" style="display:none;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);z-index:9999;background:#323b4c;color:#fff;padding:14px 28px;border-radius:8px;box-shadow:0 2px 12px #0007;font-size:1.1em;">Saved!</div>
|
27
30
|
</div>
|
28
31
|
</div>
|
29
32
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/codemirror.min.js"></script>
|
30
33
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/mode/python/python.min.js"></script>
|
34
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/mode/django/django.min.js"></script>
|
31
35
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/theme/dracula.min.js"></script>
|
32
36
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/addon/selection/active-line.min.js"></script>
|
33
37
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/addon/search/search.min.js"></script>
|
34
38
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/addon/search/searchcursor.min.js"></script>
|
35
39
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/addon/dialog/dialog.min.js"></script>
|
40
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/addon/mode/overlay.min.js"></script>
|
36
41
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/addon/dialog/dialog.min.css">
|
37
42
|
|
38
43
|
<script src="/static/editor.js"></script>
|
@@ -4,24 +4,25 @@
|
|
4
4
|
<link rel="icon" type="image/svg+xml" href="/static/termicon.svg">
|
5
5
|
<link rel="shortcut icon" type="image/x-icon" href="/static/favicon.ico">
|
6
6
|
<meta charset="UTF-8">
|
7
|
-
<title>
|
7
|
+
<title>Janito Light Editor</title>
|
8
8
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/codemirror.min.css">
|
9
9
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/theme/dracula.min.css">
|
10
10
|
<link rel="stylesheet" href="/static/termweb.css">
|
11
11
|
<link rel="stylesheet" href="/static/editor.css">
|
12
|
-
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/addon/dialog/dialog.min.css">
|
13
12
|
</head>
|
14
13
|
<body>
|
15
|
-
<div class="header
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
14
|
+
<div class="header">
|
15
|
+
<div class="header-title">Janito Light Editor</div>
|
16
|
+
<span id="filename-display" class="filename-display"></span>
|
17
|
+
<div style="flex:1 1 auto;"></div>
|
18
|
+
<button class="theme-switcher" id="theme-switcher" title="Alternator tema">
|
19
|
+
<span id="theme-icon" aria-label="Switch theme" style="pointer-events:none;">🌙</span>
|
20
|
+
</button>
|
21
|
+
</div>
|
22
|
+
<div class="footer">
|
23
|
+
<button class="save-btn" id="save-btn">Save</button>
|
23
24
|
</div>
|
24
|
-
<div id="
|
25
|
+
<div id="save-popup" style="display:none;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);z-index:9999;background:#323b4c;color:#fff;padding:14px 28px;border-radius:8px;box-shadow:0 2px 12px #0007;font-size:1.1em;">Saved!</div>
|
25
26
|
<div class="main">
|
26
27
|
<div class="editor-pane">
|
27
28
|
<textarea id="code" name="code"></textarea>
|
@@ -29,11 +30,15 @@
|
|
29
30
|
</div>
|
30
31
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/codemirror.min.js"></script>
|
31
32
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/mode/python/python.min.js"></script>
|
33
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/mode/django/django.min.js"></script>
|
32
34
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/theme/dracula.min.js"></script>
|
33
35
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/addon/selection/active-line.min.js"></script>
|
34
36
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/addon/search/search.min.js"></script>
|
35
37
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/addon/search/searchcursor.min.js"></script>
|
36
38
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/addon/dialog/dialog.min.js"></script>
|
39
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/addon/mode/overlay.min.js"></script>
|
40
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/addon/dialog/dialog.min.css">
|
41
|
+
|
37
42
|
<script src="/static/editor.js"></script>
|
38
43
|
</body>
|
39
44
|
</html>
|