diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/DetailComponentsModule.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/DetailComponentsModule.scala new file mode 100644 index 0000000..a45beaf --- /dev/null +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/DetailComponentsModule.scala @@ -0,0 +1,107 @@ +package works.iterative.ui.components.laminar + +import com.raquo.laminar.api.L.{*, given} +import works.iterative.ui.components.tailwind.ComponentContext +import works.iterative.ui.model.FileRef + +trait DetailComponentsModule: + + def details: DetailComponents + + trait DetailComponents: + def section( + title: Modifier[HtmlElement], + subtitle: Option[Modifier[HtmlElement]], + actions: Modifier[HtmlElement]* + )(fields: HtmlElement*): HtmlElement + + def field( + title: String, + content: Modifier[HtmlElement]* + ): HtmlElement + + def files(fs: List[FileRef]): HtmlElement + + def file(f: FileRef): HtmlElement + +trait DefaultDetailComponentsModule(using ctx: ComponentContext) + extends DetailComponentsModule: + self: IconsModule => + + override val details: DetailComponents = new DetailComponents: + override def section( + title: Modifier[HtmlElement], + subtitle: Option[Modifier[HtmlElement]], + actions: Modifier[HtmlElement]* + )(fields: HtmlElement*): HtmlElement = + div( + div( + cls := "px-4 sm:px-0", + h3( + cls := "text-base font-semibold leading-7 text-gray-900", + title + ), + subtitle.map(st => + p( + cls := "mt-1 max-w-2xl text-sm leading-6 text-gray-500", + st + ) + ) + // TODO: actions + ), + div( + cls := "mt-6 border-t border-gray-100", + dl( + cls := "divide-y divide-gray-100", + fields + ) + ) + ) + + override def field( + title: String, + content: Modifier[HtmlElement]* + ): HtmlElement = + div( + cls := "px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0", + dt( + cls := "text-sm font-medium leading-6 text-gray-900", + title + ), + dd( + cls := "mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0", + content + ) + ) + + override def files(fs: List[FileRef]): HtmlElement = + ul( + role := "list", + cls := "divide-y divide-gray-100 rounded-md border border-gray-200", + fs.map(file) + ) + + override def file(f: FileRef): HtmlElement = + li( + cls := "flex items-center justify-between py-4 pl-4 pr-5 text-sm leading-6", + div( + cls := "flex w-0 flex-1 items-center", + icons.`paper-clip-solid`(), + div( + cls := "ml-4 flex min-w-0 flex-1 gap-2", + span( + cls := "truncate font-medium", + f.name + ), + f.size.map(size => span(cls := "flex-shrink-0 text-gray-400", size)) + ) + ), + div( + cls := "ml-4 flex-shrink-0", + a( + href := "#", + cls := "font-medium text-indigo-600 hover:text-indigo-500", + "Uložit" + ) + ) + ) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/DetailComponentsModule.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/DetailComponentsModule.scala new file mode 100644 index 0000000..a45beaf --- /dev/null +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/DetailComponentsModule.scala @@ -0,0 +1,107 @@ +package works.iterative.ui.components.laminar + +import com.raquo.laminar.api.L.{*, given} +import works.iterative.ui.components.tailwind.ComponentContext +import works.iterative.ui.model.FileRef + +trait DetailComponentsModule: + + def details: DetailComponents + + trait DetailComponents: + def section( + title: Modifier[HtmlElement], + subtitle: Option[Modifier[HtmlElement]], + actions: Modifier[HtmlElement]* + )(fields: HtmlElement*): HtmlElement + + def field( + title: String, + content: Modifier[HtmlElement]* + ): HtmlElement + + def files(fs: List[FileRef]): HtmlElement + + def file(f: FileRef): HtmlElement + +trait DefaultDetailComponentsModule(using ctx: ComponentContext) + extends DetailComponentsModule: + self: IconsModule => + + override val details: DetailComponents = new DetailComponents: + override def section( + title: Modifier[HtmlElement], + subtitle: Option[Modifier[HtmlElement]], + actions: Modifier[HtmlElement]* + )(fields: HtmlElement*): HtmlElement = + div( + div( + cls := "px-4 sm:px-0", + h3( + cls := "text-base font-semibold leading-7 text-gray-900", + title + ), + subtitle.map(st => + p( + cls := "mt-1 max-w-2xl text-sm leading-6 text-gray-500", + st + ) + ) + // TODO: actions + ), + div( + cls := "mt-6 border-t border-gray-100", + dl( + cls := "divide-y divide-gray-100", + fields + ) + ) + ) + + override def field( + title: String, + content: Modifier[HtmlElement]* + ): HtmlElement = + div( + cls := "px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0", + dt( + cls := "text-sm font-medium leading-6 text-gray-900", + title + ), + dd( + cls := "mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0", + content + ) + ) + + override def files(fs: List[FileRef]): HtmlElement = + ul( + role := "list", + cls := "divide-y divide-gray-100 rounded-md border border-gray-200", + fs.map(file) + ) + + override def file(f: FileRef): HtmlElement = + li( + cls := "flex items-center justify-between py-4 pl-4 pr-5 text-sm leading-6", + div( + cls := "flex w-0 flex-1 items-center", + icons.`paper-clip-solid`(), + div( + cls := "ml-4 flex min-w-0 flex-1 gap-2", + span( + cls := "truncate font-medium", + f.name + ), + f.size.map(size => span(cls := "flex-shrink-0 text-gray-400", size)) + ) + ), + div( + cls := "ml-4 flex-shrink-0", + a( + href := "#", + cls := "font-medium text-indigo-600 hover:text-indigo-500", + "Uložit" + ) + ) + ) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/IconsModule.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/IconsModule.scala index 32fda8a..6713728 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/IconsModule.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/IconsModule.scala @@ -14,6 +14,7 @@ def `search-solid`(mods: Modifier[SvgElement]*): SvgElement def `filter-solid`(mods: Modifier[SvgElement]*): SvgElement def `document-chart-bar-outline`(mods: Modifier[SvgElement]*): SvgElement + def `paper-clip-solid`(mods: Modifier[SvgElement]*): SvgElement trait DefaultIconsModule(using ComponentContext) extends IconsModule: override val icons: Icons = new Icons: @@ -107,3 +108,17 @@ d := "M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25M9 16.5v.75m3-3v3M15 12v5.25m-4.5-15H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z" ) ) + + override def `paper-clip-solid`(mods: Modifier[SvgElement]*): SvgElement = + svg( + withDefault(mods, cls := "h-5 w-5"), + cls := "flex-shrink-0 text-gray-400", + viewBox := "0 0 20 20", + fill := "currentColor", + aria.hidden := true, + path( + fillRule := "evenodd", + d := "M15.621 4.379a3 3 0 00-4.242 0l-7 7a3 3 0 004.241 4.243h.001l.497-.5a.75.75 0 011.064 1.057l-.498.501-.002.002a4.5 4.5 0 01-6.364-6.364l7-7a4.5 4.5 0 016.368 6.36l-3.455 3.553A2.625 2.625 0 119.52 9.52l3.45-3.451a.75.75 0 111.061 1.06l-3.45 3.451a1.125 1.125 0 001.587 1.595l3.454-3.553a3 3 0 000-4.242z", + clipRule := "evenodd" + ) + ) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/DetailComponentsModule.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/DetailComponentsModule.scala new file mode 100644 index 0000000..a45beaf --- /dev/null +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/DetailComponentsModule.scala @@ -0,0 +1,107 @@ +package works.iterative.ui.components.laminar + +import com.raquo.laminar.api.L.{*, given} +import works.iterative.ui.components.tailwind.ComponentContext +import works.iterative.ui.model.FileRef + +trait DetailComponentsModule: + + def details: DetailComponents + + trait DetailComponents: + def section( + title: Modifier[HtmlElement], + subtitle: Option[Modifier[HtmlElement]], + actions: Modifier[HtmlElement]* + )(fields: HtmlElement*): HtmlElement + + def field( + title: String, + content: Modifier[HtmlElement]* + ): HtmlElement + + def files(fs: List[FileRef]): HtmlElement + + def file(f: FileRef): HtmlElement + +trait DefaultDetailComponentsModule(using ctx: ComponentContext) + extends DetailComponentsModule: + self: IconsModule => + + override val details: DetailComponents = new DetailComponents: + override def section( + title: Modifier[HtmlElement], + subtitle: Option[Modifier[HtmlElement]], + actions: Modifier[HtmlElement]* + )(fields: HtmlElement*): HtmlElement = + div( + div( + cls := "px-4 sm:px-0", + h3( + cls := "text-base font-semibold leading-7 text-gray-900", + title + ), + subtitle.map(st => + p( + cls := "mt-1 max-w-2xl text-sm leading-6 text-gray-500", + st + ) + ) + // TODO: actions + ), + div( + cls := "mt-6 border-t border-gray-100", + dl( + cls := "divide-y divide-gray-100", + fields + ) + ) + ) + + override def field( + title: String, + content: Modifier[HtmlElement]* + ): HtmlElement = + div( + cls := "px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0", + dt( + cls := "text-sm font-medium leading-6 text-gray-900", + title + ), + dd( + cls := "mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0", + content + ) + ) + + override def files(fs: List[FileRef]): HtmlElement = + ul( + role := "list", + cls := "divide-y divide-gray-100 rounded-md border border-gray-200", + fs.map(file) + ) + + override def file(f: FileRef): HtmlElement = + li( + cls := "flex items-center justify-between py-4 pl-4 pr-5 text-sm leading-6", + div( + cls := "flex w-0 flex-1 items-center", + icons.`paper-clip-solid`(), + div( + cls := "ml-4 flex min-w-0 flex-1 gap-2", + span( + cls := "truncate font-medium", + f.name + ), + f.size.map(size => span(cls := "flex-shrink-0 text-gray-400", size)) + ) + ), + div( + cls := "ml-4 flex-shrink-0", + a( + href := "#", + cls := "font-medium text-indigo-600 hover:text-indigo-500", + "Uložit" + ) + ) + ) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/IconsModule.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/IconsModule.scala index 32fda8a..6713728 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/IconsModule.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/IconsModule.scala @@ -14,6 +14,7 @@ def `search-solid`(mods: Modifier[SvgElement]*): SvgElement def `filter-solid`(mods: Modifier[SvgElement]*): SvgElement def `document-chart-bar-outline`(mods: Modifier[SvgElement]*): SvgElement + def `paper-clip-solid`(mods: Modifier[SvgElement]*): SvgElement trait DefaultIconsModule(using ComponentContext) extends IconsModule: override val icons: Icons = new Icons: @@ -107,3 +108,17 @@ d := "M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25M9 16.5v.75m3-3v3M15 12v5.25m-4.5-15H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z" ) ) + + override def `paper-clip-solid`(mods: Modifier[SvgElement]*): SvgElement = + svg( + withDefault(mods, cls := "h-5 w-5"), + cls := "flex-shrink-0 text-gray-400", + viewBox := "0 0 20 20", + fill := "currentColor", + aria.hidden := true, + path( + fillRule := "evenodd", + d := "M15.621 4.379a3 3 0 00-4.242 0l-7 7a3 3 0 004.241 4.243h.001l.497-.5a.75.75 0 011.064 1.057l-.498.501-.002.002a4.5 4.5 0 01-6.364-6.364l7-7a4.5 4.5 0 016.368 6.36l-3.455 3.553A2.625 2.625 0 119.52 9.52l3.45-3.451a.75.75 0 111.061 1.06l-3.45 3.451a1.125 1.125 0 001.587 1.595l3.454-3.553a3 3 0 000-4.242z", + clipRule := "evenodd" + ) + ) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/PagesModule.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/PagesModule.scala index 3f3e7d0..b713d8a 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/PagesModule.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/PagesModule.scala @@ -34,7 +34,7 @@ children: Modifier[HtmlElement]* ): HtmlElement = div( - cls("max-w-7xl mx-auto h-full px-4 sm:px-6 lg:px-8"), + cls("max-w-7xl mx-auto h-full px-4 sm:px-6 lg:px-8 overflow-y-auto"), children ) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/DetailComponentsModule.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/DetailComponentsModule.scala new file mode 100644 index 0000000..a45beaf --- /dev/null +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/DetailComponentsModule.scala @@ -0,0 +1,107 @@ +package works.iterative.ui.components.laminar + +import com.raquo.laminar.api.L.{*, given} +import works.iterative.ui.components.tailwind.ComponentContext +import works.iterative.ui.model.FileRef + +trait DetailComponentsModule: + + def details: DetailComponents + + trait DetailComponents: + def section( + title: Modifier[HtmlElement], + subtitle: Option[Modifier[HtmlElement]], + actions: Modifier[HtmlElement]* + )(fields: HtmlElement*): HtmlElement + + def field( + title: String, + content: Modifier[HtmlElement]* + ): HtmlElement + + def files(fs: List[FileRef]): HtmlElement + + def file(f: FileRef): HtmlElement + +trait DefaultDetailComponentsModule(using ctx: ComponentContext) + extends DetailComponentsModule: + self: IconsModule => + + override val details: DetailComponents = new DetailComponents: + override def section( + title: Modifier[HtmlElement], + subtitle: Option[Modifier[HtmlElement]], + actions: Modifier[HtmlElement]* + )(fields: HtmlElement*): HtmlElement = + div( + div( + cls := "px-4 sm:px-0", + h3( + cls := "text-base font-semibold leading-7 text-gray-900", + title + ), + subtitle.map(st => + p( + cls := "mt-1 max-w-2xl text-sm leading-6 text-gray-500", + st + ) + ) + // TODO: actions + ), + div( + cls := "mt-6 border-t border-gray-100", + dl( + cls := "divide-y divide-gray-100", + fields + ) + ) + ) + + override def field( + title: String, + content: Modifier[HtmlElement]* + ): HtmlElement = + div( + cls := "px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0", + dt( + cls := "text-sm font-medium leading-6 text-gray-900", + title + ), + dd( + cls := "mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0", + content + ) + ) + + override def files(fs: List[FileRef]): HtmlElement = + ul( + role := "list", + cls := "divide-y divide-gray-100 rounded-md border border-gray-200", + fs.map(file) + ) + + override def file(f: FileRef): HtmlElement = + li( + cls := "flex items-center justify-between py-4 pl-4 pr-5 text-sm leading-6", + div( + cls := "flex w-0 flex-1 items-center", + icons.`paper-clip-solid`(), + div( + cls := "ml-4 flex min-w-0 flex-1 gap-2", + span( + cls := "truncate font-medium", + f.name + ), + f.size.map(size => span(cls := "flex-shrink-0 text-gray-400", size)) + ) + ), + div( + cls := "ml-4 flex-shrink-0", + a( + href := "#", + cls := "font-medium text-indigo-600 hover:text-indigo-500", + "Uložit" + ) + ) + ) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/IconsModule.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/IconsModule.scala index 32fda8a..6713728 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/IconsModule.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/IconsModule.scala @@ -14,6 +14,7 @@ def `search-solid`(mods: Modifier[SvgElement]*): SvgElement def `filter-solid`(mods: Modifier[SvgElement]*): SvgElement def `document-chart-bar-outline`(mods: Modifier[SvgElement]*): SvgElement + def `paper-clip-solid`(mods: Modifier[SvgElement]*): SvgElement trait DefaultIconsModule(using ComponentContext) extends IconsModule: override val icons: Icons = new Icons: @@ -107,3 +108,17 @@ d := "M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25M9 16.5v.75m3-3v3M15 12v5.25m-4.5-15H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z" ) ) + + override def `paper-clip-solid`(mods: Modifier[SvgElement]*): SvgElement = + svg( + withDefault(mods, cls := "h-5 w-5"), + cls := "flex-shrink-0 text-gray-400", + viewBox := "0 0 20 20", + fill := "currentColor", + aria.hidden := true, + path( + fillRule := "evenodd", + d := "M15.621 4.379a3 3 0 00-4.242 0l-7 7a3 3 0 004.241 4.243h.001l.497-.5a.75.75 0 011.064 1.057l-.498.501-.002.002a4.5 4.5 0 01-6.364-6.364l7-7a4.5 4.5 0 016.368 6.36l-3.455 3.553A2.625 2.625 0 119.52 9.52l3.45-3.451a.75.75 0 111.061 1.06l-3.45 3.451a1.125 1.125 0 001.587 1.595l3.454-3.553a3 3 0 000-4.242z", + clipRule := "evenodd" + ) + ) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/PagesModule.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/PagesModule.scala index 3f3e7d0..b713d8a 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/PagesModule.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/PagesModule.scala @@ -34,7 +34,7 @@ children: Modifier[HtmlElement]* ): HtmlElement = div( - cls("max-w-7xl mx-auto h-full px-4 sm:px-6 lg:px-8"), + cls("max-w-7xl mx-auto h-full px-4 sm:px-6 lg:px-8 overflow-y-auto"), children ) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/TableComponentsModule.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/TableComponentsModule.scala index a0f0768..f70ee87 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/TableComponentsModule.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/TableComponentsModule.scala @@ -29,7 +29,7 @@ trait DefaultTableComponentsModule extends TableComponentsModule: - override val tables: TableComponents = new TableComponents: + override lazy val tables: TableComponents = new TableComponents: override def tableSection( title: Modifier[HtmlElement], diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/DetailComponentsModule.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/DetailComponentsModule.scala new file mode 100644 index 0000000..a45beaf --- /dev/null +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/DetailComponentsModule.scala @@ -0,0 +1,107 @@ +package works.iterative.ui.components.laminar + +import com.raquo.laminar.api.L.{*, given} +import works.iterative.ui.components.tailwind.ComponentContext +import works.iterative.ui.model.FileRef + +trait DetailComponentsModule: + + def details: DetailComponents + + trait DetailComponents: + def section( + title: Modifier[HtmlElement], + subtitle: Option[Modifier[HtmlElement]], + actions: Modifier[HtmlElement]* + )(fields: HtmlElement*): HtmlElement + + def field( + title: String, + content: Modifier[HtmlElement]* + ): HtmlElement + + def files(fs: List[FileRef]): HtmlElement + + def file(f: FileRef): HtmlElement + +trait DefaultDetailComponentsModule(using ctx: ComponentContext) + extends DetailComponentsModule: + self: IconsModule => + + override val details: DetailComponents = new DetailComponents: + override def section( + title: Modifier[HtmlElement], + subtitle: Option[Modifier[HtmlElement]], + actions: Modifier[HtmlElement]* + )(fields: HtmlElement*): HtmlElement = + div( + div( + cls := "px-4 sm:px-0", + h3( + cls := "text-base font-semibold leading-7 text-gray-900", + title + ), + subtitle.map(st => + p( + cls := "mt-1 max-w-2xl text-sm leading-6 text-gray-500", + st + ) + ) + // TODO: actions + ), + div( + cls := "mt-6 border-t border-gray-100", + dl( + cls := "divide-y divide-gray-100", + fields + ) + ) + ) + + override def field( + title: String, + content: Modifier[HtmlElement]* + ): HtmlElement = + div( + cls := "px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0", + dt( + cls := "text-sm font-medium leading-6 text-gray-900", + title + ), + dd( + cls := "mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0", + content + ) + ) + + override def files(fs: List[FileRef]): HtmlElement = + ul( + role := "list", + cls := "divide-y divide-gray-100 rounded-md border border-gray-200", + fs.map(file) + ) + + override def file(f: FileRef): HtmlElement = + li( + cls := "flex items-center justify-between py-4 pl-4 pr-5 text-sm leading-6", + div( + cls := "flex w-0 flex-1 items-center", + icons.`paper-clip-solid`(), + div( + cls := "ml-4 flex min-w-0 flex-1 gap-2", + span( + cls := "truncate font-medium", + f.name + ), + f.size.map(size => span(cls := "flex-shrink-0 text-gray-400", size)) + ) + ), + div( + cls := "ml-4 flex-shrink-0", + a( + href := "#", + cls := "font-medium text-indigo-600 hover:text-indigo-500", + "Uložit" + ) + ) + ) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/IconsModule.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/IconsModule.scala index 32fda8a..6713728 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/IconsModule.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/IconsModule.scala @@ -14,6 +14,7 @@ def `search-solid`(mods: Modifier[SvgElement]*): SvgElement def `filter-solid`(mods: Modifier[SvgElement]*): SvgElement def `document-chart-bar-outline`(mods: Modifier[SvgElement]*): SvgElement + def `paper-clip-solid`(mods: Modifier[SvgElement]*): SvgElement trait DefaultIconsModule(using ComponentContext) extends IconsModule: override val icons: Icons = new Icons: @@ -107,3 +108,17 @@ d := "M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25M9 16.5v.75m3-3v3M15 12v5.25m-4.5-15H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z" ) ) + + override def `paper-clip-solid`(mods: Modifier[SvgElement]*): SvgElement = + svg( + withDefault(mods, cls := "h-5 w-5"), + cls := "flex-shrink-0 text-gray-400", + viewBox := "0 0 20 20", + fill := "currentColor", + aria.hidden := true, + path( + fillRule := "evenodd", + d := "M15.621 4.379a3 3 0 00-4.242 0l-7 7a3 3 0 004.241 4.243h.001l.497-.5a.75.75 0 011.064 1.057l-.498.501-.002.002a4.5 4.5 0 01-6.364-6.364l7-7a4.5 4.5 0 016.368 6.36l-3.455 3.553A2.625 2.625 0 119.52 9.52l3.45-3.451a.75.75 0 111.061 1.06l-3.45 3.451a1.125 1.125 0 001.587 1.595l3.454-3.553a3 3 0 000-4.242z", + clipRule := "evenodd" + ) + ) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/PagesModule.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/PagesModule.scala index 3f3e7d0..b713d8a 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/PagesModule.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/PagesModule.scala @@ -34,7 +34,7 @@ children: Modifier[HtmlElement]* ): HtmlElement = div( - cls("max-w-7xl mx-auto h-full px-4 sm:px-6 lg:px-8"), + cls("max-w-7xl mx-auto h-full px-4 sm:px-6 lg:px-8 overflow-y-auto"), children ) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/TableComponentsModule.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/TableComponentsModule.scala index a0f0768..f70ee87 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/TableComponentsModule.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/TableComponentsModule.scala @@ -29,7 +29,7 @@ trait DefaultTableComponentsModule extends TableComponentsModule: - override val tables: TableComponents = new TableComponents: + override lazy val tables: TableComponents = new TableComponents: override def tableSection( title: Modifier[HtmlElement], diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/laminar/LaminarExtensions.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/laminar/LaminarExtensions.scala index a5093b3..4c5e68b 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/laminar/LaminarExtensions.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/laminar/LaminarExtensions.scala @@ -23,3 +23,8 @@ ctx: ComponentContext ): Conversion[UserMessage, Modifier[HtmlElement]] with inline def apply(msg: UserMessage) = ctx.messages(msg) + + inline given userMessageToString(using + ctx: ComponentContext + ): Conversion[UserMessage, String] with + inline def apply(msg: UserMessage) = ctx.messages(msg) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/DetailComponentsModule.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/DetailComponentsModule.scala new file mode 100644 index 0000000..a45beaf --- /dev/null +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/DetailComponentsModule.scala @@ -0,0 +1,107 @@ +package works.iterative.ui.components.laminar + +import com.raquo.laminar.api.L.{*, given} +import works.iterative.ui.components.tailwind.ComponentContext +import works.iterative.ui.model.FileRef + +trait DetailComponentsModule: + + def details: DetailComponents + + trait DetailComponents: + def section( + title: Modifier[HtmlElement], + subtitle: Option[Modifier[HtmlElement]], + actions: Modifier[HtmlElement]* + )(fields: HtmlElement*): HtmlElement + + def field( + title: String, + content: Modifier[HtmlElement]* + ): HtmlElement + + def files(fs: List[FileRef]): HtmlElement + + def file(f: FileRef): HtmlElement + +trait DefaultDetailComponentsModule(using ctx: ComponentContext) + extends DetailComponentsModule: + self: IconsModule => + + override val details: DetailComponents = new DetailComponents: + override def section( + title: Modifier[HtmlElement], + subtitle: Option[Modifier[HtmlElement]], + actions: Modifier[HtmlElement]* + )(fields: HtmlElement*): HtmlElement = + div( + div( + cls := "px-4 sm:px-0", + h3( + cls := "text-base font-semibold leading-7 text-gray-900", + title + ), + subtitle.map(st => + p( + cls := "mt-1 max-w-2xl text-sm leading-6 text-gray-500", + st + ) + ) + // TODO: actions + ), + div( + cls := "mt-6 border-t border-gray-100", + dl( + cls := "divide-y divide-gray-100", + fields + ) + ) + ) + + override def field( + title: String, + content: Modifier[HtmlElement]* + ): HtmlElement = + div( + cls := "px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0", + dt( + cls := "text-sm font-medium leading-6 text-gray-900", + title + ), + dd( + cls := "mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0", + content + ) + ) + + override def files(fs: List[FileRef]): HtmlElement = + ul( + role := "list", + cls := "divide-y divide-gray-100 rounded-md border border-gray-200", + fs.map(file) + ) + + override def file(f: FileRef): HtmlElement = + li( + cls := "flex items-center justify-between py-4 pl-4 pr-5 text-sm leading-6", + div( + cls := "flex w-0 flex-1 items-center", + icons.`paper-clip-solid`(), + div( + cls := "ml-4 flex min-w-0 flex-1 gap-2", + span( + cls := "truncate font-medium", + f.name + ), + f.size.map(size => span(cls := "flex-shrink-0 text-gray-400", size)) + ) + ), + div( + cls := "ml-4 flex-shrink-0", + a( + href := "#", + cls := "font-medium text-indigo-600 hover:text-indigo-500", + "Uložit" + ) + ) + ) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/IconsModule.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/IconsModule.scala index 32fda8a..6713728 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/IconsModule.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/IconsModule.scala @@ -14,6 +14,7 @@ def `search-solid`(mods: Modifier[SvgElement]*): SvgElement def `filter-solid`(mods: Modifier[SvgElement]*): SvgElement def `document-chart-bar-outline`(mods: Modifier[SvgElement]*): SvgElement + def `paper-clip-solid`(mods: Modifier[SvgElement]*): SvgElement trait DefaultIconsModule(using ComponentContext) extends IconsModule: override val icons: Icons = new Icons: @@ -107,3 +108,17 @@ d := "M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25M9 16.5v.75m3-3v3M15 12v5.25m-4.5-15H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z" ) ) + + override def `paper-clip-solid`(mods: Modifier[SvgElement]*): SvgElement = + svg( + withDefault(mods, cls := "h-5 w-5"), + cls := "flex-shrink-0 text-gray-400", + viewBox := "0 0 20 20", + fill := "currentColor", + aria.hidden := true, + path( + fillRule := "evenodd", + d := "M15.621 4.379a3 3 0 00-4.242 0l-7 7a3 3 0 004.241 4.243h.001l.497-.5a.75.75 0 011.064 1.057l-.498.501-.002.002a4.5 4.5 0 01-6.364-6.364l7-7a4.5 4.5 0 016.368 6.36l-3.455 3.553A2.625 2.625 0 119.52 9.52l3.45-3.451a.75.75 0 111.061 1.06l-3.45 3.451a1.125 1.125 0 001.587 1.595l3.454-3.553a3 3 0 000-4.242z", + clipRule := "evenodd" + ) + ) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/PagesModule.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/PagesModule.scala index 3f3e7d0..b713d8a 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/PagesModule.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/PagesModule.scala @@ -34,7 +34,7 @@ children: Modifier[HtmlElement]* ): HtmlElement = div( - cls("max-w-7xl mx-auto h-full px-4 sm:px-6 lg:px-8"), + cls("max-w-7xl mx-auto h-full px-4 sm:px-6 lg:px-8 overflow-y-auto"), children ) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/TableComponentsModule.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/TableComponentsModule.scala index a0f0768..f70ee87 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/TableComponentsModule.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/TableComponentsModule.scala @@ -29,7 +29,7 @@ trait DefaultTableComponentsModule extends TableComponentsModule: - override val tables: TableComponents = new TableComponents: + override lazy val tables: TableComponents = new TableComponents: override def tableSection( title: Modifier[HtmlElement], diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/laminar/LaminarExtensions.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/laminar/LaminarExtensions.scala index a5093b3..4c5e68b 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/laminar/LaminarExtensions.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/laminar/LaminarExtensions.scala @@ -23,3 +23,8 @@ ctx: ComponentContext ): Conversion[UserMessage, Modifier[HtmlElement]] with inline def apply(msg: UserMessage) = ctx.messages(msg) + + inline given userMessageToString(using + ctx: ComponentContext + ): Conversion[UserMessage, String] with + inline def apply(msg: UserMessage) = ctx.messages(msg) diff --git a/ui/shared/src/main/scala/works/iterative/ui/model/FileRef.scala b/ui/shared/src/main/scala/works/iterative/ui/model/FileRef.scala new file mode 100644 index 0000000..64d6e04 --- /dev/null +++ b/ui/shared/src/main/scala/works/iterative/ui/model/FileRef.scala @@ -0,0 +1,4 @@ +package works.iterative.ui.model + +/** Represents a reference to a file */ +case class FileRef(name: String, size: Option[String], url: String)