11import { faPlus } from " @fortawesome/free-solid-svg-icons" ;
22import type { File } from " app/util/workspace" ;
33import * as styles from " ./tabs.style.module.scss" ;
4+ import EXAMPLE_TEMPLATES from " ./examples"
45export interface Input {
56 files: File [];
67 filesChange: (files : File []) => void ;
@@ -10,53 +11,53 @@ export interface Input {
1011
1112let /tabs := input .files
1213let /selected := input .selected
14+ let /editingIndex = - 1
1315
1416div class = styles .tabs
1517 div class = styles .files
1618 for |tab , i | of = tabs
1719 const /isSelected = selected === i
1820 const /isEditable = i !== 0
19- let / editing = false valueChange = ( isEditable ? undefined : () => {})
21+ const / isEditing = editingIndex === i
2022
2123 div
2224 ,aria-selected = isSelected && " true"
2325 ,tabindex = 0
2426 ,role = " button"
2527 ,onClick () {
26- if (isSelected ) {
27- editing = true ;
28- } else {
28+ if (isSelected && ! isEditing ) {
29+ editingIndex = i ;
30+ } else if ( ! isEditing ) {
2931 selected = i ;
3032 }
3133 }
3234 ,onKeyPress (e , el ) {
3335 if (e .target === el && (e .key === " " || e .key === " Enter" )) {
34- if (isSelected ) {
35- editing = true ;
36- } else {
36+ if (isSelected && ! isEditing ) {
37+ editingIndex = i ;
38+ } else if ( ! isEditing ) {
3739 selected = i ;
3840 }
3941 }
4042 }
4143 ,class = styles .tab
42- if = editing
44+ if = isEditing
4345 let /length = (tab .path .length )
4446 input /$input
4547 ,value = tab .path
4648 ,size = length
47- ,onInput () {
48- length = $input () .value .length ;
49+ ,onInput (_ , el ) {
50+ length = el .value .length ;
4951 }
50- ,onBlur () {
51- tabs = tabs .toSpliced (i , 1 , { ... tab , path: $input () .value });
52- editing = false ;
52+ ,onBlur (_ , el ) {
53+ tabs = tabs .toSpliced (i , 1 , { ... tab , path: el .value });
54+ editingIndex = - 1 ;
5355 }
5456 ,onKeyPress (e ) {
5557 if (e .key === " Enter" ) {
56- $input ().blur ();
57- editing = false ;
58+ document .querySelector <HTMLElement >(" .cm-content" )?.focus ();
5859 } else if (e .key === " Escape" ) {
59- editing = false ;
60+ editingIndex = - 1 ;
6061 }
6162 }
6263 script --
@@ -77,21 +78,53 @@ div class=styles.tabs
7778 ,class = styles .close
7879 -- ×
7980
81+ id /popoverId
82+
8083 button
8184 ,title = " Add file"
82- ,onClick () {
83- let filename = prompt (
84- " What filename (extension optional)?" ,
85- tabs .some ((tab ) => tab .path === " Tag.marko" )
86- ? ` Tag${tabs .length } `
87- : " Tag" ,
88- );
85+ ,popovertarget = popoverId
86+ ,class = styles .add
87+ ,onClick (_ , btn ) {
88+ const { top, right } = btn .getBoundingClientRect ();
89+ $popover ().style .top = ` ${top }px ` ;
90+ $popover ().style .right = ` ${innerWidth - right }px ` ;
91+ }
92+ fa-icon = faPlus
8993
90- if (filename ) {
91- if (! filename .includes (" ." )) filename += " .marko" ;
92- tabs = [... tabs , { path: filename , content: " " }];
93- selected = tabs .length - 1 ;
94+ div /$popover
95+ ,id = popoverId
96+ ,class = styles .popover
97+ ,popover
98+ ,role = " menu"
99+ ,onFocusOut (e ) {
100+ if (! $popover ().contains (e .relatedTarget as Node )) {
101+ $popover ().hidePopover ();
94102 }
95103 }
96- ,class = styles .add
97- fa-icon = faPlus
104+
105+ button
106+ ,role = " menuitem"
107+ ,autofocus
108+ ,onClick () {
109+ const newIndex = tabs .length ;
110+ tabs = [... tabs , {
111+ path: ` Tag${tabs .filter (t => / ^ Tag\d * \. marko$ / .test (t .path )).length || " " }.marko ` ,
112+ content: " "
113+ }];
114+ selected = newIndex ;
115+ editingIndex = newIndex ;
116+ }
117+ ,class = styles .templateButton
118+ -- Blank
119+
120+ for |template | of = EXAMPLE_TEMPLATES
121+ if = ! tabs .some (({ path }) => path === template .name + " .marko" )
122+ button
123+ ,role = " menuitem"
124+ ,onClick () {
125+ selected = tabs .length ;
126+ tabs = [... tabs , { path: template .name + " .marko" , content: template .content }];
127+ document .querySelector <HTMLElement >(" .cm-content" )?.focus ();
128+ }
129+ ,class = styles .templateButton
130+ -- ${` <${template .name }> ` }
0 commit comments