From 7cbeeb90f67b80c876248255a32532bae35fad87 Mon Sep 17 00:00:00 2001 From: Junwei Zhao Date: Sat, 5 Oct 2024 17:48:28 +1000 Subject: [PATCH] Add logic to create custom link --- .gitignore | 3 + data/db.sqlite3 | Bin 167936 -> 192512 bytes links/__pycache__/forms.cpython-312.pyc | Bin 849 -> 0 bytes links/__pycache__/models.cpython-312.pyc | Bin 1581 -> 0 bytes links/__pycache__/urls.cpython-312.pyc | Bin 1700 -> 0 bytes links/forms.py | 25 +- ...ype_link_text_alter_link_alias_and_more.py | 34 +++ links/migrations/0005_alter_link_text.py | 18 ++ .../__pycache__/0001_initial.cpython-312.pyc | Bin 1127 -> 0 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 148 -> 0 bytes links/models.py | 17 +- links/templates/links/link_form.html | 181 ++++++++---- links/views.py | 14 +- new_theme/static/css/dist/styles.css | 279 ++++++++++++++++++ requirements.txt | 1 + templates/base.html | 2 + .../__pycache__/settings.cpython-312.pyc | Bin 2678 -> 0 bytes url_manager/__pycache__/urls.cpython-312.pyc | Bin 667 -> 0 bytes url_manager/settings.py | 20 +- url_manager/tailwind.config.js | 12 + url_manager/urls.py | 8 +- 21 files changed, 543 insertions(+), 71 deletions(-) delete mode 100644 links/__pycache__/forms.cpython-312.pyc delete mode 100644 links/__pycache__/models.cpython-312.pyc delete mode 100644 links/__pycache__/urls.cpython-312.pyc create mode 100644 links/migrations/0004_link_link_type_link_text_alter_link_alias_and_more.py create mode 100644 links/migrations/0005_alter_link_text.py delete mode 100644 links/migrations/__pycache__/0001_initial.cpython-312.pyc delete mode 100644 links/migrations/__pycache__/__init__.cpython-312.pyc delete mode 100644 url_manager/__pycache__/settings.cpython-312.pyc delete mode 100644 url_manager/__pycache__/urls.cpython-312.pyc create mode 100644 url_manager/tailwind.config.js diff --git a/.gitignore b/.gitignore index a83cc85..c39b2e7 100644 --- a/.gitignore +++ b/.gitignore @@ -71,3 +71,6 @@ node_modules/ /data **/__pycache__ +links/__pycache__/ + +staticfiles/ diff --git a/data/db.sqlite3 b/data/db.sqlite3 index 8dcfc9a269c2ec8a187a6e8c0e3a1b52f5e4e14c..0e914eb3cbafaebe39c1d98e061b85b50a271721 100644 GIT binary patch delta 14155 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 diff --git a/links/__pycache__/forms.cpython-312.pyc b/links/__pycache__/forms.cpython-312.pyc deleted file mode 100644 index 50ca4ef1b746e71f1aaaa19317d0b825814adbdc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 849 zcmY*XziSjh6rR~%w>d6nG#byKvKAJraAze5l2RLUh$zZ7!;qP~Oq|^{GrN*Ylje$~ zvW)%-a({=FO~B?D2nbf`f~N?ne6yQVGVFfudpmF5oA2%Wy13Xxu)dJv!5&8Fhjr%5 zKPR&nKn@W@3`>;a1Y^V;=1M1Z6BjsQp7c^b2{3ZdQ^fo+Vgbin?RldAcH-7N2}g}M zJh4uUjX%g$s!yQ4^}J^ydkeNTVCmf-)1^CEtDYa#QH2iU3rcvQfl$gf4V9dM-KDJlfdIb1*bw zVld!}XGN4}yxWgM6B3fqloMi_grqqurR6O`wo5AO9c9%RA2vBu9SAO&Hkg<;S1MN| z^xA)19N6ufMInIdz?t_NnWwHV@ir1>#i)pdWk6PJ_B+VQKzZ zU9+r;x^7uG2P;Om0LJK#)9{-=5kMViWBT!e3D_3RhPko>Wr9k#uA9)Qce-UEr0y1q zW?IrhJ~)XU$1WioVpm}W7MghhrhfKH}}gA Ndk1^J5zy*>e*w+J&QSmW diff --git a/links/__pycache__/models.cpython-312.pyc b/links/__pycache__/models.cpython-312.pyc deleted file mode 100644 index b2902532641029cb00f4964e2f5f8b431d61bda2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1581 zcmah}&rcgi6rR~1c)eaXwIPv$EVXGc>K+17gisGCD1s2RAwD#u2Ol!pcm`*k^=>k| zn_|Slia5XtdZK><2&Cpu=)ISqS^|yKUV6%{s;Me*>YH8LKoTV@`R$uG-+S|U-uL#m zeBMOx)K>mno>dU~OD_74-gCMXoE=0F#U5(nD#l1b_YhUq5mgy(X#Iq<_r99?RW(6s zfYd*M)LKJ!=B-S#u^4IwlzCz8tRg}KI&UDlgBYq}imHl&nA$MT15=-3s!-)X9Z=B| zr1d^>zZa@z62#~4BcP79kJETH`w^5rK$!{Z$_Hu<9b^V5iyG^wnr~%oQ)r8>|LpB8 z$XK#fVK$u=;xWG-JrzT-@4kqcFz6HF`joBgVPQFO6c9i7kvNpXjT!wlhc?P9%uu%M z#9mbE@lKdXU$&+@3T6kbp+*wEXdXg(1uE!{=Q<%cTFAWRQ09JlIzIU*WIUW~#Qw|4 z8gyyW1KMHFrfr*e-Vzx?!iW>HYRSJf(OXHeg|Y>0bbM)eYjtz=jd8UrkFVID34;*d zX);2DNeGmRJ?UG7yoeny-QkkG$j&`=_=3wk$}h>a@#y=-WGSqGyLH!hJQ8zH++yWSVk#g)t{@ZZW8XX0m}#V1yamKbKvJ-;;Rc$G@dYbQ-ns~q>XEk>tX-d+%immYx$m5r#krO72fK$d@zs|pqu|c?%%v=aKbL;+n)=F9~GIMtx&fS^6D>Ny3E{8~% zXUw=P_6`MpO~$0j!!Mi$0}OJdjp?IY=`dINd1?2DUmov0?&N0L^XDYd6Ul!dfb0Jt zFezPGsAB6POB;?~4<_i7l&bzfelSyYCMRCJh*M)Gou}LU22{Y3%GY52Rx!qZpwfwE f;L(lgt(nc469n$bh>ovsyxdybT>BS+n;iZ>wi-~h diff --git a/links/__pycache__/urls.cpython-312.pyc b/links/__pycache__/urls.cpython-312.pyc deleted file mode 100644 index 2e7ba5e2e59bbe10b7c5a9e6045b80719ec0b830..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1700 zcmb_cJxtp`6h0?TLP(qhVkjX5G9YLWV19)XqA);JsYQs2rmB$I$ckNXaDHSvw0P^5 zk*WiX9b3_Xu_JpI+*q<|i7uVksMt`4-klRA4Ja*YZ#cjAzVCf^?~9$!6x9jfO1%B{ z;)@-C?fG0STx92+Qjg4o{(}?TQ zQ7zycADu_=Oti3u3u<_+ym@b{(b1yeh8n)+ZYyr9(b=Nmfg1JMo21%mcw00msL|cj zTnjm03(pUE^mSg_vjQy|T~MR5bc;e^CnE~7f+z(x&#SJi z#Ip*|m>!H-nHngUI8;pv1tn41N!4MitOht<-ioy!w zwF9iO>XLa@%5F2J(+X4{x?O{<27k|aPEZ)tsT7N%%$N@RRJ}=AkrJ#ZureHgmLN%j z_sJ;5Oi>cHgaRw7F8)=iC@GBTwE}2PVMktz1xyc@V+&iw$+9HM68icjC)ylvGrg;j zwF+%~0*y6Yteim(n?6)t#(rV|=V|O@BVWPRpN@)L{LEqKr zy9Pa_(Nk4==2Ju`??dR+9X?DOk!dY5ZA9W)Bwmdyo=oWE`rlzQT4d%l{y--m{()~@ zVOXPw4SHOo$E)<@@l%~l;kMA>yb)%!Fk^%lwD3YT96zCSat&jH?;J*SPK(YN(WDkl zR->ttXF9n7u}a_m{K3+jB_lYd1;?tv@#6)ZTtvX&VUH1-)k3qUiFKWPgi6?f5se;s S{~UU95u*II*B&VX&HM!x;DI{; diff --git a/links/forms.py b/links/forms.py index 0178869..d9ce794 100644 --- a/links/forms.py +++ b/links/forms.py @@ -1,13 +1,26 @@ from django import forms from .models import Link -from django.utils.translation import gettext_lazy as _ +from simplemde.fields import SimpleMDEField class LinkForm(forms.ModelForm): + text = SimpleMDEField() + class Meta: model = Link - fields = ['alias', 'original_url'] - error_messages = { - 'alias': { - 'unique': _("This alias already exists. Please choose a different one."), - } + fields = ['alias', 'link_type', 'original_url', 'text'] + widgets = { + 'link_type': forms.RadioSelect(), } + + def clean(self): + cleaned_data = super().clean() + link_type = cleaned_data.get('link_type') + original_url = cleaned_data.get('original_url') + text = cleaned_data.get('text') + + if link_type == Link.LinkType.LINK and not original_url: + raise forms.ValidationError(_("Original URL is required for Link type.")) + elif link_type == Link.LinkType.CUSTOM and not text: + raise forms.ValidationError(_("Text is required for Custom type.")) + + return cleaned_data diff --git a/links/migrations/0004_link_link_type_link_text_alter_link_alias_and_more.py b/links/migrations/0004_link_link_type_link_text_alter_link_alias_and_more.py new file mode 100644 index 0000000..d17db07 --- /dev/null +++ b/links/migrations/0004_link_link_type_link_text_alter_link_alias_and_more.py @@ -0,0 +1,34 @@ +# Generated by Django 5.0.8 on 2024-10-05 06:26 + +import ckeditor.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('links', '0003_clicklog'), + ] + + operations = [ + migrations.AddField( + model_name='link', + name='link_type', + field=models.CharField(choices=[('LINK', 'Link'), ('CUSTOM', 'Custom')], default='LINK', max_length=10), + ), + migrations.AddField( + model_name='link', + name='text', + field=ckeditor.fields.RichTextField(blank=True, null=True), + ), + migrations.AlterField( + model_name='link', + name='alias', + field=models.SlugField(max_length=100, unique=True), + ), + migrations.AlterField( + model_name='link', + name='original_url', + field=models.URLField(blank=True, null=True), + ), + ] diff --git a/links/migrations/0005_alter_link_text.py b/links/migrations/0005_alter_link_text.py new file mode 100644 index 0000000..0047f05 --- /dev/null +++ b/links/migrations/0005_alter_link_text.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.8 on 2024-10-05 07:33 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('links', '0004_link_link_type_link_text_alter_link_alias_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='link', + name='text', + field=models.TextField(blank=True, null=True), + ), + ] diff --git a/links/migrations/__pycache__/0001_initial.cpython-312.pyc b/links/migrations/__pycache__/0001_initial.cpython-312.pyc deleted file mode 100644 index bb3e09f740df36f5d06a9869dbfd60b34f3be106..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1127 zcmaJwC-6rD>Nm)q0w+ zgU8+6ae5Ky4&rIY9R)8b7CIgX15djZHW7C6C28q|;X8c!{qp_3Kks|r_jp_Y^n88s zbK{5s;Fm{+Cp-Y>vlP4s2q0*HDwJWBkr@aWPy&eA1t^4Jg&PKqzU@$ewh0i>a zV~9}IHA`*iHPa?swT7@^mq#%GL7yWQc&wASj14AhQg>;Y#dkK!6d0Lew`_ z5wGz<1QCnEhg_Qtyc-M}^VP{~)DZ*^`8FMfcc@bEm8pPVwe10+ny9atxatis%@u3Y zn|O!n;{VZ&k91o2@W!wM4a%{Wm`f0Tc{sUM!Y=9N7GZR>NSJ2}IhMp!r%_YN7FHV= zk!ao0tE$yfws4E^Hnw!t(BEJZYhr7?W@E)vtC)o8Pt`s{v^D=>)YpoEO|7v>ILFkt z9jdQcx~7||p*WU7gh6^mZRFsfqFH;Ts0b0ksUxp+;EVX(P#?|9`n9+X9UI7A$;C-T z@yja;5fp`PfMZ~aV~VovsD>w|Y)m)x25p+e5UyhrVY94b+wwMwMCbimE_=IUc@Iir zbGr6~-ha`nLHPMi)e2x_?d4K{;tRC9RlSM>D%9$Du!Wz&In4ns9~IWkJxWnS5{op>ZWa1Y@8%+xtaX_R4=3H^UALUZx7h#?k z`k`o&d;8qFH*9)^E)S0?s;Skc(Yiljf2hH=vYyP>PEm9jc^tggtaYDKZ>{ay)bv9T Z!ap2=ixNvR^Ye=J +{% endblock %} {% block content %} -
+
-
-

