Akoda35 commited on
Commit
d368fe5
·
verified ·
1 Parent(s): 8fccd34

Upload 3 files

Browse files
templates/cpanel/tags/create.html ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends "base.html" %}
2
+
3
+ {% block title %}Create Tag - PyRunner{% endblock %}
4
+
5
+ {% block content %}
6
+ <div class="flex">
7
+ {% include "cpanel/_sidebar.html" %}
8
+
9
+ <div class="flex-1 p-8">
10
+ <!-- Header -->
11
+ <div class="mb-8">
12
+ <nav class="flex items-center space-x-2 text-sm text-code-muted mb-4">
13
+ <a href="{% url 'cpanel:tag_list' %}" class="hover:text-code-accent">Tags</a>
14
+ <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
15
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/>
16
+ </svg>
17
+ <span class="text-code-text">Create Tag</span>
18
+ </nav>
19
+ <h1 class="text-2xl font-bold text-code-text">Create New Tag</h1>
20
+ <p class="text-code-muted">Add a tag to organize and categorize your scripts</p>
21
+ </div>
22
+
23
+ <!-- Form -->
24
+ <div class="bg-code-surface border border-code-border rounded-xl p-6 max-w-2xl">
25
+ <form method="post">
26
+ {% csrf_token %}
27
+
28
+ <!-- Tag Name -->
29
+ <div class="mb-6">
30
+ <label for="id_name" class="block text-sm font-medium text-code-text mb-2">
31
+ {{ form.name.label }}
32
+ </label>
33
+ {{ form.name }}
34
+ {% if form.name.errors %}
35
+ <p class="mt-1 text-sm text-code-red">{{ form.name.errors.0 }}</p>
36
+ {% endif %}
37
+ </div>
38
+
39
+ <!-- Color -->
40
+ <div class="mb-6">
41
+ <label class="block text-sm font-medium text-code-text mb-2">
42
+ {{ form.color.label }}
43
+ </label>
44
+ <input type="hidden" name="color" id="id_color" value="gray">
45
+ <div class="flex items-center gap-3">
46
+ <button type="button" data-color="gray" class="color-circle w-8 h-8 rounded-full ring-2 ring-white ring-offset-2 ring-offset-code-surface transition-all hover:scale-110" style="background-color: rgb(107, 114, 128);"></button>
47
+ <button type="button" data-color="red" class="color-circle w-8 h-8 rounded-full ring-2 ring-transparent ring-offset-2 ring-offset-code-surface transition-all hover:scale-110" style="background-color: rgb(239, 68, 68);"></button>
48
+ <button type="button" data-color="orange" class="color-circle w-8 h-8 rounded-full ring-2 ring-transparent ring-offset-2 ring-offset-code-surface transition-all hover:scale-110" style="background-color: rgb(249, 115, 22);"></button>
49
+ <button type="button" data-color="yellow" class="color-circle w-8 h-8 rounded-full ring-2 ring-transparent ring-offset-2 ring-offset-code-surface transition-all hover:scale-110" style="background-color: rgb(234, 179, 8);"></button>
50
+ <button type="button" data-color="green" class="color-circle w-8 h-8 rounded-full ring-2 ring-transparent ring-offset-2 ring-offset-code-surface transition-all hover:scale-110" style="background-color: rgb(34, 197, 94);"></button>
51
+ <button type="button" data-color="blue" class="color-circle w-8 h-8 rounded-full ring-2 ring-transparent ring-offset-2 ring-offset-code-surface transition-all hover:scale-110" style="background-color: rgb(59, 130, 246);"></button>
52
+ <button type="button" data-color="purple" class="color-circle w-8 h-8 rounded-full ring-2 ring-transparent ring-offset-2 ring-offset-code-surface transition-all hover:scale-110" style="background-color: rgb(168, 85, 247);"></button>
53
+ <button type="button" data-color="pink" class="color-circle w-8 h-8 rounded-full ring-2 ring-transparent ring-offset-2 ring-offset-code-surface transition-all hover:scale-110" style="background-color: rgb(236, 72, 153);"></button>
54
+ </div>
55
+ <div class="mt-3">
56
+ <span class="text-sm text-code-muted mr-2">Preview:</span>
57
+ <span id="tag-preview" class="inline-flex items-center px-3 py-1 text-sm rounded-full tag-gray">
58
+ Sample Tag
59
+ </span>
60
+ </div>
61
+ </div>
62
+
63
+ <!-- Actions -->
64
+ <div class="flex items-center justify-end space-x-4 pt-6 border-t border-code-border">
65
+ <a href="{% url 'cpanel:tag_list' %}"
66
+ class="px-4 py-2 bg-code-surface border border-code-border hover:border-code-accent text-code-text rounded-lg transition-colors">
67
+ Cancel
68
+ </a>
69
+ <button type="submit"
70
+ class="px-4 py-2 bg-code-accent hover:bg-code-accent/90 text-white font-semibold rounded-lg transition-colors">
71
+ Create Tag
72
+ </button>
73
+ </div>
74
+ </form>
75
+ </div>
76
+ </div>
77
+ </div>
78
+
79
+ <script>
80
+ document.addEventListener('DOMContentLoaded', function() {
81
+ const colorInput = document.getElementById('id_color');
82
+ const nameInput = document.getElementById('id_name');
83
+ const preview = document.getElementById('tag-preview');
84
+ const colorCircles = document.querySelectorAll('.color-circle');
85
+
86
+ function updatePreview() {
87
+ const color = colorInput.value || 'gray';
88
+ const name = nameInput.value || 'Sample Tag';
89
+
90
+ preview.className = preview.className.replace(/tag-\w+/g, '');
91
+ preview.classList.add('tag-' + color);
92
+ preview.classList.add('inline-flex', 'items-center', 'px-3', 'py-1', 'text-sm', 'rounded-full');
93
+ preview.textContent = name;
94
+ }
95
+
96
+ function selectColor(color) {
97
+ colorInput.value = color;
98
+ colorCircles.forEach(circle => {
99
+ if (circle.dataset.color === color) {
100
+ circle.classList.remove('ring-transparent');
101
+ circle.classList.add('ring-white');
102
+ } else {
103
+ circle.classList.remove('ring-white');
104
+ circle.classList.add('ring-transparent');
105
+ }
106
+ });
107
+ updatePreview();
108
+ }
109
+
110
+ colorCircles.forEach(circle => {
111
+ circle.addEventListener('click', () => selectColor(circle.dataset.color));
112
+ });
113
+
114
+ nameInput.addEventListener('input', updatePreview);
115
+ updatePreview();
116
+ });
117
+ </script>
118
+ {% endblock %}
templates/cpanel/tags/edit.html ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends "base.html" %}
2
+
3
+ {% block title %}Edit Tag - PyRunner{% endblock %}
4
+
5
+ {% block content %}
6
+ <div class="flex">
7
+ {% include "cpanel/_sidebar.html" %}
8
+
9
+ <div class="flex-1 p-8">
10
+ <!-- Header -->
11
+ <div class="mb-8">
12
+ <nav class="flex items-center space-x-2 text-sm text-code-muted mb-4">
13
+ <a href="{% url 'cpanel:tag_list' %}" class="hover:text-code-accent">Tags</a>
14
+ <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
15
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/>
16
+ </svg>
17
+ <span class="text-code-text">Edit Tag</span>
18
+ </nav>
19
+ <h1 class="text-2xl font-bold text-code-text">Edit Tag</h1>
20
+ <p class="text-code-muted">Update tag name or color</p>
21
+ </div>
22
+
23
+ <!-- Form -->
24
+ <div class="bg-code-surface border border-code-border rounded-xl p-6 max-w-2xl">
25
+ <form method="post">
26
+ {% csrf_token %}
27
+
28
+ <!-- Tag Name -->
29
+ <div class="mb-6">
30
+ <label for="id_name" class="block text-sm font-medium text-code-text mb-2">
31
+ {{ form.name.label }}
32
+ </label>
33
+ {{ form.name }}
34
+ {% if form.name.errors %}
35
+ <p class="mt-1 text-sm text-code-red">{{ form.name.errors.0 }}</p>
36
+ {% endif %}
37
+ </div>
38
+
39
+ <!-- Color -->
40
+ <div class="mb-6">
41
+ <label class="block text-sm font-medium text-code-text mb-2">
42
+ {{ form.color.label }}
43
+ </label>
44
+ <input type="hidden" name="color" id="id_color" value="{{ tag.color }}">
45
+ <div class="flex items-center gap-3">
46
+ <button type="button" data-color="gray" class="color-circle w-8 h-8 rounded-full ring-2 {% if tag.color == 'gray' %}ring-white{% else %}ring-transparent{% endif %} ring-offset-2 ring-offset-code-surface transition-all hover:scale-110" style="background-color: rgb(107, 114, 128);"></button>
47
+ <button type="button" data-color="red" class="color-circle w-8 h-8 rounded-full ring-2 {% if tag.color == 'red' %}ring-white{% else %}ring-transparent{% endif %} ring-offset-2 ring-offset-code-surface transition-all hover:scale-110" style="background-color: rgb(239, 68, 68);"></button>
48
+ <button type="button" data-color="orange" class="color-circle w-8 h-8 rounded-full ring-2 {% if tag.color == 'orange' %}ring-white{% else %}ring-transparent{% endif %} ring-offset-2 ring-offset-code-surface transition-all hover:scale-110" style="background-color: rgb(249, 115, 22);"></button>
49
+ <button type="button" data-color="yellow" class="color-circle w-8 h-8 rounded-full ring-2 {% if tag.color == 'yellow' %}ring-white{% else %}ring-transparent{% endif %} ring-offset-2 ring-offset-code-surface transition-all hover:scale-110" style="background-color: rgb(234, 179, 8);"></button>
50
+ <button type="button" data-color="green" class="color-circle w-8 h-8 rounded-full ring-2 {% if tag.color == 'green' %}ring-white{% else %}ring-transparent{% endif %} ring-offset-2 ring-offset-code-surface transition-all hover:scale-110" style="background-color: rgb(34, 197, 94);"></button>
51
+ <button type="button" data-color="blue" class="color-circle w-8 h-8 rounded-full ring-2 {% if tag.color == 'blue' %}ring-white{% else %}ring-transparent{% endif %} ring-offset-2 ring-offset-code-surface transition-all hover:scale-110" style="background-color: rgb(59, 130, 246);"></button>
52
+ <button type="button" data-color="purple" class="color-circle w-8 h-8 rounded-full ring-2 {% if tag.color == 'purple' %}ring-white{% else %}ring-transparent{% endif %} ring-offset-2 ring-offset-code-surface transition-all hover:scale-110" style="background-color: rgb(168, 85, 247);"></button>
53
+ <button type="button" data-color="pink" class="color-circle w-8 h-8 rounded-full ring-2 {% if tag.color == 'pink' %}ring-white{% else %}ring-transparent{% endif %} ring-offset-2 ring-offset-code-surface transition-all hover:scale-110" style="background-color: rgb(236, 72, 153);"></button>
54
+ </div>
55
+ <div class="mt-3">
56
+ <span class="text-sm text-code-muted mr-2">Preview:</span>
57
+ <span id="tag-preview" class="inline-flex items-center px-3 py-1 text-sm rounded-full tag-{{ tag.color }}">
58
+ {{ tag.name }}
59
+ </span>
60
+ </div>
61
+ </div>
62
+
63
+ <!-- Usage Info -->
64
+ {% if tag.script_count > 0 %}
65
+ <div class="mb-6 p-4 bg-code-bg border border-code-border rounded-lg">
66
+ <p class="text-sm text-code-muted">
67
+ This tag is used by <strong class="text-code-text">{{ tag.script_count }} script{{ tag.script_count|pluralize }}</strong>.
68
+ Changes will be reflected immediately.
69
+ </p>
70
+ </div>
71
+ {% endif %}
72
+
73
+ <!-- Actions -->
74
+ <div class="flex items-center justify-end space-x-4 pt-6 border-t border-code-border">
75
+ <a href="{% url 'cpanel:tag_list' %}"
76
+ class="px-4 py-2 bg-code-surface border border-code-border hover:border-code-accent text-code-text rounded-lg transition-colors">
77
+ Cancel
78
+ </a>
79
+ <button type="submit"
80
+ class="px-4 py-2 bg-code-accent hover:bg-code-accent/90 text-white font-semibold rounded-lg transition-colors">
81
+ Update Tag
82
+ </button>
83
+ </div>
84
+ </form>
85
+ </div>
86
+ </div>
87
+ </div>
88
+
89
+ <script>
90
+ document.addEventListener('DOMContentLoaded', function() {
91
+ const colorInput = document.getElementById('id_color');
92
+ const nameInput = document.getElementById('id_name');
93
+ const preview = document.getElementById('tag-preview');
94
+ const colorCircles = document.querySelectorAll('.color-circle');
95
+
96
+ function updatePreview() {
97
+ const color = colorInput.value || 'gray';
98
+ const name = nameInput.value || 'Sample Tag';
99
+
100
+ preview.className = preview.className.replace(/tag-\w+/g, '');
101
+ preview.classList.add('tag-' + color);
102
+ preview.classList.add('inline-flex', 'items-center', 'px-3', 'py-1', 'text-sm', 'rounded-full');
103
+ preview.textContent = name;
104
+ }
105
+
106
+ function selectColor(color) {
107
+ colorInput.value = color;
108
+ colorCircles.forEach(circle => {
109
+ if (circle.dataset.color === color) {
110
+ circle.classList.remove('ring-transparent');
111
+ circle.classList.add('ring-white');
112
+ } else {
113
+ circle.classList.remove('ring-white');
114
+ circle.classList.add('ring-transparent');
115
+ }
116
+ });
117
+ updatePreview();
118
+ }
119
+
120
+ colorCircles.forEach(circle => {
121
+ circle.addEventListener('click', () => selectColor(circle.dataset.color));
122
+ });
123
+
124
+ nameInput.addEventListener('input', updatePreview);
125
+ });
126
+ </script>
127
+ {% endblock %}
templates/cpanel/tags/list.html ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends "base.html" %}
2
+
3
+ {% block title %}Tags - PyRunner{% endblock %}
4
+
5
+ {% block content %}
6
+ <div class="flex">
7
+ {% include "cpanel/_sidebar.html" %}
8
+
9
+ <div class="flex-1 p-8">
10
+ <!-- Header -->
11
+ <div class="flex items-start justify-between mb-8">
12
+ <div>
13
+ <h1 class="text-2xl font-bold text-code-text">Tags</h1>
14
+ <p class="text-code-muted">Organize and categorize your scripts with tags</p>
15
+ </div>
16
+ <a href="{% url 'cpanel:tag_create' %}"
17
+ class="px-4 py-2 bg-code-accent hover:bg-code-accent/90 text-white font-semibold rounded-lg transition-colors inline-flex items-center">
18
+ <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
19
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"/>
20
+ </svg>
21
+ New Tag
22
+ </a>
23
+ </div>
24
+
25
+ <!-- Messages -->
26
+ {% if messages %}
27
+ <div class="mb-6 space-y-2">
28
+ {% for message in messages %}
29
+ <div class="p-4 rounded-lg {% if message.tags == 'error' %}bg-code-red/10 border border-code-red/30 text-code-red{% elif message.tags == 'success' %}bg-code-green/10 border border-code-green/30 text-code-green{% else %}bg-code-accent/10 border border-code-accent/30 text-code-accent{% endif %}">
30
+ {{ message }}
31
+ </div>
32
+ {% endfor %}
33
+ </div>
34
+ {% endif %}
35
+
36
+ <!-- Tags Table -->
37
+ {% if tags %}
38
+ <div class="bg-code-surface border border-code-border rounded-xl overflow-hidden">
39
+ <table class="w-full">
40
+ <thead class="bg-code-bg border-b border-code-border">
41
+ <tr>
42
+ <th class="px-6 py-3 text-left text-xs font-semibold text-code-muted uppercase tracking-wider">Tag</th>
43
+ <th class="px-6 py-3 text-left text-xs font-semibold text-code-muted uppercase tracking-wider">Scripts</th>
44
+ <th class="px-6 py-3 text-left text-xs font-semibold text-code-muted uppercase tracking-wider">Created</th>
45
+ <th class="px-6 py-3 text-right text-xs font-semibold text-code-muted uppercase tracking-wider">Actions</th>
46
+ </tr>
47
+ </thead>
48
+ <tbody class="divide-y divide-code-border">
49
+ {% for tag in tags %}
50
+ <tr class="hover:bg-code-bg/50 transition-colors">
51
+ <td class="px-6 py-4">
52
+ <span class="inline-flex items-center px-3 py-1 text-sm rounded-full tag-{{ tag.color }}">
53
+ {{ tag.name }}
54
+ </span>
55
+ </td>
56
+ <td class="px-6 py-4 text-code-text">
57
+ <a href="{% url 'cpanel:script_list' %}?tag={{ tag.pk }}" class="hover:text-code-accent transition-colors">
58
+ {{ tag.script_count }} script{{ tag.script_count|pluralize }}
59
+ </a>
60
+ </td>
61
+ <td class="px-6 py-4 text-code-muted text-sm">
62
+ {{ tag.created_at|timesince }} ago
63
+ </td>
64
+ <td class="px-6 py-4 text-right">
65
+ <div class="flex items-center justify-end space-x-2">
66
+ <a href="{% url 'cpanel:tag_edit' pk=tag.pk %}"
67
+ class="px-3 py-1.5 text-sm bg-code-surface border border-code-border hover:border-code-accent text-code-text rounded transition-colors">
68
+ Edit
69
+ </a>
70
+ <form method="post" action="{% url 'cpanel:tag_delete' pk=tag.pk %}"
71
+ onsubmit="return confirm('Are you sure you want to delete the tag &quot;{{ tag.name }}&quot;? It will be removed from all scripts.');"
72
+ class="inline">
73
+ {% csrf_token %}
74
+ <button type="submit"
75
+ class="px-3 py-1.5 text-sm bg-code-red/10 border border-code-red/30 hover:bg-code-red/20 text-code-red rounded transition-colors">
76
+ Delete
77
+ </button>
78
+ </form>
79
+ </div>
80
+ </td>
81
+ </tr>
82
+ {% endfor %}
83
+ </tbody>
84
+ </table>
85
+ </div>
86
+ {% else %}
87
+ <div class="bg-code-surface border border-code-border rounded-xl p-12 text-center">
88
+ <div class="w-16 h-16 bg-code-accent/20 rounded-full flex items-center justify-center mx-auto mb-4">
89
+ <svg class="w-8 h-8 text-code-accent" fill="none" stroke="currentColor" viewBox="0 0 24 24">
90
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z"/>
91
+ </svg>
92
+ </div>
93
+ <h3 class="text-lg font-semibold text-code-text mb-2">No tags yet</h3>
94
+ <p class="text-code-muted mb-6">Create tags to organize and filter your scripts.</p>
95
+ <a href="{% url 'cpanel:tag_create' %}"
96
+ class="px-6 py-2 bg-code-accent hover:bg-code-accent/90 text-white font-semibold rounded-lg transition-colors inline-flex items-center">
97
+ <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
98
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"/>
99
+ </svg>
100
+ Create Tag
101
+ </a>
102
+ </div>
103
+ {% endif %}
104
+ </div>
105
+ </div>
106
+ {% endblock %}