From e8a9bd1aa5bf267ad0cc10e4fbbdcab263878f89 Mon Sep 17 00:00:00 2001 From: Junwei Zhao Date: Sun, 3 Nov 2024 10:11:25 +1100 Subject: [PATCH] Add help page --- data/db.sqlite3 | Bin 204800 -> 204800 bytes links/patches.py | 4 + links/templates/links/help.html | 141 +++++++++++++ links/templates/links/link_detail.html | 2 +- links/templates/links/link_list.html | 6 +- links/templatetags/markdown_extras.py | 8 + links/urls.py | 9 +- links/views.py | 3 + new_theme/static/css/dist/styles.css | 270 +++++++++---------------- templates/base.html | 1 + url_manager/settings.py | 2 + 11 files changed, 264 insertions(+), 182 deletions(-) create mode 100644 links/patches.py create mode 100644 links/templates/links/help.html create mode 100644 links/templatetags/markdown_extras.py diff --git a/data/db.sqlite3 b/data/db.sqlite3 index 6d0342bd19b5bb27f2c781990b3bd3939231bf22..6d07b08edf22685f529fc05033d732dd0592ce44 100644 GIT binary patch delta 829 zcmZva%}Z2K7{<@J*YSSL%zZ~j8|Xtv2_n#Q&)0S4UU4zCQ4+Cb;KD&I`yj`h85l@( z2wF-Jav`DqgCZoZizo$mE=)rr+Vrt-)zGF@NL^YXv(#OdBKbr-;GV(#J0ZJ z<+Pw2=9J4m#`-8vbMA51V}dY8a90$%WD_9kaY=+jT`me~5dz8yhpb1lgi9u92Ki~; zoDhUA3M#WQL|790JdS(dTXu2eJH^g48tWD0BL=JJ~$0Y>yx!-ZChIq zgUDKUddPAjD#nGzD_d0sBVROxH-t5W)@8*$!e>eFqf<%Ewd>{xf=w8OgtZsH5i`s~ zb0lJK2@|xyAC@De#0;L3ZG#gcAy3aYi$z&wALf( z!Tw97cPt7ss2kM~szK#-OikhB@djze;o8XX=oSCjsxlTl#Ok+r8X?q%lDQo2Kw*Gz z+-gf9+W3gatJ=K3ds|8Q%b-R(PV`T@GAmmA7oeu<(M~mw7W@HqE1o#&ZKHJ}>$+0& XKb%uP9$WtF0dxBMBf+~)HHZHKCMUwC delta 290 zcmV+-0p0$9zzl%E43HZEPmvr$0Z*}D@Gb!dlTj}u0WE`eFSm9t0gliEEDA`K2Lf5M zAt2}pw@3;CyafX+4(*o*5CT0M56cgm4}1@G4^R(D4?+(+4>S)g4;l{>4-5|lvmqdj z4!7+d0vB--2MYZF55W&k4-gL04QC7q3jMPoAm<9V{h9&?1ri4j)c_Cs5A_e>58Dsb z5AF}=vk_pw54Y8?0xVDq0000X0PX+)?hk0S3tjx6G1@%6#xK%DRY<6YXTRSpAQ2Im*;;18JEKk0~42we*!zU5Cg*v o5HT@2F)%tZG%htVG%__f1DDes1J{?I-vS1gm)-(fmkS>Q_2rpWmH+?% diff --git a/links/patches.py b/links/patches.py new file mode 100644 index 0000000..e137f1c --- /dev/null +++ b/links/patches.py @@ -0,0 +1,4 @@ +import sys +from django import urls + +sys.modules['django.core.urlresolvers'] = urls diff --git a/links/templates/links/help.html b/links/templates/links/help.html new file mode 100644 index 0000000..d4ac24b --- /dev/null +++ b/links/templates/links/help.html @@ -0,0 +1,141 @@ +{% extends 'base.html' %} +{% load i18n %} +{% load markdown_extras %} + +{% block extra_css %} + + + +{% endblock %} + +{% block content %} +
+
+ {% filter markdown %} +# Frequently Asked Questions (FAQ) + +## Link Types + +GoLinks supports three types of links: Normal Links, Template Links, and Custom Pages. Each type serves different purposes and has its own use cases. + +### 1. Normal Links + +Normal links are the simplest type - they provide direct redirection to a target URL. + +**Example:** +- Original URL: `https://github.com/microsoft/vscode` +- Alias: `vscode` +- Access: `http://go/vscode` → Redirects to VS Code GitHub repository + +**Use Cases:** +- Quick access to frequently visited websites +- Shortening long URLs +- Creating memorable aliases for complex URLs + +### 2. Template Links + +Template links allow you to create dynamic URLs that can generate the final URL based on parameters. This is particularly useful for search links, API calls, or any URL that needs dynamic parameters. + +**Basic Syntax:** +Use the syntax `{parameter_name, default=default_value}` to define variables in your URL: `https://google.com?q={query, default=hello}`, and set the alias to `google`. + +**Examples:** +- Use the syntax `{query, default=default_value}` to define variables in your URL: `https://google.com?q={query, default=hello}`, and set the alias to `google`. + + Then you can access the link by `http://go/google/`, and the URL will be `https://google.com?q=`. + + When you access the url with `http://go/google/`, the URL will be `https://google.com?q=hello`, which will leverage the `default` value. + +### 3. Custom Pages + +Custom pages allow you to create markdown-based web pages that can serve as documentation, link collections, or any other content you need. + +**Key Features:** +- Write content in Markdown format +- Support for headings, lists, code blocks, and links +- Can include multiple sections and navigation +- Perfect for creating documentation or resource collections + +**Example Use Cases:** + Check http://go.junv.cc/custom/today/ + {% endfilter %} +
+
+{% endblock %} diff --git a/links/templates/links/link_detail.html b/links/templates/links/link_detail.html index 273e2ef..f1eaec3 100644 --- a/links/templates/links/link_detail.html +++ b/links/templates/links/link_detail.html @@ -23,7 +23,7 @@ {% endif %}
- + diff --git a/links/templates/links/link_list.html b/links/templates/links/link_list.html index a6bba24..05a4c06 100644 --- a/links/templates/links/link_list.html +++ b/links/templates/links/link_list.html @@ -119,7 +119,11 @@ {{ link.click_count }} diff --git a/links/templatetags/markdown_extras.py b/links/templatetags/markdown_extras.py new file mode 100644 index 0000000..a4186bf --- /dev/null +++ b/links/templatetags/markdown_extras.py @@ -0,0 +1,8 @@ +from django import template +import markdown as md + +register = template.Library() + +@register.filter +def markdown(value): + return md.markdown(value, extensions=['fenced_code', 'tables']) diff --git a/links/urls.py b/links/urls.py index 02dd6a7..af8f5fb 100644 --- a/links/urls.py +++ b/links/urls.py @@ -8,14 +8,17 @@ urlpatterns = [ path('delete//', views.LinkDeleteView.as_view(), name='link_delete'), path('delete-selected/', views.delete_selected, name='delete_selected'), path('detail//', views.LinkDetailView.as_view(), name='link_detail'), - path('search/', views.SearchView.as_view(), name='search'), + path('ui/search/', views.SearchView.as_view(), name='search'), path('link//', views.LinkDetailView.as_view(), name='link_detail'), path('link//edit/', views.LinkUpdateView.as_view(), name='link_update'), - path('tools/', views.ToolsView.as_view(), name='tools'), + path('ui/tools/', views.ToolsView.as_view(), name='tools'), path('tools/export-database/', views.export_database, name='export_database'), + path('ui/help/', views.HelpView.as_view(), name='help'), + path('export/', views.export_links, name='export_links'), + # Aliases path('/', views.redirect_to_original, name='redirect_to_original'), path('//', views.redirect_to_original, name='redirect_to_original_with_param'), - path('export/', views.export_links, name='export_links'), path('alias//', views.LinkDetailView.as_view(), name='link_detail_by_alias'), + ] diff --git a/links/views.py b/links/views.py index bff9b92..f73997b 100644 --- a/links/views.py +++ b/links/views.py @@ -429,3 +429,6 @@ def export_database(request): logger.error(f"Database export failed: {str(e)}") messages.error(request, _("Failed to export database: {}").format(str(e))) return redirect('tools') + +class HelpView(TemplateView): + template_name = 'links/help.html' diff --git a/new_theme/static/css/dist/styles.css b/new_theme/static/css/dist/styles.css index 04d2eba..ed31bb6 100644 --- a/new_theme/static/css/dist/styles.css +++ b/new_theme/static/css/dist/styles.css @@ -670,6 +670,14 @@ video { margin-right: auto; } +.-ml-px { + margin-left: -1px; +} + +.mb-1 { + margin-bottom: 0.25rem; +} + .mb-2 { margin-bottom: 0.5rem; } @@ -694,10 +702,6 @@ video { margin-left: 0.5rem; } -.ml-3 { - margin-left: 0.75rem; -} - .ml-4 { margin-left: 1rem; } @@ -746,14 +750,6 @@ video { margin-top: 2rem; } -.mb-1 { - margin-bottom: 0.25rem; -} - -.-ml-px { - margin-left: -1px; -} - .block { display: block; } @@ -782,6 +778,14 @@ video { display: none; } +.h-12 { + height: 3rem; +} + +.h-16 { + height: 4rem; +} + .h-4 { height: 1rem; } @@ -794,12 +798,12 @@ video { height: 100vh; } -.h-12 { - height: 3rem; +.w-12 { + width: 3rem; } -.h-16 { - height: 4rem; +.w-16 { + width: 4rem; } .w-4 { @@ -818,22 +822,14 @@ video { width: 100%; } -.w-12 { - width: 3rem; -} - -.w-16 { - width: 4rem; +.min-w-0 { + min-width: 0px; } .min-w-full { min-width: 100%; } -.min-w-0 { - min-width: 0px; -} - .max-w-4xl { max-width: 56rem; } @@ -850,6 +846,10 @@ video { max-width: 32rem; } +.max-w-md { + max-width: 28rem; +} + .max-w-none { max-width: none; } @@ -862,14 +862,6 @@ video { max-width: 20rem; } -.max-w-3xl { - max-width: 48rem; -} - -.max-w-md { - max-width: 28rem; -} - .flex-1 { flex: 1 1 0%; } @@ -920,10 +912,6 @@ video { align-items: flex-start; } -.items-end { - align-items: flex-end; -} - .items-center { align-items: center; } @@ -953,6 +941,12 @@ video { row-gap: 2rem; } +.space-x-2 > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 0; + margin-right: calc(0.5rem * var(--tw-space-x-reverse)); + margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse))); +} + .space-x-3 > :not([hidden]) ~ :not([hidden]) { --tw-space-x-reverse: 0; margin-right: calc(0.75rem * var(--tw-space-x-reverse)); @@ -995,12 +989,6 @@ video { margin-bottom: calc(2rem * var(--tw-space-y-reverse)); } -.space-x-2 > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-right: calc(0.5rem * var(--tw-space-x-reverse)); - margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse))); -} - .divide-y > :not([hidden]) ~ :not([hidden]) { --tw-divide-y-reverse: 0; border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); @@ -1030,6 +1018,10 @@ video { white-space: nowrap; } +.break-all { + word-break: break-all; +} + .rounded { border-radius: 0.25rem; } @@ -1165,11 +1157,21 @@ video { background-color: rgb(34 197 94 / var(--tw-bg-opacity)); } +.bg-purple-100 { + --tw-bg-opacity: 1; + background-color: rgb(243 232 255 / var(--tw-bg-opacity)); +} + .bg-purple-50 { --tw-bg-opacity: 1; background-color: rgb(250 245 255 / var(--tw-bg-opacity)); } +.bg-purple-500 { + --tw-bg-opacity: 1; + background-color: rgb(168 85 247 / var(--tw-bg-opacity)); +} + .bg-red-500 { --tw-bg-opacity: 1; background-color: rgb(239 68 68 / var(--tw-bg-opacity)); @@ -1194,30 +1196,14 @@ video { background-color: rgb(254 249 195 / var(--tw-bg-opacity)); } -.bg-purple-500 { - --tw-bg-opacity: 1; - background-color: rgb(168 85 247 / var(--tw-bg-opacity)); -} - -.bg-green-600 { - --tw-bg-opacity: 1; - background-color: rgb(22 163 74 / var(--tw-bg-opacity)); -} - -.bg-purple-600 { - --tw-bg-opacity: 1; - background-color: rgb(147 51 234 / var(--tw-bg-opacity)); -} - -.bg-purple-100 { - --tw-bg-opacity: 1; - background-color: rgb(243 232 255 / var(--tw-bg-opacity)); -} - .p-2 { padding: 0.5rem; } +.p-3 { + padding: 0.75rem; +} + .p-4 { padding: 1rem; } @@ -1226,10 +1212,6 @@ video { padding: 1.5rem; } -.p-3 { - padding: 0.75rem; -} - .px-2 { padding-left: 0.5rem; padding-right: 0.5rem; @@ -1265,6 +1247,11 @@ video { padding-bottom: 0.25rem; } +.py-12 { + padding-top: 3rem; + padding-bottom: 3rem; +} + .py-2 { padding-top: 0.5rem; padding-bottom: 0.5rem; @@ -1290,23 +1277,10 @@ video { padding-bottom: 2rem; } -.py-12 { - padding-top: 3rem; - padding-bottom: 3rem; -} - .pr-3 { padding-right: 0.75rem; } -.pl-5 { - padding-left: 1.25rem; -} - -.pr-10 { - padding-right: 2.5rem; -} - .text-left { text-align: left; } @@ -1334,6 +1308,11 @@ video { line-height: 1; } +.text-base { + font-size: 1rem; + line-height: 1.5rem; +} + .text-lg { font-size: 1.125rem; line-height: 1.75rem; @@ -1354,11 +1333,6 @@ video { line-height: 1rem; } -.text-base { - font-size: 1rem; - line-height: 1.5rem; -} - .font-bold { font-weight: 700; } @@ -1411,6 +1385,11 @@ video { color: rgb(30 64 175 / var(--tw-text-opacity)); } +.text-gray-300 { + --tw-text-opacity: 1; + color: rgb(209 213 219 / var(--tw-text-opacity)); +} + .text-gray-400 { --tw-text-opacity: 1; color: rgb(156 163 175 / var(--tw-text-opacity)); @@ -1466,11 +1445,26 @@ video { color: rgb(79 70 229 / var(--tw-text-opacity)); } +.text-purple-500 { + --tw-text-opacity: 1; + color: rgb(168 85 247 / var(--tw-text-opacity)); +} + +.text-purple-600 { + --tw-text-opacity: 1; + color: rgb(147 51 234 / var(--tw-text-opacity)); +} + .text-purple-700 { --tw-text-opacity: 1; color: rgb(126 34 206 / var(--tw-text-opacity)); } +.text-purple-800 { + --tw-text-opacity: 1; + color: rgb(107 33 168 / var(--tw-text-opacity)); +} + .text-red-600 { --tw-text-opacity: 1; color: rgb(220 38 38 / var(--tw-text-opacity)); @@ -1491,26 +1485,6 @@ video { color: rgb(161 98 7 / var(--tw-text-opacity)); } -.text-gray-300 { - --tw-text-opacity: 1; - color: rgb(209 213 219 / var(--tw-text-opacity)); -} - -.text-purple-500 { - --tw-text-opacity: 1; - color: rgb(168 85 247 / var(--tw-text-opacity)); -} - -.text-purple-600 { - --tw-text-opacity: 1; - color: rgb(147 51 234 / var(--tw-text-opacity)); -} - -.text-purple-800 { - --tw-text-opacity: 1; - color: rgb(107 33 168 / var(--tw-text-opacity)); -} - .underline { text-decoration-line: underline; } @@ -1519,12 +1493,6 @@ video { text-decoration-line: line-through; } -.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); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); -} - .shadow-md { --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); @@ -1543,20 +1511,6 @@ video { box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } -.ring-1 { - --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(1px + 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); -} - -.ring-inset { - --tw-ring-inset: inset; -} - -.ring-blue-700\/10 { - --tw-ring-color: rgb(29 78 216 / 0.1); -} - .blur { --tw-blur: blur(8px); filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); @@ -1678,6 +1632,11 @@ video { background-color: rgb(21 128 61 / var(--tw-bg-opacity)); } +.hover\:bg-purple-600:hover { + --tw-bg-opacity: 1; + background-color: rgb(147 51 234 / var(--tw-bg-opacity)); +} + .hover\:bg-red-600:hover { --tw-bg-opacity: 1; background-color: rgb(220 38 38 / var(--tw-bg-opacity)); @@ -1688,16 +1647,6 @@ video { background-color: rgb(185 28 28 / var(--tw-bg-opacity)); } -.hover\:bg-purple-600:hover { - --tw-bg-opacity: 1; - background-color: rgb(147 51 234 / var(--tw-bg-opacity)); -} - -.hover\:bg-purple-700:hover { - --tw-bg-opacity: 1; - background-color: rgb(126 34 206 / var(--tw-bg-opacity)); -} - .hover\:text-blue-700:hover { --tw-text-opacity: 1; color: rgb(29 78 216 / var(--tw-text-opacity)); @@ -1782,18 +1731,18 @@ video { box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); } -.focus\:ring-2:focus { - --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(2px + 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); -} - .focus\:ring-1:focus { --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(1px + 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); } +.focus\:ring-2:focus { + --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(2px + 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); +} + .focus\:ring-blue-200:focus { --tw-ring-opacity: 1; --tw-ring-color: rgb(191 219 254 / var(--tw-ring-opacity)); @@ -1819,16 +1768,6 @@ video { --tw-ring-color: rgb(239 68 68 / var(--tw-ring-opacity)); } -.focus\:ring-green-500:focus { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(34 197 94 / var(--tw-ring-opacity)); -} - -.focus\:ring-purple-500:focus { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(168 85 247 / var(--tw-ring-opacity)); -} - .focus\:ring-opacity-50:focus { --tw-ring-opacity: 0.5; } @@ -1846,10 +1785,6 @@ video { grid-column: span 2 / span 2; } - .sm\:mt-0 { - margin-top: 0px; - } - .sm\:block { display: block; } @@ -1900,30 +1835,20 @@ video { margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse))); } - .sm\:space-x-4 > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-right: calc(1rem * var(--tw-space-x-reverse)); - margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse))); - } - .sm\:space-y-0 > :not([hidden]) ~ :not([hidden]) { --tw-space-y-reverse: 0; margin-top: calc(0px * calc(1 - var(--tw-space-y-reverse))); margin-bottom: calc(0px * var(--tw-space-y-reverse)); } - .sm\:rounded-md { - border-radius: 0.375rem; + .sm\:p-12 { + padding: 3rem; } .sm\:p-6 { padding: 1.5rem; } - .sm\:p-12 { - padding: 3rem; - } - .sm\:px-6 { padding-left: 1.5rem; padding-right: 1.5rem; @@ -1943,11 +1868,6 @@ video { font-size: 1rem; line-height: 1.5rem; } - - .sm\:text-sm { - font-size: 0.875rem; - line-height: 1.25rem; - } } @media (min-width: 768px) { @@ -1965,10 +1885,6 @@ video { grid-template-columns: repeat(5, minmax(0, 1fr)); } - .lg\:p-8 { - padding: 2rem; - } - .lg\:px-8 { padding-left: 2rem; padding-right: 2rem; diff --git a/templates/base.html b/templates/base.html index a8242c3..6571431 100644 --- a/templates/base.html +++ b/templates/base.html @@ -70,6 +70,7 @@
diff --git a/url_manager/settings.py b/url_manager/settings.py index 5fa1db0..a47df01 100644 --- a/url_manager/settings.py +++ b/url_manager/settings.py @@ -1,6 +1,7 @@ import os from pathlib import Path from django.utils.translation import gettext_lazy as _ +import links.patches # 添加这一行在文件最上方 # 构建路径,如 BASE_DIR / 'subdir' BASE_DIR = Path(__file__).resolve().parent.parent @@ -17,6 +18,7 @@ INSTALLED_APPS = [ 'tailwind', 'new_theme', 'simplemde', + 'markdown', # 只需要基本的markdown包 ] ROOT_URLCONF = 'url_manager.urls'