@@ -7,6 +7,24 @@ import { DiscourseNode } from "~/types";
77import { ConfirmationModal } from "./ConfirmationModal" ;
88import { getTemplateFiles , getTemplatePluginInfo } from "~/utils/templates" ;
99
10+ const generateTagPlaceholder = ( format : string , nodeName ?: string ) : string => {
11+ if ( ! format ) return "Enter tag (e.g., clm-candidate or #clm-candidate)" ;
12+
13+ // Extract the prefix before " - {content}" or " -{content}" or " -{content}" etc.
14+ const match = format . match ( / ^ ( [ A - Z ] + ) \s * - \s * \{ c o n t e n t \} / i) ;
15+ if ( match && match [ 1 ] ) {
16+ const prefix = match [ 1 ] . toLowerCase ( ) ;
17+ return `Enter tag (e.g., ${ prefix } -candidate)` ;
18+ }
19+
20+ if ( nodeName && nodeName . length >= 3 ) {
21+ const prefix = nodeName . substring ( 0 , 3 ) . toLowerCase ( ) ;
22+ return `Enter tag (e.g., ${ prefix } -candidate)` ;
23+ }
24+
25+ return "Enter tag (e.g., clm-candidate)" ;
26+ } ;
27+
1028type EditableFieldKey = keyof Omit < DiscourseNode , "id" | "shortcut" > ;
1129
1230type BaseFieldConfig = {
@@ -75,6 +93,29 @@ const FIELD_CONFIGS: Record<EditableFieldKey, BaseFieldConfig> = {
7593 type : "color" ,
7694 required : false ,
7795 } ,
96+ tag : {
97+ key : "tag" ,
98+ label : "Node tag" ,
99+ description : "Tags that signal a line is a node candidate" ,
100+ type : "text" ,
101+ required : false ,
102+ validate : ( value : string ) => {
103+ if ( ! value . trim ( ) ) return { isValid : true } ;
104+ if ( / \s / . test ( value ) ) {
105+ return { isValid : false , error : "Tag cannot contain spaces" } ;
106+ }
107+ const invalidTagChars = / [ ^ a - z A - Z 0 - 9 - ] / ;
108+ const invalidCharMatch = value . match ( invalidTagChars ) ;
109+ if ( invalidCharMatch ) {
110+ return {
111+ isValid : false ,
112+ error : `Tag contains invalid character: ${ invalidCharMatch [ 0 ] } . Tags can only contain letters, numbers, and dashes.` ,
113+ } ;
114+ }
115+
116+ return { isValid : true } ;
117+ } ,
118+ } ,
78119} ;
79120
80121const FIELD_CONFIG_ARRAY = Object . values ( FIELD_CONFIGS ) ;
@@ -84,20 +125,32 @@ const TextField = ({
84125 value,
85126 error,
86127 onChange,
128+ nodeType,
87129} : {
88130 fieldConfig : BaseFieldConfig ;
89131 value : string ;
90132 error ?: string ;
91133 onChange : ( value : string ) => void ;
92- } ) => (
93- < input
94- type = "text"
95- value = { value || "" }
96- onChange = { ( e ) => onChange ( e . target . value ) }
97- placeholder = { fieldConfig . placeholder }
98- className = { `w-full ${ error ? "input-error" : "" } ` }
99- />
100- ) ;
134+ nodeType ?: DiscourseNode ;
135+ } ) => {
136+ // Generate dynamic placeholder for tag field based on node format and name
137+ const getPlaceholder = ( ) : string => {
138+ if ( fieldConfig . key === "tag" && nodeType ?. format ) {
139+ return generateTagPlaceholder ( nodeType . format , nodeType . name ) ;
140+ }
141+ return fieldConfig . placeholder || "" ;
142+ } ;
143+
144+ return (
145+ < input
146+ type = "text"
147+ value = { value || "" }
148+ onChange = { ( e ) => onChange ( e . target . value ) }
149+ placeholder = { getPlaceholder ( ) }
150+ className = { `w-full ${ error ? "input-error" : "" } ` }
151+ />
152+ ) ;
153+ } ;
101154
102155const ColorField = ( {
103156 value,
@@ -163,8 +216,12 @@ const FieldWrapper = ({
163216 < div className = "setting-item-description" > { fieldConfig . description } </ div >
164217 </ div >
165218 < div className = "setting-item-control" >
166- { children }
167- { error && < div className = "text-error mt-1 text-xs" > { error } </ div > }
219+ < div className = "flex flex-col" >
220+ { children }
221+ < div className = "mt-1 min-h-[1rem] text-xs" >
222+ { error && < div className = "text-error" > { error } </ div > }
223+ </ div >
224+ </ div >
168225 </ div >
169226 </ div >
170227) ;
@@ -256,6 +313,7 @@ const NodeTypeSettings = () => {
256313 name : "" ,
257314 format : "" ,
258315 template : "" ,
316+ tag : "" ,
259317 } ;
260318 setEditingNodeType ( newNodeType ) ;
261319 setSelectedNodeIndex ( nodeTypes . length ) ;
@@ -403,6 +461,7 @@ const NodeTypeSettings = () => {
403461 value = { value }
404462 error = { error }
405463 onChange = { handleChange }
464+ nodeType = { editingNodeType }
406465 />
407466 ) }
408467 </ FieldWrapper >
0 commit comments