- {% if form.instance.pk %}{% trans "Edit Link" %}{% else %}{% trans "Create New Link" %}{% endif %} -

-
-
-
- {% csrf_token %} - {% for field in form %} +
+

+ {% if form.instance.pk %}{% trans "Edit Link" %}{% else %}{% trans "Create New Link" %}{% endif %} +

+
+
+
- - {% if field.errors %} -
    - {% for error in field.errors %} -
  • {{ error }}
  • - {% endfor %} -
- {% endif %} - - {% if field.help_text %} -

{{ field.help_text }}

- {% endif %} +
+ + +
- {% endfor %} -
- - {% trans "Cancel" %} - - -
- -

{% trans "Note:" %}

-
-

- {% trans "Please note that special characters are not allowed in the alias when creating or updating a link." %} -
- {% trans "For example:" %} -

    -
  • {% trans "Valid alias: helloworld" %}
  • -
  • {% trans "Invalid alias: hello@world!" %}
  • -
  • {% trans "Accessing 'helloworld' as: hello-world or hello_world" %}
  • -
-

+ + + + + +
+ {% csrf_token %} + + {% for field in form %} + {% if field.name != 'link_type' %} + + {% endif %} + {% endfor %} +
+ + {% trans "Cancel" %} + + +
+
-
-
+
+{% endblock %} + +{% block extra_js %} + + {% endblock %} diff --git a/links/views.py b/links/views.py index eef889b..47731b4 100644 --- a/links/views.py +++ b/links/views.py @@ -63,7 +63,7 @@ class LinkListView(ListView): class LinkCreateView(CreateView): model = Link form_class = LinkForm - template_name = 'links/link_form.html' + template_name = 'links/link_form.html' # 确保这里的路径是正确的 success_url = reverse_lazy('link_list') def get_initial(self): @@ -74,9 +74,8 @@ class LinkCreateView(CreateView): return initial def form_valid(self, form): - # 将输入转换为小写 form.instance.alias = form.instance.alias.lower() - alias = form.cleaned_data.get('alias').lower() # 确保检查时使用小写 + alias = form.cleaned_data.get('alias').lower() if not self.is_valid_alias(alias): form.add_error('alias', _("Alias cannot contain special characters.")) return self.form_invalid(form) @@ -86,8 +85,7 @@ class LinkCreateView(CreateView): return super().form_valid(form) def is_valid_alias(self, alias): - # 检查别名是否包含特殊字符 - return alias.isalnum() # 只允许字母和数字 + return alias.isalnum() class LinkUpdateView(UpdateView): model = Link @@ -96,9 +94,8 @@ class LinkUpdateView(UpdateView): success_url = reverse_lazy('link_list') def form_valid(self, form): - # 将输入转换为小写 form.instance.alias = form.instance.alias.lower() - alias = form.cleaned_data.get('alias').lower() # 确保检查时使用小写 + alias = form.cleaned_data.get('alias').lower() if not self.is_valid_alias(alias): form.add_error('alias', _("Alias cannot contain special characters.")) return self.form_invalid(form) @@ -113,6 +110,9 @@ class LinkUpdateView(UpdateView): messages.error(self.request, f"{error}") return super().form_invalid(form) + def is_valid_alias(self, alias): + return alias.isalnum() + class LinkDeleteView(DeleteView): model = Link template_name = 'links/link_confirm_delete.html' diff --git a/new_theme/static/css/dist/styles.css b/new_theme/static/css/dist/styles.css index 4d8685f..085ebea 100644 --- a/new_theme/static/css/dist/styles.css +++ b/new_theme/static/css/dist/styles.css @@ -717,6 +717,18 @@ video { margin-top: 2rem; } +.ml-3 { + margin-left: 0.75rem; +} + +.mr-3 { + margin-right: 0.75rem; +} + +.ml-2 { + margin-left: 0.5rem; +} + .block { display: block; } @@ -757,6 +769,10 @@ video { height: 100vh; } +.h-6 { + height: 1.5rem; +} + .w-1\/12 { width: 8.333333%; } @@ -785,6 +801,10 @@ video { width: 100%; } +.w-11 { + width: 2.75rem; +} + .min-w-full { min-width: 100%; } @@ -809,6 +829,10 @@ video { transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } +.cursor-pointer { + cursor: pointer; +} + .select-all { -webkit-user-select: all; -moz-user-select: all; @@ -869,6 +893,18 @@ video { margin-bottom: calc(1rem * var(--tw-space-y-reverse)); } +.space-y-6 > :not([hidden]) ~ :not([hidden]) { + --tw-space-y-reverse: 0; + margin-top: calc(1.5rem * calc(1 - var(--tw-space-y-reverse))); + margin-bottom: calc(1.5rem * var(--tw-space-y-reverse)); +} + +.space-y-1 > :not([hidden]) ~ :not([hidden]) { + --tw-space-y-reverse: 0; + margin-top: calc(0.25rem * calc(1 - var(--tw-space-y-reverse))); + margin-bottom: calc(0.25rem * var(--tw-space-y-reverse)); +} + .divide-y > :not([hidden]) ~ :not([hidden]) { --tw-divide-y-reverse: 0; border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); @@ -914,6 +950,10 @@ video { border-radius: 0.375rem; } +.rounded-full { + border-radius: 9999px; +} + .rounded-l-md { border-top-left-radius: 0.375rem; border-bottom-left-radius: 0.375rem; @@ -936,6 +976,14 @@ video { border-top-width: 1px; } +.border-b-2 { + border-bottom-width: 2px; +} + +.border-l-4 { + border-left-width: 4px; +} + .border-gray-200 { --tw-border-opacity: 1; border-color: rgb(229 231 235 / var(--tw-border-opacity)); @@ -956,6 +1004,25 @@ video { border-color: rgb(234 179 8 / var(--tw-border-opacity)); } +.border-transparent { + border-color: transparent; +} + +.border-blue-400 { + --tw-border-opacity: 1; + border-color: rgb(96 165 250 / var(--tw-border-opacity)); +} + +.border-blue-600 { + --tw-border-opacity: 1; + border-color: rgb(37 99 235 / var(--tw-border-opacity)); +} + +.border-green-400 { + --tw-border-opacity: 1; + border-color: rgb(74 222 128 / var(--tw-border-opacity)); +} + .bg-blue-500 { --tw-bg-opacity: 1; background-color: rgb(59 130 246 / var(--tw-bg-opacity)); @@ -1000,6 +1067,26 @@ video { background-color: rgb(254 249 195 / var(--tw-bg-opacity)); } +.bg-blue-600 { + --tw-bg-opacity: 1; + background-color: rgb(37 99 235 / var(--tw-bg-opacity)); +} + +.bg-yellow-50 { + --tw-bg-opacity: 1; + background-color: rgb(254 252 232 / var(--tw-bg-opacity)); +} + +.bg-blue-50 { + --tw-bg-opacity: 1; + background-color: rgb(239 246 255 / var(--tw-bg-opacity)); +} + +.bg-green-50 { + --tw-bg-opacity: 1; + background-color: rgb(240 253 244 / var(--tw-bg-opacity)); +} + .p-2 { padding: 0.5rem; } @@ -1047,6 +1134,11 @@ video { padding-bottom: 1rem; } +.py-5 { + padding-top: 1.25rem; + padding-bottom: 1.25rem; +} + .text-left { text-align: left; } @@ -1176,6 +1268,26 @@ video { color: rgb(161 98 7 / var(--tw-text-opacity)); } +.text-gray-900 { + --tw-text-opacity: 1; + color: rgb(17 24 39 / var(--tw-text-opacity)); +} + +.text-yellow-600 { + --tw-text-opacity: 1; + color: rgb(202 138 4 / var(--tw-text-opacity)); +} + +.text-blue-700 { + --tw-text-opacity: 1; + color: rgb(29 78 216 / var(--tw-text-opacity)); +} + +.text-green-700 { + --tw-text-opacity: 1; + color: rgb(21 128 61 / var(--tw-text-opacity)); +} + .shadow { --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); @@ -1221,6 +1333,75 @@ video { transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); } +.after\:absolute::after { + content: var(--tw-content); + position: absolute; +} + +.after\:left-\[2px\]::after { + content: var(--tw-content); + left: 2px; +} + +.after\:top-\[2px\]::after { + content: var(--tw-content); + top: 2px; +} + +.after\:h-5::after { + content: var(--tw-content); + height: 1.25rem; +} + +.after\:w-5::after { + content: var(--tw-content); + width: 1.25rem; +} + +.after\:rounded-full::after { + content: var(--tw-content); + border-radius: 9999px; +} + +.after\:border::after { + content: var(--tw-content); + border-width: 1px; +} + +.after\:border-gray-300::after { + content: var(--tw-content); + --tw-border-opacity: 1; + border-color: rgb(209 213 219 / var(--tw-border-opacity)); +} + +.after\:bg-white::after { + content: var(--tw-content); + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); +} + +.after\:transition-all::after { + content: var(--tw-content); + transition-property: all; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; +} + +.after\:content-\[\'\'\]::after { + --tw-content: ''; + content: var(--tw-content); +} + +.hover\:border-gray-300:hover { + --tw-border-opacity: 1; + border-color: rgb(209 213 219 / var(--tw-border-opacity)); +} + +.hover\:border-blue-700:hover { + --tw-border-opacity: 1; + border-color: rgb(29 78 216 / var(--tw-border-opacity)); +} + .hover\:bg-blue-600:hover { --tw-bg-opacity: 1; background-color: rgb(37 99 235 / var(--tw-bg-opacity)); @@ -1246,6 +1427,11 @@ video { background-color: rgb(220 38 38 / var(--tw-bg-opacity)); } +.hover\:bg-blue-700:hover { + --tw-bg-opacity: 1; + background-color: rgb(29 78 216 / var(--tw-bg-opacity)); +} + .hover\:text-blue-800:hover { --tw-text-opacity: 1; color: rgb(30 64 175 / var(--tw-text-opacity)); @@ -1276,6 +1462,16 @@ video { color: rgb(127 29 29 / var(--tw-text-opacity)); } +.hover\:text-gray-700:hover { + --tw-text-opacity: 1; + color: rgb(55 65 81 / var(--tw-text-opacity)); +} + +.hover\:text-blue-700:hover { + --tw-text-opacity: 1; + color: rgb(29 78 216 / var(--tw-text-opacity)); +} + .hover\:underline:hover { text-decoration-line: underline; } @@ -1285,6 +1481,11 @@ video { border-color: rgb(147 197 253 / var(--tw-border-opacity)); } +.focus\:border-indigo-300:focus { + --tw-border-opacity: 1; + border-color: rgb(165 180 252 / var(--tw-border-opacity)); +} + .focus\:outline-none:focus { outline: 2px solid transparent; outline-offset: 2px; @@ -1312,10 +1513,57 @@ video { --tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity)); } +.focus\:ring-gray-500:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(107 114 128 / var(--tw-ring-opacity)); +} + +.focus\:ring-indigo-200:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(199 210 254 / var(--tw-ring-opacity)); +} + .focus\:ring-opacity-50:focus { --tw-ring-opacity: 0.5; } +.focus\:ring-offset-2:focus { + --tw-ring-offset-width: 2px; +} + +.peer:checked ~ .peer-checked\:bg-blue-600 { + --tw-bg-opacity: 1; + background-color: rgb(37 99 235 / var(--tw-bg-opacity)); +} + +.peer:checked ~ .peer-checked\:after\:translate-x-full::after { + content: var(--tw-content); + --tw-translate-x: 100%; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + +.peer:checked ~ .peer-checked\:after\:border-white::after { + content: var(--tw-content); + --tw-border-opacity: 1; + border-color: rgb(255 255 255 / var(--tw-border-opacity)); +} + +.peer:focus ~ .peer-focus\:outline-none { + outline: 2px solid transparent; + outline-offset: 2px; +} + +.peer:focus ~ .peer-focus\:ring-4 { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); +} + +.peer:focus ~ .peer-focus\:ring-blue-300 { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(147 197 253 / var(--tw-ring-opacity)); +} + @media (min-width: 640px) { .sm\:inline { display: inline; @@ -1324,6 +1572,15 @@ video { .sm\:grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } + + .sm\:p-6 { + padding: 1.5rem; + } + + .sm\:px-6 { + padding-left: 1.5rem; + padding-right: 1.5rem; + } } @media (min-width: 768px) { @@ -1340,4 +1597,26 @@ video { .lg\:grid-cols-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); } + + .lg\:px-8 { + padding-left: 2rem; + padding-right: 2rem; + } +} + +@media (prefers-color-scheme: dark) { + .dark\:border-gray-600 { + --tw-border-opacity: 1; + border-color: rgb(75 85 99 / var(--tw-border-opacity)); + } + + .dark\:bg-gray-700 { + --tw-bg-opacity: 1; + background-color: rgb(55 65 81 / var(--tw-bg-opacity)); + } + + .peer:focus ~ .dark\:peer-focus\:ring-blue-800 { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(30 64 175 / var(--tw-ring-opacity)); + } } diff --git a/requirements.txt b/requirements.txt index ed96b18..f930391 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,3 +9,4 @@ django-tailwind==3.8.0 fontawesome-free==5.15.3 gunicorn==22.0.0 whitenoise==5.3.0 +django-simplemde-x==1.2.0 diff --git a/templates/base.html b/templates/base.html index 2449cf3..a8242c3 100644 --- a/templates/base.html +++ b/templates/base.html @@ -49,6 +49,8 @@ cursor: text; } + {{ form.media }} + {% block extra_css %}{% endblock %}