From 7cbdf919f43dde2ab7a90e258b7f2422a5b7f77c Mon Sep 17 00:00:00 2001 From: eikek Date: Thu, 7 Oct 2021 22:02:31 +0200 Subject: [PATCH] Show item detail for a shared item --- modules/webapp/elm.json | 4 +- modules/webapp/src/main/elm/App/Update.elm | 15 +- modules/webapp/src/main/elm/App/View2.elm | 2 + .../main/elm/Comp/ItemDetail/ShowQrCode.elm | 5 +- modules/webapp/src/main/elm/Comp/OtpSetup.elm | 5 +- .../webapp/src/main/elm/Comp/ShareView.elm | 5 +- .../webapp/src/main/elm/Comp/SourceManage.elm | 5 +- modules/webapp/src/main/elm/Comp/UrlCopy.elm | 95 +++++++ .../src/main/elm/Messages/Page/Share.elm | 8 + .../main/elm/Messages/Page/ShareDetail.elm | 26 ++ modules/webapp/src/main/elm/Page.elm | 3 + .../webapp/src/main/elm/Page/Share/Data.elm | 17 +- .../webapp/src/main/elm/Page/Share/View.elm | 33 ++- .../src/main/elm/Page/ShareDetail/Data.elm | 14 +- .../src/main/elm/Page/ShareDetail/Update.elm | 26 +- .../src/main/elm/Page/ShareDetail/View.elm | 241 +++++++++++++++--- modules/webapp/src/main/elm/Styles.elm | 7 +- modules/webapp/src/main/webjar/docspell.js | 4 +- 18 files changed, 458 insertions(+), 57 deletions(-) create mode 100644 modules/webapp/src/main/elm/Comp/UrlCopy.elm diff --git a/modules/webapp/elm.json b/modules/webapp/elm.json index 047c5cda..b1071ec9 100644 --- a/modules/webapp/elm.json +++ b/modules/webapp/elm.json @@ -16,12 +16,13 @@ "elm/html": "1.0.0", "elm/http": "2.0.0", "elm/json": "1.1.3", + "elm/svg": "1.0.1", "elm/time": "1.0.0", "elm/url": "1.0.0", "elm-explorations/markdown": "1.0.0", "justinmimbs/date": "3.1.2", "norpan/elm-html5-drag-drop": "3.1.4", - "pablohirafuji/elm-qrcode": "3.3.1", + "pablohirafuji/elm-qrcode": "4.0.1", "ryannhg/date-format": "2.3.0", "truqu/elm-base64": "2.0.4", "ursi/elm-scroll": "1.0.0", @@ -33,7 +34,6 @@ "elm/bytes": "1.0.8", "elm/parser": "1.1.0", "elm/regex": "1.0.0", - "elm/svg": "1.0.1", "elm/virtual-dom": "1.0.2", "elm-community/list-extra": "8.2.4", "folkertdev/elm-flate": "2.0.4", diff --git a/modules/webapp/src/main/elm/App/Update.elm b/modules/webapp/src/main/elm/App/Update.elm index 19a689cb..66002c92 100644 --- a/modules/webapp/src/main/elm/App/Update.elm +++ b/modules/webapp/src/main/elm/App/Update.elm @@ -613,8 +613,19 @@ initPage model_ page = ] model - SharePage _ -> - ( model, Cmd.none, Sub.none ) + SharePage id -> + let + cmd = + Cmd.map ShareMsg (Page.Share.Data.initCmd id model.flags) + + shareModel = + model.shareModel + in + if shareModel.initialized then + ( model, Cmd.none, Sub.none ) + + else + ( { model | shareModel = { shareModel | initialized = True } }, cmd, Sub.none ) ShareDetailPage _ _ -> case model_.page of diff --git a/modules/webapp/src/main/elm/App/View2.elm b/modules/webapp/src/main/elm/App/View2.elm index 3dcaba5a..6e5652a5 100644 --- a/modules/webapp/src/main/elm/App/View2.elm +++ b/modules/webapp/src/main/elm/App/View2.elm @@ -451,6 +451,8 @@ viewShareDetail texts shareId itemId model = model.sidebarVisible model.flags model.uiSettings + shareId + itemId model.shareDetailModel ) , Html.map ShareDetailMsg diff --git a/modules/webapp/src/main/elm/Comp/ItemDetail/ShowQrCode.elm b/modules/webapp/src/main/elm/Comp/ItemDetail/ShowQrCode.elm index cfd1ae22..a6e3a96f 100644 --- a/modules/webapp/src/main/elm/Comp/ItemDetail/ShowQrCode.elm +++ b/modules/webapp/src/main/elm/Comp/ItemDetail/ShowQrCode.elm @@ -17,6 +17,7 @@ import Html.Attributes exposing (..) import Html.Events exposing (onClick) import QRCode import Styles as S +import Svg.Attributes as SvgA view : Flags -> String -> Model -> UrlId -> Html Msg @@ -111,7 +112,7 @@ type UrlId qrCodeView : String -> Html msg qrCodeView message = - QRCode.encode message - |> Result.map QRCode.toSvg + QRCode.fromString message + |> Result.map (QRCode.toSvg [ SvgA.class "w-64 h-64" ]) |> Result.withDefault (text "Error generating QR code") diff --git a/modules/webapp/src/main/elm/Comp/OtpSetup.elm b/modules/webapp/src/main/elm/Comp/OtpSetup.elm index 46db0f75..c972eb95 100644 --- a/modules/webapp/src/main/elm/Comp/OtpSetup.elm +++ b/modules/webapp/src/main/elm/Comp/OtpSetup.elm @@ -23,6 +23,7 @@ import Markdown import Messages.Comp.OtpSetup exposing (Texts) import QRCode import Styles as S +import Svg.Attributes as SvgA type Model @@ -389,8 +390,8 @@ viewDisabled texts model = qrCodeView : Texts -> String -> Html msg qrCodeView texts message = - QRCode.encode message - |> Result.map QRCode.toSvg + QRCode.fromString message + |> Result.map (QRCode.toSvg [ SvgA.class "w-64 h-64" ]) |> Result.withDefault (Html.text texts.errorGeneratingQR) diff --git a/modules/webapp/src/main/elm/Comp/ShareView.elm b/modules/webapp/src/main/elm/Comp/ShareView.elm index f7d4962f..dbb33752 100644 --- a/modules/webapp/src/main/elm/Comp/ShareView.elm +++ b/modules/webapp/src/main/elm/Comp/ShareView.elm @@ -14,6 +14,7 @@ import Html.Attributes exposing (..) import Messages.Comp.ShareView exposing (Texts) import QRCode import Styles as S +import Svg.Attributes as SvgA type alias ViewSettings = @@ -178,7 +179,7 @@ viewDisabled cfg texts share = qrCodeView : Texts -> String -> Html msg qrCodeView texts message = - QRCode.encode message - |> Result.map QRCode.toSvg + QRCode.fromString message + |> Result.map (QRCode.toSvg [ SvgA.class "w-64 h-64" ]) |> Result.withDefault (Html.text texts.qrCodeError) diff --git a/modules/webapp/src/main/elm/Comp/SourceManage.elm b/modules/webapp/src/main/elm/Comp/SourceManage.elm index 5ce42136..629ac18e 100644 --- a/modules/webapp/src/main/elm/Comp/SourceManage.elm +++ b/modules/webapp/src/main/elm/Comp/SourceManage.elm @@ -32,6 +32,7 @@ import Messages.Comp.SourceManage exposing (Texts) import Ports import QRCode import Styles as S +import Svg.Attributes as SvgA type alias Model = @@ -226,8 +227,8 @@ update flags msg model = qrCodeView : Texts -> String -> Html msg qrCodeView texts message = - QRCode.encode message - |> Result.map QRCode.toSvg + QRCode.fromString message + |> Result.map (QRCode.toSvg [ SvgA.class "w-64 h-64" ]) |> Result.withDefault (Html.text texts.errorGeneratingQR) diff --git a/modules/webapp/src/main/elm/Comp/UrlCopy.elm b/modules/webapp/src/main/elm/Comp/UrlCopy.elm new file mode 100644 index 00000000..2a6f048b --- /dev/null +++ b/modules/webapp/src/main/elm/Comp/UrlCopy.elm @@ -0,0 +1,95 @@ +module Comp.UrlCopy exposing (..) + +import Comp.Basic as B +import Html exposing (..) +import Html.Attributes exposing (..) +import Html.Events exposing (onClick) +import Ports +import QRCode +import Styles as S +import Svg.Attributes as SvgA + + +type Msg + = Print String + + +update : Msg -> Cmd msg +update msg = + case msg of + Print id -> + Ports.printElement id + + +initCopy : String -> Cmd msg +initCopy data = + Ports.initClipboard <| clipboardData data + + +clipboardData : String -> ( String, String ) +clipboardData data = + ( "share-url", "#button-share-url" ) + + +view : String -> Html Msg +view data = + let + ( elementId, buttonId ) = + clipboardData data + + btnId = + String.dropLeft 1 buttonId + + printId = + "print-qr-code" + in + div [ class "flex flex-col items-center" ] + [ div + [ class S.border + , class S.qrCode + , id printId + ] + [ qrCodeView data + ] + , div + [ class "flex w-64" + ] + [ p + [ id elementId + , class "font-mono text-xs py-2 mx-auto break-all" + ] + [ text data + ] + ] + , div [ class "flex flex-row mt-1 space-x-2 items-center w-full" ] + [ B.primaryButton + { label = "Copy" + , icon = "fa fa-copy" + , handler = href "#" + , disabled = False + , attrs = + [ id btnId + , class "flex flex-grow items-center justify-center" + , attribute "data-clipboard-target" ("#" ++ elementId) + ] + } + , B.primaryButton + { label = "Print" + , icon = "fa fa-print" + , handler = onClick (Print printId) + , disabled = False + , attrs = + [ href "#" + , class "flex flex-grow items-center justify-center" + ] + } + ] + ] + + +qrCodeView : String -> Html msg +qrCodeView message = + QRCode.fromString message + |> Result.map (QRCode.toSvg [ SvgA.class "w-64 h-64" ]) + |> Result.withDefault + (text "Error generating QR code") diff --git a/modules/webapp/src/main/elm/Messages/Page/Share.elm b/modules/webapp/src/main/elm/Messages/Page/Share.elm index f6b73d31..20884777 100644 --- a/modules/webapp/src/main/elm/Messages/Page/Share.elm +++ b/modules/webapp/src/main/elm/Messages/Page/Share.elm @@ -7,7 +7,9 @@ module Messages.Page.Share exposing (..) +import Http import Messages.Basics +import Messages.Comp.HttpError import Messages.Comp.ItemCardList import Messages.Comp.SearchMenu import Messages.Comp.SharePasswordForm @@ -18,6 +20,8 @@ type alias Texts = , basics : Messages.Basics.Texts , itemCardList : Messages.Comp.ItemCardList.Texts , passwordForm : Messages.Comp.SharePasswordForm.Texts + , httpError : Http.Error -> String + , authFailed : String } @@ -27,6 +31,8 @@ gb = , basics = Messages.Basics.gb , itemCardList = Messages.Comp.ItemCardList.gb , passwordForm = Messages.Comp.SharePasswordForm.gb + , authFailed = "This share does not exist." + , httpError = Messages.Comp.HttpError.gb } @@ -36,4 +42,6 @@ de = , basics = Messages.Basics.de , itemCardList = Messages.Comp.ItemCardList.de , passwordForm = Messages.Comp.SharePasswordForm.de + , authFailed = "Diese Freigabe existiert nicht." + , httpError = Messages.Comp.HttpError.de } diff --git a/modules/webapp/src/main/elm/Messages/Page/ShareDetail.elm b/modules/webapp/src/main/elm/Messages/Page/ShareDetail.elm index a9392d9a..70397991 100644 --- a/modules/webapp/src/main/elm/Messages/Page/ShareDetail.elm +++ b/modules/webapp/src/main/elm/Messages/Page/ShareDetail.elm @@ -1,28 +1,54 @@ module Messages.Page.ShareDetail exposing (..) +import Data.Fields exposing (Field) +import Http +import Messages.Basics +import Messages.Comp.HttpError import Messages.Comp.SharePasswordForm +import Messages.Data.Fields import Messages.DateFormat import Messages.UiLanguage exposing (UiLanguage(..)) type alias Texts = { passwordForm : Messages.Comp.SharePasswordForm.Texts + , basics : Messages.Basics.Texts + , field : Field -> String , formatDateLong : Int -> String , formatDateShort : Int -> String + , httpError : Http.Error -> String + , authFailed : String + , tagsAndFields : String + , noName : String + , unconfirmed : String } gb : Texts gb = { passwordForm = Messages.Comp.SharePasswordForm.gb + , basics = Messages.Basics.gb + , field = Messages.Data.Fields.gb , formatDateLong = Messages.DateFormat.formatDateLong English , formatDateShort = Messages.DateFormat.formatDateShort English + , authFailed = "This share does not exist." + , httpError = Messages.Comp.HttpError.gb + , tagsAndFields = "Tags & Fields" + , noName = "No name" + , unconfirmed = "Unconfirmed" } de : Texts de = { passwordForm = Messages.Comp.SharePasswordForm.de + , basics = Messages.Basics.de + , field = Messages.Data.Fields.de , formatDateLong = Messages.DateFormat.formatDateLong German , formatDateShort = Messages.DateFormat.formatDateShort German + , authFailed = "Diese Freigabe existiert nicht." + , httpError = Messages.Comp.HttpError.de + , tagsAndFields = "Tags & Felder" + , noName = "Kein Name" + , unconfirmed = "Nicht bestÃĪtigt" } diff --git a/modules/webapp/src/main/elm/Page.elm b/modules/webapp/src/main/elm/Page.elm index 2f42ee2e..a14e5295 100644 --- a/modules/webapp/src/main/elm/Page.elm +++ b/modules/webapp/src/main/elm/Page.elm @@ -116,6 +116,9 @@ hasSidebar page = SharePage _ -> True + ShareDetailPage _ _ -> + True + _ -> isSecured page diff --git a/modules/webapp/src/main/elm/Page/Share/Data.elm b/modules/webapp/src/main/elm/Page/Share/Data.elm index 4be43360..505f4908 100644 --- a/modules/webapp/src/main/elm/Page/Share/Data.elm +++ b/modules/webapp/src/main/elm/Page/Share/Data.elm @@ -5,7 +5,7 @@ -} -module Page.Share.Data exposing (Mode(..), Model, Msg(..), PageError(..), init) +module Page.Share.Data exposing (Mode(..), Model, Msg(..), PageError(..), init, initCmd) import Api import Api.Model.ItemLightList exposing (ItemLightList) @@ -41,6 +41,7 @@ type alias Model = , powerSearchInput : Comp.PowerSearchInput.Model , searchInProgress : Bool , itemListModel : Comp.ItemCardList.Model + , initialized : Bool } @@ -54,17 +55,27 @@ emptyModel flags = , powerSearchInput = Comp.PowerSearchInput.init , searchInProgress = False , itemListModel = Comp.ItemCardList.init + , initialized = False } init : Maybe String -> Flags -> ( Model, Cmd Msg ) init shareId flags = + let + em = + emptyModel flags + in case shareId of Just id -> - ( emptyModel flags, Api.verifyShare flags (ShareSecret id Nothing) VerifyResp ) + ( { em | initialized = True }, Api.verifyShare flags (ShareSecret id Nothing) VerifyResp ) Nothing -> - ( emptyModel flags, Cmd.none ) + ( em, Cmd.none ) + + +initCmd : String -> Flags -> Cmd Msg +initCmd shareId flags = + Api.verifyShare flags (ShareSecret shareId Nothing) VerifyResp type Msg diff --git a/modules/webapp/src/main/elm/Page/Share/View.elm b/modules/webapp/src/main/elm/Page/Share/View.elm index 49bf8803..924b4631 100644 --- a/modules/webapp/src/main/elm/Page/Share/View.elm +++ b/modules/webapp/src/main/elm/Page/Share/View.elm @@ -42,13 +42,18 @@ viewContent texts flags versionInfo uiSettings shareId model = ModeInitial -> div [ id "content" - , class "h-full w-full flex flex-col text-5xl" + , class "h-full w-full flex flex-col" , class S.content ] - [ B.loadingDimmer - { active = model.pageError == PageErrorNone - , label = "" - } + [ div [ class " text-5xl" ] + [ B.loadingDimmer + { active = model.pageError == PageErrorNone + , label = "" + } + ] + , div [ class "my-4 text-lg" ] + [ errorMessage texts model + ] ] ModePassword -> @@ -76,10 +81,28 @@ mainContent texts flags settings shareId model = [ text <| Maybe.withDefault "" model.verifyResult.name ] , Menubar.view texts model + , errorMessage texts model , Results.view texts settings flags shareId model ] +errorMessage : Texts -> Model -> Html Msg +errorMessage texts model = + case model.pageError of + PageErrorNone -> + span [ class "hidden" ] [] + + PageErrorAuthFail -> + div [ class S.errorMessage ] + [ text texts.authFailed + ] + + PageErrorHttp err -> + div [ class S.errorMessage ] + [ text (texts.httpError err) + ] + + passwordContent : Texts -> Flags -> VersionInfo -> Model -> Html Msg passwordContent texts flags versionInfo model = div diff --git a/modules/webapp/src/main/elm/Page/ShareDetail/Data.elm b/modules/webapp/src/main/elm/Page/ShareDetail/Data.elm index 08c412bd..0f262dab 100644 --- a/modules/webapp/src/main/elm/Page/ShareDetail/Data.elm +++ b/modules/webapp/src/main/elm/Page/ShareDetail/Data.elm @@ -5,6 +5,7 @@ import Api.Model.ItemDetail exposing (ItemDetail) import Api.Model.ShareSecret exposing (ShareSecret) import Api.Model.ShareVerifyResult exposing (ShareVerifyResult) import Comp.SharePasswordForm +import Comp.UrlCopy import Data.Flags exposing (Flags) import Http @@ -27,6 +28,8 @@ type alias Model = , passwordModel : Comp.SharePasswordForm.Model , viewMode : ViewMode , pageError : PageError + , attachMenuOpen : Bool + , visibleAttach : Int } @@ -34,6 +37,9 @@ type Msg = VerifyResp (Result Http.Error ShareVerifyResult) | GetItemResp (Result Http.Error ItemDetail) | PasswordMsg Comp.SharePasswordForm.Msg + | SelectActiveAttachment Int + | ToggleSelectAttach + | UrlCopyMsg Comp.UrlCopy.Msg emptyModel : ViewMode -> Model @@ -43,14 +49,18 @@ emptyModel vm = , passwordModel = Comp.SharePasswordForm.init , viewMode = vm , pageError = PageErrorNone + , attachMenuOpen = False + , visibleAttach = 0 } init : Maybe ( String, String ) -> Flags -> ( Model, Cmd Msg ) init mids flags = case mids of - Just ( shareId, _ ) -> - ( emptyModel ViewLoading, Api.verifyShare flags (ShareSecret shareId Nothing) VerifyResp ) + Just ( shareId, itemId ) -> + ( emptyModel ViewLoading + , Api.verifyShare flags (ShareSecret shareId Nothing) VerifyResp + ) Nothing -> ( emptyModel ViewLoading, Cmd.none ) diff --git a/modules/webapp/src/main/elm/Page/ShareDetail/Update.elm b/modules/webapp/src/main/elm/Page/ShareDetail/Update.elm index 40aa5757..93ddabe2 100644 --- a/modules/webapp/src/main/elm/Page/ShareDetail/Update.elm +++ b/modules/webapp/src/main/elm/Page/ShareDetail/Update.elm @@ -2,7 +2,9 @@ module Page.ShareDetail.Update exposing (update) import Api import Comp.SharePasswordForm +import Comp.UrlCopy import Data.Flags exposing (Flags) +import Page exposing (Page(..)) import Page.ShareDetail.Data exposing (..) @@ -36,12 +38,16 @@ update shareId itemId flags msg model = ( { model | pageError = PageErrorHttp err }, Cmd.none ) GetItemResp (Ok item) -> + let + url = + Page.pageToString (ShareDetailPage shareId itemId) + in ( { model | item = item , viewMode = ViewNormal , pageError = PageErrorNone } - , Cmd.none + , Comp.UrlCopy.initCopy url ) GetItemResp (Err err) -> @@ -62,3 +68,21 @@ update shareId itemId flags msg model = Nothing -> ( { model | passwordModel = m }, Cmd.map PasswordMsg c ) + + SelectActiveAttachment pos -> + ( { model + | visibleAttach = pos + , attachMenuOpen = False + } + , Cmd.none + ) + + ToggleSelectAttach -> + ( { model | attachMenuOpen = not model.attachMenuOpen }, Cmd.none ) + + UrlCopyMsg lm -> + let + cmd = + Comp.UrlCopy.update lm + in + ( model, cmd ) diff --git a/modules/webapp/src/main/elm/Page/ShareDetail/View.elm b/modules/webapp/src/main/elm/Page/ShareDetail/View.elm index 7d06fc65..56ef7cbb 100644 --- a/modules/webapp/src/main/elm/Page/ShareDetail/View.elm +++ b/modules/webapp/src/main/elm/Page/ShareDetail/View.elm @@ -1,30 +1,41 @@ module Page.ShareDetail.View exposing (viewContent, viewSidebar) import Api +import Api.Model.Attachment exposing (Attachment) import Api.Model.VersionInfo exposing (VersionInfo) import Comp.Basic as B import Comp.SharePasswordForm +import Comp.UrlCopy +import Data.Fields import Data.Flags exposing (Flags) import Data.Icons as Icons import Data.ItemTemplate as IT exposing (ItemTemplate) import Data.UiSettings exposing (UiSettings) import Html exposing (..) import Html.Attributes exposing (..) +import Html.Events exposing (onClick) import Messages.Page.ShareDetail exposing (Texts) import Page exposing (Page(..)) import Page.ShareDetail.Data exposing (..) import Styles as S import Util.CustomField import Util.Item +import Util.List +import Util.Size +import Util.String -viewSidebar : Texts -> Bool -> Flags -> UiSettings -> Model -> Html Msg -viewSidebar texts visible flags settings model = +viewSidebar : Texts -> Bool -> Flags -> UiSettings -> String -> String -> Model -> Html Msg +viewSidebar texts visible flags settings shareId itemId model = div [ id "sidebar" - , class "hidden" + , classList [ ( "hidden", not visible ) ] + , class S.sidebar + ] + [ div [ class "pt-2" ] + [ itemData texts flags model shareId itemId + ] ] - [] viewContent : Texts -> Flags -> UiSettings -> VersionInfo -> String -> String -> Model -> Html Msg @@ -36,10 +47,15 @@ viewContent texts flags uiSettings versionInfo shareId itemId model = , class "h-full w-full flex flex-col text-5xl" , class S.content ] - [ B.loadingDimmer - { active = model.pageError == PageErrorNone - , label = "" - } + [ div [ class "text-5xl" ] + [ B.loadingDimmer + { active = model.pageError == PageErrorNone + , label = "" + } + ] + , div [ class "my-4 text-lg" ] + [ errorMessage texts model + ] ] ViewPassword -> @@ -60,18 +76,18 @@ mainContent texts flags settings shareId model = , class S.content ] [ itemHead texts shareId model - , div [ class "flex flex-col sm:flex-row sm:space-x-4 relative h-full" ] - [ itemData texts model - , itemPreview texts flags settings model + , errorMessage texts model + , div [ class "relative h-full" ] + [ itemPreview texts flags settings model ] ] -itemData : Texts -> Model -> Html Msg -itemData texts model = +itemData : Texts -> Flags -> Model -> String -> String -> Html Msg +itemData texts flags model shareId itemId = let boxStyle = - "mb-4 sm:mb-6 max-w-sm" + "mb-4 sm:mb-6" headerStyle = "py-2 bg-blue-50 hover:bg-blue-100 dark:bg-bluegray-700 dark:hover:bg-opacity-100 dark:hover:bg-bluegray-600 text-lg font-medium rounded-lg" @@ -92,11 +108,11 @@ itemData texts model = ] Nothing in - div [ class "flex flex-col pr-2 sm:w-1/3" ] + div [ class "flex flex-col" ] [ div [ class boxStyle ] [ div [ class headerStyle ] [ Icons.dateIcon2 "mr-2 ml-2" - , text "Date" + , text (texts.field Data.Fields.Date) ] , div [ class "text-lg ml-2" ] [ Util.Item.toItemLight model.item @@ -104,10 +120,24 @@ itemData texts model = |> text ] ] + , div + [ class boxStyle + , classList [ ( "hidden", model.item.dueDate == Nothing ) ] + ] + [ div [ class headerStyle ] + [ Icons.dueDateIcon2 "mr-2 ml-2" + , text (texts.field Data.Fields.DueDate) + ] + , div [ class "text-lg ml-2" ] + [ Util.Item.toItemLight model.item + |> IT.render IT.dueDateLong (templateCtx texts) + |> text + ] + ] , div [ class boxStyle ] [ div [ class headerStyle ] [ Icons.tagsIcon2 "mr-2 ml-2" - , text "Tags & Fields" + , text texts.tagsAndFields ] , div [ class "flex flex-row items-center flex-wrap font-medium my-1" ] (List.map showTag model.item.tags ++ List.map showField model.item.customfields) @@ -115,7 +145,7 @@ itemData texts model = , div [ class boxStyle ] [ div [ class headerStyle ] [ Icons.correspondentIcon2 "mr-2 ml-2" - , text "Correspondent" + , text texts.basics.correspondent ] , div [ class "text-lg ml-2" ] [ Util.Item.toItemLight model.item @@ -126,7 +156,7 @@ itemData texts model = , div [ class boxStyle ] [ div [ class headerStyle ] [ Icons.concernedIcon2 "mr-2 ml-2" - , text "Concerning" + , text texts.basics.concerning ] , div [ class "text-lg ml-2" ] [ Util.Item.toItemLight model.item @@ -134,40 +164,110 @@ itemData texts model = |> text ] ] + , div [ class boxStyle ] + [ div [ class headerStyle ] + [ i [ class "fa fa-copy mr-2 ml-2" ] [] + , text "Copy URL" + ] + , div [ class "flex flex-col items-center py-2" ] + [ Html.map UrlCopyMsg + (Comp.UrlCopy.view + (flags.config.baseUrl + ++ Page.pageToString + (ShareDetailPage shareId itemId) + ) + ) + ] + ] ] itemPreview : Texts -> Flags -> UiSettings -> Model -> Html Msg itemPreview texts flags settings model = let - id = - List.head model.item.attachments - |> Maybe.map .id - |> Maybe.withDefault "" + attach = + Util.List.get model.item.attachments model.visibleAttach + |> Maybe.withDefault Api.Model.Attachment.empty + + attachName = + Maybe.withDefault (texts.noName ++ ".pdf") attach.name in div - [ class "flex flex-grow" - , style "min-height" "500px" + [ class "flex flex-grow flex-col h-full border-t dark:border-bluegray-600" ] - [ embed - [ src (Data.UiSettings.pdfUrl settings flags (Api.shareFileURL id)) - , class " h-full w-full mx-0 py-0" + [ div [ class "flex flex-col sm:flex-row items-center py-1 px-1 border-l border-r dark:border-bluegray-600" ] + [ div [ class "text-base font-bold flex-grow w-full text-center sm:text-left break-all" ] + [ text attachName + , text " (" + , text (Util.Size.bytesReadable Util.Size.B (toFloat attach.size)) + , text ")" + ] + , div [ class "flex flex-row space-x-2" ] + [ B.secondaryBasicButton + { label = "" + , icon = "fa fa-eye" + , disabled = False + , handler = href (Api.shareFileURL attach.id) + , attrs = + [ target "_new" + ] + } + , B.secondaryBasicButton + { label = "" + , icon = "fa fa-download" + , disabled = False + , handler = href (Api.shareFileURL attach.id) + , attrs = + [ download attachName + ] + } + , B.secondaryBasicButton + { label = "" + , icon = "fa fa-ellipsis-v" + , disabled = False + , handler = onClick ToggleSelectAttach + , attrs = + [ href "#" + , classList [ ( "hidden", List.length model.item.attachments <= 1 ) ] + ] + } + ] + ] + , attachmentSelect texts model + , div + [ class "flex w-full h-full mb-4 border-b border-l border-r dark:border-bluegray-600" + , style "min-height" "500px" + ] + [ embed + [ src (Data.UiSettings.pdfUrl settings flags (Api.shareFileURL attach.id)) + , class " h-full w-full mx-0 py-0" + ] + [] ] - [] ] itemHead : Texts -> String -> Model -> Html Msg itemHead texts shareId model = - div [ class "flex flex-col sm:flex-row" ] + div [ class "flex flex-col sm:flex-row mt-1" ] [ div [ class "flex flex-grow items-center" ] - [ h1 [ class S.header1 ] + [ h1 + [ class S.header1 + , class "items-center flex flex-row" + ] [ text model.item.name + , span + [ classList [ ( "hidden", model.item.state /= "created" ) ] + , class S.blueBasicLabel + , class "inline ml-4 text-sm" + ] + [ text texts.unconfirmed + ] ] ] , div [ class "flex flex-row items-center justify-end mb-2 sm:mb-0" ] [ B.secondaryBasicButton - { label = "Close" + { label = texts.basics.back , icon = "fa fa-times" , disabled = False , handler = Page.href (SharePage shareId) @@ -189,6 +289,83 @@ passwordContent texts flags versionInfo model = ] +attachmentSelect : Texts -> Model -> Html Msg +attachmentSelect texts model = + div + [ class "flex flex-row border-l border-t border-r px-2 py-2 dark:border-bluegray-600 " + , class "overflow-x-auto overflow-y-none" + , classList + [ ( "hidden", not model.attachMenuOpen ) + ] + ] + (List.indexedMap (menuItem texts model) model.item.attachments) + + +menuItem : Texts -> Model -> Int -> Attachment -> Html Msg +menuItem texts model pos attach = + let + iconClass = + "fa fa-circle ml-1" + + visible = + model.visibleAttach == pos + in + a + [ classList <| + [ ( "border-blue-500 dark:border-lightblue-500", pos == 0 ) + , ( "dark:border-bluegray-600", pos /= 0 ) + ] + , class "flex flex-col relative border rounded px-1 py-1 mr-2" + , class " hover:shadow dark:hover:border-bluegray-500" + , href "#" + , onClick (SelectActiveAttachment pos) + ] + [ div + [ classList + [ ( "hidden", not visible ) + ] + , class "absolute right-1 top-1 text-blue-400 dark:text-lightblue-400 text-xl" + ] + [ i [ class iconClass ] [] + ] + , div [ class "flex-grow" ] + [ img + [ src (Api.shareAttachmentPreviewURL attach.id) + , class "block w-20 mx-auto" + ] + [] + ] + , div [ class "mt-1 text-sm break-all w-28 text-center" ] + [ Maybe.map (Util.String.ellipsis 36) attach.name + |> Maybe.withDefault texts.noName + |> text + ] + ] + + +errorMessage : Texts -> Model -> Html Msg +errorMessage texts model = + case model.pageError of + PageErrorNone -> + span [ class "hidden" ] [] + + PageErrorAuthFail -> + div + [ class S.errorMessage + , class "my-4" + ] + [ text texts.authFailed + ] + + PageErrorHttp err -> + div + [ class S.errorMessage + , class "my-4" + ] + [ text (texts.httpError err) + ] + + templateCtx : Texts -> IT.TemplateContext templateCtx texts = { dateFormatLong = texts.formatDateLong diff --git a/modules/webapp/src/main/elm/Styles.elm b/modules/webapp/src/main/elm/Styles.elm index 2c8167dd..645d2324 100644 --- a/modules/webapp/src/main/elm/Styles.elm +++ b/modules/webapp/src/main/elm/Styles.elm @@ -10,7 +10,7 @@ module Styles exposing (..) sidebar : String sidebar = - " flex flex-col flex-none md:w-80 w-full min-h-max px-2 dark:text-gray-200 shadow overflow-y-auto h-full transition-opacity transition-duration-200 scrollbar-thin scrollbar-light-sidebar dark:scrollbar-dark-sidebar" + " flex flex-col flex-none md:w-80 w-full min-h-max px-2 dark:text-gray-200 overflow-y-auto h-full transition-opacity transition-duration-200 scrollbar-thin scrollbar-light-sidebar dark:scrollbar-dark-sidebar" sidebarBg : String @@ -100,6 +100,11 @@ basicLabel = " label border-gray-600 text-gray-600 dark:border-bluegray-300 dark:text-bluegray-300 " +blueBasicLabel : String +blueBasicLabel = + " label border-blue-500 text-blue-500 dark:border-lightblue-200 dark:text-lightblue-200 " + + --- Primary Button diff --git a/modules/webapp/src/main/webjar/docspell.js b/modules/webapp/src/main/webjar/docspell.js index a5518163..ef4ef03c 100644 --- a/modules/webapp/src/main/webjar/docspell.js +++ b/modules/webapp/src/main/webjar/docspell.js @@ -127,8 +127,10 @@ elmApp.ports.printElement.subscribe(function(id) { w.document.write(''); } w.document.write(''); + w.document.write(''); + w.document.write(''); w.document.write(''); } }