package works.iterative.services.files package components.tailwind import com.raquo.laminar.api.L.{*, given} import com.raquo.domtypes.generic.codecs.StringAsIsCodec import works.iterative.ui.components.tailwind.Icons import java.time.format.DateTimeFormatter import java.time.format.FormatStyle import java.time.ZoneId import java.util.Locale import works.iterative.ui.components.tailwind.TimeUtils def FileTable( files: Signal[List[File]], maybeSelection: Option[Var[Set[File]]] = None ): HtmlElement = val scope = customHtmlAttr("scope", StringAsIsCodec) val selectedFiles = maybeSelection.getOrElse(Var(Set.empty)) val openCategories = Var[Set[String]]( maybeSelection.map(_.now().map(_.category)).getOrElse(Set.empty) ) def headerRow: HtmlElement = val col = scope("col") val baseM: Modifier[HtmlElement] = Seq(cls("px-6 py-3"), col) val textH = cls( "text-left text-xs font-medium text-gray-500 uppercase tracking-wider" ) tr( maybeSelection.map(_ => th(baseM, span(cls("sr-only"), "Vybrat"))), th(baseM, textH, "Soubor"), th(baseM, cls("w-40"), textH, "Vytvořen"), th(baseM, cls("w-32 relative"), span(cls("sr-only"), "Otevřít")) ) def tableRow( selected: File => Boolean, toggleSelection: File => Observer[Unit] )( f: File ): HtmlElement = val baseC = cls("px-6 py-4 whitespace-nowrap text-sm") tr( maybeSelection.map(_ => td( cls("font-medium cursor-pointer"), onClick.mapTo(()) --> toggleSelection(f), cls(if selected(f) then "text-green-900" else "text-gray-200"), Icons.outline.`check-circle`("w-6 h-6 mx-auto"), span(cls("sr-only"), if selected(f) then "Vybráno" else "Nevybráno") ) ), td( baseC, cls("font-medium text-gray-900"), f.name, onClick.mapTo(()) --> toggleSelection(f) ), td( baseC, cls("font-medium text-gray-600 text-right"), TimeUtils.formatDateTime(f.created), onClick.mapTo(()) --> toggleSelection(f) ), td( baseC, cls("text-right font-medium"), a( href(f.url), target("_blank"), cls( "flex items-center space-x-4 text-indigo-600 hover:text-indigo-900" ), Icons.outline.`external-link`("w-6 h-6"), "Otevřít" ) ) ) def category( renderRow: File => HtmlElement )(name: String, files: List[File]): Signal[List[HtmlElement]] = openCategories.signal.map(o => tr( cls("border-t border-gray-200"), th( cls("cursor-pointer"), onClick.mapTo( if o.contains(name) then o - name else o + name ) --> openCategories, colSpan(if (maybeSelection.isDefined) then 4 else 3), scope("colgroup"), cls( "bg-gray-50 px-4 py-2 text-left text-sm font-semibold text-gray-900 sm:px-6" ), name ) ) :: (if o.contains(name) then files.map(renderRow) else Nil) ) div( cls("flex flex-col"), div(cls("overflow-x-auto sm:-mx-6 lg:-mx-8")), div( cls("py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8"), div( cls("shadow overflow-hidden border-b border-gray-200 sm:rounded-lg"), table( cls("min-w-full divide-y divide-gray-200"), thead( cls("bg-gray-50"), headerRow ), tbody( cls("bg-white"), children <-- files .combineWithFn(selectedFiles)((f, sel) => val active = sel.contains val renderCategory = category( tableRow( active, file => selectedFiles.writer.contramap(_ => if active(file) then sel - file else sel + file ) ) ) Signal .combineSeq( f.groupBy(_.category) .to(List) .map(renderCategory(_, _)) ) .map(_.flatten) ) .flatten ) ) ) ) )