From 1566d6c207c6d9b53f1102eac1d7d6da25b6b558 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Thu, 20 Nov 2025 17:15:00 +0000 Subject: [PATCH] custom instructions --- core/__pycache__/admin.cpython-311.pyc | Bin 460 -> 759 bytes core/__pycache__/models.cpython-311.pyc | Bin 3577 -> 4089 bytes core/__pycache__/urls.cpython-311.pyc | Bin 1081 -> 1176 bytes core/__pycache__/views.cpython-311.pyc | Bin 17663 -> 18996 bytes core/admin.py | 7 +- core/migrations/0006_setting.py | 21 ++ .../__pycache__/0006_setting.cpython-311.pyc | Bin 0 -> 1072 bytes core/models.py | 9 +- core/templates/base.html | 3 + core/templates/core/settings.html | 18 ++ core/urls.py | 1 + core/views.py | 30 ++- static/css/custom.css | 69 +++++- static/css/custom.css.bak | 230 ++++++++++++++++++ staticfiles/css/custom.css | 69 +++++- staticfiles/css/custom.css.bak | 230 ++++++++++++++++++ 16 files changed, 680 insertions(+), 7 deletions(-) create mode 100644 core/migrations/0006_setting.py create mode 100644 core/migrations/__pycache__/0006_setting.cpython-311.pyc create mode 100644 core/templates/core/settings.html create mode 100644 static/css/custom.css.bak create mode 100644 staticfiles/css/custom.css.bak diff --git a/core/__pycache__/admin.cpython-311.pyc b/core/__pycache__/admin.cpython-311.pyc index 20f0cc2c4b13b60e6a44b59d6598c3c64f11716b..42269e66457f05c28c20254238dc0711fd0fd1e2 100644 GIT binary patch literal 759 zcmbVJJ4*vW5T5m3G5A2zCSuAIdSESrh^U}8T3vVE4)Nmct?cdjDD3?Z&M6r+zv-4uUdF}Q1co{UEzD~#QT0a@5Pu92bHctR9fC426FcJ^~ zbc9;T2(to<*@4ZRz+rCSGB5B5AZeBQB`!z%)}Th~N>{wq?~DG0v4_AoLtxw?Fy3zr zwYQ<+Je&0zL^&a4ar$ibZ8*wX5;BewRHYqG`MN}=yls>+PMd0MnWu*+vQWl6Ro*6M zS=hv_Mp;eJR+u*VT*Ol;;$2}rN4bnsOfunUN4Q3KMws&pb9rTFvDA$OHseg9xPdnv zh2E^c#~J$hZl22A$776g$%TK!#eQ}WM(9Uep#M4b+`&n&w4nRs2`-8$jW%m!cUrty zgpe-G6hFBOE5-l#5uCH~161yza=zMzY6q$XRJ#MwwKmi`P%EG|82vkUqYd>A)C;Kp MovTZ07L$7N4<&=4O#lD@ delta 152 zcmey)dWM;IIWI340}yCf%4If9^QxOM{zQtCWmswbvIystMpIwvj7ISuL<>Y>LF(rPeYQ6aQ;*z5Hcw?aA zVoo5@z;J_KxTm6nfAV2=rTRdiNRcGSAl9#a=+7 z0S<3)Np+}Q;gVXAyg}sxm-$65^DA8D4bC@sWIEig@W@=`k-Nep*Wmhrg^^X_0|Pq2 z&nf}22V{kxCdcICJUWbili%~ma)$y%7(w>2GENrfy<{c9$_O+7ljun6$@vHp|AIvl GY&Za`|6{!X delta 96 zcmew<|5KWGIWI340}xCNmCKZz$ScXXYNGl|wiK>l22Jjbf8KF3`)RUIp24T1A`4Vh pBmyD?fy6Hko80`A(wtPgB7Y#45r~U#GfaNVcWLrmer{HP{!x1jp~k!6DP20ils7V@xY{0#MiJd zV`gAj4a5+T&KbpDY?0bQH)WdinBPiq$D#hy;%Pi2aM^b$v3&1DUy#DCJHE@GqkvLEs01IjqiU0rr diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index 53fe095954643d42691694fc728d4b07f90e430e..8f27c3c0a4f42a9cf3bed96e020b4a3494b8e639 100644 GIT binary patch delta 4077 zcma)9YiwLc6~1%#>9u#)`?S}Oc)i}(Ub~I+wiBn0A90$N#Bt*^4bEe;_1rk?>?6#* zc3X2dPNhguX$5YlKLQO9L`hq0vP7*J|F|E1otZ#3I36UDEGZRJA?%Mu3Ev`;^fr9WGG0R~u1e#z)CCx! zm4J1MgH~OYZh^tuB{ONf9<=TZ#_a<7CyFqCX*O{ z-!V$!yvo@Tei&K}o0d{9s;U*_Xte(di}AzGYhbYKY$G-NU(UuX#kBN9MoFeAL*i5%DH@HM-aMsNs%WWnhV}74<$e-h z7_0n@_z$2%o5EP0rRQPeSO*_);o zh@#q|1_MI@qCRoglF@~Kxc^M%2GOeO(DCD=$z#I@hmQ>(V}4L2?CXOVcB*6)O);!T zhK~<0F#}}1#8^MbYy`k?Fy*|$6jowwZJm{7|0K?Zod82zn|d1H3O`qU8W{Yb`Uitz zSev=5^_?37D<(!Gf>IS@c+IaHm`&xTFA2vgJIQbQ`hdPa_y!z}NQ`0C@-&~Yup~M; zhk)wYZax?3=2~RL-jCHs_{()6em62@Lo#Ohd|flo)(w*r3k!8Bc?{QU*faUbNrf5K zbnbkf4TEZZqK18fDJe~1L#P&eQ$8T8!-g@QZ`gh06pCjM(8h4)lxIv{`ca20vZDZM z1%TKtbIYJ+c$H_BiD^wqPUN%MRF1Oz!WRucw~$}+pF|tTU-(DSUpc;^lX)w<#(y7e z;U6>)lH;$$zL2#|ynl0u2UT;pZv2`=<7Nxl%xgEdSXv7Key+8P1o(Vw#Jf`FN>E{?ZO~zBJhW@$?D2Gn zqWjASCei4ipbnHZH{fK$G*RvYu9J<^YTSl-YpqOS$`nNpl=mtGX@?%1 zk=ToR5P7QTNK0mf@$WS^HFy4xwO!j^@+3(*^yPhRkx)pt(}ymKm}D}of>`qu!bngg zq=(;e-Gb!#HYQL}h=kVs-L^Io;=gMf79@tFxw(1yrD%(!?JXHf(p0o0YlHk``v91J zk_hwL?QZwR;9KM4;qtixA6p7FVw-AUn}YG&6nMuBwpQYBo(r{Q%!)ARr(Jrji1V%Q zY%4!);B&k7XvqOEP+LAG_PQ4upClrcwU=viPAV1Pms>l&>f2FnUx@Hr$F7GT+u%{6 zJN1Ze)4sB<(~hjmQ?2|7ZulLO4faN0Vp`Sm*f4X6`stQK3vlEn2@iB)mQq*22A zWkdF^f~w)nDyo{AR8;YJU^A$*r!HMmAo1c_nHx23xbc&DmR!35bZih8a|5)S=pAlJwD@ zLFcF}e@tYkd~E4Oxz7r6QSKS-vlaJRP=17<+&4g=vLw02+AK@1fxuYI@|&0qDiipe zDHVL9;ZFYbJnwRCF~);huhU^rVpk!MQR#D>F~%)l;h zxu9h;?3-W#kGA#T$7iwmUX{&=`5`Fo9XgQ1qK|;5V5aJJ&|Q)4^4kNU?z@$~`L<$x zPqBBTIC`eI_v~V2a=9{Dv?f^`%pSb5YQnd=wsup3D}iT-wLCG3X9y|Cx-^AEh(c{^ zSHh6ao0^+r(AQGlOD9RBP86Nobiln9_- zJa+8c0OkJ=+@%rB^Y8{3oWfnW0m2pO)0U3c_upyhUux-JscK&FN3L(5$3qYwz(WwX z!y$;<7w4?eqP6CF&8kasdaqu-9$s=Z6&+10@y^!|--+*BitjA$di=w|#rVP3qImka6Y@ai8rVU=uS(S;ud`)0ucvI;unfwIgi&Q$9 zx|BBaV+Ewv!{)2onM~$VStXe?Q)vryVm%0b2%`x2w}PES5J?hqhZ(!b+FO#CQJqLJ z|8(xl=IL}s>0>{IHavjp_xa_av+cu0>Hqrhe-9at4p;~*_C7plm&rK-EUcr`gO>M$ HnA3j&5sj0z delta 2823 zcmai0U2Gf25#Bu>DM}RoMM=~zB~lV8Dw3ThvE)dyXjPGn)PItHYPB_S=ALEBibEgLhX5(kA}RV(6fM%3 zqiCB>(Jsi3v$Hd^GqcBU?`N;l&#%zHkNo}y0%KO~Dn2!OEzm0ci(E^exJ(Iiv$|5S z99j&4Oqg5>FNWdQTZ)vUi&07>qSh}rp)U?Kc8d~n8@`pX*v#s;$YKj?0BmJGz_?n+ z8n?(TFt}YcBa3aI^?yN|Z3lJW3+fIQgg~7v%tBjqv5UzIBoh&%bb-p^B|5nME;S{O zAA<9c7?V%fy>Qc ze<@VZxjJ%Q(atE^@Hw+w%6K_8ink%OBXj`RfrVqaW5*Zr({qOpOwTOvPF(3iZ~MB!BrC8z%4ds&WdM1k@4H| zvY~6XyQC}3u;nv4+u+Z_3U?zoWe=hh7eDZihOr`BW{RoseW;xhANpI{oKhldE1*~N zred7W8>V8e8T{~eB=9k9%Ar@|+_7Uv^7Av#&CJit^RNhnx~80sup`xGIYAGic^y~J zs$AvOhV7K-V`@p=*@Yh$rBD(2_50A9`@mT7 z-5s@hql{Zs$ITYZ-_=>Mjdj)9UMH-(vO*K$t-hqIXETJYp&`*T5O@EfnzYP%!R)^~-o&J|5q-!&TCS*37oMUK$V`xfg%dpF2H8LS7!oRT@s|nO1RtK6V zt(fyzW`8_XslVz15uY%Tns$cu*foY;4-S5HFz$( zpMC;)wi=PJ5v$p9n=@4nA?EBuc{wS*?dp4G*A3S#;PKnY<<5YcZTBG_0@)#eOQA#R zdSY7FE&v@WW>MENl%E#wWJiF6{*ukoKG8aqlufYTUK?8Qc^r;8E$-||M0Q~iWDEmO z5ig2YMu(+;6R~Sl2j;vv`l4qQO{T@}u{0eNi(|rb3Kd@ye;@lvI|K1jG^Zt;dn2J2 z3TvFJY;S@`#IN>FIrn8I#aqzB$=6|YA5QTCw#;dQszNQMrV3H&-;E*#O9w?O=sg^ISDnbj?s5+O-?iizZhJ zX5K`hh^}}9{5b>-VGiK{!ZO112-yFJmw2Y7a(}O&*5PUcC8t|gP%0795BJo$qG9TM z!*-R8CB6X*cEH#$OtqZfDUm-Z3gdnB1#x9OJLDAVKU>t4(t~y6a@${cj&#mrwQs_XnZth@?eBPe1MKcq|I7Za~Fd{qjU>4%B*XVUi1C-2KgXFHC{ z3d{>e|zUvu1BDwEQxk@H6o*TC0ZLMed1a-@1EO;-e$Y9x zUNGQ$5GD`~BOFIKiQt?CR`eF(NmSsg#6P{`Wu2{+)JcvnjCf@m8{*};)4k*O$p86> S=mC4+n-Z=2jQlTjHv11-BY0W> diff --git a/core/admin.py b/core/admin.py index 19afb57..fab9d55 100644 --- a/core/admin.py +++ b/core/admin.py @@ -1,5 +1,8 @@ from django.contrib import admin -from .models import Article, TodoItem +from .models import Article, TodoItem, Setting, Conversation, Message admin.site.register(Article) -admin.site.register(TodoItem) \ No newline at end of file +admin.site.register(TodoItem) +admin.site.register(Setting) +admin.site.register(Conversation) +admin.site.register(Message) diff --git a/core/migrations/0006_setting.py b/core/migrations/0006_setting.py new file mode 100644 index 0000000..cc29edb --- /dev/null +++ b/core/migrations/0006_setting.py @@ -0,0 +1,21 @@ +# Generated by Django 5.2.7 on 2025-11-20 10:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0005_alter_message_options_remove_message_is_from_user_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='Setting', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('key', models.CharField(max_length=255, unique=True)), + ('value', models.TextField()), + ], + ), + ] diff --git a/core/migrations/__pycache__/0006_setting.cpython-311.pyc b/core/migrations/__pycache__/0006_setting.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..49bfd5f2d7ceb59aca9deb09585984800f15c903 GIT binary patch literal 1072 zcmZuvy-yTD6rcULz1!tLFzQ{dz>g5a5#(sJG7?2F8l{m~Tr*j2-W?13an9}{SW#G5 zl32iBfKezcEiEmVrh&4e#DFk zr^D^Y3H(qPUckT&Te+v)Gcvdze?+lOfHW0GnkrK|N>ft_=qouX{56v&#!68-%E5G; z1!n9QcXcFzt3TQ*D`l3Y{DhfI-?w%#;XPbuRs)%pnV;+;*vl2tRy*2$`ClJoWwAj_ za7dWX^2{(zy%lf}Gt<-4x2f$$z^MmeXm@}H-7I;^!3);l?AQrun+G0^L$tMhMm-sz z_#C3h@jF6w*y6lUA3vujz23>^>VWPKVyUuG6EG*mk9{)EIQZXW+LS2)XRN7?{oYJ(C^gvJs;E!0Fsa=JPVNFlU!-ehL?1J?cX% z=)&pi_&|WR=V-`RW-2YcWBtJ+f;Xh z8yF=M5`^ziY@W^3Am*ZyYU(9p^J!`k^XglxR~kJWseK!{oKz;Z)_RqR&-&M~q)8K> zCzbG^680)#G8`R_TuG|qJ4UZM{%Q7$o>b=!s&l>STrxa=I8se&6FWD1wTXk;WUn@v z4BtwN`lX??P&BP0g5sAHsb*d@HlN7Jujecmu)`)>vHeak#g?*SX7%gmaZQ?Kwl@%+ xl_}ex`p<3l-#@`7BWnNv literal 0 HcmV?d00001 diff --git a/core/models.py b/core/models.py index b9cb4ae..01752e5 100644 --- a/core/models.py +++ b/core/models.py @@ -42,4 +42,11 @@ class Message(models.Model): ordering = ['created_at'] def __str__(self): - return f"Message from {self.get_sender_display()} at {self.created_at}" \ No newline at end of file + return f"Message from {self.get_sender_display()} at {self.created_at}" + +class Setting(models.Model): + key = models.CharField(max_length=255, unique=True) + value = models.TextField() + + def __str__(self): + return self.key diff --git a/core/templates/base.html b/core/templates/base.html index 905e789..bdd75c5 100644 --- a/core/templates/base.html +++ b/core/templates/base.html @@ -30,6 +30,9 @@ + diff --git a/core/templates/core/settings.html b/core/templates/core/settings.html new file mode 100644 index 0000000..f4a5f3d --- /dev/null +++ b/core/templates/core/settings.html @@ -0,0 +1,18 @@ +{% extends "base.html" %} + +{% block content %} +
+

Settings

+
+ {% csrf_token %} +
+ + +
+ These instructions will be added to the AI's system prompt. +
+
+ +
+
+{% endblock %} diff --git a/core/urls.py b/core/urls.py index 1a7b1a1..b1dc985 100644 --- a/core/urls.py +++ b/core/urls.py @@ -12,4 +12,5 @@ urlpatterns = [ path('chat/', views.chat_view, name='chat'), path('chat//', views.chat_view, name='chat_detail'), path('cleanup_tasks/', views.cleanup_tasks, name='cleanup_tasks'), + path('settings/', views.settings_view, name='settings'), ] \ No newline at end of file diff --git a/core/views.py b/core/views.py index 73e0364..29c919f 100644 --- a/core/views.py +++ b/core/views.py @@ -3,7 +3,7 @@ from django.http import JsonResponse from django.views.decorators.http import require_POST import json import logging -from .models import Article, TodoItem, Conversation, Message +from .models import Article, TodoItem, Conversation, Message, Setting from .forms import TodoItemForm import time from ai.local_ai_api import LocalAIApi @@ -170,9 +170,15 @@ def chat_view(request, conversation_id=None): history.append({"role": role, "content": msg.content}) try: + custom_instructions, created = Setting.objects.get_or_create( + key='custom_instructions', + defaults={'value': ''} + ) + custom_instructions_text = custom_instructions.value + '\n\n' if custom_instructions.value else '' + system_message = { "role": "system", - "content": '''You are a project management assistant. To communicate with the user, you MUST use the `send_message` command. + "content": custom_instructions_text + '''You are a project management assistant. To communicate with the user, you MUST use the `send_message` command. **Commands must be in a specific JSON format.** Your response must be a JSON object with the following structure: @@ -333,3 +339,23 @@ def chat_view(request, conversation_id=None): 'selected_conversation': selected_conversation, 'timestamp': int(time.time()), }) + +def conversation_list(request): + conversations = Conversation.objects.order_by('-created_at') + return render(request, 'core/conversation_list.html', {'conversation_list': conversations}) + +def settings_view(request): + # Get or create the custom_instructions setting + custom_instructions, created = Setting.objects.get_or_create( + key='custom_instructions', + defaults={'value': ''} + ) + + if request.method == 'POST': + custom_instructions.value = request.POST.get('custom_instructions', '') + custom_instructions.save() + return redirect('core:settings') + + return render(request, 'core/settings.html', { + 'custom_instructions': custom_instructions + }) \ No newline at end of file diff --git a/static/css/custom.css b/static/css/custom.css index 551c68f..293163a 100644 --- a/static/css/custom.css +++ b/static/css/custom.css @@ -227,4 +227,71 @@ body { position: absolute; top: 10px; right: 10px; -} \ No newline at end of file +} + +/* Kanban Board Styles */ +.kanban-board-container { + width: 100%; + overflow-x: auto; + padding: 1rem; +} + +.kanban-board { + display: flex; + gap: 1rem; + min-width: max-content; /* Ensure board expands horizontally */ +} + +.kanban-column { + flex: 1 1 300px; /* Flex-grow, flex-shrink, and basis */ + min-width: 300px; + max-width: 320px; + background-color: #f0f2f5; + border-radius: 0.5rem; + display: flex; + flex-direction: column; + max-height: calc(100vh - 250px); /* Adjust based on your layout */ +} + +.kanban-column h2 { + position: sticky; + top: 0; + z-index: 2; +} + +.kanban-cards { + overflow-y: auto; + flex-grow: 1; + min-height: 150px; /* Ensure drop zone is available even when empty */ +} + +.kanban-card { + cursor: grab; + transition: background-color 0.2s, box-shadow 0.2s; +} + +.kanban-card:hover { + background-color: #f8f9fa; + box-shadow: 0 4px 8px rgba(0,0,0,0.1); +} + +.kanban-card .btn-close { + transition: opacity 0.2s; + opacity: 0; +} + +.kanban-card:hover .btn-close { + opacity: 1; +} + +/* For the drag-and-drop placeholder */ +.sortable-ghost { + background-color: #e9ecef; + border: 2px dashed #ced4da; +} + +.sortable-drag { + opacity: 1 !important; /* Override Sortable.js default opacity */ + box-shadow: 0 8px 16px rgba(0,0,0,0.2); + transform: rotate(3deg); +} diff --git a/static/css/custom.css.bak b/static/css/custom.css.bak new file mode 100644 index 0000000..551c68f --- /dev/null +++ b/static/css/custom.css.bak @@ -0,0 +1,230 @@ +/* General App Body & Layout */ +body { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + background-color: #f8f9fa; + color: #212529; +} + +/* Main Chat Layout */ +.chat-container { + display: flex; + height: calc(100vh - 120px); /* Adjusted for header/footer */ + width: 100%; + background-color: #fff; + border: 1px solid #dee2e6; + border-radius: 0.5rem; +} + +/* Sidebar Styles */ +.chat-sidebar { + width: 280px; + background-color: #f8f9fa; + border-right: 1px solid #dee2e6; + display: flex; + flex-direction: column; + padding: 1rem; + flex-shrink: 0; +} + +.new-chat-form { + display: flex; + margin-bottom: 1rem; +} + +.new-chat-form input { + flex: 1; + padding: 0.75rem; + border: 1px solid #ced4da; + border-radius: 0.375rem 0 0 0.375rem; + font-size: 0.9rem; +} + +.new-chat-form button { + padding: 0.75rem 1rem; + background-color: #0d6efd; + color: #fff; + border: 1px solid #0d6efd; + border-radius: 0 0.375rem 0.375rem 0; + cursor: pointer; +} + +.conversation-list { + list-style: none; + padding: 0; + margin: 0; + overflow-y: auto; +} + +.conversation-list a { + display: block; + padding: 0.75rem 1rem; + color: #495057; + text-decoration: none; + border-radius: 0.375rem; + margin-bottom: 0.25rem; +} + +.conversation-list a:hover { + background-color: #e9ecef; +} + +.conversation-list a.active { + background-color: #0d6efd; + color: #fff; +} + +/* Main Content Area */ +.chat-main { + flex: 1; + display: flex; + flex-direction: column; + background-color: #ffffff; + position: relative; /* Needed for loader overlay */ +} + +/* Chat Header */ +.chat-header { + padding: 1rem 1.5rem; + border-bottom: 1px solid #dee2e6; + flex-shrink: 0; +} + +.chat-header h3 { + margin: 0; + font-size: 1.1rem; +} + +/* Message Area */ +.chat-messages { + flex: 1; + padding: 1.5rem; + overflow-y: auto; +} + +.message { + margin-bottom: 1rem; + display: flex; +} + +.message-content { + max-width: 80%; + padding: 0.75rem 1rem; + border-radius: 0.5rem; + line-height: 1.5; +} + +.message.user { + justify-content: flex-end; +} + +.message.user .message-content { + background-color: #0d6efd; + color: #fff; +} + +.message.ai .message-content { + background-color: #e9ecef; + color: #343a40; +} + +.message-author { + font-weight: bold; + font-size: 0.8rem; + margin-bottom: 0.25rem; +} + +/* Message Input Form */ +.chat-form-container { + padding: 1rem 1.5rem; + border-top: 1px solid #dee2e6; + background-color: #f8f9fa; +} + +.chat-form { + display: flex; +} + +.chat-form textarea { + flex: 1; + padding: 0.75rem; + border: 1px solid #ced4da; + border-radius: 0.375rem; + font-size: 1rem; + resize: none; +} + +.chat-form button { + margin-left: 1rem; + padding: 0.75rem 1.5rem; + background-color: #0d6efd; + color: #fff; + border: none; + border-radius: 0.375rem; + cursor: pointer; +} + +/* Empty State for Chat */ +.no-conversation-selected { + display: flex; + justify-content: center; + align-items: center; + height: 100%; + color: #6c757d; +} + +/* Loader Styles */ +.loader-overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(255, 255, 255, 0.8); + display: flex; + justify-content: center; + align-items: center; + z-index: 10; +} + +.loader { + border: 5px solid #f3f3f3; /* Light grey */ + border-top: 5px solid #0d6efd; /* Blue */ + border-radius: 50%; + width: 50px; + height: 50px; + animation: spin 1s linear infinite; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +/* System and AI Command Messages */ +.message.system .message-content { + background-color: #f8d7da; + color: #721c24; + border: 1px solid #f5c6cb; +} + +.message.ai_command .message-content { + background-color: #d1ecf1; + color: #0c5460; + border: 1px solid #bee5eb; +} + +.message.ai_command .message-content pre { + white-space: pre-wrap; + word-wrap: break-word; + margin: 0; +} + +.kanban-card .card-body { + position: relative; +} + +.delete-task-form { + position: absolute; + top: 10px; + right: 10px; +} \ No newline at end of file diff --git a/staticfiles/css/custom.css b/staticfiles/css/custom.css index 551c68f..293163a 100644 --- a/staticfiles/css/custom.css +++ b/staticfiles/css/custom.css @@ -227,4 +227,71 @@ body { position: absolute; top: 10px; right: 10px; -} \ No newline at end of file +} + +/* Kanban Board Styles */ +.kanban-board-container { + width: 100%; + overflow-x: auto; + padding: 1rem; +} + +.kanban-board { + display: flex; + gap: 1rem; + min-width: max-content; /* Ensure board expands horizontally */ +} + +.kanban-column { + flex: 1 1 300px; /* Flex-grow, flex-shrink, and basis */ + min-width: 300px; + max-width: 320px; + background-color: #f0f2f5; + border-radius: 0.5rem; + display: flex; + flex-direction: column; + max-height: calc(100vh - 250px); /* Adjust based on your layout */ +} + +.kanban-column h2 { + position: sticky; + top: 0; + z-index: 2; +} + +.kanban-cards { + overflow-y: auto; + flex-grow: 1; + min-height: 150px; /* Ensure drop zone is available even when empty */ +} + +.kanban-card { + cursor: grab; + transition: background-color 0.2s, box-shadow 0.2s; +} + +.kanban-card:hover { + background-color: #f8f9fa; + box-shadow: 0 4px 8px rgba(0,0,0,0.1); +} + +.kanban-card .btn-close { + transition: opacity 0.2s; + opacity: 0; +} + +.kanban-card:hover .btn-close { + opacity: 1; +} + +/* For the drag-and-drop placeholder */ +.sortable-ghost { + background-color: #e9ecef; + border: 2px dashed #ced4da; +} + +.sortable-drag { + opacity: 1 !important; /* Override Sortable.js default opacity */ + box-shadow: 0 8px 16px rgba(0,0,0,0.2); + transform: rotate(3deg); +} diff --git a/staticfiles/css/custom.css.bak b/staticfiles/css/custom.css.bak new file mode 100644 index 0000000..551c68f --- /dev/null +++ b/staticfiles/css/custom.css.bak @@ -0,0 +1,230 @@ +/* General App Body & Layout */ +body { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + background-color: #f8f9fa; + color: #212529; +} + +/* Main Chat Layout */ +.chat-container { + display: flex; + height: calc(100vh - 120px); /* Adjusted for header/footer */ + width: 100%; + background-color: #fff; + border: 1px solid #dee2e6; + border-radius: 0.5rem; +} + +/* Sidebar Styles */ +.chat-sidebar { + width: 280px; + background-color: #f8f9fa; + border-right: 1px solid #dee2e6; + display: flex; + flex-direction: column; + padding: 1rem; + flex-shrink: 0; +} + +.new-chat-form { + display: flex; + margin-bottom: 1rem; +} + +.new-chat-form input { + flex: 1; + padding: 0.75rem; + border: 1px solid #ced4da; + border-radius: 0.375rem 0 0 0.375rem; + font-size: 0.9rem; +} + +.new-chat-form button { + padding: 0.75rem 1rem; + background-color: #0d6efd; + color: #fff; + border: 1px solid #0d6efd; + border-radius: 0 0.375rem 0.375rem 0; + cursor: pointer; +} + +.conversation-list { + list-style: none; + padding: 0; + margin: 0; + overflow-y: auto; +} + +.conversation-list a { + display: block; + padding: 0.75rem 1rem; + color: #495057; + text-decoration: none; + border-radius: 0.375rem; + margin-bottom: 0.25rem; +} + +.conversation-list a:hover { + background-color: #e9ecef; +} + +.conversation-list a.active { + background-color: #0d6efd; + color: #fff; +} + +/* Main Content Area */ +.chat-main { + flex: 1; + display: flex; + flex-direction: column; + background-color: #ffffff; + position: relative; /* Needed for loader overlay */ +} + +/* Chat Header */ +.chat-header { + padding: 1rem 1.5rem; + border-bottom: 1px solid #dee2e6; + flex-shrink: 0; +} + +.chat-header h3 { + margin: 0; + font-size: 1.1rem; +} + +/* Message Area */ +.chat-messages { + flex: 1; + padding: 1.5rem; + overflow-y: auto; +} + +.message { + margin-bottom: 1rem; + display: flex; +} + +.message-content { + max-width: 80%; + padding: 0.75rem 1rem; + border-radius: 0.5rem; + line-height: 1.5; +} + +.message.user { + justify-content: flex-end; +} + +.message.user .message-content { + background-color: #0d6efd; + color: #fff; +} + +.message.ai .message-content { + background-color: #e9ecef; + color: #343a40; +} + +.message-author { + font-weight: bold; + font-size: 0.8rem; + margin-bottom: 0.25rem; +} + +/* Message Input Form */ +.chat-form-container { + padding: 1rem 1.5rem; + border-top: 1px solid #dee2e6; + background-color: #f8f9fa; +} + +.chat-form { + display: flex; +} + +.chat-form textarea { + flex: 1; + padding: 0.75rem; + border: 1px solid #ced4da; + border-radius: 0.375rem; + font-size: 1rem; + resize: none; +} + +.chat-form button { + margin-left: 1rem; + padding: 0.75rem 1.5rem; + background-color: #0d6efd; + color: #fff; + border: none; + border-radius: 0.375rem; + cursor: pointer; +} + +/* Empty State for Chat */ +.no-conversation-selected { + display: flex; + justify-content: center; + align-items: center; + height: 100%; + color: #6c757d; +} + +/* Loader Styles */ +.loader-overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(255, 255, 255, 0.8); + display: flex; + justify-content: center; + align-items: center; + z-index: 10; +} + +.loader { + border: 5px solid #f3f3f3; /* Light grey */ + border-top: 5px solid #0d6efd; /* Blue */ + border-radius: 50%; + width: 50px; + height: 50px; + animation: spin 1s linear infinite; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +/* System and AI Command Messages */ +.message.system .message-content { + background-color: #f8d7da; + color: #721c24; + border: 1px solid #f5c6cb; +} + +.message.ai_command .message-content { + background-color: #d1ecf1; + color: #0c5460; + border: 1px solid #bee5eb; +} + +.message.ai_command .message-content pre { + white-space: pre-wrap; + word-wrap: break-word; + margin: 0; +} + +.kanban-card .card-body { + position: relative; +} + +.delete-task-form { + position: absolute; + top: 10px; + right: 10px; +} \ No newline at end of file