diff --git a/links/forms.py b/links/forms.py index f9702c2..ad33f32 100644 --- a/links/forms.py +++ b/links/forms.py @@ -54,15 +54,17 @@ class LinkForm(forms.ModelForm): # 动作链接的配置字段(不入模型,clean 时组装进 action_config JSON) action_type = forms.ChoiceField( required=False, - choices=[('', _('选择动作')), ('discord_send', _('发 Discord 消息'))], - label=_('Action'), - widget=forms.Select(attrs={'class': 'shadow appearance-none rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline'}), + choices=[('discord_send', _('发消息到 Discord'))], + label=_('动作'), + initial='discord_send', + widget=forms.RadioSelect(attrs={'class': 'action-type-radio'}), + help_text=_('打开链接时执行的动作'), ) action_message_template = forms.CharField( required=False, - label=_('Message template'), - help_text=_('消息模板,{query} 会被链接 URL 中的参数替换。例如:@小黑 {query}'), - widget=forms.Textarea(attrs={'rows': 2, 'placeholder': '@小黑 {query}', + label=_('消息内容'), + help_text=_('链接地址后面加的字会自动放在 {query} 的位置。例如链接 go/ask/今天天气 → 消息会是“@小黑 今天天气”'), + widget=forms.Textarea(attrs={'rows': 2, 'placeholder': '@小黑 帮我看看 {query}', 'class': 'shadow appearance-none rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline'}), ) diff --git a/links/templates/links/link_form.html b/links/templates/links/link_form.html index bddd08b..8092193 100644 --- a/links/templates/links/link_form.html +++ b/links/templates/links/link_form.html @@ -22,6 +22,48 @@ padding: 2px 8px !important; margin: 3px !important; } + /* ── Apple-style Action card picker ── */ + .action-type-radio { display: none; } + .action-card { + display: flex; align-items: center; gap: 1rem; + border: 2px solid #e5e7eb; border-radius: 14px; + padding: 0.9rem 1.1rem; cursor: pointer; + transition: border-color .2s, background .2s, box-shadow .2s; + background: #fff; + } + .action-card:hover { border-color: #c4b5fd; background: #faf9ff; } + .action-card.selected { border-color: #8b5cf6; background: #f5f3ff; box-shadow: 0 0 0 3px rgba(139,92,246,.12); } + .action-card-icon { + width: 2.6rem; height: 2.6rem; flex-shrink: 0; + border-radius: 12px; background: #f5f3ff; color: #7c3aed; + display: flex; align-items: center; justify-content: center; + font-size: 1.3rem; + } + .action-card-title { font-weight: 600; font-size: .95rem; color: #1f2937; } + .action-card-desc { font-size: .8rem; color: #6b7280; margin-top: 2px; line-height: 1.4; } + .action-card-check { + margin-left: auto; width: 1.5rem; height: 1.5rem; flex-shrink: 0; + border-radius: 50%; border: 2px solid #d1d5db; + display: flex; align-items: center; justify-content: center; + color: transparent; font-size: .8rem; transition: all .2s; + } + .action-card.selected .action-card-check { background: #8b5cf6; border-color: #8b5cf6; color: #fff; } + /* ── Message preview bubble ── */ + .msg-preview { + margin-top: .6rem; border-radius: 14px; background: #f9fafb; + border: 1px solid #e5e7eb; padding: .7rem .9rem; + } + .msg-preview-label { font-size: .7rem; font-weight: 600; color: #9ca3af; text-transform: uppercase; letter-spacing: .04em; margin-bottom: .35rem; } + .msg-preview-bubble { + display: inline-block; background: #fff; border: 1px solid #e5e7eb; + border-radius: 12px; padding: .45rem .8rem; font-size: .85rem; color: #111827; + box-shadow: 0 1px 2px rgba(0,0,0,.04); + } + .msg-preview-bubble .qchip { + background: #ede9fe; color: #6d28d9; border-radius: 6px; + padding: 0 .3rem; font-weight: 600; + } + .msg-preview-hint { font-size: .72rem; color: #9ca3af; margin-top: .4rem; } {% endblock %} @@ -89,7 +131,7 @@ {% endif %} {% for field in form %} - {% if field.name != 'link_type' %} + {% if field.name != 'link_type' and field.name != 'action_config' %}