diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index b0a037e0e..000000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,32 +0,0 @@ -version: 2 -updates: -- package-ecosystem: pip - directory: "/" - schedule: - interval: weekly - time: "10:00" - open-pull-requests-limit: 10 - target-branch: develop - ignore: - - dependency-name: ipdb - versions: - - 0.13.4 - - 0.13.5 - - 0.13.6 - - dependency-name: django-crispy-forms - versions: - - 1.10.0 - - 1.11.0 - - 1.11.1 - - dependency-name: django - versions: - - 2.2.13 - - dependency-name: coverage - versions: - - "5.4" - - dependency-name: pytest-django - versions: - - 4.1.0 - - dependency-name: wagtail - versions: - - 2.9.3 diff --git a/LICENSE.md b/LICENSE.md index 310f5fc5f..a148280a3 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -186,6 +186,7 @@ third-party archives. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, diff --git a/apps/cms/models.py b/apps/cms/models.py index 08f6bdea2..a40719de2 100644 --- a/apps/cms/models.py +++ b/apps/cms/models.py @@ -46,7 +46,7 @@ class CollectionsPage(Page): FieldPanel('paragraph', classname="full"), FieldPanel('layout', classname="full"), ] - initial = {"sort": "title", "order": "asc", "display": "grid"} + initial = {"sort": "title", "order": "asc", "display": "grid", "per_page": "60"} sort_fields = { "title": "label", "added": "created_at", @@ -99,7 +99,15 @@ def get_context(self, request): form = self.get_form(request) query_set = self.get_queryset(form, self.collections) - paginator = Paginator(query_set, 8) # Show 8 collections per page + per_page_default = int(self.initial.get("per_page", 20)) + per_page = per_page_default + if form.is_valid(): + try: + per_page = int(form.cleaned_data.get("per_page") or per_page_default) + except (TypeError, ValueError): + per_page = per_page_default + + paginator = Paginator(query_set, per_page) page = request.GET.get("page", 1) try: @@ -142,7 +150,7 @@ class VolumesPage(Page): FieldPanel('paragraph', classname="full"), FieldPanel('layout', classname="full"), ] - initial = {"sort": "title", "order": "asc", "display": "grid"} + initial = {"sort": "title", "order": "asc", "display": "grid", "per_page": "60"} sort_fields = { "title": "label", "author": "author", @@ -197,7 +205,15 @@ def get_context(self, request): form = self.get_form(request) query_set = self.get_queryset(form, self.volumes) - paginator = Paginator(query_set, 8) # Show 8 volumes per page + per_page_default = int(self.initial.get("per_page", 60)) + per_page = per_page_default + if form.is_valid(): + try: + per_page = int(form.cleaned_data.get("per_page") or per_page_default) + except (TypeError, ValueError): + per_page = per_page_default + + paginator = Paginator(query_set, per_page) # Show volumes per selected page size page = request.GET.get("page", 1) try: diff --git a/apps/iiif/manifests/models.py b/apps/iiif/manifests/models.py index 779cf38d4..378ddaca6 100644 --- a/apps/iiif/manifests/models.py +++ b/apps/iiif/manifests/models.py @@ -272,6 +272,17 @@ class Meta: # pylint: disable = too-few-public-methods, missing-class-docstring ordering = ["published_date"] # indexes = [GinIndex(fields=['search_vector'])] + @property + def authors(self): + """Convert authors string into list + + :return: List of authors or ["[no author]"] if author field is empty + :rtype: list + """ + if self.author: + return [s.strip() for s in self.author.split(";")] + return ["[no author]"] + @property def publisher_bib(self): """Concatenated property for bib citation. diff --git a/apps/iiif/manifests/tests/tests.py b/apps/iiif/manifests/tests/tests.py index 1370ec18e..1ec4f5a78 100644 --- a/apps/iiif/manifests/tests/tests.py +++ b/apps/iiif/manifests/tests/tests.py @@ -94,6 +94,28 @@ def test_properties(self): "/iiif/%s/canvas/%s" % (self.volume.pid, self.start_canvas.pid) ) + def test_authors_property(self): + """Test the authors property returns a list of authors from the author field.""" + # Test with no author + manifest = Manifest(author=None) + assert manifest.authors == ["[no author]"] + + # Test with empty string + manifest = Manifest(author="") + assert manifest.authors == ["[no author]"] + + # Test with single author + manifest = Manifest(author="John Doe") + assert manifest.authors == ["John Doe"] + + # Test with multiple authors separated by semicolon + manifest = Manifest(author="John Doe; Jane Smith") + assert manifest.authors == ["John Doe", "Jane Smith"] + + # Test with multiple authors with extra whitespace + manifest = Manifest(author="John Doe ; Jane Smith ; Bob Jones") + assert manifest.authors == ["John Doe", "Jane Smith", "Bob Jones"] + def test_default_start_canvas(self): image_server = ImageServerFactory.create(server_base="https://fake.info") manifest = Manifest(image_server=image_server) diff --git a/apps/readux/forms.py b/apps/readux/forms.py index 3630976bd..9bd567870 100644 --- a/apps/readux/forms.py +++ b/apps/readux/forms.py @@ -52,6 +52,12 @@ def valid_value(self, value): class ManifestSearchForm(forms.Form): """Django form for searching Manifests via Elasticsearch""" + PER_PAGE_CHOICES = [ + ("20", "20"), + ("40", "40"), + ("60", "60"), + ("100", "100"), + ] q = forms.CharField( label="Search for individual whole keywords. Multiple words will be searched as 'or' (e.g. Rome London = Rome or London).", required=False, @@ -73,11 +79,7 @@ class ManifestSearchForm(forms.Form): ("metadata", "Metadata only"), ("text", "Textual contents only"), ), - widget=forms.Select( - attrs={ - "class": "uk-select", - }, - ), + widget=forms.Select(attrs={"class": "uk-select"}), ) language = FacetedMultipleChoiceField( label="Language", @@ -121,9 +123,32 @@ class ManifestSearchForm(forms.Form): ("-label_alphabetical", "Title (Z-A)"), ("_score", "Relevance"), ), + widget=forms.Select(attrs={"class": "uk-select"}), + ) + display = forms.ChoiceField( + label="View mode", + required=False, + choices=( + ("list", "List view"), + ("grid", "Grid view"), + ), + initial="list", widget=forms.Select( attrs={ "class": "uk-select", + "aria-label": "Select view mode", + }, + ), + ) + per_page = forms.ChoiceField( + label="Items per page", + required=False, + choices=PER_PAGE_CHOICES, + initial="60", + widget=forms.Select( + attrs={ + "class": "uk-select", + "aria-label": "Items per page", }, ), ) @@ -222,6 +247,12 @@ class AllVolumesForm(forms.Form): ("asc", "Ascending"), ("desc", "Descending"), ] + PER_PAGE_CHOICES = [ + ("20", "20"), + ("40", "40"), + ("60", "60"), + ("100", "100"), + ] sort = forms.ChoiceField( label="Sort by", choices=SORT_CHOICES, @@ -234,6 +265,13 @@ class AllVolumesForm(forms.Form): required=False, widget=CustomDropdownSelect, ) + per_page = forms.ChoiceField( + label="Items per page", + choices=PER_PAGE_CHOICES, + required=False, + initial="60", + widget=CustomDropdownSelect, + ) class AllCollectionsForm(forms.Form): @@ -248,6 +286,12 @@ class AllCollectionsForm(forms.Form): ("asc", "Ascending"), ("desc", "Descending"), ] + PER_PAGE_CHOICES = [ + ("20", "20"), + ("40", "40"), + ("60", "60"), + ("100", "100"), + ] sort = forms.ChoiceField( label="Sort by", choices=SORT_CHOICES, @@ -260,3 +304,10 @@ class AllCollectionsForm(forms.Form): required=False, widget=CustomDropdownSelect, ) + per_page = forms.ChoiceField( + label="Items per page", + choices=PER_PAGE_CHOICES, + required=False, + initial="60", + widget=CustomDropdownSelect, + ) diff --git a/apps/readux/templatetags/readux_extras.py b/apps/readux/templatetags/readux_extras.py index 5e0b53db9..1e2912f50 100644 --- a/apps/readux/templatetags/readux_extras.py +++ b/apps/readux/templatetags/readux_extras.py @@ -19,6 +19,42 @@ def dict_item(dictionary, key): return None +@register.filter +def attr(obj, attr_name): + """Safely access an attribute on an object without raising if missing.""" + try: + return getattr(obj, attr_name) + except AttributeError: + return None + + +@register.filter +def manifest_year(volume): + """Return a 4-digit published year from a manifest or hit object.""" + # try standard published_date first + published = getattr(volume, "published_date", None) + if published: + # handle datetime/date objects with a year attribute + year = getattr(published, "year", None) + if year: + return f"{int(year):04d}" + # fall back to parsing string content + match = re.search(r"\d{4}", str(published)) + if match: + return match.group(0) + return str(published)[:4] + + # fall back to elasticsearch stored string (may be missing on some hits) + edtf = getattr(volume, "published_date_edtf", None) + if edtf: + match = re.search(r"\d{4}", str(edtf)) + if match: + return match.group(0) + return str(edtf)[:4] + + return "" + + @register.filter def has_inner_hits(volume): """Template filter to determine if there are any inner hits across the volume""" @@ -84,3 +120,21 @@ def vimeo_embed_url(vimeo_url): # get the embed url from a vimeo link # i.e. https://vimeo.com/76979871 --> https://player.vimeo.com/video/76979871 return re.sub(r"vimeo\.com\/(\d+)", r"player.vimeo.com/video/\1", vimeo_url) + + +@register.filter +def spaced_semicolons(value): + """Ensure a single space follows each semicolon in a metadata string.""" + try: + return re.sub(r";\s*", "; ", str(value)) + except TypeError: + return value + + +@register.filter +def strip_trailing_commas(value): + """Remove any trailing commas and surrounding whitespace.""" + try: + return re.sub(r",\s*$", "", str(value)) + except TypeError: + return value diff --git a/apps/readux/views.py b/apps/readux/views.py index 866dbca4a..b7ed06d84 100644 --- a/apps/readux/views.py +++ b/apps/readux/views.py @@ -37,7 +37,7 @@ class CollectionDetail(DetailView, FormMixin): slug_url_kwarg = "collection" form_class = AllVolumesForm model = Collection - initial = {"sort": "title", "order": "asc", "display": "grid"} + initial = {"sort": "title", "order": "asc", "display": "grid", "per_page": "60"} sort_fields = { "title": "label", "author": "author", @@ -60,9 +60,9 @@ def get_form_kwargs(self): return kwargs - def get_volumes(self): + def get_volumes(self, form=None): """Get the sorted set of volumes to display""" - form = self.get_form() + form = form or self.get_form() collection = self.get_object() queryset = collection.manifests.all() @@ -93,11 +93,19 @@ def get_volumes(self): def get_context_data(self, **kwargs): """Context function.""" context = super().get_context_data(**kwargs) + form = self.get_form() + volumes = self.get_volumes(form=form) - volumes = self.get_volumes() + per_page_default = int(self.initial.get("per_page", 60)) + per_page = per_page_default + if form.is_valid(): + try: + per_page = int(form.cleaned_data.get("per_page") or per_page_default) + except (TypeError, ValueError): + per_page = per_page_default # add paginator manually since this isn't a ListView - paginator = Paginator(volumes, 8) # Show 8 volumes per page + paginator = Paginator(volumes, per_page) page = self.request.GET.get("page", 1) try: @@ -113,17 +121,7 @@ def get_context_data(self, **kwargs): context.update( { "volumes": volumes, - "user_annotation": UserAnnotation.objects.filter( - owner_id=self.request.user.id - ), - "paginator_range": paginator.get_elided_page_range( - page, on_each_side=2 - ), - } - ) - context.update( - { - "volumes": volumes, + "form": form, "user_annotation": UserAnnotation.objects.filter( owner_id=self.request.user.id ), @@ -335,7 +333,7 @@ class VolumeSearchView(ListView, FormMixin): form_class = ManifestSearchForm template_name = "search_results.html" context_object_name = "volumes" - paginate_by = 25 + paginate_by = 20 # default fields to search when using query box; ^ with number indicates a boosted field query_search_fields = ["pid", "label^5", "summary^2", "author"] @@ -355,7 +353,7 @@ class VolumeSearchView(ListView, FormMixin): ), ), ] - defaults = {"sort": "label_alphabetical"} + defaults = {"sort": "label_alphabetical", "display": "list", "per_page": "60"} def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -404,6 +402,17 @@ def get_form_kwargs(self): kwargs["data"] = form_data return kwargs + def get_paginate_by(self, queryset): + """Allow per-page size selection via form.""" + form = self.get_form() + default_per_page = int(self.defaults.get("per_page", 20)) + if form.is_valid(): + try: + return int(form.cleaned_data.get("per_page") or default_per_page) + except (TypeError, ValueError): + return default_per_page + return default_per_page + def get_context_data(self, **kwargs): context_data = super().get_context_data(**kwargs) # add configured custom metadata keys to context data @@ -449,6 +458,39 @@ def get_context_data(self, **kwargs): getattr(max_date, "value_as_string"), ) + # Attach start_canvas to each volume in the current page. + # Handle both: paginator page and raw list-like. + vol_page = context_data.get("volumes") + + if vol_page is not None: + # Get the underlying sequence (Paginator Page vs list) + items = getattr(vol_page, "object_list", vol_page) + + # ES hits should have a "pid"; collect them + pids = [getattr(v, "pid", None) for v in items if getattr(v, "pid", None)] + + if pids: + # Use the default reverse name: canvas_set + manifests = { + m.pid: m + for m in Manifest.objects + .filter(pid__in=pids) + .prefetch_related("canvas_set") + } + + for v in items: + pid = getattr(v, "pid", None) + m = manifests.get(pid) + if not m: + v.start_canvas = None + continue + + # Prefer an explicitly marked starting page, else first by position + start = m.canvas_set.filter(is_starting_page=True).order_by("position").first() + if start is None: + start = m.canvas_set.order_by("position").first() + v.start_canvas = start + return context_data def get_queryset(self): diff --git a/apps/static/css/_components/colors.scss b/apps/static/css/_components/colors.scss deleted file mode 100644 index 8e29e511e..000000000 --- a/apps/static/css/_components/colors.scss +++ /dev/null @@ -1,6 +0,0 @@ -// Colors -$rx-color-grey-1: #595959; -$rx-color-grey-2: #737373; -$rx-color-grey-3: #eeeeee; -$rx-color-accent-1: #950953; -$rx-color-accent-2: #510029; \ No newline at end of file diff --git a/apps/static/css/readux2/collection.scss b/apps/static/css/components/collection.scss similarity index 50% rename from apps/static/css/readux2/collection.scss rename to apps/static/css/components/collection.scss index f85061614..385b5a350 100644 --- a/apps/static/css/readux2/collection.scss +++ b/apps/static/css/components/collection.scss @@ -1,27 +1,40 @@ +@import '../partials/colors'; +@import '../partials/_mixin.scss'; + +#modal-full p { + color: $color-white; + ; +} + +#modal-full h2 { + font-size: xx-large; +} + .full-width-bg { background-size: cover; background-position: center; position: relative; - height: 50vh; - color: white; + height: auto; + color: $color-white; } .overlay { - background: linear-gradient(to right, rgba(0, 0, 0, 0.8) 0%, rgba(0, 0, 0, 0.6) 100%); - height: 50vh; + background: linear-gradient(to right, rgba($color-black, 0.8) 0%, rgba($color-black, 0.6) 100%); width: 33%; - position: absolute; - top: 0; - left: 0; + position: relative; + height: auto; + min-height: 0; padding: 50px; box-sizing: border-box; - min-height: 0; + color: $color-white; } .overlay h1 { font-size: 2rem; /* Reduced title size */ margin-bottom: 15px; + color: $color-white; + } .overlay p { @@ -29,14 +42,15 @@ /* Adjusted font size */ line-height: 1.5; /* Reduced line-height */ + color: $color-white; } .description-button { margin-top: 20px; - background-color: #E60000; + background-color: $rx-color-mario-red; /* Removed gradient background */ border: none; - color: white; + color: $color-white; font-weight: bold; height: 40px; border-radius: 5px; @@ -47,23 +61,17 @@ transition: background-color 0.3s ease; } -// .uk-button-default { -// background-color: #222; /* Removed gradient background */ -// border: none; -// color: white; -// } - .modal-bg { background-size: cover; background-position: center; position: relative; height: 100%; width: 100%; - color: white; + color: $color-white; } .modal-overlay { - background: rgba(0, 0, 0, 0.6); + background: rgba($color-black, 0.6); /* Dark overlay */ height: 100%; width: 100%; @@ -83,11 +91,38 @@ z-index: 1; } -.uk-modal-close-full { - color: white; - /* Set the close button color to white */ - background: none; - /* Remove the background */ - border: none; - /* Remove any borders */ -} \ No newline at end of file +.rx-collection-modal { + h1, + h2, + h3, + h4, + h5, + h6, + p { + color: $color-white; + } + + h2 { + margin-bottom: 1rem; + } + + a { + color: $rx-color-faded-mint; + text-decoration: underline; + @include link-variant($rx-color-faded-mint, 600, true); + &:hover, + &:active { + color: $color-white; + text-decoration: underline; + } + } + + .uk-close { + color: $color-white; + &:hover { + color: darken($color-white, 10%); + } + background: none; + border: none; + } +} diff --git a/apps/static/css/components/flatpage.scss b/apps/static/css/components/flatpage.scss new file mode 100644 index 000000000..af373fb8b --- /dev/null +++ b/apps/static/css/components/flatpage.scss @@ -0,0 +1,143 @@ +@import '../partials/colors'; + +.navigation { + background-color: $rx-color-faded-mint; + padding: 30px; + position: sticky; + top: 20px; + border-radius: 10px 10px; /* Rounded corners on the right-hand side */ + width: auto; /* Fit to content width */ +} + +.navigation a { + color: $rx-color-midnight-blue; + text-decoration: none; + display: block; + padding: 5px 15px !important; + position: relative; + font-weight: normal; + font-size: medium; +} + +.navigation a.active { + font-weight: bold; /* Bold text for active item */ + color: $rx-color-midnight-blue; + + &:hover { + color: darken($rx-color-midnight-blue, 10%) !important; + } +} + +.navigation a.active::before { + content: ''; + position: absolute; + left: 3px; + top: 50%; + transform: translateY(-50%); + height: 75%; + width: 4px; + background-color: $rx-color-midnight-blue; +} + +.content { + padding: 40px; +} + +.section { + padding-bottom: 40px; +} + +.static-content-title { + font-weight: bold; + margin: unset; +} + +.content p, .content ul { + margin-top: 0; + margin-bottom: 1rem; + color: $color-black; +} + +.content ol, .content li { + margin-top: 0; + color: $color-black; +} + +$content-heading-sizes: ( + h1: 2.5rem, + h2: 2rem, + h3: 1.5rem, + h4: 1.25rem, + h5: 1rem, + h6: 0.75rem +); + +.content { + h1, h2, h3, h4, h5, h6 { + margin-top: 1.25rem !important; + margin-bottom: 0.5rem !important; + } + + @each $heading, $size in $content-heading-sizes { + #{$heading} { + font-size: $size; + } + } +} + +.content li:first-of-type, +.content p:first-of-type { + margin-top: 0; +} + +.content ul:first-of-type { + margin-top: 0.5rem; +} + +.content li:last-of-type { + margin-bottom: 0; +} + +/* a series of indentation for the side nav headers */ +.indent-h1 a { + color: $rx-color-midnight-blue !important; +} + +.indent-h2 a { + color: $rx-color-midnight-blue !important; +} + +.indent-h3 a { + color: $rx-color-midnight-blue !important; + margin-left: 1.5rem; +} + +.indent-h4 a { + color: $rx-color-midnight-blue !important; + margin-left: 2.5rem; +} + +.content ul, .content ol { + padding-left: 1.75rem !important; + li { + margin-bottom: 0.5rem !important; + } +} + +.content ul { + list-style: disc !important; +} + +.content ol { + list-style: decimal !important; +} + +blockquote { + border-left: 4px solid $rx-color-linen-blue !important; + padding-left: 1rem !important; + color: darken($color-black, 10%) !important; + margin: 1rem 0 !important; +} + +/* prevent the sidebar from overlapping content */ +.sidebar-sticky { z-index: 0; } diff --git a/apps/static/css/components/footer.scss b/apps/static/css/components/footer.scss new file mode 100644 index 000000000..15b0a923f --- /dev/null +++ b/apps/static/css/components/footer.scss @@ -0,0 +1,10 @@ +@import '../partials/colors'; + +/* -------------------------------------------------------------------------- */ +/* FOOTER */ +/* -------------------------------------------------------------------------- */ +.footer { background-color: $rx-color-linen-blue; color: $color-white; padding: 20px; } +.footer-links { display: flex; flex-direction: column; font-weight: bold; } +.footer-links a { color: $color-white; text-decoration: none; &:hover { text-decoration: underline; } } +.footer-logo { display: flex; align-items: center; svg { width: 50px; height: 50px; } } +.footer-bottom { text-align: left; margin-top: 10px; color: $color-white; } \ No newline at end of file diff --git a/apps/static/css/readux2/login.scss b/apps/static/css/components/login.scss similarity index 74% rename from apps/static/css/readux2/login.scss rename to apps/static/css/components/login.scss index 8d2bbdc5d..697503b52 100644 --- a/apps/static/css/readux2/login.scss +++ b/apps/static/css/components/login.scss @@ -1,9 +1,11 @@ +@import '../partials/colors'; + .custom-modal .uk-modal-dialog { width: 400px; padding: 20px; } .modal-header { - color: #1D3557; + color: $rx-color-midnight-blue; padding: 20px; text-align: center; } @@ -20,7 +22,7 @@ .uk-input-icon span { position: absolute; padding-left: 10px; - color: #1D3557; + color: $rx-color-midnight-blue; } .uk-divider { margin: 20px 0; @@ -29,14 +31,8 @@ margin-bottom: 10px; width: 100%; } -.uk-modal-close-default { - -} -.uk-link { - color: #1D3557; -} .help-link { - color: #1D3557; + color: $rx-color-midnight-blue; display: block; text-align: center; margin-top: 20px; @@ -44,7 +40,6 @@ .sso-text { margin-bottom: 20px; text-align: center; - // color: #1D3557; } .sso-buttons .uk-grid { gap: 10px; @@ -62,9 +57,9 @@ gap: 10px; } .sign-in-btn { - background-color: #1D3557; - color: #F1FAEE; + background-color: $rx-color-midnight-blue; + color: $rx-color-faded-mint; &:hover { - background-color: darken(#1D3557, 10%); + background-color: darken($rx-color-midnight-blue, 10%); } } \ No newline at end of file diff --git a/apps/static/css/components/menu-inverse.scss b/apps/static/css/components/menu-inverse.scss new file mode 100644 index 000000000..c03d6c0b6 --- /dev/null +++ b/apps/static/css/components/menu-inverse.scss @@ -0,0 +1,57 @@ +@import '../partials/colors'; + +/* Inverse the color for content pages */ +.menu-item { + color: rgba($rx-color-midnight-blue, 1.0) !important; + text-decoration: none !important; + transition: color 0.1s ease !important; + + &:hover { + color: rgba($rx-color-midnight-blue, 0.8) !important; // Slightly dim + } + + &:active { + color: rgba($rx-color-midnight-blue, 0.6) !important; // A bit darker + } +} + +.brand-logo { + font-size: large; + color: $rx-color-midnight-blue !important; + font-weight: bold; + + &:hover { + color: rgba($rx-color-midnight-blue, 0.8) !important; // Slightly dim + } + + &:active { + color: rgba($rx-color-midnight-blue, 0.6) !important; // A bit darker + } +} + +.brand-tagline { + font-size: small; + color: $rx-color-midnight-blue; +} + +.brand-readux { + color: $rx-color-midnight-blue; + + &:hover { + color: rgba($rx-color-midnight-blue, 0.8) !important; // Slightly dim + } + + &:active { + color: rgba($rx-color-midnight-blue, 0.6) !important; // A bit darker + } +} + +.brand-inline { + font-size: small; + font-weight: normal; + text-decoration: underline !important; +} + +.uk-navbar-container { + position: relative; +} \ No newline at end of file diff --git a/apps/static/css/components/reader.scss b/apps/static/css/components/reader.scss new file mode 100644 index 000000000..a95919787 --- /dev/null +++ b/apps/static/css/components/reader.scss @@ -0,0 +1,91 @@ +@import '../partials/colors'; + +.reader-navbar { + padding: 0 1rem; height: 36px; +} + +.rx-accordion-head { + background-color: $rx-color-faded-mint; + color: $rx-color-midnight-blue; + border: none; + &:hover { + color: $rx-color-midnight-blue !important; + background-color: darken($rx-color-faded-mint, 5%) !important; + border: none; + .rx-accordion-head::before { + color: $rx-color-midnight-blue !important; + } + } + &:active { + border: none; + } +} + +.rx-accordion-head::before { + color: $rx-color-midnight-blue !important; +} + +.rx-anchor { + color: $rx-color-midnight-blue !important; +} + +.uk-tab > .uk-active > a { + border-color: $rx-color-midnight-blue !important; + color: $rx-color-midnight-blue !important; +} + +.uk-search-default .uk-search-input:focus, .uk-input:focus, .uk-select:focus, .uk-textarea:focus { + border-color: $rx-color-midnight-blue; +} + +.scrollable-container { + max-height: 350px; + overflow-y: auto; + white-space: pre-wrap; + word-break: break-word; +} + +/* target success notifications */ +.uk-notification-message-success { + background-color: $rx-color-faded-mint; + font-weight: 700; + color: $rx-color-dark-charcoal; + border-radius: 4px; +} + +.uk-disabled, .disabled{ + opacity: 0.5; +} + +.ocr-notification { + background-color: $rx-color-faded-mint; + color: $rx-color-dark-charcoal; + border-radius: 4px; + padding: 0.5rem; +} + +.rx-collection-link { + color: $rx-color-midnight-blue !important; + font-weight: 500; + &:hover { + color: darken($rx-color-midnight-blue, 10%) !important; + } +} + +.rx-collection-separator { margin: 0 0.35rem; color: $rx-color-cement-gray; } + +.uk-modal-close-full { + margin: 25px 22px 0px 0px !important; + padding: 5px; + &:hover { + background-color: #e1f4da; + } +} + +.uk-tab::before { + right: 240px; +} + +.uk-search { + padding-right: 10px; +} \ No newline at end of file diff --git a/apps/static/css/components/search.scss b/apps/static/css/components/search.scss new file mode 100644 index 000000000..b6d5dcb05 --- /dev/null +++ b/apps/static/css/components/search.scss @@ -0,0 +1,265 @@ +@import '../partials/colors'; + +/* -------------------------------------------------------------------------- */ +/* SEARCH RESULTS PAGE */ +/* -------------------------------------------------------------------------- */ + +// ————————————————————————————————————————————— +// Layout: Info line +// ————————————————————————————————————————————— +.info-line { + display: flex; + justify-content: space-between; + align-items: center; + flex-wrap: wrap; // wrap on smaller screens + margin-bottom: 20px; + font-weight: 600; + color: $rx-color-midnight-blue; + + .info-group, + .pagination-controls { + display: flex; + align-items: center; + gap: 5px; + flex-wrap: wrap; + } + + a, + select { + color: $rx-color-midnight-blue; + text-decoration: underline; + } + + .pagination-controls { + .uk-icon-button { + color: $rx-color-midnight-blue; + + &[disabled] { + color: $rx-color-light-pearl; + cursor: not-allowed; + } + } + } + + @media (max-width: 768px) { + flex-direction: column; + align-items: flex-start; + + .info-group, + .pagination-controls { + width: 100%; + justify-content: space-between; + margin-bottom: 10px; + } + + .info-group { gap: 10px; } + } +} + +// ————————————————————————————————————————————— +// Form normals & search form +// ————————————————————————————————————————————— +fieldset { + margin: inherit; + border: 0; + padding: inherit; +} + +form#search-form { + input[type="search"][name="q"] { width: 100%; } + + .uk-button-danger { + background-color: $rx-color-rose-red; + color: $color-white; + border: 1px solid transparent; + } + + .uk-button-secondary { + background-color: $rx-color-dark-charcoal; + color: $color-white; + border: 1px solid transparent; + } +} + +// ————————————————————————————————————————————— +// Filters +// ————————————————————————————————————————————— +#search-filters { + input[type="text"]#authors-filter { width: 100%; } + + select[multiple] { + height: 150px; + width: 100%; + overflow-y: scroll; + overflow-x: auto; + } + + .noUi-target { margin: 45px 21px 10px; } +} + +// ————————————————————————————————————————————— +// UI Kit tweaks +// ————————————————————————————————————————————— +.uk-button-primary { + background-color: $rx-color-midnight-blue; + + &:hover { + background-color: darken($rx-color-midnight-blue, 10%); // darker on hover + } +} + +.uk-container ul { list-style: none; } + +.uk-checkbox:checked, +.uk-checkbox:indeterminate, +.uk-radio:checked { + background-color: $rx-color-midnight-blue !important; +} + +.uk-search-default { + .uk-search-input:focus { + border-color: $rx-color-midnight-blue; + border-right: 0; + } +} + +.uk-input:focus, +.uk-select:focus, +.uk-textarea:focus { + border-color: $rx-color-midnight-blue; +} + +// ————————————————————————————————————————————— +// Grid +// ————————————————————————————————————————————— +#search-grid { + margin-left: 0; + gap: 1.5rem; +} + +// ————————————————————————————————————————————— +// Selectize +// ————————————————————————————————————————————— +.selectize-control.multi .selectize-input > div { + background: $rx-color-midnight-blue !important; + border: none !important; +} + +.selectize-dropdown .active:not(.selected) { + background-color: $rx-color-faded-mint !important; +} + +.selectize-control.plugin-clear_button .clear { + height: 85%; + top: -3px !important; +} + +// ————————————————————————————————————————————— +// noUi Slider (date slider) +// ————————————————————————————————————————————— +.noUi-connect { + background: $rx-color-midnight-blue !important; + + [disabled] & { + background: $rx-color-midnight-blue !important; + opacity: 0.2; + } +} + +.noUi-tooltip { + font-size: .875rem; + font-family: monospace; + font-weight: normal; + padding: 0.125rem 0.25rem !important; + background-color: none; + border: none !important; +} + +// ————————————————————————————————————————————— +// Typography +// ————————————————————————————————————————————— +.sui-item-heading { + letter-spacing: 1.5px; + text-transform: uppercase; + font-weight: 600; + font-family: -apple-system, 'Helvetica Neue', 'Helvetica', 'Arial', 'Segoe UI', 'Roboto', 'Ubuntu', sans-serif; + font-size: 13px; + margin-top: 0.65rem; + + a { color: $rx-color-midnight-blue; } +} + +// ————————————————————————————————————————————— +// Search results +// ————————————————————————————————————————————— +#search-results { + list-style: none; + + dl { margin-left: 2rem; } + + .result-volume-summary { + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 3; + overflow: hidden; // clamp to 3 lines + } + + // highlighting + em { + color: $rx-color-mario-red !important; + font-weight: bold; + font-style: normal; + } + + // result snippet within full text + .result-page { + background-color: $rx-color-faded-mint; + color: $rx-color-midnight-blue; + + a { + display: flex; + flex-flow: row nowrap; + justify-content: flex-start; + align-items: flex-start; + gap: 1rem; + margin: 0.5rem 0; + font-size: 0.8rem; + color: $rx-color-midnight-blue; + } + + .page-number { + min-width: 4rem; // keeps previous 50px/4rem intent consistent + max-width: 4rem; + font-size: large; + font-weight: 600; + letter-spacing: -1px; + text-transform: uppercase; + } + + ul li { list-style: disc; } + } +} + +.result-title { + color: $rx-color-midnight-blue; + + &:hover { + color: darken($rx-color-midnight-blue, 10%); + } +} + +// ————————————————————————————————————————————— +// Search actions +// ————————————————————————————————————————————— +.search-button { + background-color: $rx-color-mario-red; + color: $color-white; + padding: 4px 9px 0 9px; + border: none; + height: 40px; + font-size: 1.25rem; + transition: ease 0.1s; + + &:hover { background-color: darken($rx-color-mario-red, 10%); } + &:active { background-color: darken($rx-color-mario-red, 25%); } +} diff --git a/apps/static/css/components/social-auth.scss b/apps/static/css/components/social-auth.scss new file mode 100644 index 000000000..37db33d6f --- /dev/null +++ b/apps/static/css/components/social-auth.scss @@ -0,0 +1,16 @@ +@import '../partials/colors'; + +/* Social Auth Buttons */ +a.rdx-provider-button { + color: $color-white; + padding: 1rem; +} + +a.rdx-provider-button:hover { + color: $rx-color-light-pearl; +} + +.rdx-indented-help-block { + text-indent: 1.25rem; +} +/* End of Social Auth Buttons */ \ No newline at end of file diff --git a/apps/static/css/_components/uk-switch.scss b/apps/static/css/components/uk-switch.scss similarity index 55% rename from apps/static/css/_components/uk-switch.scss rename to apps/static/css/components/uk-switch.scss index be3b29089..9082caf20 100644 --- a/apps/static/css/_components/uk-switch.scss +++ b/apps/static/css/components/uk-switch.scss @@ -1,4 +1,4 @@ -@import './colors.scss'; +@import '../partials/colors'; .uk-switch { position: relative; @@ -14,7 +14,7 @@ /* Slider */ .uk-switch-slider { - background-color: rgba(0, 0, 0, 0.22); + background-color: $rx-color-light-pearl; position: absolute; top: 0; left: 0; @@ -24,13 +24,12 @@ cursor: pointer; transition-property: background-color; transition-duration: .2s; - box-shadow: inset 0 0 2px rgba(0, 0, 0, 0.07); } /* Switch pointer */ .uk-switch-slider:before { content: ''; - background-color: #fff; + background-color: $color-white; position: absolute; width: 15px; height: 15px; @@ -43,7 +42,7 @@ /* Slider active color */ input:checked+.uk-switch-slider { - background-color: #1D3557 !important; + background-color: $rx-color-midnight-blue !important; } /* Pointer active animation */ @@ -51,30 +50,6 @@ input:checked+.uk-switch-slider:before { transform: translateX(13px); } -/* Modifiers */ -.uk-switch-slider.uk-switch-on-off { - background-color: #f0506e; -} - -input:checked+.uk-switch-slider.uk-switch-on-off { - background-color: #32d296 !important; -} - -/* Style Modifier */ -.uk-switch-slider.uk-switch-big:before { - transform: scale(1.2); - box-shadow: 0 0 6px rgba(0, 0, 0, 0.22); -} - -.uk-switch-slider.uk-switch-small:before { - box-shadow: 0 0 6px rgba(0, 0, 0, 0.22); -} - input:checked+.uk-switch-slider.uk-switch-big:before { transform: translateX(13px) scale(1.2); -} - -/* Inverse Modifier - affects only default */ -.uk-light .uk-switch-slider:not(.uk-switch-on-off) { - background-color: rgba(255, 255, 255, 0.22); } \ No newline at end of file diff --git a/apps/static/css/components/wagtail.scss b/apps/static/css/components/wagtail.scss new file mode 100644 index 000000000..1e8663564 --- /dev/null +++ b/apps/static/css/components/wagtail.scss @@ -0,0 +1,22 @@ +@import '../partials/colors'; + +/* Wagtail embedded objects */ +.rich-text img { + max-width: 100%; + height: auto; +} + +.responsive-object { + position: relative; +} + +.responsive-object iframe, +.responsive-object object, +.responsive-object embed { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} +/* end of Wagtail embedded objects */ \ No newline at end of file diff --git a/apps/static/css/partials/_colors.scss b/apps/static/css/partials/_colors.scss new file mode 100644 index 000000000..1bc4958b0 --- /dev/null +++ b/apps/static/css/partials/_colors.scss @@ -0,0 +1,23 @@ +// Theme +$rx-color-midnight-blue: #1D3557; +$rx-color-linen-blue: #457B9D; +$rx-color-mario-red: #E60000; +$rx-color-faded-mint: #F1FAEE; + +// ============================== +// Auxilary +// ============================== +$rx-color-rose-red: #f0506e; + +// ============================== +// Base +// ============================== +$color-black: #000000; +$color-white: #ffffff; + +// ============================== +// Black to White Scale +// ============================== +$rx-color-dark-charcoal: #333333; +$rx-color-cement-gray: #595959; +$rx-color-light-pearl: #cccccc; \ No newline at end of file diff --git a/apps/static/css/partials/_media.scss b/apps/static/css/partials/_media.scss new file mode 100644 index 000000000..2cecd4070 --- /dev/null +++ b/apps/static/css/partials/_media.scss @@ -0,0 +1,25 @@ +/* ========================================================================== */ +/* RESPONSIVE MEDIA QUERIES */ +/* ========================================================================== */ + +@media (max-width: 639px) { .uk-logo { padding: 0; } } + +@media (min-width: 640px) { + .rx-splash { display: flex; flex-direction: column; align-self: flex-start; position: sticky; top: 0; justify-content: space-between; height: calc(100vh - 200px); } +} + +@media (min-width: 768px) { .modal-dialog > .modal-content { top: 200px; } } + +@media (min-width: 960px) { .uk-navbar-right { flex-wrap: initial; } } + +@media (min-width: 320px) and (max-width: 959px) { + .rx-title-image { object-fit: cover; height: 150px; width: 100%; } + footer { padding: 2rem 0 0 0 !important; } + .content { padding: 0 !important; } +} + +@media only screen and (max-width: 480px) { #box { width: 100%; padding-bottom: 100%; } } +@media only screen and (max-width: 650px) and (min-width: 481px) { #box { width: 50%; padding-bottom: 50%; } } +@media only screen and (max-width: 1050px) and (min-width: 651px) { #box { width: 33.3%; padding-bottom: 33.3%; } } +@media only screen and (max-width: 1290px) and (min-width: 1051px) { #box { width: 25%; padding-bottom: 25%; } } +@media only screen and (max-width: 1250px) { ol { columns: 1; -webkit-columns: 1; -moz-columns: 1; } } \ No newline at end of file diff --git a/apps/static/css/partials/_mixin.scss b/apps/static/css/partials/_mixin.scss new file mode 100644 index 000000000..5feb178ee --- /dev/null +++ b/apps/static/css/partials/_mixin.scss @@ -0,0 +1,57 @@ +// ===================================== +// Helpers & Mixins +// ===================================== + +// a11y: visually hidden but focusable +@mixin sr-only() { + position: absolute !important; + width: 1px !important; + height: 1px !important; + padding: 0 !important; + margin: -1px !important; + overflow: hidden !important; + clip: rect(0 0 0 0) !important; + clip-path: inset(50%) !important; + border: 0 !important; + white-space: nowrap !important; +} + +// Generate hover/active shades for a given base color +@mixin interactive-color($base, $prop: color) { + #{$prop}: $base !important; + transition: #{$prop} 0.1s ease; + + &:hover { #{$prop}: if(type-of($base) == 'color', darken($base, 10%), $base) !important; } + &:active { #{$prop}: if(type-of($base) == 'color', darken($base, 25%), $base) !important; } +} + +// Border-only interactive (for outlines, etc.) +@mixin interactive-border($base) { + transition: border-color 0.1s ease; + &:hover { border-color: darken($base, 10%); } + &:active { border-color: darken($base, 25%); } +} + +// Link variant that underlines on hover and darkens progressively +@mixin link-variant($base, $weight: 600, $underline-on-hover: true) { + color: $base; + font-weight: $weight; + transition: color 0.1s ease; + + &:hover { + color: darken($base, 10%); + @if $underline-on-hover { text-decoration: underline; } + } + + &:active { + color: darken($base, 25%); + @if $underline-on-hover { text-decoration: underline; } + } +} + +// List reset +@mixin no-list-style { + list-style: none; + padding-left: 0; + margin-left: 0; +} \ No newline at end of file diff --git a/apps/static/css/project.scss b/apps/static/css/project.scss deleted file mode 100644 index a6a054262..000000000 --- a/apps/static/css/project.scss +++ /dev/null @@ -1,3635 +0,0 @@ -@import './ecds-annotator.min.css'; -@import './_components/colors.scss'; -@import './_components/uk-switch.scss'; - -.selectize-control.plugin-clear_button .clear { - top: -3px !important; -} - -:root { - --link-color: $rx-color-accent-1; - --contrast: 200%; -} - -// .uk-input { -// border-width: 3px; -// width: 50%; -// } - -.uk-link, -a { - color: var(--link-color); -} - -.uk-alert { - z-index: 99; -} - -a.nav-link { - text-decoration: none; -} - -em { - color: inherit !important; -} - -.uk-button-primary { - background-color: var(--link-color); -} - -.uk-button-primary:hover, -.uk-button-primary:active { - background-color: var(--link-color); - filter: contrast(var(--contrast)); -} - -// .uk-button-default { -// font-size: 1.25rem; -// } - -#search-form .uk-button-danger { - background-color: #f0506e; - color: #fff; - border: 1px solid transparent; -} - -#search-form .uk-button-secondary { - background-color: #222; - color: #fff; - border: 1px solid transparent; -} - -.uk-tab>.uk-active>a { - border-color: var(--link-color) !important; - color: var(--link-color) !important; -} - -.uk-checkbox, -.uk-radio { - border: 1px solid #ccc !important; -} - -.uk-container ul { - list-style: none; -} - -.block-paragraph_block li { - list-style: circle; -} - -.uk-navbar-nav { - font-weight: bold; -} - -.alert-debug { - color: black; - background-color: white; - border-color: #d6e9c6; -} - -.alert-error { - color: #b94a48; - background-color: #f2dede; - border-color: #eed3d7; -} - -// .rdx-viewer-container { -// height: calc(100vh - 120px); -// } - -.manifest-info>a, -.manifest-info>h3 { - display: none !important; -} - -#ocr-layer { - position: absolute !important; - z-index: 999; -} - -.openseadragon-container span { - color: transparent; - display: inline-flex !important; - font-size: 100%; - line-height: initial; - white-space: nowrap; -} - -/* Social Auth Buttons */ -a.rdx-provider-button { - color: #fff; - padding: 1rem; -} - -a.rdx-provider-button:hover { - color: lightgrey; -} - -.rdx-indented-help-block { - text-indent: 1.25rem; -} - -/* End of Social Auth Buttons */ - -/* Wagtail embedded objects */ -.rich-text img { - max-width: 100%; - height: auto; -} - -.responsive-object { - position: relative; -} - -.responsive-object iframe, -.responsive-object object, -.responsive-object embed { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; -} - -/* end of Wagtail embedded objects */ - -#id_featured_collections { - height: 200px; - overflow: hidden; - overflow-y: scroll; -} - -.breadcrumbs { - font-size: 80%; - margin: 0; -} - -header.page-header { - position: relative; - z-index: 10; - width: 100%; -} - -header.page-header .container img { - width: 100%; -} - -h1, -h2, -h3, -p.text-lead { - color: $rx-color-grey-1; -} - -h3 { - font-size: 2.2rem; -} - -header#page-bg .collection-image-info { - display: inline-block; - background: rgba(0, 0, 0, 0.62); - position: absolute; - bottom: 0; - right: 0; - padding: 1em 1.5em 5px 3.5em; - font-size: 12px; - color: #dedede; - z-index: 100; - -webkit-transition: bottom 0.6s ease, right 0.6s ease, - background-color 0.6s ease, opacity 0.6s ease; - -moz-transition: bottom 0.6s ease, right 0.6s ease, background-color 0.6s ease, - opacity 0.6s ease; - transition: bottom 0.6s ease, right 0.6s ease, background-color 0.6s ease, - opacity 0.6s ease; - max-width: 300px; - min-height: 10px; - cursor: pointer; -} - -header#page-bg .collection-label h1 { - font-size: 3em; - color: #dedede; - width: 100%; - height: 100%; - position: absolute; - top: 0; - left: 0px; - justify-content: center; - flex-direction: column; - align-items: center; - display: flex; -} - -ol { - columns: 2; - -webkit-columns: 2; - -moz-columns: 2; -} - -ol>li { - break-inside: avoid-column; - -webkit-column-break-inside: avoid; - page-break-inside: avoid; -} - -// ul.listing-thumbs > li > img.thumbnail-image { -// height: 150px; -// } - -ul>li>.collectionbox { - width: 100%; - padding-bottom: 15%; - position: relative; - border: 1px; - border-style: solid; -} - -ul>li>.collectionbox>.collectioncontainer { - position: absolute; - left: 0; - right: 0; - top: 0; - bottom: 0; - overflow: hidden; -} - -ul>li>.collectionbox>.collectioncontainer img { - width: 100%; - overflow: hidden; -} - -ul>li>.collectionbox>.collectioncontainer>.collection-label { - height: 0; -} - -ul>li>.collectionbox>.collectioncontainer>.collection-label a.nav-link { - font-size: 3em; - color: #dedede; - position: absolute; - left: 10px; - right: 10px; - top: 30%; - bottom: 10px; - text-align: center; - color: black; -} - -ul>li>.collectionbox>.collectioncontainer>.collection-label a.nav-link span { - background-color: rgba(255, 255, 255, 0.62); - padding: 0.3em; - border-radius: 20px; -} - -.count-icon { - display: inline-block; - position: relative; -} - -.count { - position: absolute; - top: 0; - right: 0; - padding-top: 20%; - padding-right: 20%; - height: 10px; - width: 10px; - font-size: 10px; - text-align: center; -} - - -header#page-bg .collection-label h1 span { - background-color: rgba(0, 0, 0, 0.62); - padding: 0.3em; -} - -header#page-bg .collection-image-info:before { - content: "i"; - position: absolute; - border: 1px solid; - width: 20px; - text-align: center; - top: 0; - left: 0; - margin: 10px 10px; - height: 20px; - font-family: -apple-system, 'Helvetica Neue', 'Helvetica', 'Arial', 'Segoe UI', 'Roboto', 'Ubuntu', sans-serif; -} - -header#page-bg .collection-image-info h3 { - margin: 0; - font-size: 1.5em; - color: #dedede; -} - -header#page-bg .collection-image-info p { - width: 100%; - color: #dedede !important; - text-align: left; - margin-bottom: 0px; - margin-top: 0px; -} - -header#page-bg .collection-image-info p.credit { - font-size: 0.9em; -} - -header#page-bg .collection-image-info.collapsed { - padding: 1.5em 1.75em; - background-color: rgba(22, 22, 22, 0.33); - opacity: 0.8; - color: #dedede !important; -} - -header#page-bg .collection-image-info.collapsed:hover { - opacity: 1; - background-color: rgba(0, 0, 0, 0.62); -} - -header#page-bg .collection-image-info.collapsed h3, -header#page-bg .collection-image-info.collapsed .info { - display: none; -} - -#wrap { - overflow: hidden; -} - -.box { - width: 25%; - padding-bottom: 25%; - position: relative; - float: left; -} - -.box a img { - width: 100%; - overflow: hidden; -} - -.boxInner { - position: absolute; - left: 0; - right: 0; - top: 0; - bottom: 0; - overflow: hidden; -} - -.boxInner { - position: absolute; - left: 0; - right: 0; - top: 0; - bottom: 0; - max-height: 225px; - overflow: hidden; -} - -.boxInner img { - -webkit-filter: blur(2px); - /* Safari 6.0 - 9.0 */ - filter: blur(2px); - width: 100%; -} - -.boxInner img { - -webkit-filter: blur(2px); - /* Safari 6.0 - 9.0 */ - filter: blur(2px); - width: 100%; -} - -.innerContent { - position: absolute; - left: 10px; - right: 10px; - top: 10px; - bottom: 10px; - text-align: center; - color: black; - transition: 0.5s; - opacity: 0; -} - -.innerContent:hover { - opacity: 1; -} - -.innerContent p { - text-align: center; - background: rgba(255, 255, 255, 0.7); - color: #4f4f4f; - border-radius: 15px; -} - -.innerContent p em { - color: black; -} - -.innerContent a { - color: black; - background: rgba(255, 255, 255, 0.7); - text-decoration: underline; -} - -.innerContentb { - position: absolute; - left: 10px; - right: 10px; - top: 10px; - bottom: 10px; - text-align: center; - color: black; -} - -.innerContentc { - position: absolute; - left: 10px; - right: 10px; - top: 10px; - bottom: 10px; - text-align: center; - color: black; -} - -.innerContentb h2 { - text-align: center; - background: rgba(255, 255, 255, 0.7); - color: #4f4f4f; - border-radius: 15px; -} - -.innerContentb h2 em { - color: black; -} - -.innerContentb a { - color: black; - background: rgba(255, 255, 255, 0.7); - text-decoration: underline; -} - -.readux-home-tagline { - font-size: 3em; - font-weight: 700; -} - -.readux-home-ecds { - width: 20em; -} - -.readux-group-title { - font-size: 2em; - font-weight: 700; -} - -// #rx-sort { -// position: sticky; -// top: 72px; -// } - -.rx-card-title { - font-size: 1.25em; - font-weight: 700; - color: $rx-color-grey-1; - line-height: 1.25em; -} - -a:hover { - text-decoration: initial !important; -} - -.rx-offcanvas-bar, -.rx-offcanvas-base { - background: white; - box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23); -} - -p { - color: $rx-color-grey-1; -} - -.rx-breadcrumb, -.rx-action-title, -.rx-action-btn, -.rx-page-breadcrumb-item, -.rx-page-breadcrumb { - color: var(--link-color); - filter: brightness(0.4%); - text-transform: uppercase; - font-weight: bold; - /* letter-spacing: 0.1em; */ - display: inline-flex; - padding: 0; - margin: 0; - user-select: auto; -} - -.rx-action-btn { - letter-spacing: 0.1em; - font-size: small; -} - -.rx-page-breadcrumb-item a { - color: var(--link-color); -} - -.rx-page-breadcrumb { - white-space: nowrap; -} - -.rx-page-logo { - min-width: 65px; -} - -// .rx-breadcrumb-item:not(:last-child)::after, -// .rx-page-breadcrumb-item:not(:last-child)::after { -// content: "-"; -// padding: 0 0.5em; -// } - -.rx-page-title-container { - padding: 0 15px; - overflow-wrap: anywhere; - align-self: center; -} - -.rx-breadcrumb-item>a, -.rx-page-breadcrumb-item>a, -.rx-action-btn, -.rx-icon-btn, -.uk-dropdown-nav>li>a:hover { - color: var(--link-color) !important; - filter: brightness(1); - opacity: 0.75; - transition: all ease-in-out 100ms; -} - -.rx-breadcrumb-item>a:hover, -.rx-page-breadcrumb-item>a:hover, -.rx-action-btn:hover, -.rx-icon-btn:hover, -.uk-dropdown-nav>li.uk-active>a { - color: var(--link-color); - opacity: 1; - transition: all ease-in-out 100ms; -} - -.rx-head-container { - margin: 0em 0 3em; -} - -.rx-info { - margin: 1rem 0; -} - -.rx-info-title { - border: 0.5px solid #e2e2e2; - padding: 0.7em 1em 0.5em; - color: $rx-color-grey-1; - letter-spacing: 0.15em; - text-transform: uppercase; - font-size: 0.875em; - font-weight: bold; -} - -.rx-info-content-container { - border: 0.5px solid #e2e2e2; - padding: 1em 1em; - word-break: break-word; -} - -.rx-info-content { - padding: 0 0 1.25em; - font-size: 0.9rem; - - &:last-child { - padding: 0; - } -} - -.rx-info-content-label { - color: $rx-color-grey-1 !important; - font-weight: 600 !important; - font-size: 0.9rem !important; -} - -.rx-info-content-value { - color: $rx-color-grey-1; - line-height: 1.5; -} - -.rx-card-body { - text-align: left; - min-width: 0; - flex: 1 1 auto; - /* margin-left: 2rem; */ -} - -.rx-card-image-container { - /* width: 150px; */ - flex: 0 0 auto; -} - -.rx-card-image { - background-origin: border-box !important; - background-size: cover !important; - width: 100% !important; - height: 100% !important; - display: block !important; - color: inherit; - text-decoration: none; - background-color: none; -} - -.rx-card-text { - padding: 0; - color: $rx-color-grey-1; - margin: 0.5em 0; - overflow: hidden; - text-overflow: ellipsis; - display: -webkit-box; - -webkit-line-clamp: 3; - /* number of lines to show */ - -webkit-box-orient: vertical; - font-size: 14px; -} - -.rx-card-title { - overflow: hidden; - text-overflow: ellipsis; - display: -webkit-box; - -webkit-line-clamp: 1; - /* number of lines to show */ - -webkit-box-orient: vertical; -} - -.rx-grid-right { - overflow: auto; -} - -#rx-nav { - /* position: fixed; - top: 0; - left: 5%; - right: 5%; - background: white; */ - /* position: sticky; - top: 0; */ - background: white; -} - -.rx-grid-right { - margin-left: 50%; -} - -.rx-btn { - border-radius: 3px; - border: solid 1px var(--link-color); - filter: contrast(var(--contrast)); - color: var(--link-color); - filter: contrast(var(--contrast)); - font-family: -apple-system, 'Helvetica Neue', 'Helvetica', 'Arial', 'Segoe UI', 'Roboto', 'Ubuntu', sans-serif; - font-size: 14px; - font-weight: 500; - line-height: 1.28; - letter-spacing: normal; - text-align: center; - padding: 5px 12px; - display: inline-block; - - &:hover { - border: solid 1px var(--link-color); - color: white; - background: var(--link-color); - filter: contrast(var(--contrast)); - transition: all ease-in-out 100ms; - cursor: pointer; - } -} - -.rx-btn-extension { - border-radius: 3px; - border: solid 1px var(--link-color); - filter: contrast(var(--contrast)); - color: white; - font-family: -apple-system, 'Helvetica Neue', 'Helvetica', 'Arial', 'Segoe UI', 'Roboto', 'Ubuntu', sans-serif; - font-size: 15px; - font-weight: 600; - line-height: 1.28; - text-transform: uppercase; - letter-spacing: 0.7px; - text-align: center; - padding: 8px 16px; - display: inline-block; - background: var(--link-color); - color: white; - border: solid 1px var(--link-color); - - &:hover { - background: #5e0035; - color: white; - border: solid 1px #5e0035; - transition: all ease-in-out 100ms; - opacity: 1; - cursor: pointer; - } -} - -// .rx-annotation-badge { -// border-radius: 3px; -// background: $rx-color-grey-1; -// color: white; -// text-transform: uppercase; -// font-weight: bold; -// padding: 0.1rem 0.5rem; -// font-size: 0.75rem; -// display: inline-block; -// cursor: default; -// } - -.rx-annotation-badge { - border-radius: 3px; - background: white; - color: $rx-color-grey-1 !important; - border: $rx-color-grey-1 1px solid; - font-size: 0.75rem; - letter-spacing: 0.1rem; - font-weight: 600; - display: inline-block; - cursor: default; - text-transform: uppercase; - padding: 0.1rem 0.5rem; -} - -.rx-padding-bottom-10 { - padding-bottom: 10px; -} - -.uk-active>.rx-btn-annotation { - background-color: $rx-color-accent-1 !important; - color: white; -} - -.uk-offcanvas-container { - top: -80px; - position: inherit; -} - -.readux-group-title:not(:first-child) { - margin-top: 3rem; -} - -.rx-footer { - display: flex; - list-style: none; - font-weight: bold; - - &>a { - padding: 1rem; - color: $rx-color-grey-2; - transition: all ease-in-out 100ms; - - &:first-child { - padding-left: 0; - } - - &:hover { - color: #666; - } - } -} - -.rx-anchor { - color: var(--link-color) !important; - opacity: 0.75; - word-break: break-all; - transition: all ease-in-out 100ms; - - &:hover { - color: var(--link-color); - opacity: 1; - } -} - -::selection { - background-color: $rx-color-grey-1; -} - -.rx-label-copy { - background: white; - color: var(--link-color) !important; - border: var(--link-color) 1px solid; - font-size: 0.75rem; - letter-spacing: 0.1rem; - cursor: pointer; - transition: all ease-in-out 100ms; - font-weight: 600; - font-family: 'Consolas', 'Monaco', 'Andale Mono', 'Ubuntu Mono', 'monospace' !important; - - &:active { - background-color: #1D3557 !important; - border: 1px solid #1D3557 !important; - opacity: 1; - } - - &:hover { - background: #1D3557; - border-color: #1D3557; - color: white !important; - font-size: 0.75rem; - letter-spacing: 0.1rem; - cursor: pointer; - opacity: 1; - } -} - -.rx-action-btn:hover .rx-label-copy { - background: #1D3557; - border-color: #1D3557; - color: white !important; - font-size: 0.75rem; - letter-spacing: 0.1rem; - cursor: pointer; - opacity: 1; -} - -.rx-label-solid { - background: #1D3557; - color: white; - border: #1D3557 1px solid; - font-size: 0.75rem; - letter-spacing: 0.1rem; - opacity: 0.75; - cursor: pointer; - transition: all ease-in-out 100ms; - font-weight: 600; - - &:active { - background-color: darken(#1D3557, 5%) !important; - border: 1px solid darken(#1D3557, 5%) !important; - opacity: 1; - } - - &:hover { - background: #1D3557; - border-color: #1D3557; - color: white !important; - font-size: 0.75rem; - letter-spacing: 0.1rem; - cursor: pointer; - opacity: 1; - } -} - -.rx-page-navbar-right>a { - margin-left: 1em; -} - -.rx-flex { - display: flex; -} - -.rx-tooltip-hidden { - visibility: hidden; - opacity: 0; - transition: visibility 0s 2s, opacity 2s linear; -} - -.rx-grid { - margin: 40px auto; - max-width: 1024px; - display: flex; - flex-wrap: wrap; -} - -.rx-col { - border: 1px dashed gray; - flex: 1 1 100px; - text-align: center; - padding: 12px; -} - -.rx-top-left { - position: absolute; - top: 8px; - left: 16px; -} - -.rx-image-container>figure { - margin: auto; - background-position: center; - background-size: cover; - width: 100%; - height: 200px; -} - -.rx-volume-na { - background: #fbecf9; - padding: 15px; - font-size: 14px; - color: var(--link-color); -} - -a.rx-nav-item { - color: var(--link-color) !important; -} - -.rx-nav-item.uk-active { - color: var(--link-color); -} - -.rx-btn-small { - font-size: 14px; - font-weight: bold; - letter-spacing: normal; - text-align: center; - padding: 6px 12px; -} - -.rx-fieldset { - border: none; -} - -.rx-info-content .uk-tab a { - color: $rx-color-grey-2; -} - -.rx-info-content .uk-tab a:hover { - color: #666; -} - - - -.rx-collection-title { - font-weight: bold; - color: $rx-color-grey-1; -} - -/* Grid layout */ - -.rx-grid { - display: grid; - margin: 15px auto; - max-width: 1400px; - grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); - grid-column-gap: 30px; - /* justify-content: space-between; */ -} - -.rx-grid-layout { - height: 425px; - width: 275px; - position: relative; - background: white; - margin-bottom: 75px; -} - -.rx-grid-image-container>img { - object-fit: cover; - height: 400px; - /* width: 200px; */ - width: 100%; - /* height: 100%; */ -} - -/* Banner Layout */ -.rx-banner-layout { - display: grid; - margin: 20px auto; - max-width: 100%; - /* grid-template-columns: repeat(auto-fill, minmax(100%, 1fr)); */ - grid-template-columns: 1fr; - /* grid-column-gap: 15px; */ - /* justify-content: space-between; */ -} - -.rx-volume-in-banner { - /* border: 1px solid black; */ - /* text-align: center; */ - /* height: 150px; */ - width: 100%; - margin: 15px 0; - position: relative; - background: black; -} - -.rx-banner-image-container>img { - object-fit: cover; - height: 150px; - width: 100%; - opacity: 0.4; -} - -.rx-banner-text-container { - position: absolute; - left: 0; - bottom: 0; - padding: 1rem; - color: $rx-color-grey-3; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, - Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; -} - -.rx-collection-title-banner { - color: white; - font-size: 1.5rem; -} - -.rx-sticky { - position: sticky; - top: 0; - z-index: 1; -} - -/*mirador overrides*/ -// .mirador-container .manifest-info { -// width: initial !important; -// } - -// .mirador-container .mirador-viewer a.mirador-icon-view-type, -// .mirador-container .mirador-viewer a.mirador-icon-metadata-view, -// .mirador-container .mirador-viewer a.mirador-osd-fullscreen { -// padding: 5px; -// margin: 0; -// } - -// .mirador-container .mirador-viewer { -// top: -12px !important; -// } -// .mirador-container .workspace-container { -// left: -3px !important; -// } - -// .mirador-container .manifest-info { -// width: auto !important; -// float: right; -// z-index: 2; -// } - -// .mirador-container .window-manifest-navigation { -// float: right; -// margin-left: 1em; -// } - -// .mirador-container .manifest-info { -// padding: 0.5rem; -// overflow: initial !important; -// margin-top: 0px !important; -// } - -// .mirador-container .window-manifest-navigation { -// margin-left: initial; -// } - -// .mirador-container .mirador-viewer a.mirador-icon-view-type, -// .mirador-container .mirador-viewer a.mirador-icon-metadata-view, -// .mirador-container .mirador-viewer a.mirador-osd-fullscreen { -// display: flex; -// flex-direction: row; -// } - -// .mirador-container .mirador-viewer a.mirador-icon-view-type, -// .mirador-container .mirador-viewer a.mirador-icon-metadata-view, -// .mirador-container .mirador-viewer a.mirador-osd-fullscreen { -// margin-right: 0 !important; -// padding-bottom: 0 !important; -// } - -// .mirador-btn { -// padding: 0.5rem; -// } - -.window-manifest-navigation { - display: flex; - justify-content: space-between; - width: 55px; -} - -.tooltip { - position: relative; - display: inline-block; - border-bottom: 1px dotted black; -} - -.tooltip .tooltiptext { - visibility: hidden; - width: 120px; - background-color: black; - color: #fff; - text-align: center; - border-radius: 6px; - padding: 5px 0; - position: absolute; - z-index: 1; - top: 150%; - left: 50%; - margin-left: -60px; - font-size: 14px; -} - -.tooltip .tooltiptext::after { - content: ""; - position: absolute; - bottom: 100%; - left: 50%; - margin-left: -5px; - border-width: 5px; - border-style: solid; - border-color: transparent transparent black transparent; -} - -.tooltip:hover .tooltiptext { - visibility: visible; -} - -.rx-page-info-btn, -.rx-btn-secondary, -.rx-page-info-btn>.uk-icon-button { - color: var(--link-color) !important; - filter: contrast(var(--contrast)); - opacity: 0.75; - font-size: 1rem; - font-weight: 600; -} - -.rx-page-info-btn:hover, -.rx-btn-secondary:hover, -.rx-page-info-btn>.uk-icon-button:hover { - color: white !important; -} - -.rx-offcanvas-close { - position: relative; - top: 0; - right: 0; - color: var(--link-color) !important; - filter: contrast(var(--contrast)); -} - -.rx-offcanvas-close:hover { - color: var(--link-color) !important; - filter: contrast(var(--contrast)); -} - -.rx-btn-secondary { - border: 3px solid var(--link-color); - filter: contrast(var(--contrast)); - padding: 0.35em 1em; - white-space: nowrap; -} - -.rx-btn-secondary:hover { - color: white; - background-color: var(--link-color); - filter: contrast(var(--contrast)); - opacity: 1; - transition: all ease-in-out 100ms; -} - -.rx-page-info-btn:hover { - opacity: 1; - transition: all ease-in-out 100ms; - color: var(--link-color); - filter: contrast(var(--contrast)); -} - -.rx-btn-secondary:active { - background-color: var(--link-color); - border-color: var(--link-color); - filter: brightness(75%); -} - -.rx-info-container { - position: absolute; - background: white; - padding: 2rem; - z-index: 2; - right: 0; - width: 50%; - bottom: 0; - overflow: scroll; - top: 0; - box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23); -} - - - -fieldset { - margin: inherit; - border: 0; - padding: inherit; -} - -#sidenav { - background: white; - position: absolute; - top: 0; -} - -// page search -.rx-page-search-container { - width: calc(100% - 30px) !important; - /* display: flex; */ - /* align-items: center; */ - /* justify-content: space-between; */ - color: $rx-color-grey-1 !important; -} - -.rx-page-search-options, -.rx-page-search-option-label { - display: block; -} - -// end of page search - -// page.html flexbox with clipping text -.flex-parent { - display: -webkit-box; - display: flex; - -webkit-box-align: center; - align-items: center; - padding: 10px; - margin: 30px 0; -} - -.long-and-truncated { - -webkit-box-flex: 1; - flex: 1; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.short-and-fixed { - white-space: nowrap; -} - -.short-and-fixed>div { - width: 30px; - height: 30px; - border-radius: 10px; - background: lightgreen; - display: inline-block; -} - -// end of page.html flexbox with clipping text - -// rx-search -.rx-search-icon { - color: $rx-color-grey-1 !important; -} - -.rx-search-input { - border: none !important; - color: $rx-color-grey-1 !important; - - &::placeholder { - color: $rx-color-grey-2 !important; - } - -} - -.rx-search-result { - font-size: 14px; - - a { - color: var(--link-color) !important; - opacity: 0.7; - - &:hover { - color: var(--link-color) !important; - opacity: 1; - transition: all ease-in-out 100ms; - } - } -} - -// end of rx-search - -// rx-title -.rx-title-container { - background: white; - padding: 1em 0; - position: sticky; - top: 0; - z-index: 3; -} - -.rx-title { - font-size: 2em; - font-weight: bold; - color: var(--link-color); -} - -.rx-title-2 { - font-size: 1.5em; - font-weight: bold; - color: $rx-color-grey-1; -} - -.rx-title-tagline { - font-size: 14px; - color: $rx-color-grey-2; -} - -.rx-title-tagline-banner { - color: #eeeeee; -} - -.rx-title-image { - object-fit: cover; - height: 150px; - width: 100%; -} - -.rx-volume-title { - font-size: 1rem; - font-weight: bold; - color: var(--link-color); - - &:hover { - color: $rx-color-accent-2; - } -} - -// end of rx-title - -.rx-breadcrumb-item { - font-size: 1rem; - font-weight: bold; - color: var(--link-color); - - &:hover { - color: $rx-color-accent-2; - } -} - -.long-and-truncated.rx-volume-title { - display: flex; - align-items: center; -} - -.long-and-truncated.rx-volume-title .uk-icon { - display: flex; - align-items: center; - margin-left: 8px; - /* Optional: Add space between text and icon */ -} - -// End of breadcrumb - -@media (max-width: 395px) { - header#page-bg .collection-label h1 { - font-size: 0.7em; - } -} - -@media (max-width: 555px) { - header#page-bg .collection-label h1 { - font-size: 1em; - } -} - -@media (max-width: 750px) { - header#page-bg .collection-label h1 { - font-size: 1.5em; - } -} - -@media (max-width: 639px) { - .rx-offcanvas-bar { - width: 100%; - } - - #offcanvas-usage { - width: 100%; - left: 0; - } - - .rx-navbar-nav { - display: block; - } - - .uk-logo { - padding: 0; - } -} - -@media (min-width: 640px) { - .rx-splash { - /* position: fixed; */ - display: flex; - flex-direction: column; - align-self: flex-start; - position: sticky; - top: 0; - justify-content: space-between; - height: calc(100vh - 200px); - } - - .rx-offcanvas-bar { - width: 100%; - } - - #offcanvas-usage { - width: 50%; - left: 50%; - } -} - -@media (max-width: 750px) { - .rx-page-logo { - display: none; - } - - .rx-page-title-container { - padding: 0 15px 0 0; - font-size: 0.9rem; - } - - .rx-btn-secondary { - border: none; - padding: none; - white-space: inherit; - margin-left: -1rem !important; - } - - .rx-page-breadcrumb { - display: block; - white-space: normal; - } - - .rx-page-title { - line-height: 1rem; - } -} - -@media (min-width: 768px) { - .modal-dialog>.modal-content { - top: 200px; - } -} - -@media (max-width: 960px) { - .rx-info-container { - width: 100%; - left: 0; - right: 0; - padding: 0; - } - - .rx-volume-image { - margin-bottom: 1rem; - } -} - -@media (min-width: 960px) { - .rx-article { - display: flex; - align-items: stretch; - /* flex: 1 1 auto; */ - max-width: 680px; - width: 100%; - margin: 3rem 0; - } - - .rx-article>.rx-card-image-container { - padding: 0; - } - - .uk-navbar-right { - flex-wrap: initial; - } -} - -@media (min-width: 320px) and (max-width: 959px) { - .readux-home-ecds { - display: none; - } - - .readux-group-title { - font-size: 1.5rem; - } - - .rx-splash-item { - font-size: 1.5rem; - } - - .rx-title-image { - object-fit: cover; - height: 150px; - width: 100%; - } - - .rx-card-image-container { - height: 150px; - width: 100%; - } - - .rx-card-body { - margin: 1rem 0 2rem 0; - } - - .rx-card-title { - overflow: inherit; - display: block; - } - - .rx-card-text { - overflow: inherit; - display: block; - } - - .rx-footer>a { - padding: 0 0 1rem 0; - } - - footer { - padding: 2rem 0 0 0 !important; - } -} - -@media (max-width: 1095px) { - header#page-bg .collection-label h1 { - font-size: 2em; - } -} - -@media only screen and (max-width: 480px) { - - /* Smartphone view: 1 tile */ - #box { - width: 100%; - padding-bottom: 100%; - } -} - -@media only screen and (max-width: 650px) and (min-width: 481px) { - - /* Tablet view: 2 tiles */ - #box { - width: 50%; - padding-bottom: 50%; - } -} - -@media only screen and (max-width: 1050px) and (min-width: 651px) { - - /* Small desktop / ipad view: 3 tiles */ - #box { - width: 33.3%; - padding-bottom: 33.3%; - } -} - -@media only screen and (max-width: 1290px) and (min-width: 1051px) { - - /* Medium desktop: 4 tiles */ - #box { - width: 25%; - padding-bottom: 25%; - } -} - -@media only screen and (max-width: 1290px) and (min-width: 1051px) { - - /* Medium desktop: 4 tiles */ - ul>li>.collectionbox>.collectioncontainer>.collection-label a.nav-link { - font-size: 3em; - } -} - -@media only screen and (max-width: 1050px) and (min-width: 651px) { - - /* Small desktop / ipad view: 3 tiles */ - ul>li>.collectionbox>.collectioncontainer>.collection-label a.nav-link { - font-size: 2.5em; - } -} - -@media only screen and (max-width: 650px) and (min-width: 481px) { - - /* Tablet view: 2 tiles */ - ul>li>.collectionbox>.collectioncontainer>.collection-label a.nav-link { - font-size: 2em; - } -} - -@media only screen and (max-width: 480px) { - - /* Smartphone view: 1 tile */ - ul>li>.collectionbox>.collectioncontainer>.collection-label a.nav-link { - font-size: 1em; - } -} - -@media only screen and (max-width: 1250px) { - ol { - columns: 1; - -webkit-columns: 1; - -moz-columns: 1; - } -} - -.rx-accordion-head { - background: white; - color: var(--link-color); - border: var(--link-color) 1px solid; - font-size: 0.85rem; - letter-spacing: 0.1rem; - cursor: pointer; - transition: all ease-in-out 100ms; - font-weight: 600; - font-family: 'Consolas', 'Monaco', 'Andale Mono', 'Ubuntu Mono', 'monospace' !important; - - &::before { - color: white; - } - - // &:active { - // background-color: $rx-color-accent-2 !important; - // border: 1px solid $rx-color-accent-2 !important; - // opacity: 1; - // } - - // &:hover { - // background: var(--link-color); - // color: white !important; - // font-size: 0.85rem; - // letter-spacing: 0.1rem; - // cursor: pointer; - // opacity: 1; - // } -} - -.rx-accordion-handle { - color: var(--link-color) !important; -} - -.uk-accordion-content { - color: #595959 !important; -} - -.rx-fixed-width-100 { - min-width: 100px; - text-align: center; -} - -.rx-accordion-content { - margin: 0; - padding: 0 0 10px 0; -} - -.rx-accordion-container { - margin: 20px 0 0 0; -} - -.uk-offcanvas-bar .uk-open>.uk-accordion-title::before { - background-image: url("data:image/svg+xml;charset=UTF-8,%8Csvg+width%3D%2213%22+height%3D%2213%22+viewBox%3D%220+0+13+13%22+xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0D%0A++++%3Crect+fill%3D%22rgba%28149%2C+9%2C+83%2C+1%29%22+width%3D%2213%22+height%3D%221%22+x%3D%220%22+y%3D%226%22+%2F%3E%0D%0A%3C%2Fsvg%3E") !important; -} - -:root { - --link-color: #666; - --contrast: 200%; -} - -// .uk-input { -// border-width: 3px; -// width: 50%; -// } - -.uk-link, -a { - color: var(--link-color); -} - -a.nav-link { - text-decoration: none; -} - -.uk-button-primary { - background-color: var(--link-color); -} - -.uk-button-primary:hover, -.uk-button-primary:active { - background-color: var(--link-color); - -webkit-filter: contrast(var(--contrast)); - filter: contrast(var(--contrast)); -} - -// .uk-button-default { -// font-size: 1.25rem; -// } - -.uk-tab>.uk-active>a { - border-color: var(--link-color) !important; - color: var(--link-color) !important; -} - -.uk-checkbox, -.uk-radio { - border: 1px solid #ccc !important; -} - -.uk-navbar-right { - // padding-top: 1rem; -} - -.uk-container ul { - list-style: none; -} - -.block-paragraph_block li { - list-style: circle; -} - -.uk-navbar-nav { - font-weight: bold; -} - -.alert-debug { - color: black; - background-color: white; - border-color: #d6e9c6; -} - -.alert-error { - color: #b94a48; - background-color: #f2dede; - border-color: #eed3d7; -} - -.rdx-viewer-container { - /* width: 100%; - height: calc(100% - 120px); */ - position: absolute; - left: 0; - bottom: 0px; - /* background: none !important; */ - - height: -webkit-calc(100% - 36px); - height: -moz-calc(100% - 36px); - height: calc(100% - 36px); - width: 100%; - /* Remove any browser-default margins. */ - margin: 0; -} - -#rdx-viewer>div>div>div.py-8.grid.grid-cols-2.gap-2 { - padding-bottom: 0; -} - -.manifest-info>a, -.manifest-info>h3 { - display: none !important; -} - -#ocr-layer { - position: absolute !important; - z-index: 999; -} - -.openseadragon-container span { - color: transparent; - display: -webkit-inline-box !important; - display: -ms-inline-flexbox !important; - display: inline-flex !important; - font-size: 100%; - line-height: initial; - white-space: nowrap; -} - -/* Social Auth Buttons */ -a.rdx-provider-button { - color: #fff; - padding: 1rem; -} - -a.rdx-provider-button:hover { - color: lightgrey; -} - -.rdx-indented-help-block { - text-indent: 1.25rem; -} - -/* End of Social Auth Buttons */ -/* Wagtail embedded objects */ -.rich-text img { - max-width: 100%; - height: auto; -} - -.responsive-object { - position: relative; -} - -.responsive-object iframe, -.responsive-object object, -.responsive-object embed { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; -} - -/* end of Wagtail embedded objects */ -#id_featured_collections { - height: 200px; - overflow: hidden; - overflow-y: scroll; -} - -.breadcrumbs { - font-size: 80%; - margin: 0; -} - -header.page-header { - position: relative; - z-index: 10; - width: 100%; -} - -header.page-header .container img { - width: 100%; -} - -h1, -h2, -h3, -p.text-lead { - color: #595959; -} - -h3 { - font-size: 2.2rem; -} - -header#page-bg .collection-image-info { - display: inline-block; - background: rgba(0, 0, 0, 0.62); - position: absolute; - bottom: 0; - right: 0; - padding: 1em 1.5em 5px 3.5em; - font-size: 12px; - color: #dedede; - z-index: 100; - -webkit-transition: bottom 0.6s ease, right 0.6s ease, background-color 0.6s ease, opacity 0.6s ease; - transition: bottom 0.6s ease, right 0.6s ease, background-color 0.6s ease, opacity 0.6s ease; - max-width: 300px; - min-height: 10px; - cursor: pointer; -} - -header#page-bg .collection-label h1 { - font-size: 3em; - color: #dedede; - width: 100%; - height: 100%; - position: absolute; - top: 0; - left: 0px; - -webkit-box-pack: center; - -ms-flex-pack: center; - justify-content: center; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -ms-flex-direction: column; - flex-direction: column; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - display: -webkit-box; - display: -ms-flexbox; - display: flex; -} - -ol { - columns: 2; - -webkit-columns: 2; - -moz-columns: 2; -} - -ol>li { - break-inside: avoid-column; - -webkit-column-break-inside: avoid; - page-break-inside: avoid; -} - -ul.listing-thumbs>li>img.thumbnail-image { - height: 150px; -} - -ul>li>.collectionbox { - width: 100%; - padding-bottom: 15%; - position: relative; - border: 1px; - border-style: solid; -} - -ul>li>.collectionbox>.collectioncontainer { - position: absolute; - left: 0; - right: 0; - top: 0; - bottom: 0; - overflow: hidden; -} - -ul>li>.collectionbox>.collectioncontainer img { - width: 100%; - overflow: hidden; -} - -ul>li>.collectionbox>.collectioncontainer>.collection-label { - height: 0; -} - -ul>li>.collectionbox>.collectioncontainer>.collection-label a.nav-link { - font-size: 3em; - color: #dedede; - position: absolute; - left: 10px; - right: 10px; - top: 30%; - bottom: 10px; - text-align: center; - color: black; -} - -ul>li>.collectionbox>.collectioncontainer>.collection-label a.nav-link span { - background-color: rgba(255, 255, 255, 0.62); - padding: 0.3em; - border-radius: 20px; -} - -.count-icon { - display: inline-block; - position: relative; -} - -.count { - position: absolute; - top: 0; - right: 0; - padding-top: 20%; - padding-right: 20%; - height: 10px; - width: 10px; - font-size: 10px; - text-align: center; -} - -header#page-bg .collection-label h1 span { - background-color: rgba(0, 0, 0, 0.62); - padding: 0.3em; -} - -header#page-bg .collection-image-info:before { - content: "i"; - position: absolute; - border: 1px solid; - width: 20px; - text-align: center; - top: 0; - left: 0; - margin: 10px 10px; - height: 20px; - font-family: serif; -} - -header#page-bg .collection-image-info h3 { - margin: 0; - font-size: 1.5em; - color: #dedede; -} - -header#page-bg .collection-image-info p { - width: 100%; - color: #dedede !important; - text-align: left; - margin-bottom: 0px; - margin-top: 0px; -} - -header#page-bg .collection-image-info p.credit { - font-size: 0.9em; -} - -header#page-bg .collection-image-info.collapsed { - padding: 1.5em 1.75em; - background-color: rgba(22, 22, 22, 0.33); - opacity: 0.8; - color: #dedede !important; -} - -header#page-bg .collection-image-info.collapsed:hover { - opacity: 1; - background-color: rgba(0, 0, 0, 0.62); -} - -header#page-bg .collection-image-info.collapsed h3, -header#page-bg .collection-image-info.collapsed .info { - display: none; -} - -#wrap { - overflow: hidden; -} - -.box { - width: 25%; - padding-bottom: 25%; - position: relative; - float: left; -} - -.box a img { - width: 100%; - overflow: hidden; -} - -.boxInner { - position: absolute; - left: 0; - right: 0; - top: 0; - bottom: 0; - overflow: hidden; -} - -.boxInnerb { - position: absolute; - left: 0; - right: 0; - top: 0; - bottom: 0; - max-height: 225px; - overflow: hidden; -} - -.boxInner img { - -webkit-filter: blur(2px); - /* Safari 6.0 - 9.0 */ - filter: blur(2px); - width: 100%; -} - -.boxInnerb img { - -webkit-filter: blur(2px); - /* Safari 6.0 - 9.0 */ - filter: blur(2px); - width: 100%; -} - -.innerContent { - position: absolute; - left: 10px; - right: 10px; - top: 10px; - bottom: 10px; - text-align: center; - color: black; - -webkit-transition: 0.5s; - transition: 0.5s; - opacity: 0; -} - -.innerContent:hover { - opacity: 1; -} - -.innerContent p { - text-align: center; - background: rgba(255, 255, 255, 0.7); - color: #4f4f4f; - border-radius: 15px; -} - -.innerContent p em { - color: black; -} - -.innerContent a { - color: black; - background: rgba(255, 255, 255, 0.7); - text-decoration: underline; -} - -.innerContentb { - position: absolute; - left: 10px; - right: 10px; - top: 10px; - bottom: 10px; - text-align: center; - color: black; -} - -.innerContentc { - position: absolute; - left: 10px; - right: 10px; - top: 10px; - bottom: 10px; - text-align: center; - color: black; -} - -.innerContentb h2 { - text-align: center; - background: rgba(255, 255, 255, 0.7); - color: #4f4f4f; - border-radius: 15px; -} - -.innerContentb h2 em { - color: black; -} - -.innerContentb a { - color: black; - background: rgba(255, 255, 255, 0.7); - text-decoration: underline; -} - -.readux-home-tagline { - font-size: 3em; - font-weight: 700; -} - -.readux-home-ecds { - width: 20em; -} - -.readux-group-title { - font-size: 2em; - font-weight: 700; -} - -#rx-sort { - position: -webkit-sticky; - position: sticky; - top: 72px; -} - -// .rx-card-title { -// font-size: 1.25em; -// font-weight: 700; -// color: #595959; -// line-height: 1.25em; -// } - -// a:hover { -// text-decoration: initial !important; -// } - -// .rx-offcanvas-bar, -// .rx-offcanvas-base { -// background: white; -// -webkit-box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23); -// box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23); -// } - -p { - color: #595959; -} - -// .rx-breadcrumb, -// .rx-action-title, -// .rx-action-btn, -// .rx-page-breadcrumb-item, -// .rx-page-breadcrumb { -// color: var(--link-color); -// -webkit-filter: brightness(0.4%); -// filter: brightness(0.4%); -// text-transform: uppercase; -// font-weight: bold; -// letter-spacing: 0.1em; -// display: -webkit-inline-box; -// display: -ms-inline-flexbox; -// display: inline-flex; -// padding: 0; -// margin: 0; -// } - -.rx-page-breadcrumb-item a { - color: var(--link-color); -} - -.rx-page-breadcrumb { - white-space: nowrap; -} - -// .rx-page-logo { -// min-width: 65px; -// } - -// .rx-breadcrumb-item:not(:last-child)::after, -// .rx-page-breadcrumb-item:not(:last-child)::after { -// content: "-"; -// padding: 0 0.5em; -// } - -// .rx-page-title-container { -// padding: 0 15px; -// overflow-wrap: anywhere; -// -ms-flex-item-align: center; -// -ms-grid-row-align: center; -// align-self: center; -// } - -// .rx-breadcrumb-item > a, -// .rx-page-breadcrumb-item > a, -// .rx-action-btn, -// .rx-icon-btn, -// .uk-dropdown-nav > li > a:hover { -// color: var(--link-color) !important; -// -webkit-filter: brightness(1); -// filter: brightness(1); -// opacity: 0.75; -// -webkit-transition: all ease-in-out 100ms; -// transition: all ease-in-out 100ms; -// } - -// .rx-breadcrumb-item > a:hover, -// .rx-page-breadcrumb-item > a:hover, -// .rx-action-btn:hover, -// .rx-icon-btn:hover, -// .uk-dropdown-nav > li.uk-active > a { -// color: var(--link-color); -// opacity: 1; -// -webkit-transition: all ease-in-out 100ms; -// transition: all ease-in-out 100ms; -// } - -// .rx-head-container { -// margin: 0em 0 3em; -// } - -// .rx-info { -// margin: 1rem 0; -// } - -// .rx-info-title { -// border: 0.5px solid #e2e2e2; -// padding: 0.7em 1em 0.5em; -// color: #595959; -// letter-spacing: 0.15em; -// text-transform: uppercase; -// font-size: 0.875em; -// font-weight: bold; -// } - -// .rx-info-content-container { -// border: 0.5px solid #e2e2e2; -// padding: 1em 1em; -// word-break: break-word; -// } - -// .rx-info-content { -// padding: 0.5em 0; -// font-size: 0.9rem; -// } - -// .rx-info-content-label { -// color: #595959 !important; -// font-weight: 600 !important; -// line-height: 1em !important; -// font-size: 0.9rem !important; -// } - -// .rx-info-content-value { -// color: #595959; -// line-height: 1.5; -// } - -// .rx-card-body { -// text-align: left; -// min-width: 0; -// -webkit-box-flex: 1; -// -ms-flex: 1 1 auto; -// flex: 1 1 auto; -// /* margin-left: 2rem; */ -// } - -// .rx-card-image-container { -// /* width: 150px; */ -// -webkit-box-flex: 0; -// -ms-flex: 0 0 auto; -// flex: 0 0 auto; -// } - -// .rx-card-image { -// background-origin: border-box !important; -// background-size: cover !important; -// width: 100% !important; -// height: 100% !important; -// display: block !important; -// color: inherit; -// text-decoration: none; -// background-color: none; -// } - -// .rx-card-text { -// padding: 0; -// color: #595959; -// margin: 0.5em 0; -// overflow: hidden; -// text-overflow: ellipsis; -// display: -webkit-box; -// -webkit-line-clamp: 3; -// /* number of lines to show */ -// -webkit-box-orient: vertical; -// font-size: 14px; -// } - -// .rx-card-title { -// overflow: hidden; -// text-overflow: ellipsis; -// display: -webkit-box; -// -webkit-line-clamp: 1; -// /* number of lines to show */ -// -webkit-box-orient: vertical; -// } - -// .rx-grid-right { -// overflow: auto; -// } - -// #rx-nav { -/* position: fixed; - top: 0; - left: 5%; - right: 5%; - background: white; */ -/* position: sticky; - top: 0; */ -// background: white; -// } - -// .rx-grid-right { -// margin-left: 50%; -// } - -// .rx-btn { -// border-radius: 3px; -// border: solid 1px var(--link-color); -// -webkit-filter: contrast(var(--contrast)); -// filter: contrast(var(--contrast)); -// color: var(--link-color); -// filter: contrast(var(--contrast)); -// font-family: HelveticaNeue, Helvetica, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; -// font-size: 14px; -// font-weight: 500; -// line-height: 1.28; -// letter-spacing: normal; -// text-align: center; -// padding: 5px 12px; -// display: inline-block; -// } - -// .rx-btn:hover { -// border: solid 1px var(--link-color); -// color: white; -// background: var(--link-color); -// -webkit-filter: contrast(var(--contrast)); -// filter: contrast(var(--contrast)); -// -webkit-transition: all ease-in-out 100ms; -// transition: all ease-in-out 100ms; -// cursor: pointer; -// } - -// .rx-btn-extension { -// border-radius: 3px; -// border: solid 1px var(--link-color); -// -webkit-filter: contrast(var(--contrast)); -// filter: contrast(var(--contrast)); -// color: white; -// font-family: HelveticaNeue, Helvetica, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; -// font-size: 15px; -// font-weight: 600; -// line-height: 1.28; -// text-transform: uppercase; -// letter-spacing: 0.7px; -// text-align: center; -// padding: 8px 16px; -// display: inline-block; -// background: var(--link-color); -// color: white; -// border: solid 1px var(--link-color); -// } - -// .rx-btn-extension:hover { -// background: #5e0035; -// color: white; -// border: solid 1px #5e0035; -// -webkit-transition: all ease-in-out 100ms; -// transition: all ease-in-out 100ms; -// opacity: 1; -// cursor: pointer; -// } - -// .rx-annotation-badge { -// border-radius: 3px; -// background: white; -// color: #595959 !important; -// border: #595959 1px solid; -// font-size: 0.75rem; -// letter-spacing: 0.1rem; -// font-weight: 600; -// display: inline-block; -// cursor: default; -// text-transform: uppercase; -// padding: 0.1rem 0.5rem; -// } - -// .rx-padding-bottom-10 { -// padding-bottom: 10px; -// } - -// .uk-active > .rx-btn-annotation { -// background-color: #950953 !important; -// color: white; -// } - -// .uk-offcanvas-container { -// top: -80px; -// position: inherit; -// } - -// .readux-group-title:not(:first-child) { -// margin-top: 3rem; -// } - -// .rx-footer { -// display: -webkit-box; -// display: -ms-flexbox; -// display: flex; -// list-style: none; -// font-weight: bold; -// } - -// .rx-footer > a { -// padding: 1rem; -// color: #737373; -// -webkit-transition: all ease-in-out 100ms; -// transition: all ease-in-out 100ms; -// } - -// .rx-footer > a:first-child { -// padding-left: 0; -// } - -// .rx-footer > a:hover { -// color: #666; -// } - -// .rx-anchor { -// color: var(--link-color) !important; -// opacity: 0.75; -// -webkit-transition: all ease-in-out 100ms; -// transition: all ease-in-out 100ms; -// } - -// .rx-anchor:hover { -// color: var(--link-color); -// opacity: 1; -// } - -// ::-moz-selection { -// background-color: #595959; -// } - -// ::selection { -// background-color: #595959; -// } - -// .rx-label-copy { -// background: white; -// color: var(--link-color) !important; -// border: var(--link-color) 1px solid; -// font-size: 0.75rem; -// letter-spacing: 0.1rem; -// opacity: 0.75; -// cursor: pointer; -// -webkit-transition: all ease-in-out 100ms; -// transition: all ease-in-out 100ms; -// font-weight: 600; -// } - -// .rx-label-copy:active { -// background-color: #510029 !important; -// border: 1px solid #510029 !important; -// opacity: 1; -// } - -// .rx-page-navbar-right > a { -// margin-left: 1em; -// } - -// .rx-label-copy:hover { -// background: var(--link-color); -// color: white !important; -// font-size: 0.75rem; -// letter-spacing: 0.1rem; -// cursor: pointer; -// opacity: 1; -// } - -// .rx-flex { -// display: -webkit-box; -// display: -ms-flexbox; -// display: flex; -// } - -// .rx-tooltip-hidden { -// visibility: hidden; -// opacity: 0; -// -webkit-transition: visibility 0s 2s, opacity 2s linear; -// transition: visibility 0s 2s, opacity 2s linear; -// } - -// .rx-grid { -// margin: 40px auto; -// max-width: 1024px; -// display: -webkit-box; -// display: -ms-flexbox; -// display: flex; -// -ms-flex-wrap: wrap; -// flex-wrap: wrap; -// } - -// .rx-col { -// border: 1px dashed gray; -// -webkit-box-flex: 1; -// -ms-flex: 1 1 100px; -// flex: 1 1 100px; -// text-align: center; -// padding: 12px; -// } - -// .rx-top-left { -// position: absolute; -// top: 8px; -// left: 16px; -// } - -// .rx-image-container > figure { -// margin: auto; -// background-position: center; -// background-size: cover; -// width: 100%; -// height: 200px; -// } - -// .rx-volume-na { -// background: #fbecf9; -// padding: 15px; -// font-size: 14px; -// color: var(--link-color); -// } - -// a.rx-nav-item { -// color: var(--link-color) !important; -// } - -// .rx-nav-item.uk-active { -// color: var(--link-color); -// } - -// .rx-btn-small { -// font-size: 14px; -// font-weight: bold; -// letter-spacing: normal; -// text-align: center; -// padding: 6px 12px; -// } - -// .rx-fieldset { -// border: none; -// } - -// .rx-info-content .uk-tab a { -// color: #737373; -// } - -// .rx-info-content .uk-tab a:hover { -// color: #666; -// } - -// .rx-collection-title { -// font-weight: bold; -// color: #595959; -// } - -// /* Grid layout */ -// .rx-grid { -// display: -ms-grid; -// display: grid; -// margin: 15px auto; -// max-width: 1400px; -// -ms-grid-columns: (minmax(300px, 1fr))[auto-fill]; -// grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); -// grid-column-gap: 30px; -// /* justify-content: space-between; */ -// } - -// .rx-grid-layout { -// height: 425px; -// width: 275px; -// position: relative; -// background: white; -// margin-bottom: 75px; -// } - -// .rx-grid-image-container > img { -// -o-object-fit: cover; -// object-fit: cover; -// height: 400px; -// /* width: 200px; */ -// width: 100%; -// /* height: 100%; */ -// } - -/* Banner Layout */ -// .rx-banner-layout { -// display: -ms-grid; -// display: grid; -// margin: 20px auto; -// max-width: 100%; -// /* grid-template-columns: repeat(auto-fill, minmax(100%, 1fr)); */ -// -ms-grid-columns: 1fr; -// grid-template-columns: 1fr; -// /* grid-column-gap: 15px; */ -// /* justify-content: space-between; */ -// } - -// .rx-volume-in-banner { -// /* border: 1px solid black; */ -// /* text-align: center; */ -// /* height: 150px; */ -// width: 100%; -// margin: 15px 0; -// position: relative; -// background: black; -// } - -// .rx-banner-image-container > img { -// -o-object-fit: cover; -// object-fit: cover; -// height: 150px; -// width: 100%; -// opacity: 0.4; -// } - -// .rx-banner-text-container { -// position: absolute; -// left: 0; -// bottom: 0; -// padding: 1rem; -// color: #eeeeee; -// font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; -// } - -// .rx-collection-title-banner { -// color: white; -// font-size: 1.5rem; -// } - -// .rx-sticky { -// position: -webkit-sticky; -// position: sticky; -// top: 0; -// z-index: 1; -// } - -/*mirador overrides*/ -// .mirador-container .manifest-info { -// width: initial !important; -// } - -// .mirador-container .mirador-viewer a.mirador-icon-view-type, -// .mirador-container .mirador-viewer a.mirador-icon-metadata-view, -// .mirador-container .mirador-viewer a.mirador-osd-fullscreen { -// padding: 5px; -// margin: 0; -// } - -// .mirador-container .mirador-viewer { -// top: -12px !important; -// } - -// .mirador-container .workspace-container { -// left: -3px !important; -// } - -// .mirador-container .manifest-info { -// width: auto !important; -// float: right; -// z-index: 2; -// margin-top: 0px !important; -// } - -// .mirador-container .window-manifest-navigation { -// float: right; -// margin-left: 1em; -// } - -// .mirador-container .manifest-info { -// padding: 0.5rem; -// overflow: initial !important; -// } - -// .mirador-container .window-manifest-navigation { -// margin-left: initial; -// } - -// .mirador-container .mirador-viewer a.mirador-icon-view-type, -// .mirador-container .mirador-viewer a.mirador-icon-metadata-view, -// .mirador-container .mirador-viewer a.mirador-osd-fullscreen { -// display: -webkit-box; -// display: -ms-flexbox; -// display: flex; -// -webkit-box-orient: horizontal; -// -webkit-box-direction: normal; -// -ms-flex-direction: row; -// flex-direction: row; -// } - -// .mirador-container .mirador-viewer a.mirador-icon-view-type, -// .mirador-container .mirador-viewer a.mirador-icon-metadata-view, -// .mirador-container .mirador-viewer a.mirador-osd-fullscreen { -// margin-right: 0 !important; -// padding-bottom: 0 !important; -// } - -// .mirador-btn { -// padding: 0.5rem; -// } - -// .window-manifest-navigation { -// display: -webkit-box; -// display: -ms-flexbox; -// display: flex; -// -webkit-box-pack: justify; -// -ms-flex-pack: justify; -// justify-content: space-between; -// width: 55px; -// } - -// .tooltip { -// position: relative; -// display: inline-block; -// border-bottom: 1px dotted black; -// } - -// .tooltip .tooltiptext { -// visibility: hidden; -// width: 120px; -// background-color: black; -// color: #fff; -// text-align: center; -// border-radius: 6px; -// padding: 5px 0; -// position: absolute; -// z-index: 1; -// top: 150%; -// left: 50%; -// margin-left: -60px; -// font-size: 14px; -// } - -// .tooltip .tooltiptext::after { -// content: ""; -// position: absolute; -// bottom: 100%; -// left: 50%; -// margin-left: -5px; -// border-width: 5px; -// border-style: solid; -// border-color: transparent transparent black transparent; -// } - -// .tooltip:hover .tooltiptext { -// visibility: visible; -// } - -.rx-page-info-btn, -.rx-btn-secondary, -.rx-page-info-btn>.uk-icon-button { - color: var(--link-color) !important; - -webkit-filter: contrast(var(--contrast)); - filter: contrast(var(--contrast)); - opacity: 0.75; - font-size: 1rem; - font-weight: 600; -} - -.rx-page-info-btn:hover, -.rx-btn-secondary:hover, -.rx-page-info-btn>.uk-icon-button:hover { - color: white !important; -} - -.rx-offcanvas-close { - position: relative; - top: 0; - right: 0; - color: var(--link-color) !important; - -webkit-filter: contrast(var(--contrast)); - filter: contrast(var(--contrast)); -} - -.rx-offcanvas-close:hover { - color: var(--link-color) !important; - -webkit-filter: contrast(var(--contrast)); - filter: contrast(var(--contrast)); -} - -.rx-btn-secondary { - border: 3px solid var(--link-color); - -webkit-filter: contrast(var(--contrast)); - filter: contrast(var(--contrast)); - padding: 0.35em 1em; - white-space: nowrap; -} - -.rx-btn-secondary:hover { - color: white; - background-color: var(--link-color); - -webkit-filter: contrast(var(--contrast)); - filter: contrast(var(--contrast)); - opacity: 1; - -webkit-transition: all ease-in-out 100ms; - transition: all ease-in-out 100ms; -} - -.rx-page-info-btn:hover { - opacity: 1; - -webkit-transition: all ease-in-out 100ms; - transition: all ease-in-out 100ms; - color: var(--link-color); - -webkit-filter: contrast(var(--contrast)); - filter: contrast(var(--contrast)); -} - -.rx-btn-secondary:active { - background-color: var(--link-color); - border-color: var(--link-color); - -webkit-filter: brightness(75%); - filter: brightness(75%); -} - -// .rx-info-container { -// position: absolute; -// background: white; -// padding: 2rem; -// z-index: 2; -// right: 0; -// width: 50%; -// bottom: 0; -// overflow: scroll; -// top: 0; -// -webkit-box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23); -// box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23); -// } - -// fieldset { -// margin: inherit; -// border: 0; -// padding: inherit; -// } - -// #sidenav { -// background: white; -// position: absolute; -// top: 0; -// } - -// .rx-page-search-container { -// width: 100%; -// display: -webkit-box; -// display: -ms-flexbox; -// display: flex; -// -webkit-box-align: center; -// -ms-flex-align: center; -// align-items: center; -// -webkit-box-pack: justify; -// -ms-flex-pack: justify; -// justify-content: space-between; -// color: #595959 !important; -// } - -// .rx-page-search-options, -// .rx-page-search-option-label { -// display: block; -// } - -// .flex-parent { -// display: -webkit-box; -// display: -ms-flexbox; -// display: flex; -// -webkit-box-align: center; -// -ms-flex-align: center; -// align-items: center; -// padding: 10px; -// margin: 30px 0; -// } - -// .long-and-truncated { -// -webkit-box-flex: 1; -// -ms-flex: 1; -// flex: 1; -// white-space: nowrap; -// overflow: hidden; -// text-overflow: ellipsis; -// } - -// .short-and-fixed { -// white-space: nowrap; -// } - -// .short-and-fixed > div { -// width: 30px; -// height: 30px; -// border-radius: 10px; -// background: lightgreen; -// display: inline-block; -// } - -// .rx-search-icon { -// color: #595959 !important; -// } - -// .rx-search-input { -// border: none !important; -// color: #595959 !important; -// } - -// .rx-search-input::-webkit-input-placeholder { -// color: #737373 !important; -// } - -// .rx-search-input:-ms-input-placeholder { -// color: #737373 !important; -// } - -// .rx-search-input::-ms-input-placeholder { -// color: #737373 !important; -// } - -// .rx-search-input::placeholder { -// color: #737373 !important; -// } - -// .rx-search-result { -// font-size: 14px; -// } - -// .rx-search-result a { -// color: var(--link-color) !important; -// opacity: 0.7; -// } - -// .rx-search-result a:hover { -// color: var(--link-color) !important; -// opacity: 1; -// -webkit-transition: all ease-in-out 100ms; -// transition: all ease-in-out 100ms; -// } - -// .rx-title-container { -// background: white; -// padding: 1em 0; -// position: -webkit-sticky; -// position: sticky; -// top: 0; -// z-index: 3; -// } - -// .rx-title { -// font-size: 2em; -// font-weight: bold; -// color: var(--link-color); -// } - -// .rx-title-2 { -// font-size: 1.5em; -// font-weight: bold; -// color: #595959; -// } - -// .rx-title-tagline { -// font-size: 14px; -// color: #737373; -// } - -// .rx-title-tagline-banner { -// color: #eeeeee; -// } - -// .rx-title-image { -// -o-object-fit: cover; -// object-fit: cover; -// height: 150px; -// width: 100%; -// } - -// @media (max-width: 395px) { -// header#page-bg .collection-label h1 { -// font-size: 0.7em; -// } -// } - -// @media (max-width: 555px) { -// header#page-bg .collection-label h1 { -// font-size: 1em; -// } -// } - -// @media (max-width: 750px) { -// header#page-bg .collection-label h1 { -// font-size: 1.5em; -// } -// } - -// @media (max-width: 639px) { -// .rx-offcanvas-bar { -// width: 100%; -// } -// #offcanvas-usage { -// width: 100%; -// left: 0; -// } -// .rx-navbar-nav { -// display: block; -// } -// .uk-logo { -// padding: 0; -// } -// } - -// @media (min-width: 640px) { -// .rx-splash { -// /* position: fixed; */ -// display: -webkit-box; -// display: -ms-flexbox; -// display: flex; -// -webkit-box-orient: vertical; -// -webkit-box-direction: normal; -// -ms-flex-direction: column; -// flex-direction: column; -// -ms-flex-item-align: start; -// align-self: flex-start; -// position: -webkit-sticky; -// position: sticky; -// top: 0; -// -webkit-box-pack: justify; -// -ms-flex-pack: justify; -// justify-content: space-between; -// height: calc(100vh - 200px); -// } -// .rx-offcanvas-bar { -// width: 100%; -// } -// #offcanvas-usage { -// width: 50%; -// left: 50%; -// } -// } - -// @media (max-width: 750px) { -// .rx-page-logo { -// display: none; -// } -// .rx-page-title-container { -// padding: 0 15px 0 0; -// font-size: 0.9rem; -// } -// .rx-btn-secondary { -// border: none; -// padding: none; -// white-space: inherit; -// margin-left: -1rem !important; -// } -// .rx-page-breadcrumb { -// display: block; -// white-space: normal; -// } -// .rx-page-title { -// line-height: 1rem; -// } -// } - -// @media (min-width: 768px) { -// .modal-dialog > .modal-content { -// top: 200px; -// } -// } - -// @media (max-width: 960px) { -// .rx-info-container { -// width: 100%; -// left: 0; -// right: 0; -// padding: 0; -// } -// .rx-volume-image { -// margin-bottom: 1rem; -// } -// } - -// @media (min-width: 960px) { -// .rx-article { -// display: -webkit-box; -// display: -ms-flexbox; -// display: flex; -// -webkit-box-align: stretch; -// -ms-flex-align: stretch; -// align-items: stretch; -// /* flex: 1 1 auto; */ -// max-width: 680px; -// width: 100%; -// margin: 3rem 0; -// } -// .rx-article > .rx-card-image-container { -// padding: 0; -// } -// .uk-navbar-right { -// -ms-flex-wrap: initial; -// flex-wrap: initial; -// } -// } - -// @media (min-width: 320px) and (max-width: 959px) { -// .readux-home-ecds { -// display: none; -// } -// .readux-group-title { -// font-size: 1.5rem; -// } -// .rx-splash-item { -// font-size: 1.5rem; -// } -// .rx-title-image { -// -o-object-fit: cover; -// object-fit: cover; -// height: 150px; -// width: 100%; -// } -// // .rx-card-image-container { -// // height: 150px; -// // width: 100%; -// // } -// // .rx-card-body { -// // margin: 1rem 0 2rem 0; -// // } -// // .rx-card-title { -// // overflow: inherit; -// // display: block; -// // } -// .rx-card-text { -// overflow: inherit; -// display: block; -// } -// .rx-footer > a { -// padding: 0 0 1rem 0; -// } -// footer { -// padding: 2rem 0 0 0 !important; -// } -// } - -// @media (max-width: 1095px) { -// header#page-bg .collection-label h1 { -// font-size: 2em; -// } -// } - -// @media only screen and (max-width: 480px) { -// /* Smartphone view: 1 tile */ -// #box { -// width: 100%; -// padding-bottom: 100%; -// } -// } - -// @media only screen and (max-width: 650px) and (min-width: 481px) { -// /* Tablet view: 2 tiles */ -// #box { -// width: 50%; -// padding-bottom: 50%; -// } -// } - -// @media only screen and (max-width: 1050px) and (min-width: 651px) { -// /* Small desktop / ipad view: 3 tiles */ -// #box { -// width: 33.3%; -// padding-bottom: 33.3%; -// } -// } - -// @media only screen and (max-width: 1290px) and (min-width: 1051px) { -// /* Medium desktop: 4 tiles */ -// #box { -// width: 25%; -// padding-bottom: 25%; -// } -// } - -// @media only screen and (max-width: 1290px) and (min-width: 1051px) { -// /* Medium desktop: 4 tiles */ -// ul -// > li -// > .collectionbox -// > .collectioncontainer -// > .collection-label -// a.nav-link { -// font-size: 3em; -// } -// } - -// @media only screen and (max-width: 1050px) and (min-width: 651px) { -// /* Small desktop / ipad view: 3 tiles */ -// ul -// > li -// > .collectionbox -// > .collectioncontainer -// > .collection-label -// a.nav-link { -// font-size: 2.5em; -// } -// } - -// @media only screen and (max-width: 650px) and (min-width: 481px) { -// /* Tablet view: 2 tiles */ -// ul -// > li -// > .collectionbox -// > .collectioncontainer -// > .collection-label -// a.nav-link { -// font-size: 2em; -// } -// } - -// @media only screen and (max-width: 480px) { -// /* Smartphone view: 1 tile */ -// ul -// > li -// > .collectionbox -// > .collectioncontainer -// > .collection-label -// a.nav-link { -// font-size: 1em; -// } -// } - -// @media only screen and (max-width: 1250px) { -// ol { -// columns: 1; -// -webkit-columns: 1; -// -moz-columns: 1; -// } -// } - -// .rx-accordion-handle { -// color: var(--link-color) !important; -// } - -// .uk-accordion-content { -// color: #595959 !important; -// } - -// .rx-fixed-width-100 { -// min-width: 100px; -// text-align: center; -// } - -// .rx-accordion-content { -// margin: 0; -// padding: 0 0 10px 0; -// } - -// .rx-accordion-container { -// margin: 20px 0 0 0; -// } - -// .uk-offcanvas-bar .uk-open > .uk-accordion-title::before { -// background-image: url("data:image/svg+xml;charset=UTF-8,%8Csvg+width%3D%2213%22+height%3D%2213%22+viewBox%3D%220+0+13+13%22+xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0D%0A++++%3Crect+fill%3D%22rgba%28149%2C+9%2C+83%2C+1%29%22+width%3D%2213%22+height%3D%221%22+x%3D%220%22+y%3D%226%22+%2F%3E%0D%0A%3C%2Fsvg%3E") !important; -// } - -/* Search results page styles */ - -/* search form */ -form#search-form input[type="search"][name="q"] { - width: 100%; -} - -/* grid layout for filter panel and search results */ -div#search-grid { - margin-left: 0; -} - -// div#search-grid :first-child { -// padding-left: 0; -// } -// div#search-grid :first-child button#reset-filters { -// padding-left: 30px; -// } - -/* Date published filter toggle - * Adapted from https://codepen.io/adamhutch/pen/JoKEPp - */ - -/* -div#search-grid input[type="checkbox"]#toggle-date { - font-size: 14px; - display: none; -} -div#search-grid input[type="checkbox"]#toggle-date + label { - -webkit-transition: 0.3s background; - -moz-transition: 0.3s background; - transition: 0.3s background; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - cursor: pointer; - position: relative; - display: inline-block; - height: 1.5em; - width: 3em; - background: #ECECEC; - border-radius: 20em; - vertical-align: middle; -} -div#search-grid input[type="checkbox"]#toggle-date + label:before, input[type=checkbox]#toggle-date + label:after { - position: absolute; - top: 0; - left: 0; -} -div#search-grid input[type="checkbox"]#toggle-date + label:before { - -webkit-transition: 0.3s left; - -moz-transition: 0.3s left; - transition: 0.3s left; - content: ""; - display: inline-block; - background: rgba(0, 0, 0, 0.5); - height: 1.125em; - width: 1.125em; - margin: 0.1875em; - border-radius: 50%; - z-index: 5; -} -div#search-grid input[type="checkbox"]#toggle-date + label:after { - color: #fff; - content: "\f00d"; - font: 1.125em "FontAwesome"; - top: 50%; - margin-top: -0.5em; - left: 1.5em; -} -div#search-grid input[type="checkbox"]#toggle-date:checked + label { - background: #3FB8AF; -} -div#search-grid input[type="checkbox"]#toggle-date:checked + label:before { - left: 1.5em; -} -div#search-grid input[type="checkbox"]#toggle-date:checked + label:after { - content: "\f00c"; - left: 0.375em; -} -div#search-grid input[type="checkbox"]#toggle-date + label { - margin: 16px 0 0; -} -div#search-grid input[type="checkbox"]#toggle-date + label span { - position: absolute; - top: 0; - left: 55px; - width: 170px; -}*/ - -#search-filters input[type="text"]#authors-filter { - width: 100%; -} - -/* Multiselect filter */ -#search-filters select[multiple] { - height: 150px; - width: 100%; - overflow-y: scroll; - overflow-x: auto; -} - -/* Selectize */ - -.selectize-control.multi .selectize-input>div { - background: #950953 !important; - border: none !important; -} - -.selectize-dropdown .active:not(.selected) { - background-color: #fff7fb !important; -} - -.noUi-connect { - background: #950953 !important; -} - -[disabled] .noUi-connect { - background: #950953 !important; - opacity: 0.2; -} - -/* Date slider */ -.noUi-tooltip { - font-size: .875rem; - font-family: monospace; - font-weight: normal; - padding: 0.125rem 0.25rem !important; - background-color: none; - border: none !important; -} - -#search-filters .noUi-target { - margin: 45px 21px 10px; -} - -/* Individual search results */ -ol#search-results { - list-style: none; -} - -ol#search-results dl { - margin-left: 2rem; -} - -/* Clamp summary to 3 lines */ -#search-results .result-volume-summary { - display: -webkit-box; - -webkit-box-orient: vertical; - -webkit-line-clamp: 3; - overflow: hidden; -} - -/* search result highlighting */ -#search-results em { - color: #510029 !important; - font-weight: bold; - font-style: normal; -} - -/* results within full text */ -#search-results .result-page a { - display: flex; - flex-flow: row nowrap; - justify-content: flex-start; - align-items: flex-start; - font-size: 0.8rem; - gap: 1rem; - margin: 0.5rem 0; -} - -#search-results .result-page .page-number { - min-width: 4rem; - max-width: 4rem; -} - -#search-results .result-page ul li { - list-style: disc; -} - -.sr-only { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip: rect(0, 0, 0, 0); - border: 0; -} - -.sui-item-heading { - letter-spacing: 1.5px; - text-transform: uppercase; - font-weight: 600; - font-family: -apple-system, 'Helvetica Neue', 'Helvetica', 'Arial', 'Segoe UI', 'Roboto', 'Ubuntu', sans-serif; - font-size: 13px; -} - -.reader-modal { - /* display: block !important; */ - width: 400px !important; - height: fit-content !important; - padding: 0 !important; - left: 75px !important; - top: 60px !important; - background: white; -} - -.rx-line-height-sm { - line-height: 1.25em; -} - -.rx-volume-search em { - color: #E60000 !important; -} - -.rx-volume-search { - max-height: 75vh; -} - -.rx-padding-extra-small { - padding: 10px; -} - -.uk-accordion>:nth-child(n+2) { - margin-top: 10px; -} - -.rx-scrollable-area { - max-height: 75vh; - /* Maximum height set to 100% of the viewport height */ - overflow-y: auto; - /* Enables vertical scrolling */ - margin-right: -5px; - -ms-overflow-style: none; - /* IE and Edge */ - scrollbar-width: none; - /* Firefox */ - - &::-webkit-scrollbar { - display: none; - /* Safari and Chrome */ - } -} - - -.padding-right-1rem { - padding-right: 1rem; -} - -/* Override the minus sign in UI Kit accordion */ -.uk-open>.uk-accordion-title::before { - /* "-" Change the stroke color of the accordion icons to #1D3557 */ - background-image: url(data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22%231D3557%22%20width%3D%2213%22%20height%3D%221%22%20x%3D%220%22%20y%3D%226%22%20%2F%3E%0A%3C%2Fsvg%3E); -} - -.uk-open>.uk-accordion-title:hover { - - /* "-" Change the stroke color of the accordion icons to #1D3557 */ - &::before { - background-image: url(data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22%231D3557%22%20width%3D%2213%22%20height%3D%221%22%20x%3D%220%22%20y%3D%226%22%20%2F%3E%0A%3C%2Fsvg%3E) - } -} - -.uk-accordion-title::before { - /* "+" Change the stroke color of the accordion icons to white */ - background-image: url(data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22%231D3557%22%20width%3D%2213%22%20height%3D%221%22%20x%3D%220%22%20y%3D%226%22%20%2F%3E%0A%20%20%20%20%3Crect%20fill%3D%22%231D3557%22%20width%3D%221%22%20height%3D%2213%22%20x%3D%226%22%20y%3D%220%22%20%2F%3E%0A%3C%2Fsvg%3E); -} - -.uk-accordion-title:hover { - - /* "+" Change the stroke color of the accordion icons to white */ - &::before { - background-image: url(data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22%231D3557%22%20width%3D%2213%22%20height%3D%221%22%20x%3D%220%22%20y%3D%226%22%20%2F%3E%0A%20%20%20%20%3Crect%20fill%3D%22%231D3557%22%20width%3D%221%22%20height%3D%2213%22%20x%3D%226%22%20y%3D%220%22%20%2F%3E%0A%3C%2Fsvg%3E); - } -} - -/* End */ - - -.uk-padding-1-2 { - padding: 0.5rem; -} - -/* Set the theme color of the component */ -// $themeColor: #df3f13; - -/* import theme style */ -// @import '~vue-slider-component/lib/theme/default.scss'; - -// .ShowOCR { -// color: red !important; -// font-weight: bold !important; -// background-color: white !important; -// } -/*# sourceMappingURL=project.css.map */ - - -// NOTE: Migrated from templates/page.html -#v-readux.uk-container { - padding: 0; - max-width: none; -} \ No newline at end of file diff --git a/apps/static/css/readux.scss b/apps/static/css/readux.scss new file mode 100644 index 000000000..a0569fcb0 --- /dev/null +++ b/apps/static/css/readux.scss @@ -0,0 +1,491 @@ +/* -------------------------------------------------------------------------- */ +/* 0) IMPORTS */ +/* -------------------------------------------------------------------------- */ +@import './ecds-annotator.min.css'; +@import './partials/_mixin.scss'; +@import './partials/_colors.scss'; +@import './partials/_media.scss'; +@import './components/social-auth.scss'; +@import './components/wagtail.scss'; +@import './components/uk-switch.scss'; +@import './components/footer.scss'; + +/* -------------------------------------------------------------------------- */ +/* 1) ROOT VARIABLES */ +/* -------------------------------------------------------------------------- */ +:root { + --contrast: 200%; + --link-color: $rx-color-midnight-blue; +} + +/* -------------------------------------------------------------------------- */ +/* 2) BASE / LAYOUT */ +/* -------------------------------------------------------------------------- */ +.sr-only { @include sr-only(); } + +html, body { + height: 100%; + margin: 0; + display: flex; + flex-direction: column; +} + +main { flex-grow: 1; } + +/* Home page navigation transparent */ +.home-nav { nav { background-color: transparent !important; } } + +/* Overlay & content shell */ +.overlay { + position: absolute; + inset: 0 auto auto 0; + width: 100%; + height: 80vh; + min-height: 500px; + background-color: rgba($rx-color-midnight-blue, 0.8); +} + +.content { + position: relative; + z-index: 2; + min-height: 100vh; + display: flex; + flex-flow: column; + + .space { flex-grow: 1; } + .uk-section-default:empty { background-color: transparent; } +} + +/* Text & headings */ +.paragraph { color: $rx-color-midnight-blue; line-height: normal; } +.title { color: $rx-color-midnight-blue; font-size: x-large; font-weight: bold; } +.hero { padding-top: 15vh; color: $color-white; } +.uk-container h2 { margin-bottom: 0.35rem;} + +/* Utilities */ +.slash-gap { margin: 0 0.5rem; } +.color-black { color: $color-black; } + +/* Make nav z-order above content when overlayed */ +.uk-navbar-container { z-index: 10; position: absolute; width: 100%; } + +/* -------------------------------------------------------------------------- */ +/* 3) GLOBAL LINKS & INTERACTIVE */ +/* -------------------------------------------------------------------------- */ +.uk-link, a { + color: $rx-color-midnight-blue; + // text-decoration: underline; + transition: color 0.1s ease; + &:hover { color: rgba($rx-color-midnight-blue, 0.8); } +} + +// a:hover { text-decoration: initial !important; } + +.text-anchor { @include link-variant($rx-color-mario-red, 600, false); text-decoration: underline; } +.text-anchor-blue { @include link-variant($rx-color-midnight-blue, 700, true); } + +/* Consolidated interactive text on dark backgrounds */ +.brand-logo, .menu-item, .brand-readux { + @include interactive-color($color-white); + text-decoration: none !important; +} +.brand-logo { font-size: large; font-weight: bold; } +.menu-item { text-transform: unset !important; } +.brand-inline { font-size: small; font-weight: normal; text-decoration: underline !important; } +.brand-tagline { font-size: small; color: $color-white; } + +/* Page titles */ +.page-title { font-size: xx-large; font-weight: bold; color: $color-black; } +.page-text-lead { font-size: medium; color: $color-black; } + +em { color: inherit !important; } + +/* -------------------------------------------------------------------------- */ +/* 4) BREADCRUMBS & DROPDOWNS */ +/* -------------------------------------------------------------------------- */ +.breadcrumb { + list-style: none; + display: flex; + font-family: -apple-system, 'Helvetica Neue', 'Helvetica', 'Arial', 'Segoe UI', 'Roboto', 'Ubuntu', sans-serif; + font-size: 14px; + padding: 0; + margin: 0; + + > li { margin-right: 5px; } + > li + li::before { content: "/"; margin-right: 5px; color: $rx-color-midnight-blue; } + + a { + color: $rx-color-midnight-blue; + // text-decoration: underline; + transition: color 0.1s ease; + &:hover { color: rgba($rx-color-midnight-blue, 0.8); } + } + + .icon-chevron-down { + margin-left: 3px; + top: 1px; + position: relative;} +} + +/* Breadcrumb dropdown */ +.uk-navbar-dropdown { + background-color: $rx-color-faded-mint; + border-radius: 4px; + box-shadow: 0 4px 4px rgba($color-black, 0.1); + padding: 10px 0 !important; + min-width: 0 !important; +} + +.uk-navbar-dropdown-nav a, +.uk-navbar-dropdown-nav.sort-dropdown label { + cursor: pointer; + color: $rx-color-midnight-blue !important; + font-weight: 600; + padding: 5px 15px !important; + display: block; + transition: background-color 0.1s ease; + &:hover { background-color: rgba($rx-color-midnight-blue, 0.1); } +} + +.uk-navbar-dropdown-nav.sort-dropdown label input { display: none; } +.pagination-nav span { padding: 5px 15px !important; display: block; } + +/* -------------------------------------------------------------------------- */ +/* 5) UIKIT OVERRIDES / COMPONENTS */ +/* -------------------------------------------------------------------------- */ +/* Slidenav */ +.uk-slidenav { color: rgba($rx-color-midnight-blue, 0.6); &:hover { color: $rx-color-midnight-blue; } } + +/* Focus ring */ +.uk-input:focus, .uk-select:focus, .uk-textarea:focus { border-color: $rx-color-midnight-blue; } + +/* Buttons */ +.uk-button-default { @include interactive-border($rx-color-midnight-blue); } +.uk-button-primary { + background-color: var(--link-color); + &:hover, &:active { background-color: var(--link-color); filter: contrast(var(--contrast)); } +} + +/* Close icon */ +.uk-close { color: $rx-color-midnight-blue; &:hover { color: darken($rx-color-midnight-blue, 10%); } } + +/* Slider */ +.uk-slider-items { gap: 4rem; } + +/* Tabs */ +.uk-tab > .uk-active > a { border-color: var(--link-color) !important; color: var(--link-color) !important; } + +/* Form controls */ +.uk-checkbox, .uk-radio { border: 1px solid $rx-color-light-pearl !important; } + +/* Lists & list items */ +.uk-container ul { @include no-list-style; list-style: none; } + +/* Navbar */ +.uk-navbar-right { flex-wrap: initial; } + +/* Offcanvas */ +.uk-offcanvas-container { top: -80px; position: inherit; } + +/* Accordion */ +.uk-accordion-content { color: #595959 !important; } +.uk-accordion > :nth-child(n+2) { margin-top: 10px; } + +/* Override UIkit accordion icons */ +.uk-open > .uk-accordion-title::before { + background-image: url(data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22%231D3557%22%20width%3D%2213%22%20height%3D%221%22%20x%3D%220%22%20y%3D%226%22%20%2F%3E%0A%3C%2Fsvg%3E); +} +.uk-open > .uk-accordion-title:hover::before { + background-image: url(data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22%231D3557%22%20width%3D%2213%22%20height%3D%221%22%20x%3D%220%22%20y%3D%226%22%20%2F%3E%0A%3C%2Fsvg%3E); +} +.uk-accordion-title::before { + background-image: url(data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22%231D3557%22%20width%3D%2213%22%20height%3D%221%22%20x%3D%220%22%20y%3D%226%22%20%2F%3E%0A%20%20%20%20%3Crect%20fill%3D%22%231D3557%22%20width%3D%221%22%20height%3D%2213%22%20x%3D%226%22%20y%3D%220%22%20%2F%3E%0A%3C%2Fsvg%3E); +} +.uk-accordion-title:hover::before { + background-image: url(data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22%231D3557%22%20width%3D%2213%22%20height%3D%221%22%20x%3D%220%22%20y%3D%226%22%20%2F%3E%0A%20%20%20%20%3Crect%20fill%3D%22%231D3557%22%20width%3D%221%22%20height%3D%2213%22%20x%3D%226%22%20y%3D%220%22%20%2F%3E%0A%3C%2Fsvg%3E); +} + +/* Offcanvas accordion color override */ +.uk-offcanvas-bar .uk-open > .uk-accordion-title::before { + background-image: url("data:image/svg+xml;charset=UTF-8,%8Csvg+width%3D%2213%22+height%3D%2213%22+viewBox%3D%220+0+13+13%22+xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0D%0A++++%3Crect+fill%3D%22rgba%28149%2C+9%2C+83%2C+1%29%22+width%3D%2213%22+height%3D%221%22+x%3D%220%22+y%3D%226%22+%2F%3E%0D%0A%3C%2Fsvg%3E") !important; +} + +/* -------------------------------------------------------------------------- */ +/* 6) CARDS / GRID / LISTS */ +/* -------------------------------------------------------------------------- */ +/* Volume grid */ +.volume-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 2.5rem; } + +.grid-item { + text-align: left; + background-color: transparent; + cursor: pointer; + text-decoration: none; + opacity: 0.75; + transition: opacity 0.1s ease; + display: block; + color: $color-black; + + &:hover { opacity: 1; text-decoration: none; color: $color-black; } + + img { width: 100%; height: auto; display: block; border-radius: 4px; } + h2 { text-decoration: underline; color: $rx-color-midnight-blue; font-weight: 600; font-size: medium; margin: 0; } + p { margin: 0; } +} + +.collection-summary { + display: -webkit-box; + -webkit-line-clamp: 4; + line-clamp: 4; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; + white-space: normal; +} + +/* List view table */ +.list-view-table { + margin-left: -0.5rem; + + thead th { color: $rx-color-midnight-blue; font-weight: bold; } + tbody tr { color: rgba($color-black, 0.75); transition: color 0.3s ease; } + tbody tr:hover { background-color: $rx-color-faded-mint !important; color: $color-black; } + th, td { padding: 0.5rem; } +} + +/* Info line / pagination */ +.info-line { + display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; + font-weight: 600; color: $rx-color-midnight-blue; + .info-group, .pagination-controls { display: flex; align-items: center; gap: 5px; } + a, select { color: $rx-color-mario-red; text-decoration: underline; } +} + +.pagination-controls { .uk-icon-button { color: $rx-color-midnight-blue; } .uk-icon-button[disabled] { color: $rx-color-light-pearl; cursor: not-allowed; } } + +/* Hoverable rows */ +.list-item:hover, .clickable-row:hover { cursor: pointer; } + +/* -------------------------------------------------------------------------- */ +/* 7) SEARCH */ +/* -------------------------------------------------------------------------- */ +.search-bar form { display: flex; align-items: center; width: 100%; max-width: 800px; margin: 2rem auto; } +.search-bar { + input { flex: 1; height: 50px; border-top-left-radius: 5px; border-bottom-left-radius: 5px; font-size: 1.2em; } + button { + height: 50px; border-top-right-radius: 5px; border-bottom-right-radius: 5px; font-size: 1.2em; + background-color: $rx-color-mario-red; color: $color-white; border: none; display: flex; align-items: center; justify-content: center; transition: background-color 0.3s ease; + &:hover, &:active { background-color: darken($rx-color-mario-red, 10%); } + } +} + +/* Featured text area */ +.truncate-text { display: -webkit-box; -webkit-line-clamp: 5; line-clamp: 5; -webkit-box-orient: vertical; overflow: hidden; text-overflow: ellipsis; white-space: normal; } +.section-offset { background-color: $color-white; margin-top: 200px; } + +/* Video section */ +.video-section { position: relative; text-align: center; color: $color-white; } +.video-overlay { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 100%; cursor: pointer; z-index: 2; h2 { margin-bottom: 10px; font-size: 2em; } .play-icon { font-size: 48px; margin-bottom: 10px; } p { max-width: 600px; margin: 0 auto; } } +.video-container { position: relative; width: 100%; padding-bottom: 56.25%; background: $color-black; } +.video-thumbnail, iframe, .transparent-overlay { position: absolute; inset: 0; width: 100%; height: 100%; } +.video-thumbnail { object-fit: cover; } +.transparent-overlay { background-color: rgba($color-black, 0.5); z-index: 1; } +iframe { display: none; } + +/* -------------------------------------------------------------------------- */ +/* 10) SECTIONS / HIGHLIGHTS */ +/* -------------------------------------------------------------------------- */ +.column { background-color: $rx-color-faded-mint; padding: 2rem; border-radius: 8px; text-align: center; position: relative; } + +/* -------------------------------------------------------------------------- */ +/* 11) BUTTONS / AUTH */ +/* -------------------------------------------------------------------------- */ +.description-button { @include interactive-color($rx-color-mario-red, background-color); } +button.google, button.github { color: $color-white; } + +/* -------------------------------------------------------------------------- */ +/* 12) CONTENT PADDING TWEAKS */ +/* -------------------------------------------------------------------------- */ +.content > .uk-section { padding-bottom: 0; } + +/* -------------------------------------------------------------------------- */ +/* 13) PROJECT-SPECIFIC ELEMENTS (rx-*) */ +/* -------------------------------------------------------------------------- */ +.rx-breadcrumb, .rx-action-btn { + color: var(--link-color); + text-transform: uppercase; + font-weight: bold; + display: inline-flex; + padding: 0; margin: 0; user-select: auto; +} +.rx-action-btn { letter-spacing: 0.1em; font-size: small; } +.rx-action-btn:hover { + .rx-label-copy { background-color: $rx-color-midnight-blue !important; color: $color-white !important; } +} + +.rx-breadcrumb-item > a, .rx-action-btn, .rx-icon-btn, .uk-dropdown-nav > li > a:hover { + color: var(--link-color) !important; opacity: 0.75; transition: all 100ms ease-in-out; +} +.rx-breadcrumb-item > a:hover, .rx-action-btn:hover, .rx-icon-btn:hover, .uk-dropdown-nav > li.uk-active > a { + color: var(--link-color); opacity: 1; transition: all 100ms ease-in-out; +} + +.rx-anchor { color: var(--link-color) !important; opacity: 0.75; word-break: break-all; transition: all 100ms; &:hover { color: var(--link-color); opacity: 1; } } + +.rx-label-copy { + background: $color-white; + color: var(--link-color) !important; + border: var(--link-color) 1px solid; + font-size: 0.75rem; letter-spacing: 0.1rem; cursor: pointer; transition: all 100ms ease-in-out; font-weight: 600; font-family: 'Consolas','Monaco','Andale Mono','Ubuntu Mono','monospace' !important; + &:active { background-color: $rx-color-midnight-blue !important; border: 1px solid $rx-color-midnight-blue !important; opacity: 1; } + &:hover { background: $rx-color-midnight-blue; border-color: $rx-color-midnight-blue; color: $color-white !important; } +} + +/* Navigation & bars */ +.breadcrumbs { font-size: 80%; margin: 0; } + +/* Media / imagery */ +.openseadragon-container span { color: transparent; display: inline-flex !important; font-size: 100%; line-height: initial; white-space: nowrap; } +.box { width: 25%; padding-bottom: 25%; position: relative; float: left; } +.box a img { width: 100%; overflow: hidden; } +ul.listing-thumbs > li > img.thumbnail-image { height: 150px; } + +/* Info panels */ +.rx-head-container { margin: 0 0 3em; } +.rx-info-content { padding: 0 0 1.25em; font-size: 0.9rem; &:last-child { padding: 0; } } +.rx-info-content-label { color: $rx-color-cement-gray !important; font-weight: 600 !important; font-size: 0.9rem !important; } +.rx-info-content-value { color: $rx-color-cement-gray; line-height: 1.5; } +.rx-info-content .uk-tab a { color: $rx-color-cement-gray; &:hover { color: #666; } } + +/* Badges */ +.rx-annotation-badge { border-radius: 3px; background: $color-white; color: $rx-color-cement-gray !important; border: $rx-color-cement-gray 1px solid; font-size: 0.75rem; letter-spacing: 0.1rem; font-weight: 600; display: inline-block; cursor: default; text-transform: uppercase; padding: 0.1rem 0.5rem; } + +/* Fieldsets */ +.rx-fieldset { border: none; } + +/* Titles & banners */ +.rx-sticky { position: sticky; top: 0; z-index: 1; } +.rx-title-container { background: $color-white; padding: 1em 0; position: sticky; top: 0; z-index: 3; } +.rx-title { font-size: 2em; font-weight: bold; color: var(--link-color); } +.rx-title-2 { font-size: 1.5em; font-weight: bold; color: $rx-color-cement-gray; } +.rx-title-tagline { font-size: 14px; color: $color-white; } +.rx-title-image { object-fit: cover; height: 150px; width: 100%; } +.rx-breadcrumb-item { font-size: 1rem; font-weight: bold; color: var(--link-color); } + +/* Tooltip */ +.tooltip { position: relative; display: inline-block; border-bottom: 1px dotted black; } +.tooltip .tooltiptext { visibility: hidden; width: 120px; background-color: $color-black; color: $color-white; text-align: center; border-radius: 6px; padding: 5px 0; position: absolute; z-index: 1; top: 150%; left: 50%; margin-left: -60px; font-size: 14px; } +.tooltip .tooltiptext::after { content: ""; position: absolute; bottom: 100%; left: 50%; margin-left: -5px; border-width: 5px; border-style: solid; border-color: transparent transparent black transparent; } +.tooltip:hover .tooltiptext { visibility: visible; } + +/* Page search */ +.rx-page-search-container { width: calc(100% - 30px) !important; color: $rx-color-cement-gray !important; } +.rx-page-search-option-label { display: block; } + +/* Reader / viewer & layout utils */ +.rdx-viewer-container { position: absolute; left: 0; bottom: 0; height: calc(100% - 36px); width: 100%; margin: 0; } +#rdx-viewer > div > div > div.py-8.grid.grid-cols-2.gap-2 { padding-bottom: 0; } +.reader-modal { width: 400px !important; height: fit-content !important; padding: 0 !important; left: 75px !important; top: 60px !important; background: $color-white; } +.rx-line-height-sm { line-height: 1.25em; } +.rx-volume-search em { color: $rx-color-mario-red !important; } +.rx-volume-search { max-height: 75vh; } +.rx-padding-extra-small { padding: 10px; } +.rx-scrollable-area { max-height: 75vh; overflow-y: auto; -ms-overflow-style: none; scrollbar-width: none; &::-webkit-scrollbar { display: none; } } +.count { position: absolute; top: 0; right: 0; padding-top: 20%; padding-right: 20%; height: 10px; width: 10px; font-size: 10px; text-align: center; } +.rx-flex { display: flex; } +.uk-accordion-content { padding: 0.5rem 10px;} + +/* Accordion (rx-) */ +.rx-accordion-head { background: $color-white; color: var(--link-color); border: var(--link-color) 1px solid; font-size: 0.85rem; letter-spacing: 0.1rem; cursor: pointer; transition: all 100ms ease-in-out; font-weight: 600; font-family: 'Consolas','Monaco','Andale Mono','Ubuntu Mono','monospace' !important; &::before { color: $color-white; } } +.rx-accordion-handle { color: var(--link-color) !important; } +.rx-accordion-content { margin: 0; padding: 0 0 10px 0; } +.rx-accordion-container { margin: 20px 0 0 0; } + + +.thumbnail-container { + width: 120px; +} +.thumbnail-container img { + width: 100%; + height: auto; + object-fit: cover; +} + +.cursor-default { + &:hover { + cursor: default !important; + } +} + + +/* Volume grid specific styles */ + /* square container for covers */ + .cover-square { + position: relative; + width: 100%; + aspect-ratio: 1 / 1; /* makes a perfect square */ + background: #000; + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; + border-radius: 4px; + } + .cover-square img { + max-width: 100%; + max-height: 100%; + width:auto; + height:auto; + display: block; + object-fit: contain; + object-position: center; + } + .volume-title, + .volume-title-inline { + margin-top: .5rem; + margin-bottom: .25rem; + line-height: 1.25; + } + .volume-title__link { + color: $rx-color-midnight-blue; + font-weight: 600; + font-size: medium; + text-decoration: underline; + } + .volume-title__year { + white-space: nowrap; + } + .volume-title__link:hover { + color: $rx-color-midnight-blue; + text-decoration: underline; + } + .volume-year { + margin-top: .5rem; + font-weight: 600; + color: $rx-color-midnight-blue; + line-height: 1.25; + } + .author-line { + color: #555; + line-height: 1.25; + display: -webkit-box; + -webkit-line-clamp: 3; + line-clamp: 3; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; + white-space: normal; + } +/* End */ + +.rx-line-height-lg { + line-height: 1.15em; +} + +.rx-line-height-md { + line-height: 1em; +} + +.rx-line-height-sm { + line-height: 0.85em; +} diff --git a/apps/static/css/readux2/main.scss b/apps/static/css/readux2/main.scss deleted file mode 100644 index 7f97638a8..000000000 --- a/apps/static/css/readux2/main.scss +++ /dev/null @@ -1,739 +0,0 @@ -/* base.html */ -html, -body { - height: 100%; - margin: 0; - display: flex; - flex-direction: column; -} - -#v-readux { - flex-grow: 1; - display: flex; - flex-direction: column; -} - -main { - flex-grow: 1; -} - -.home-nav { - nav { - background-color: transparent !important; - } -} - -.overlay { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 80vh; - min-height: 500px; - background-color: rgba(29, 53, 87, 0.8); - /* Adjust the opacity as needed */ -} - -.uk-alert { - z-index: 99; -} - -.content { - position: relative; - z-index: 2; - min-height: 100vh; - display: flex; - flex-flow: column; - - .space { - flex-grow: 1; - } - - .uk-section-default:empty { - background-color: transparent; - } -} - -.content-page { - // margin-top: 80px -} - -.paragraph { - color: #1D3557; - line-height: normal; -} - -.text-anchor { - color: #E60000; - text-decoration: underline; - transition: ease 0.1s; - - &:hover { - color: darken(#E60000, 10%); - /* Darken the color when hovered */ - } - - &:active { - color: #990000; - /* Darken even further when clicked */ - } -} - -.text-anchor-blue { - color: #1D3557; - font-weight: bold; - transition: ease 0.1s; - - &:hover { - color: darken(#1D3557, 10%); - /* Darken the color when hovered */ - text-decoration: underline; - } - - &:active { - color: darken(#1D3557, 25%); - /* Darken the color when hovered */ - text-decoration: underline; - } -} - -.hero { - padding-top: 15vh; - color: white; -} - -.menu-item { - color: white !important; - text-decoration: none !important; - transition: color 0.1s ease !important; - text-transform: unset !important; - font-weight: 500; - - &:hover { - color: rgba(255, 255, 255, 0.8) !important; // Slightly dim - } - - &:active { - color: rgba(255, 255, 255, 0.6) !important; // A bit darker - } -} - -.brand-logo { - transition: color 0.1s ease !important; - - &:hover { - color: rgba(255, 255, 255, 0.8) !important; // Slightly dim - } - - &:active { - color: rgba(255, 255, 255, 0.6) !important; // A bit darker - } -} - -.brand-readux { - color: white; - text-decoration: underline; - - &:hover { - color: rgba(255, 255, 255, 0.8) !important; // Slightly dim - } - - &:active { - color: rgba(255, 255, 255, 0.6) !important; // A bit darker - } -} - -.title { - color: #1D3557; - font-size: x-large; - font-weight: bold; -} - -/* util */ -.slash-gap { - margin: 0 0.5rem; -} - -.color-black { - color: black; -} - -.color-blue { - color: #1D3557; -} - - - -/* Overrides */ -.uk-slidenav { - color: rgba(29, 53, 87, 0.6); - /* Override the default colors with the blue */ - - &:hover { - color: rgba(29, 53, 87, 1); - /* Override the default colors with the blue */ - } -} - -.uk-input:focus, -.uk-select:focus, -.uk-textarea:focus { - border-color: #1D3557; -} - -.uk-button-default { - transition: ease 0.1s; - - &:hover { - border-color: darken(#1D3557, 10%); - } - - &:active { - border-color: darken(#1D3557, 25%); - } -} - -.uk-close { - color: #1D3557; - - &:hover { - border-color: darken(#1D3557, 10%); - } - - &:active { - border-color: darken(#1D3557, 25%); - } -} - -/* ui kit slider */ - -/* Add gap between items */ -.uk-slider-items { - gap: 4rem; - /* Adjust the gap size as needed */ -} - -/* Make images square */ -.square-image { - width: 100%; - aspect-ratio: 1 / 1; - object-fit: cover; - /* Ensure the image covers the entire square without distorting */ -} - -/* breadcrumb */ -.breadcrumb { - list-style: none; - display: flex; - font-family: -apple-system, 'Helvetica Neue', 'Helvetica', 'Arial', 'Segoe UI', 'Roboto', 'Ubuntu', sans-serif; - font-size: 14px; - padding: 0; - margin: 0; -} - -.breadcrumb>li { - margin-right: 5px; -} - -.breadcrumb>li+li::before { - content: "/"; - margin-right: 5px; - color: #1D3557; - /* Color of the separator */ -} - -.breadcrumb a { - text-decoration: underline; - color: rgba(29, 53, 87, 1.0); - /* Link color */ - transition: color 0.1s ease; - - &:hover { - color: rgba(29, 53, 87, 0.8); - /* Hover state */ - } -} - -.breadcrumb .icon-chevron-down { - margin-left: 3px; -} - -/* breadcrumb dropdown */ -.uk-navbar-dropdown { - background-color: #f8fdf4; - /* Light greenish background color */ - border-radius: 4px; - /* Rounded corners */ - box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.1); - /* Soft shadow for depth */ - padding: 10px 0 !important; - // margin-top: 10px !important; /* Force a gap between the trigger and dropdown */ - min-width: 0 !important; -} - -.uk-navbar-dropdown-nav a, -.uk-navbar-dropdown-nav.sort-dropdown label { - cursor: pointer; - color: #1D3557 !important; - /* Dark blue text color */ - font-weight: 600; - /* Bold text */ - padding: 5px 15px !important; - /* Add padding to the items */ - display: block; - transition: background-color 0.1s ease; -} - -.uk-navbar-dropdown-nav a:hover, -.uk-navbar-dropdown-nav.sort-dropdown label:hover { - background-color: rgba(29, 53, 87, 0.1); - /* Light blue hover effect */ -} - -.uk-navbar-dropdown-nav.sort-dropdown label input { - display: none; -} - -.pagination-nav span { - padding: 5px 15px !important; - display: block; -} - -/* page */ -.page-title { - font-size: xx-large; - font-weight: bold; - color: #000000; -} - -.page-text-lead { - font-size: medium; - color: #000000; -} - -/* volume grid */ -.info-line { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 20px; - font-weight: 600; - /* Font weight for the information line */ - color: #1D3557; - /* Color for the information line */ -} - -.info-line .info-group { - display: flex; - align-items: center; - gap: 5px; -} - -.info-line .pagination-controls { - display: flex; - align-items: center; - gap: 5px; -} - -.info-line a, -.info-line select { - color: #E60000; - /* Clickable item color */ - text-decoration: underline; - /* Underline for clickable items */ -} - -.pagination-controls .uk-icon-button { - color: #1D3557; - /* Arrow button color */ -} - -.pagination-controls .uk-icon-button[disabled] { - color: #ccc; - /* Greyed out for disabled state */ - cursor: not-allowed; -} - -.volume-grid { - display: grid; - grid-template-columns: repeat(4, 1fr); - /* Four items per row */ - gap: 2.5rem; - /* Space between items */ -} - -.grid-item { - text-align: left; - background-color: transparent; - cursor: pointer; - text-decoration: none; - opacity: 0.75; - /* Normal state opacity */ - transition: opacity 0.1s ease; - display: block; - color: black; -} - -.grid-item img { - width: 100%; - height: auto; - /* Maintain aspect ratio of images */ - display: block; - margin-bottom: 10px; - /* Space between image and title */ - border-radius: 4px; -} - -.grid-item:hover { - opacity: 1.0; - /* Change opacity on hover */ - text-decoration: none; - color: black; -} - -.grid-item h2 { - text-decoration: underline; - /* Underline for title */ - color: #1D3557; - font-weight: 600; - font-size: medium; - margin: 0; -} - -.grid-item p { - margin: 0; -} - -/* list view table */ -.list-view-table { - margin-left: -0.5rem; -} - -.list-view-table thead th { - color: #1D3557; - font-weight: bold; -} - -.list-view-table tbody tr:hover { - background-color: #F1FAEE !important; -} - -.list-view-table tbody tr { - color: rgba(0, 0, 0, 0.75); - transition: color 0.3s ease; -} - -.list-view-table tbody tr:hover { - color: rgba(0, 0, 0, 1); -} - -.list-item:hover { - cursor: pointer; -} - -.clickable-row:hover { - cursor: pointer; -} - -.list-view-table th, -.list-view-table td { - padding: 0.5rem; -} - -/* search bar */ -.search-bar form { - display: flex; - align-items: center; - width: 100%; - max-width: 800px; - margin: 2rem auto; -} - -.search-bar input { - flex: 1; - height: 50px; - /* Adjust this value for desired height */ - border-top-left-radius: 5px; - border-bottom-left-radius: 5px; - font-size: 1.2em; - /* Adjust the font size if needed */ -} - -.search-bar button { - height: 50px; - /* Match the input height */ - border-top-right-radius: 5px; - border-bottom-right-radius: 5px; - font-size: 1.2em; - /* Adjust the font size if needed */ - background-color: #E60000; - color: white; - border: none; - display: flex; - align-items: center; - justify-content: center; - transition: background-color 0.3s ease; -} - -.search-bar button:hover { - background-color: darken(#E60000, 10%); - /* Darken the color when hovered */ -} - -.search-bar button:active { - background-color: #990000; - /* Darken even further when clicked */ -} - -/* featured text area */ -.truncate-text { - display: -webkit-box; - -webkit-line-clamp: 5; - /* Number of lines to show */ - line-clamp: 5; - /* Number of lines to show */ - -webkit-box-orient: vertical; - overflow: hidden; - text-overflow: ellipsis; - white-space: normal; -} - -.section-offset { - // position: relative; - // top: 20vh; - background-color: white; - /* Ensures the background is visible */ - // padding: 20px 0; - - margin-top: 200px; -} - -/* featured books */ -.book-title { - line-height: normal; -} - -.book-title a { - color: #1D3557; - font-size: 1em; - text-decoration: underline; -} - -.featured-title { - font-size: 2em; - font-weight: bold; -} - -/* video section */ -.video-section { - position: relative; - text-align: center; - color: white; -} - -.video-overlay { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 100%; - cursor: pointer; - z-index: 2; -} - -.video-overlay h2 { - margin-bottom: 10px; - font-size: 2em; -} - -.video-overlay .play-icon { - font-size: 48px; - margin-bottom: 10px; -} - -.video-overlay p { - max-width: 600px; - margin: 0 auto; -} - -.video-container { - position: relative; - width: 100%; - padding-bottom: 56.25%; - /* 16:9 aspect ratio */ - background: black; -} - -.video-thumbnail { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - object-fit: cover; -} - -.transparent-overlay { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background-color: rgba(0, 0, 0, 0.5); - /* 50% transparent black */ - z-index: 1; -} - -iframe { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - display: none; -} - -.uk-navbar-container { - z-index: 10; - position: absolute; - width: 100%; -} - -/* footer */ -.footer { - background-color: #457B9D; - color: white; - padding: 20px; - // min-height: 20vh; -} - -.footer-content { - display: flex; - justify-content: space-between; - width: 100%; - max-width: 1200px; - margin-bottom: 10px; -} - -.footer-links { - display: flex; - flex-direction: column; - font-weight: bold; -} - -.footer-links a { - color: white; - text-decoration: none; -} - -.footer-links a:hover { - text-decoration: underline; -} - -.footer-logo { - display: flex; - align-items: center; -} - -.footer-logo svg { - width: 50px; - height: 50px; -} - -.footer-bottom { - text-align: left; - margin-top: 10px; - color: white; -} - -/* highlight section */ -.three-column-section { - padding: 50px 0; - text-align: center; -} - -.column { - background-color: #F1FAEE; - padding: 2rem; - border-radius: 8px; - text-align: center; - position: relative; -} - -.blob { - background-color: #FFFFFF; - width: 80px; - height: 80px; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - margin: 0 auto; -} - -.icon-placeholder { - width: 40px; - height: 40px; - fill: #457B9D; -} - -.column-text { - margin-top: 4rem; - color: #1D3557; - font-size: 1.75rem; - line-height: 2.5rem; -} - -.section-title { - color: #1D3557; - font-size: 2em; - font-weight: bold; - margin-bottom: 4rem; -} - -.brand-logo { - font-size: large; - color: white; - font-weight: bold; -} - -.brand-tagline { - font-size: small; - color: white; -} - -.description-button { - transition: ease 0.1s; - - &:hover { - background-color: darken(#E60000, 10%); - } - - &:active { - background-color: darken(#E60000, 25%); - } -} - -.justify-content-normal { - justify-content: normal !important; -} - -.unset-min-height { - min-height: unset !important; -} - -button.google { - background-color: #ea4335; - color: white; -} - - -button.github { - background-color: #24292e; - color: white; -} - -/* Make every .uk-section element inside .content have padding-bottom: 0 */ -.content > .uk-section { - padding-bottom: 0; -} \ No newline at end of file diff --git a/apps/static/css/readux2/menu-inverse.scss b/apps/static/css/readux2/menu-inverse.scss deleted file mode 100644 index 6bea72c9c..000000000 --- a/apps/static/css/readux2/menu-inverse.scss +++ /dev/null @@ -1,49 +0,0 @@ -/* Inverse the color for content pages */ -.menu-item { - color: rgba(29, 53, 87, 1.0) !important; - text-decoration: none !important; - transition: color 0.1s ease !important; - - &:hover { - color: rgba(29, 53, 87, 0.8) !important; // Slightly dim - } - - &:active { - color: rgba(29, 53, 87, 0.6) !important; // A bit darker - } -} - -.brand-logo { - font-size: large; - color: #1D3557; - font-weight: bold; - - &:hover { - color: rgba(29, 53, 87, 0.8) !important; // Slightly dim - } - - &:active { - color: rgba(29, 53, 87, 0.6) !important; // A bit darker - } -} - -.brand-tagline { - font-size: small; - color: #1D3557; -} - -.brand-readux { - color: #1D3557; - - &:hover { - color: rgba(29, 53, 87, 0.8) !important; // Slightly dim - } - - &:active { - color: rgba(29, 53, 87, 0.6) !important; // A bit darker - } -} - -.uk-navbar-container { - position: relative; -} \ No newline at end of file diff --git a/apps/static/css/readux2/migration.scss b/apps/static/css/readux2/migration.scss deleted file mode 100644 index 7759c9b6b..000000000 --- a/apps/static/css/readux2/migration.scss +++ /dev/null @@ -1,16 +0,0 @@ -// NOTE: Migrated from templates/page.html -#v-readux.uk-container { - padding: 0; - max-width: none; -} - -.sr-only { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip: rect(0,0,0,0); - border: 0; -} \ No newline at end of file diff --git a/apps/static/css/readux2/reader.scss b/apps/static/css/readux2/reader.scss deleted file mode 100644 index e34da8fb4..000000000 --- a/apps/static/css/readux2/reader.scss +++ /dev/null @@ -1,44 +0,0 @@ -.reader-navbar { - padding: 0 1rem; height: 36px; -} - -.rx-accordion-head { - background-color: #F1FAEE; - color: #1D3557; - border: none; - &:hover { - color: #1D3557 !important; - background-color: darken(#F1FAEE, 5%) !important; - border: none; - .rx-accordion-head::before { - color: #1D3557 !important; - } - } - &:active { - border: none; - } -} - -.rx-accordion-head::before { - color: #1D3557 !important; -} - -.rx-anchor { - color: #1D3557 !important; -} - -.rx-btn { - &:hover { - background-color: #1D3557 !important; - border-color: #1D3557 !important; - } -} - -.uk-tab > .uk-active > a { - border-color: #1D3557 !important; - color: #1D3557 !important; -} - -.uk-search-default .uk-search-input:focus, .uk-input:focus, .uk-select:focus, .uk-textarea:focus { - border-color: #1D3557; -} \ No newline at end of file diff --git a/apps/static/css/readux2/search.scss b/apps/static/css/readux2/search.scss deleted file mode 100644 index 6e7e44171..000000000 --- a/apps/static/css/readux2/search.scss +++ /dev/null @@ -1,287 +0,0 @@ -.info-line { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 20px; - font-weight: 600; - color: #1D3557; // This could be replaced by a variable if one exists in your SCSS file - flex-wrap: wrap; // Ensure wrapping on smaller screens -} - -.info-line .info-group { - display: flex; - align-items: center; - gap: 5px; - flex-wrap: wrap; // Enable wrapping for better responsiveness -} - -.info-line .pagination-controls { - display: flex; - align-items: center; - gap: 5px; -} - -.info-line a, -.info-line select { - color: #1D3557; // Again, this could use a variable if defined in your file - text-decoration: underline; -} - -.pagination-controls .uk-icon-button { - color: #1D3557; -} - -.pagination-controls .uk-icon-button[disabled] { - color: #ccc; - cursor: not-allowed; -} - -@media (max-width: 768px) { - .info-line { - flex-direction: column; - align-items: flex-start; - } - - .info-line .info-group, - .info-line .pagination-controls { - width: 100%; - justify-content: space-between; - margin-bottom: 10px; - } - - .info-line .info-group { - gap: 10px; - } -} - - -/* normalize form fieldset */ -fieldset { - margin: inherit; - border: 0; - padding: inherit; -} - -/* copied from original scss file */ -#search-form .uk-button-danger { - background-color: #f0506e; - color: #fff; - border: 1px solid transparent; -} - -#search-form .uk-button-secondary { - background-color: #222; - color: #fff; - border: 1px solid transparent; -} - -/* search form */ -form#search-form input[type="search"][name="q"] { - width: 100%; -} - -#search-filters input[type="text"]#authors-filter { - width: 100%; -} - -/* Multiselect filter */ -#search-filters select[multiple] { - height: 150px; - width: 100%; - overflow-y: scroll; - overflow-x: auto; -} - -#search-filters .noUi-target { - margin: 45px 21px 10px; -} - -.sui-item-heading { - letter-spacing: 1.5px; - text-transform: uppercase; - font-weight: 600; - font-family: -apple-system, 'Helvetica Neue', 'Helvetica', 'Arial', 'Segoe UI', 'Roboto', 'Ubuntu', sans-serif; - font-size: 13px; - margin-top: 0.65rem; - - a { - color: #1D3557; - } -} - -#search-filters select[multiple] { - height: 150px; - width: 100%; - overflow-y: scroll; - overflow-x: auto; -} - -.uk-button-primary { - background-color: #1D3557; - - &:hover { - background-color: darken(#1D3557, 10%); - /* Darken the color when hovered */ - } -} - -.uk-container ul { - list-style: none; -} - -form#search-form input[type="search"][name="q"] { - width: 100%; -} - -#search-grid { - gap: 1.5rem; -} - - - -#search-filters input[type="text"]#authors-filter { - width: 100%; -} - -/* Multiselect filter */ -#search-filters select[multiple] { - height: 150px; - width: 100%; - overflow-y: scroll; - overflow-x: auto; -} - -/* Selectize */ - -.selectize-control.multi .selectize-input>div { - background: #1D3557 !important; - border: none !important; -} - -.selectize-dropdown .active:not(.selected) { - background-color: #F1FAEE !important; -} - -.noUi-connect { - background: #1D3557 !important; -} - -[disabled] .noUi-connect { - background: #1D3557 !important; - opacity: 0.2; -} - -/* Date slider */ -.noUi-tooltip { - font-size: .875rem; - font-family: monospace; - font-weight: normal; - padding: 0.125rem 0.25rem !important; - background-color: none; - border: none !important; -} - -#search-filters .noUi-target { - margin: 45px 21px 10px; -} - -/* Individual search results */ -ol#search-results { - list-style: none; -} - -ol#search-results dl { - margin-left: 2rem; -} - -/* Clamp summary to 3 lines */ -#search-results .result-volume-summary { - display: -webkit-box; - -webkit-box-orient: vertical; - -webkit-line-clamp: 3; - overflow: hidden; -} - -/* search result highlighting */ -#search-results em { - color: #E60000 !important; - font-weight: bold; - font-style: normal; -} - -/* results within full text */ -#search-results .result-page { - background-color: #F1FAEE; - color: #1D3557; -} - -#search-results .result-page a { - display: flex; - flex-flow: row nowrap; - justify-content: flex-start; - align-items: flex-start; - font-size: 0.8rem; - gap: 1rem; - margin: 0.5rem 0; - color: #1D3557; -} - -#search-results .result-page .page-number { - min-width: 50px; - font-size: large; - font-weight: 600; - letter-spacing: -1px; - text-transform: uppercase; -} - -#search-results .result-page ul li { - list-style: disc; -} - -.result-title { - color: #1D3557; - - &:hover { - color: darken(#1D3557, 10%); - /* Darken the color when hovered */ - } -} - -.uk-checkbox:checked, -.uk-checkbox:indeterminate, -.uk-radio:checked { - background-color: #1D3557 !important; -} - -.uk-search-default .uk-search-input:focus, -.uk-input:focus, -.uk-select:focus, -.uk-textarea:focus { - border-color: #1D3557; -} - -.uk-search-default .uk-search-input:focus { - border-right: 0; -} - -.selectize-control.plugin-clear_button .clear { - height: 85%; -} - -.search-button { - background-color: #E60000; - color: white; - padding: 0 9px; - border: none; - height: 40px; - font-size: 1.25rem; - transition: ease 0.1s; - - &:hover { - background-color: darken(#E60000, 10%); - } - - &:active { - background-color: darken(#E60000, 25%); - } -} \ No newline at end of file diff --git a/apps/static/css/readux2/static.scss b/apps/static/css/readux2/static.scss deleted file mode 100644 index 3c28302b9..000000000 --- a/apps/static/css/readux2/static.scss +++ /dev/null @@ -1,86 +0,0 @@ -.navigation-wrapper { - margin-left: -2rem; -} -.navigation { - background-color: #F1FAEE; - padding: 30px; - position: sticky; - top: 20px; - border-radius: 10px 10px; /* Rounded corners on the right-hand side */ - width: auto; /* Fit to content width */ -} -.navigation a { - color: #1D3557; - text-decoration: none; - display: block; - padding: 5px 15px !important; - position: relative; - font-weight: normal; - font-size: medium; -} -.navigation a.active { - font-weight: bold; /* Bold text for active item */ - color: #1D3557; - &:hover { - color: darken(#1D3557, 10%) !important; - } -} -.navigation a.active::before { - content: ''; - position: absolute; - left: 3px; - top: 50%; - transform: translateY(-50%); - height: 75%; - width: 4px; - background-color: #1D3557; -} -.content { - padding: 40px; -} -.section { - padding-bottom: 40px; -} -.static-content-title { - font-weight: bold; - margin: unset; -} -.content p, .content ul { - margin-top: 0; - margin-bottom: 1rem; - color: black; -} -.content ol, .content li { - margin-top: 0; - color: black; -} -.content h1, .content h2, .content h3, .content h4, .content h5, .content h6 { - margin-top: 1.25rem !important; - margin-bottom: 0.5rem !important; -} -.content ul:first-of-type, .content li:first-of-type, .content p:first-of-type { - margin-top: 0; -} -.content li:last-of-type { - margin-bottom: 0; -} - -/* a series of indentation for the side nav headers */ -.indent-h1 a { - color: #1d3557 !important; - // font-size: 1.5rem; -} -.indent-h2 a { - color: #1d3557 !important; - // font-size: 1.25rem; -} -.indent-h3 a { - color: #1d3557 !important; - // font-size: 1.0rem; - margin-left: 1.5rem; -} -.indent-h4 a { - color: #1d3557 !important; - // font-size: 0.85rem; - margin-left: 2.5rem; -} \ No newline at end of file diff --git a/apps/static/js/components/InfoExport.vue b/apps/static/js/components/InfoExport.vue new file mode 100644 index 000000000..7cc72fed6 --- /dev/null +++ b/apps/static/js/components/InfoExport.vue @@ -0,0 +1,154 @@ + + + diff --git a/apps/static/js/components/InfoUrlExternal.vue b/apps/static/js/components/InfoUrlExternal.vue new file mode 100644 index 000000000..573b1faa9 --- /dev/null +++ b/apps/static/js/components/InfoUrlExternal.vue @@ -0,0 +1,53 @@ + + + diff --git a/apps/static/js/components/InfoUrlMultiple.vue b/apps/static/js/components/InfoUrlMultiple.vue new file mode 100644 index 000000000..3fdc0416b --- /dev/null +++ b/apps/static/js/components/InfoUrlMultiple.vue @@ -0,0 +1,19 @@ + + + diff --git a/apps/static/js/components/InfoUrlSingle.vue b/apps/static/js/components/InfoUrlSingle.vue new file mode 100644 index 000000000..1bc931779 --- /dev/null +++ b/apps/static/js/components/InfoUrlSingle.vue @@ -0,0 +1,37 @@ + + + diff --git a/apps/static/js/components/InfoUrlUnit.vue b/apps/static/js/components/InfoUrlUnit.vue new file mode 100644 index 000000000..8f950bf37 --- /dev/null +++ b/apps/static/js/components/InfoUrlUnit.vue @@ -0,0 +1,32 @@ + + + diff --git a/apps/static/js/components/OcrInspector.vue b/apps/static/js/components/OcrInspector.vue new file mode 100644 index 000000000..da547be63 --- /dev/null +++ b/apps/static/js/components/OcrInspector.vue @@ -0,0 +1,268 @@ + + + + + diff --git a/apps/static/js/components/VolumeAnnotations.vue b/apps/static/js/components/VolumeAnnotations.vue new file mode 100644 index 000000000..747b735c2 --- /dev/null +++ b/apps/static/js/components/VolumeAnnotations.vue @@ -0,0 +1,114 @@ + + + + + \ No newline at end of file diff --git a/apps/static/js/components/VolumeExportAnnotationBtn.vue b/apps/static/js/components/VolumeExportAnnotationBtn.vue new file mode 100644 index 000000000..a3e37d2ed --- /dev/null +++ b/apps/static/js/components/VolumeExportAnnotationBtn.vue @@ -0,0 +1,47 @@ + + + + + \ No newline at end of file diff --git a/apps/static/js/components/VolumeSearch.vue b/apps/static/js/components/VolumeSearch.vue new file mode 100644 index 000000000..53d0957cc --- /dev/null +++ b/apps/static/js/components/VolumeSearch.vue @@ -0,0 +1,164 @@ + + + + + \ No newline at end of file diff --git a/apps/static/js/fontawesome.js b/apps/static/js/fontawesome.js deleted file mode 100644 index 053bee829..000000000 --- a/apps/static/js/fontawesome.js +++ /dev/null @@ -1,2 +0,0 @@ -window.FontAwesomeKitConfig = {"asyncLoading":{"enabled":true},"autoA11y":{"enabled":true},"baseUrl":"https://ka-f.fontawesome.com","baseUrlKit":"https://kit.fontawesome.com","detectConflictsUntil":"2019-12-10T20:14:41Z","iconUploads":{},"id":45311454,"license":"free","method":"css","minify":{"enabled":true},"token":"2ebfe61a88","v4FontFaceShim":{"enabled":true},"v4shim":{"enabled":true},"v5FontFaceShim":{"enabled":false},"version":"5.15.4"}; -!function(t){"function"==typeof define&&define.amd?define("kit-loader",t):t()}((function(){"use strict";function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(e)}function e(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function n(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(t);e&&(o=o.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,o)}return n}function o(t){for(var o=1;ot.length)&&(e=t.length);for(var n=0,o=new Array(e);n2&&void 0!==arguments[2]?arguments[2]:function(){},r=e.document||r,i=u.bind(u,r,["fa","fab","fas","far","fal","fad","fak"]),f=Object.keys(t.iconUploads||{}).length>0;t.autoA11y.enabled&&n(i);var s=[{id:"fa-main",addOn:void 0}];t.v4shim&&t.v4shim.enabled&&s.push({id:"fa-v4-shims",addOn:"-v4-shims"}),t.v5FontFaceShim&&t.v5FontFaceShim.enabled&&s.push({id:"fa-v5-font-face",addOn:"-v5-font-face"}),t.v4FontFaceShim&&t.v4FontFaceShim.enabled&&s.push({id:"fa-v4-font-face",addOn:"-v4-font-face"}),f&&s.push({id:"fa-kit-upload",customCss:!0});var d=s.map((function(n){return new _((function(r,i){F(n.customCss?a(t):c(t,{addOn:n.addOn,minify:t.minify.enabled}),e).then((function(i){r(U(i,o(o({},e),{},{baseUrl:t.baseUrl,version:t.version,id:n.id,contentFilter:function(t,e){return P(t,e.baseUrl,e.version)}})))})).catch(i)}))}));return _.all(d)}function U(t,e){var n=e.contentFilter||function(t,e){return t},o=document.createElement("style"),r=document.createTextNode(n(t,e));return o.appendChild(r),o.media="all",e.id&&o.setAttribute("id",e.id),e&&e.detectingConflicts&&e.detectionIgnoreAttr&&o.setAttributeNode(document.createAttribute(e.detectionIgnoreAttr)),o}function k(t,e){e.autoA11y=t.autoA11y.enabled,"pro"===t.license&&(e.autoFetchSvg=!0,e.fetchSvgFrom=t.baseUrl+"/releases/"+("latest"===t.version?"latest":"v".concat(t.version))+"/svgs",e.fetchUploadedSvgFrom=t.uploadsUrl);var n=[];return t.v4shim.enabled&&n.push(new _((function(n,r){F(c(t,{addOn:"-v4-shims",minify:t.minify.enabled}),e).then((function(t){n(I(t,o(o({},e),{},{id:"fa-v4-shims"})))})).catch(r)}))),n.push(new _((function(n,r){F(c(t,{minify:t.minify.enabled}),e).then((function(t){var r=I(t,o(o({},e),{},{id:"fa-main"}));n(function(t,e){var n=e&&void 0!==e.autoFetchSvg?e.autoFetchSvg:void 0,o=e&&void 0!==e.autoA11y?e.autoA11y:void 0;void 0!==o&&t.setAttribute("data-auto-a11y",o?"true":"false");n&&(t.setAttributeNode(document.createAttribute("data-auto-fetch-svg")),t.setAttribute("data-fetch-svg-from",e.fetchSvgFrom),t.setAttribute("data-fetch-uploaded-svg-from",e.fetchUploadedSvgFrom));return t}(r,e))})).catch(r)}))),_.all(n)}function I(t,e){var n=document.createElement("SCRIPT"),o=document.createTextNode(t);return n.appendChild(o),n.referrerPolicy="strict-origin",e.id&&n.setAttribute("id",e.id),e&&e.detectingConflicts&&e.detectionIgnoreAttr&&n.setAttributeNode(document.createAttribute(e.detectionIgnoreAttr)),n}function L(t){var e,n=[],o=document,r=o.documentElement.doScroll,i=(r?/^loaded|^c/:/^loaded|^i|^c/).test(o.readyState);i||o.addEventListener("DOMContentLoaded",e=function(){for(o.removeEventListener("DOMContentLoaded",e),i=1;e=n.shift();)e()}),i?setTimeout(t,0):n.push(t)}function T(t){"undefined"!=typeof MutationObserver&&new MutationObserver(t).observe(document,{childList:!0,subtree:!0})}try{if(window.FontAwesomeKitConfig){var x=window.FontAwesomeKitConfig,M={detectingConflicts:x.detectConflictsUntil&&new Date<=new Date(x.detectConflictsUntil),detectionIgnoreAttr:"data-fa-detection-ignore",fetch:window.fetch,token:x.token,XMLHttpRequest:window.XMLHttpRequest,document:document},D=document.currentScript,N=D?D.parentElement:document.head;(function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return"js"===t.method?k(t,e):"css"===t.method?C(t,e,(function(t){L(t),T(t)})):void 0})(x,M).then((function(t){t.map((function(t){try{N.insertBefore(t,D?D.nextSibling:null)}catch(e){N.appendChild(t)}})),M.detectingConflicts&&D&&L((function(){D.setAttributeNode(document.createAttribute(M.detectionIgnoreAttr));var t=function(t,e){var n=document.createElement("script");return e&&e.detectionIgnoreAttr&&n.setAttributeNode(document.createAttribute(e.detectionIgnoreAttr)),n.src=c(t,{baseFilename:"conflict-detection",fileSuffix:"js",subdir:"js",minify:t.minify.enabled}),n}(x,M);document.body.appendChild(t)}))})).catch((function(t){console.error("".concat("Font Awesome Kit:"," ").concat(t))}))}}catch(t){console.error("".concat("Font Awesome Kit:"," ").concat(t))}})); diff --git a/apps/static/js/index.js b/apps/static/js/index.js index deeb23cfb..f29d81bb4 100644 --- a/apps/static/js/index.js +++ b/apps/static/js/index.js @@ -1,8 +1,11 @@ window.$ = require('jquery'); -window.Vue = require('/apps/static/js/vue.js'); window.axios = require('axios'); +window.noUiSlider = require('nouislider'); +require('@selectize/selectize'); require('/apps/static/js/vue-readux.js'); + +// UIkit window.UIkit = require('uikit'); -window.UIkitIcons = require('/apps/static/js/uikit-icons.min.js'); +window.UIkitIcons = require('uikit/dist/js/uikit-icons'); // require('/apps/static/js/project.js'); window.ECDSAnnotator = require('../../../node_modules/ecds-annotator/dist/ecds-annotator.min.js'); \ No newline at end of file diff --git a/apps/static/js/project.js b/apps/static/js/project.js index cdf652c4d..dcc108569 100644 --- a/apps/static/js/project.js +++ b/apps/static/js/project.js @@ -1,60 +1,4 @@ /* Project specific Javascript goes here. */ -// Iterate through menu items and highlight the current page if it matches the URL -$.each($(".rx-nav-item"), function(index, navItem) { - var segmentsInURL = (location.pathname.split('/').length - 1) - (location.pathname[location.pathname.length - 1] == '/' ? 1 : 0); - var atModuleRoot = (segmentsInURL > 1) ? false:true; - var activePage = window.location.pathname.replace( - /^\/([^\/]*).*$/, - "$1" - ); - if (navItem.href.includes(activePage) && (activePage != "") && atModuleRoot) { - navItem.classList.add("uk-active"); - } -}); - - -// sort items displayed by appending/updating search params in URL -function ascaddURL(element) { - $(element).attr("href", function() { - if (window.location.search.length == 0) { - this.href = this.href + "?sort=title&order=asc"; - return this.href; - } else if (window.location.search.match(/[?&]order=asc/gi)) { - this.href = this.href.replace("order=asc", "order=asc"); - return this.href; - } else if (window.location.search.match(/[?&]order=desc/gi)) { - this.href = this.href.replace("order=desc", "order=asc"); - return this.href; - } else { - this.href = this.href + "&order=asc"; - return this.href; - } - }); -} - -window.ascaddURL = ascaddURL; - -// sort items displayed by appending/updating search params in URL -function descaddURL(element) { - $(element).attr("href", function() { - if (window.location.search.length == 0) { - this.href = this.href + "?sort=title&order=desc"; - return this.href; - } else if (window.location.search.match(/[?&]order=asc/gi)) { - this.href = this.href.replace("order=asc", "order=desc"); - return this.href; - } else if (window.location.search.match(/[?&]order=desc/gi)) { - this.href = this.href.replace("order=desc", "order=desc"); - return this.href; - } else { - this.href = this.href + "&order=desc"; - return this.href; - } - }); -} - -window.descaddURL = descaddURL; - // use an a element to log out const rxFormSubmit = function(formId) { diff --git a/apps/static/js/search.js b/apps/static/js/search.js index 05526f7c2..959a386d4 100644 --- a/apps/static/js/search.js +++ b/apps/static/js/search.js @@ -3,6 +3,7 @@ let textInput; let sortElement; +let displayElement; let relevanceSortOption; let defaultSortOption; let form; @@ -36,6 +37,7 @@ window.addEventListener("DOMContentLoaded", () => { dateToggleSwitch = document.querySelector("input[type='checkbox']#toggle-date"); dateRange = document.querySelector(".noUi-tooltip"); sortElement = document.querySelector("select#id_sort"); + displayElement = document.querySelector("select#id_display"); relevanceSortOption = sortElement.querySelector("option[value='_score']"); defaultSortOption = sortElement.querySelector("option[value='label_alphabetical']"); textInput = document.querySelector("input[type='search']"); @@ -44,6 +46,9 @@ window.addEventListener("DOMContentLoaded", () => { // Attach event listener to sort dropdown to auto-submit sortElement.addEventListener("change", handleSort); + if (displayElement) { + displayElement.addEventListener("change", () => form.submit()); + } // Attach event listeners to text input to update sort textInput.addEventListener("input", autoUpdateSort); @@ -212,3 +217,59 @@ function handleFormData(e) { formData.set("end_date", `${String(dateRange[1]).padStart(4, "0")}-12-31`); } } + +// Core fix: prevent focus loss +$(document).on('mousedown', '.selectize-dropdown', function(e) { + e.preventDefault(); +}); + +// initializeSelectize stays the same +function initializeSelectize() { + $(".custom-search-selectize").each(function () { + if (!$(this).hasClass("selectized")) { + $(this).selectize({ + plugins: ["clear_button"], + placeholder: "Select one or more..." + }); + } + }); +} + +$(function () { + // 1) Initial setup: your static selects... + $("#id_collection, #id_author, #id_language").selectize({ + plugins: ["clear_button"], + placeholder: "Select one or more..." + }); + + // 2) …and any .custom-search-selectize already in the DOM + initializeSelectize(); + + // 3) Watch for dynamically inserted selects + const observer = new MutationObserver((mutations) => { + mutations.forEach(mutation => { + mutation.addedNodes.forEach(node => { + // only care about element nodes + if (node.nodeType !== Node.ELEMENT_NODE) return; + + // if the added node *is* a custom-search-selectize, or *contains* one… + if (node.matches('.custom-search-selectize') || + node.querySelector('.custom-search-selectize') + ) { + initializeSelectize(); + } + }); + }); + }); + + // Scope this to a tighter container if you know where new selects appear; + // using document.body will catch everything, but you can replace + // document.body with document.querySelector('#your-results-container') + observer.observe(document.body, { + childList: true, + subtree: true + }); + + // Optional: if at some point you no longer need to observe: + // observer.disconnect(); +}); diff --git a/apps/static/js/uikit-icons.min.js b/apps/static/js/uikit-icons.min.js deleted file mode 100644 index 662f18c44..000000000 --- a/apps/static/js/uikit-icons.min.js +++ /dev/null @@ -1 +0,0 @@ -/*! UIkit 3.17.0 | https://www.getuikit.com | (c) 2014 - 2023 YOOtheme | MIT License */(function(t,e){typeof exports=="object"&&typeof module<"u"?module.exports=e():typeof define=="function"&&define.amd?define("uikiticons",e):(t=typeof globalThis<"u"?globalThis:t||self,t.UIkitIcons=e())})(this,function(){"use strict";function t(e){t.installed||e.icon.add({youtube:'',yootheme:'',yelp:'',xing:'',world:'',wordpress:'',whatsapp:'',warning:'',vimeo:'',"video-camera":'',users:'',user:'',upload:'',unlock:'',uikit:'',twitter:'',twitch:'',tv:'',tumblr:'',tripadvisor:'',"triangle-up":'',"triangle-right":'',"triangle-left":'',"triangle-down":'',trash:'',tiktok:'',thumbnails:'',tag:'',tablet:'',"tablet-landscape":'',table:'',strikethrough:'',star:'',soundcloud:'',social:'',"sign-out":'',"sign-in":'',shrink:'',settings:'',server:'',search:'',rss:'',reply:'',refresh:'',reddit:'',receiver:'',"quote-right":'',question:'',push:'',pull:'',print:'',plus:'',"plus-circle":'',play:'',"play-circle":'',pinterest:'',phone:'',"phone-landscape":'',pencil:'',"paint-bucket":'',pagekit:'',nut:'',move:'',more:'',"more-vertical":'',minus:'',"minus-circle":'',microsoft:'',microphone:'',menu:'',mastodon:'',mail:'',lock:'',location:'',list:'',linkedin:'',link:'',lifesaver:'',laptop:'',joomla:'',italic:'',instagram:'',info:'',image:'',home:'',history:'',heart:'',hashtag:'',happy:'',grid:'',google:'',gitter:'',github:'',"github-alt":'',"git-fork":'',"git-branch":'',future:'',foursquare:'',forward:'',folder:'',flickr:'',file:'',"file-text":'',"file-pdf":'',"file-edit":'',facebook:'',eye:'',"eye-slash":'',expand:'',etsy:'',dribbble:'',download:'',discord:'',desktop:'',database:'',crosshairs:'',"credit-card":'',copy:'',comments:'',commenting:'',comment:'',cog:'',code:'',"cloud-upload":'',"cloud-download":'',close:'',clock:'',"chevron-up":'',"chevron-right":'',"chevron-left":'',"chevron-down":'',"chevron-double-right":'',"chevron-double-left":'',check:'',cart:'',camera:'',calendar:'',bookmark:'',bolt:'',bold:'',bell:'',behance:'',ban:'',bag:'',"arrow-up":'',"arrow-right":'',"arrow-left":'',"arrow-down":'',apple:'',android:'',"android-robot":'',album:'',"500px":''})}return typeof window<"u"&&window.UIkit&&window.UIkit.use(t),t}); \ No newline at end of file diff --git a/apps/static/js/vue-readux.js b/apps/static/js/vue-readux.js index 07fd25f44..91e0ff128 100644 --- a/apps/static/js/vue-readux.js +++ b/apps/static/js/vue-readux.js @@ -1,488 +1,27 @@ -Vue.component("v-volume-image", { - props: ["imgSrc", "volumeLabel"], - template: ` -
- -

Volume is being added or cover is not available.

-
- - `, - data: function () { - return { - hasImage: true, // visibility of image from src - }; - }, - mounted() { - var vm = this; - var tester = new Image(); - tester.addEventListener("load", function () { - vm.hasImage = true; - }); - tester.addEventListener("error", function () { - vm.hasImage = false; - }); - tester.src = this.imgSrc; - }, - computed: { - imgAlt() { - return `First page of ${this.volumeLabel}`; - }, - }, -}); - -Vue.component("v-volume-search", { - template: ` - - `, - props: ['pid'], - data() { - return { - searchResults: [], - annotationData: [], - textData: [], - keyword: this.keyword, - inAnnotations: 0, - inText: 0, - emptyMessage: "" - }; - }, - methods: { - getSearchResults() { - try { - if (this.keyword=="" || this.keyword==undefined) { - this.emptyMessage = "Type a keyword to search"; - } else { - $this = this; - axios.get('/search/volume/pages?keyword=' + this.keyword + '&volume_id=' + this.pid) - .then(function (response) { - this.searchResults = response.data; // Assuming data is an array of results - if (this.searchResults.hasOwnProperty("matches_in_annotations")) { - $this.inAnnotations = this.searchResults.matches_in_annotations.total_matches_in_volume; - $this.inText = this.searchResults.matches_in_text.total_matches_in_volume; - $this.annotationData = this.searchResults.matches_in_annotations.volume_matches; - $this.textData = this.searchResults.matches_in_text.volume_matches; - } - $this.emptyMessage = ($this.hasResults == 0) ? "No matches in either annotations or text." : this.emptyMessage; - }) - .catch(function (error) { - console.log(error); - }); - } - } catch (error) { - console.error('Error fetching volume search data via API call to ElasticSearch:', error); - } - } - }, - computed: { - hasResults: function () { - return this.inAnnotations + this.inText; - }, - }, -}); - -Vue.component("v-volume-export-annotation-btn", { - props: ["manifestCount"], - template: ` -
- -
- `, - data: function () { - return { - localManifestCount: this.manifestCount, - isExportVisible: true, - }; - }, - mounted() { - var vm = this; - window.addEventListener("canvasswitch", function (event) { - if (!event) return; - - if (event.detail.annotationsOnPage) { - if (event.detail.annotationAdded) { - vm.localManifestCount++; - } - if (event.detail.annotationDeleted) { - vm.localManifestCount--; - } - vm.isExportVisible = vm.localManifestCount >= 1 ? true : false; - } - - if (event.detail && event.detail.canvas && !location.pathname.includes(event.detail.canvas)) { - history.pushState({}, '', event.detail.canvas); - } - }); - vm.isExportVisible = vm.localManifestCount >= 1 ? true : false; - - }, -}); - - -Vue.component("v-volume-annotations", { - props: ["manifestCount", "pageCount"], - template: ` -
-
    -
  • - Annotation Counts -
    -
    {{localManifestCount}} in manifest
    -
    {{localPageCount}} on page
    -
    -
  • -
- - -
- `, - data: function () { - return { - hasImage: false, // visibility of image from src - localManifestCount: this.manifestCount, - localPageCount: this.pageCount, - annotationData: {}, - }; - }, - mounted() { - var vm = this; - this.annotationData = JSON.parse( - document.getElementById("context").textContent - ).json_data; - window.addEventListener("canvasswitch", function (event) { - if (event.detail.annotationAdded) { - var createNewPage = true; - for (var i = 0; i < vm.annotationData.length; i++) { - if (vm.annotationData[i].canvas__pid === event.detail.canvas) { - vm.annotationData[i].canvas__position__count++; - createNewPage = false; - } - } - if (createNewPage) { - var canvas_pid_num = (event.detail.canvas.match(/\d+$/) || []).pop(); - vm.annotationData = vm.annotationData.concat({ - canvas__manifest__label: - vm.annotationData[0].canvas__manifest__label, - canvas__pid: event.detail.canvas, - canvas__position: parseInt(canvas_pid_num) + 1, - canvas__position__count: event.detail.annotationsOnPage, - }); - } - vm.localManifestCount++; - } - if (event.detail.annotationDeleted) { - for (var i = 0; i < vm.annotationData.length; i++) { - if (vm.annotationData[i].canvas__pid === event.detail.canvas) - vm.annotationData[i].canvas__position__count--; - } - vm.localManifestCount--; - } - vm.localPageCount = event.detail.annotationsOnPage; - }); - }, -}); - - -Vue.component("v-info-content-url-single", { - props: ["label", "url"], - template: ` -
- -
- {{ url }} -
-
- `, - methods: { - copyToClipboard() { - if (navigator.clipboard) { - navigator.clipboard.writeText(this.url) - .then(() => { - alert(`You have copied: ${this.url}`); - }) - .catch(() => { - alert("Something went wrong with copy."); - }); - } else { - alert("Clipboard API not supported in this browser."); - } - } - } -}); - -Vue.component("v-info-content-url-unit", { - props: ["url"], - template: ` -
- {{ url }} -
- Copy -
-
- `, - methods: { - copyToClipboard() { - if (navigator.clipboard) { - navigator.clipboard.writeText(this.url) - .then(() => { - alert(`You have copied: ${this.url}`); - }) - .catch(() => { - alert("Something went wrong with copy."); - }); - } else { - alert("Clipboard API not supported in this browser."); - } - } - } -}); - -Vue.component("v-info-content-url-multiple", { - props: ["label"], - template: ` -
- -
- -
-
- `, -}); - -// url copy component made for when the url is modified externally (outside Vue.js) -Vue.component("v-info-content-url-external", { - props: ["label", "url", "volume"], - data: function () { - return { - localUrl: this.url, - }; - }, - template: ` -
- - -
- `, - methods: { - copyToClipboard() { - if (navigator.clipboard) { - navigator.clipboard.writeText(this.localUrl) - .then(() => { - alert(`You have copied: ${this.localUrl}`); - }) - .catch(() => { - alert("Something went wrong with copy."); - }); - } else { - alert("Clipboard API not supported in this browser."); - } - } - }, - mounted() { - var vm = this; - window.addEventListener("canvasswitch", function (event) { - if (event.detail) { - var protocol = window.location.protocol; - var host = window.location.host; - var canvas = event.detail.canvas; - var volume = vm.volume; - var url = protocol + "//" + host + volume + "/page/" + canvas; - vm.localUrl = url; - vm.vol = volume; - } - }); - }, -}); - -// url copy component made for when the url is modified externally (outside Vue.js) - trying image link -Vue.component("v-info-content-url-image-link", { - props: ["label", "pagelink"], - data: function () { - return { - localUrls: this.url, - pageresource: this.pageresource, - }; - }, - template: ` -
- - -
- `, - methods: { - copyToClipboard() { - if (navigator.clipboard) { - navigator.clipboard.writeText(this.localUrls) - .then(() => { - alert(`You have copied: ${this.localUrls}`); - }) - .catch(() => { - alert("Something went wrong with copy."); - }); - } else { - alert("Clipboard API not supported in this browser."); - } - } - }, - mounted() { - var vm = this; - window.addEventListener("canvasswitch", function (event) { - if (event.detail && vm.canvas !== event.detail.canvas) { - var protocol = window.location.protocol; - var host = window.location.host; - vm.canvas = event.detail.canvas; - var volume = event.detail.volume; - var localpagelink = vm.pagelink; - - if (vm.canvas !== 'all') { - axios.get(`iiif/resource/${event.detail.canvas}`) - .then(response => { - vm.pageresource = response.data.resource; - vm.pagetext = response.data.text; - }).catch(error => { - console.error(error); - }); - var url = localpagelink + "/" + vm.canvas + "/full/full/0/default.jpg"; - vm.localUrls = url; - vm.can = vm.canvas; - } - } - }); - }, -}); - -// adapted from (url copy component made for when the url is modified externally (outside Vue.js)) - now page text modal -Vue.component("v-info-content-url-page-text", { - props: [], - data: function () { - return { - pagetext: this.pagetext, - }; - }, - template: ` -
-
- -

Text

-

{{pagetext}}

-
-
- `, - methods: { - }, - mounted() { - var vm = this; - window.addEventListener("canvasswitch", function (event) { - if (event.detail && vm.canvas !== event.detail.canvas) { - var protocol = window.location.protocol; - var host = window.location.host; - vm.canvas = event.detail.canvas; - var volume = event.detail.volume; - var localpagelink = vm.pagelink; - if (event.detail.canvas && event.detail.canvas !== 'all') { - axios.get(`iiif/resource/${event.detail.canvas}`) - .then(response => { - vm.pageresource = response.data.resource; - vm.pagetext = response.data.text; - }).catch(error => { console.log(error); }) - } - var url = - localpagelink + "/" + vm.canvas + "/full/full/0/default.jpg"; - vm.localUrls = url; - vm.can = vm.canvas; - } - }); - }, -}); +import Vue from 'vue' +import VolumeSearch from './components/VolumeSearch.vue' +import VolumeAnnotations from './components/VolumeAnnotations.vue' +import OcrInspector from './components/OcrInspector.vue' +import InfoUrlUnit from './components/InfoUrlUnit.vue' +import InfoUrlSingle from './components/InfoUrlSingle.vue' +import InfoUrlMultiple from './components/InfoUrlMultiple.vue' +import InfoExport from './components/InfoExport.vue' +import InfoUrlExternal from './components/InfoUrlExternal.vue' +import VolumeExportAnnotationBtn from './components/VolumeExportAnnotationBtn.vue' var readux = new Vue({ el: "#v-readux", delimiters: ["[[", "]]"], + components: { + VolumeSearch, VolumeAnnotations, OcrInspector, InfoUrlUnit, InfoUrlSingle, InfoUrlMultiple, InfoExport, InfoUrlExternal, VolumeExportAnnotationBtn + }, data: { options: ["title", "author", "date published", "date added"], searchPrefix: "?sort=", currentSelection: null, itemNotFound: false, showMoreInfo: false, + manifestCount: 0, }, methods: { sortBy: function (selection) { @@ -495,38 +34,6 @@ var readux = new Vue({ toggleMoreInfo: function () { this.showMoreInfo = !this.showMoreInfo } - - // ascaddURL: function(element) { - // $(element).attr('href', function () { - // if (window.location.search.length == 0) { - // return this.href + '?sort=title&order=asc'; - // } else if (window.location.search.match(/[?&]order=asc/gi)) { - // this.href = this.href.replace('order=asc', 'order=asc'); - // return this.href; - // } else if (window.location.search.match(/[?&]order=desc/gi)) { - // this.href = this.href.replace('order=desc', 'order=asc'); - // return this.href; - // } else { - // return this.href + '&order=asc'; - // } - // }); - // }, - - // descaddURL: function(element) { - // $(element).attr('href', function () { - // if (window.location.search.length == 0) { - // return this.href + '?sort=title&order=desc'; - // } else if (window.location.search.match(/[?&]order=asc/gi)) { - // this.href = this.href.replace('order=asc', 'order=desc'); - // return this.href; - // } else if (window.location.search.match(/[?&]order=desc/gi)) { - // this.href = this.href.replace('order=desc', 'order=desc'); - // return this.href; - // } else { - // return this.href + '&order=desc'; - // } - // }); - // } }, mounted: function () { diff --git a/apps/static/js/vue.js b/apps/static/js/vue.js deleted file mode 100644 index d800532ab..000000000 --- a/apps/static/js/vue.js +++ /dev/null @@ -1,12014 +0,0 @@ -/*! - * Vue.js v2.6.14 - * (c) 2014-2021 Evan You - * Released under the MIT License. - */ -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : - typeof define === 'function' && define.amd ? define(factory) : - (global = global || self, global.Vue = factory()); -}(this, function () { 'use strict'; - - /* */ - - var emptyObject = Object.freeze({}); - - // These helpers produce better VM code in JS engines due to their - // explicitness and function inlining. - function isUndef (v) { - return v === undefined || v === null - } - - function isDef (v) { - return v !== undefined && v !== null - } - - function isTrue (v) { - return v === true - } - - function isFalse (v) { - return v === false - } - - /** - * Check if value is primitive. - */ - function isPrimitive (value) { - return ( - typeof value === 'string' || - typeof value === 'number' || - // $flow-disable-line - typeof value === 'symbol' || - typeof value === 'boolean' - ) - } - - /** - * Quick object check - this is primarily used to tell - * Objects from primitive values when we know the value - * is a JSON-compliant type. - */ - function isObject (obj) { - return obj !== null && typeof obj === 'object' - } - - /** - * Get the raw type string of a value, e.g., [object Object]. - */ - var _toString = Object.prototype.toString; - - function toRawType (value) { - return _toString.call(value).slice(8, -1) - } - - /** - * Strict object type check. Only returns true - * for plain JavaScript objects. - */ - function isPlainObject (obj) { - return _toString.call(obj) === '[object Object]' - } - - function isRegExp (v) { - return _toString.call(v) === '[object RegExp]' - } - - /** - * Check if val is a valid array index. - */ - function isValidArrayIndex (val) { - var n = parseFloat(String(val)); - return n >= 0 && Math.floor(n) === n && isFinite(val) - } - - function isPromise (val) { - return ( - isDef(val) && - typeof val.then === 'function' && - typeof val.catch === 'function' - ) - } - - /** - * Convert a value to a string that is actually rendered. - */ - function toString (val) { - return val == null - ? '' - : Array.isArray(val) || (isPlainObject(val) && val.toString === _toString) - ? JSON.stringify(val, null, 2) - : String(val) - } - - /** - * Convert an input value to a number for persistence. - * If the conversion fails, return original string. - */ - function toNumber (val) { - var n = parseFloat(val); - return isNaN(n) ? val : n - } - - /** - * Make a map and return a function for checking if a key - * is in that map. - */ - function makeMap ( - str, - expectsLowerCase - ) { - var map = Object.create(null); - var list = str.split(','); - for (var i = 0; i < list.length; i++) { - map[list[i]] = true; - } - return expectsLowerCase - ? function (val) { return map[val.toLowerCase()]; } - : function (val) { return map[val]; } - } - - /** - * Check if a tag is a built-in tag. - */ - var isBuiltInTag = makeMap('slot,component', true); - - /** - * Check if an attribute is a reserved attribute. - */ - var isReservedAttribute = makeMap('key,ref,slot,slot-scope,is'); - - /** - * Remove an item from an array. - */ - function remove (arr, item) { - if (arr.length) { - var index = arr.indexOf(item); - if (index > -1) { - return arr.splice(index, 1) - } - } - } - - /** - * Check whether an object has the property. - */ - var hasOwnProperty = Object.prototype.hasOwnProperty; - function hasOwn (obj, key) { - return hasOwnProperty.call(obj, key) - } - - /** - * Create a cached version of a pure function. - */ - function cached (fn) { - var cache = Object.create(null); - return (function cachedFn (str) { - var hit = cache[str]; - return hit || (cache[str] = fn(str)) - }) - } - - /** - * Camelize a hyphen-delimited string. - */ - var camelizeRE = /-(\w)/g; - var camelize = cached(function (str) { - return str.replace(camelizeRE, function (_, c) { return c ? c.toUpperCase() : ''; }) - }); - - /** - * Capitalize a string. - */ - var capitalize = cached(function (str) { - return str.charAt(0).toUpperCase() + str.slice(1) - }); - - /** - * Hyphenate a camelCase string. - */ - var hyphenateRE = /\B([A-Z])/g; - var hyphenate = cached(function (str) { - return str.replace(hyphenateRE, '-$1').toLowerCase() - }); - - /** - * Simple bind polyfill for environments that do not support it, - * e.g., PhantomJS 1.x. Technically, we don't need this anymore - * since native bind is now performant enough in most browsers. - * But removing it would mean breaking code that was able to run in - * PhantomJS 1.x, so this must be kept for backward compatibility. - */ - - /* istanbul ignore next */ - function polyfillBind (fn, ctx) { - function boundFn (a) { - var l = arguments.length; - return l - ? l > 1 - ? fn.apply(ctx, arguments) - : fn.call(ctx, a) - : fn.call(ctx) - } - - boundFn._length = fn.length; - return boundFn - } - - function nativeBind (fn, ctx) { - return fn.bind(ctx) - } - - var bind = Function.prototype.bind - ? nativeBind - : polyfillBind; - - /** - * Convert an Array-like object to a real Array. - */ - function toArray (list, start) { - start = start || 0; - var i = list.length - start; - var ret = new Array(i); - while (i--) { - ret[i] = list[i + start]; - } - return ret - } - - /** - * Mix properties into target object. - */ - function extend (to, _from) { - for (var key in _from) { - to[key] = _from[key]; - } - return to - } - - /** - * Merge an Array of Objects into a single Object. - */ - function toObject (arr) { - var res = {}; - for (var i = 0; i < arr.length; i++) { - if (arr[i]) { - extend(res, arr[i]); - } - } - return res - } - - /* eslint-disable no-unused-vars */ - - /** - * Perform no operation. - * Stubbing args to make Flow happy without leaving useless transpiled code - * with ...rest (https://flow.org/blog/2017/05/07/Strict-Function-Call-Arity/). - */ - function noop (a, b, c) {} - - /** - * Always return false. - */ - var no = function (a, b, c) { return false; }; - - /* eslint-enable no-unused-vars */ - - /** - * Return the same value. - */ - var identity = function (_) { return _; }; - - /** - * Generate a string containing static keys from compiler modules. - */ - function genStaticKeys (modules) { - return modules.reduce(function (keys, m) { - return keys.concat(m.staticKeys || []) - }, []).join(',') - } - - /** - * Check if two values are loosely equal - that is, - * if they are plain objects, do they have the same shape? - */ - function looseEqual (a, b) { - if (a === b) { return true } - var isObjectA = isObject(a); - var isObjectB = isObject(b); - if (isObjectA && isObjectB) { - try { - var isArrayA = Array.isArray(a); - var isArrayB = Array.isArray(b); - if (isArrayA && isArrayB) { - return a.length === b.length && a.every(function (e, i) { - return looseEqual(e, b[i]) - }) - } else if (a instanceof Date && b instanceof Date) { - return a.getTime() === b.getTime() - } else if (!isArrayA && !isArrayB) { - var keysA = Object.keys(a); - var keysB = Object.keys(b); - return keysA.length === keysB.length && keysA.every(function (key) { - return looseEqual(a[key], b[key]) - }) - } else { - /* istanbul ignore next */ - return false - } - } catch (e) { - /* istanbul ignore next */ - return false - } - } else if (!isObjectA && !isObjectB) { - return String(a) === String(b) - } else { - return false - } - } - - /** - * Return the first index at which a loosely equal value can be - * found in the array (if value is a plain object, the array must - * contain an object of the same shape), or -1 if it is not present. - */ - function looseIndexOf (arr, val) { - for (var i = 0; i < arr.length; i++) { - if (looseEqual(arr[i], val)) { return i } - } - return -1 - } - - /** - * Ensure a function is called only once. - */ - function once (fn) { - var called = false; - return function () { - if (!called) { - called = true; - fn.apply(this, arguments); - } - } - } - - var SSR_ATTR = 'data-server-rendered'; - - var ASSET_TYPES = [ - 'component', - 'directive', - 'filter' - ]; - - var LIFECYCLE_HOOKS = [ - 'beforeCreate', - 'created', - 'beforeMount', - 'mounted', - 'beforeUpdate', - 'updated', - 'beforeDestroy', - 'destroyed', - 'activated', - 'deactivated', - 'errorCaptured', - 'serverPrefetch' - ]; - - /* */ - - - - var config = ({ - /** - * Option merge strategies (used in core/util/options) - */ - // $flow-disable-line - optionMergeStrategies: Object.create(null), - - /** - * Whether to suppress warnings. - */ - silent: false, - - /** - * Show production mode tip message on boot? - */ - productionTip: "development" !== 'production', - - /** - * Whether to enable devtools - */ - devtools: "development" !== 'production', - - /** - * Whether to record perf - */ - performance: false, - - /** - * Error handler for watcher errors - */ - errorHandler: null, - - /** - * Warn handler for watcher warns - */ - warnHandler: null, - - /** - * Ignore certain custom elements - */ - ignoredElements: [], - - /** - * Custom user key aliases for v-on - */ - // $flow-disable-line - keyCodes: Object.create(null), - - /** - * Check if a tag is reserved so that it cannot be registered as a - * component. This is platform-dependent and may be overwritten. - */ - isReservedTag: no, - - /** - * Check if an attribute is reserved so that it cannot be used as a component - * prop. This is platform-dependent and may be overwritten. - */ - isReservedAttr: no, - - /** - * Check if a tag is an unknown element. - * Platform-dependent. - */ - isUnknownElement: no, - - /** - * Get the namespace of an element - */ - getTagNamespace: noop, - - /** - * Parse the real tag name for the specific platform. - */ - parsePlatformTagName: identity, - - /** - * Check if an attribute must be bound using property, e.g. value - * Platform-dependent. - */ - mustUseProp: no, - - /** - * Perform updates asynchronously. Intended to be used by Vue Test Utils - * This will significantly reduce performance if set to false. - */ - async: true, - - /** - * Exposed for legacy reasons - */ - _lifecycleHooks: LIFECYCLE_HOOKS - }); - - /* */ - - /** - * unicode letters used for parsing html tags, component names and property paths. - * using https://www.w3.org/TR/html53/semantics-scripting.html#potentialcustomelementname - * skipping \u10000-\uEFFFF due to it freezing up PhantomJS - */ - var unicodeRegExp = /a-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD/; - - /** - * Check if a string starts with $ or _ - */ - function isReserved (str) { - var c = (str + '').charCodeAt(0); - return c === 0x24 || c === 0x5F - } - - /** - * Define a property. - */ - function def (obj, key, val, enumerable) { - Object.defineProperty(obj, key, { - value: val, - enumerable: !!enumerable, - writable: true, - configurable: true - }); - } - - /** - * Parse simple path. - */ - var bailRE = new RegExp(("[^" + (unicodeRegExp.source) + ".$_\\d]")); - function parsePath (path) { - if (bailRE.test(path)) { - return - } - var segments = path.split('.'); - return function (obj) { - for (var i = 0; i < segments.length; i++) { - if (!obj) { return } - obj = obj[segments[i]]; - } - return obj - } - } - - /* */ - - // can we use __proto__? - var hasProto = '__proto__' in {}; - - // Browser environment sniffing - var inBrowser = typeof window !== 'undefined'; - var inWeex = typeof WXEnvironment !== 'undefined' && !!WXEnvironment.platform; - var weexPlatform = inWeex && WXEnvironment.platform.toLowerCase(); - var UA = inBrowser && window.navigator.userAgent.toLowerCase(); - var isIE = UA && /msie|trident/.test(UA); - var isIE9 = UA && UA.indexOf('msie 9.0') > 0; - var isEdge = UA && UA.indexOf('edge/') > 0; - var isAndroid = (UA && UA.indexOf('android') > 0) || (weexPlatform === 'android'); - var isIOS = (UA && /iphone|ipad|ipod|ios/.test(UA)) || (weexPlatform === 'ios'); - var isChrome = UA && /chrome\/\d+/.test(UA) && !isEdge; - var isPhantomJS = UA && /phantomjs/.test(UA); - var isFF = UA && UA.match(/firefox\/(\d+)/); - - // Firefox has a "watch" function on Object.prototype... - var nativeWatch = ({}).watch; - - var supportsPassive = false; - if (inBrowser) { - try { - var opts = {}; - Object.defineProperty(opts, 'passive', ({ - get: function get () { - /* istanbul ignore next */ - supportsPassive = true; - } - })); // https://github.com/facebook/flow/issues/285 - window.addEventListener('test-passive', null, opts); - } catch (e) {} - } - - // this needs to be lazy-evaled because vue may be required before - // vue-server-renderer can set VUE_ENV - var _isServer; - var isServerRendering = function () { - if (_isServer === undefined) { - /* istanbul ignore if */ - if (!inBrowser && !inWeex && typeof global !== 'undefined') { - // detect presence of vue-server-renderer and avoid - // Webpack shimming the process - _isServer = global['process'] && global['process'].env.VUE_ENV === 'server'; - } else { - _isServer = false; - } - } - return _isServer - }; - - // detect devtools - var devtools = inBrowser && window.__VUE_DEVTOOLS_GLOBAL_HOOK__; - - /* istanbul ignore next */ - function isNative (Ctor) { - return typeof Ctor === 'function' && /native code/.test(Ctor.toString()) - } - - var hasSymbol = - typeof Symbol !== 'undefined' && isNative(Symbol) && - typeof Reflect !== 'undefined' && isNative(Reflect.ownKeys); - - var _Set; - /* istanbul ignore if */ // $flow-disable-line - if (typeof Set !== 'undefined' && isNative(Set)) { - // use native Set when available. - _Set = Set; - } else { - // a non-standard Set polyfill that only works with primitive keys. - _Set = /*@__PURE__*/(function () { - function Set () { - this.set = Object.create(null); - } - Set.prototype.has = function has (key) { - return this.set[key] === true - }; - Set.prototype.add = function add (key) { - this.set[key] = true; - }; - Set.prototype.clear = function clear () { - this.set = Object.create(null); - }; - - return Set; - }()); - } - - /* */ - - var warn = noop; - var tip = noop; - var generateComponentTrace = (noop); // work around flow check - var formatComponentName = (noop); - - { - var hasConsole = typeof console !== 'undefined'; - var classifyRE = /(?:^|[-_])(\w)/g; - var classify = function (str) { return str - .replace(classifyRE, function (c) { return c.toUpperCase(); }) - .replace(/[-_]/g, ''); }; - - warn = function (msg, vm) { - var trace = vm ? generateComponentTrace(vm) : ''; - - if (config.warnHandler) { - config.warnHandler.call(null, msg, vm, trace); - } else if (hasConsole && (!config.silent)) { - console.error(("[Vue warn]: " + msg + trace)); - } - }; - - tip = function (msg, vm) { - if (hasConsole && (!config.silent)) { - console.warn("[Vue tip]: " + msg + ( - vm ? generateComponentTrace(vm) : '' - )); - } - }; - - formatComponentName = function (vm, includeFile) { - if (vm.$root === vm) { - return '' - } - var options = typeof vm === 'function' && vm.cid != null - ? vm.options - : vm._isVue - ? vm.$options || vm.constructor.options - : vm; - var name = options.name || options._componentTag; - var file = options.__file; - if (!name && file) { - var match = file.match(/([^/\\]+)\.vue$/); - name = match && match[1]; - } - - return ( - (name ? ("<" + (classify(name)) + ">") : "") + - (file && includeFile !== false ? (" at " + file) : '') - ) - }; - - var repeat = function (str, n) { - var res = ''; - while (n) { - if (n % 2 === 1) { res += str; } - if (n > 1) { str += str; } - n >>= 1; - } - return res - }; - - generateComponentTrace = function (vm) { - if (vm._isVue && vm.$parent) { - var tree = []; - var currentRecursiveSequence = 0; - while (vm) { - if (tree.length > 0) { - var last = tree[tree.length - 1]; - if (last.constructor === vm.constructor) { - currentRecursiveSequence++; - vm = vm.$parent; - continue - } else if (currentRecursiveSequence > 0) { - tree[tree.length - 1] = [last, currentRecursiveSequence]; - currentRecursiveSequence = 0; - } - } - tree.push(vm); - vm = vm.$parent; - } - return '\n\nfound in\n\n' + tree - .map(function (vm, i) { return ("" + (i === 0 ? '---> ' : repeat(' ', 5 + i * 2)) + (Array.isArray(vm) - ? ((formatComponentName(vm[0])) + "... (" + (vm[1]) + " recursive calls)") - : formatComponentName(vm))); }) - .join('\n') - } else { - return ("\n\n(found in " + (formatComponentName(vm)) + ")") - } - }; - } - - /* */ - - var uid = 0; - - /** - * A dep is an observable that can have multiple - * directives subscribing to it. - */ - var Dep = function Dep () { - this.id = uid++; - this.subs = []; - }; - - Dep.prototype.addSub = function addSub (sub) { - this.subs.push(sub); - }; - - Dep.prototype.removeSub = function removeSub (sub) { - remove(this.subs, sub); - }; - - Dep.prototype.depend = function depend () { - if (Dep.target) { - Dep.target.addDep(this); - } - }; - - Dep.prototype.notify = function notify () { - // stabilize the subscriber list first - var subs = this.subs.slice(); - if (!config.async) { - // subs aren't sorted in scheduler if not running async - // we need to sort them now to make sure they fire in correct - // order - subs.sort(function (a, b) { return a.id - b.id; }); - } - for (var i = 0, l = subs.length; i < l; i++) { - subs[i].update(); - } - }; - - // The current target watcher being evaluated. - // This is globally unique because only one watcher - // can be evaluated at a time. - Dep.target = null; - var targetStack = []; - - function pushTarget (target) { - targetStack.push(target); - Dep.target = target; - } - - function popTarget () { - targetStack.pop(); - Dep.target = targetStack[targetStack.length - 1]; - } - - /* */ - - var VNode = function VNode ( - tag, - data, - children, - text, - elm, - context, - componentOptions, - asyncFactory - ) { - this.tag = tag; - this.data = data; - this.children = children; - this.text = text; - this.elm = elm; - this.ns = undefined; - this.context = context; - this.fnContext = undefined; - this.fnOptions = undefined; - this.fnScopeId = undefined; - this.key = data && data.key; - this.componentOptions = componentOptions; - this.componentInstance = undefined; - this.parent = undefined; - this.raw = false; - this.isStatic = false; - this.isRootInsert = true; - this.isComment = false; - this.isCloned = false; - this.isOnce = false; - this.asyncFactory = asyncFactory; - this.asyncMeta = undefined; - this.isAsyncPlaceholder = false; - }; - - var prototypeAccessors = { child: { configurable: true } }; - - // DEPRECATED: alias for componentInstance for backwards compat. - /* istanbul ignore next */ - prototypeAccessors.child.get = function () { - return this.componentInstance - }; - - Object.defineProperties( VNode.prototype, prototypeAccessors ); - - var createEmptyVNode = function (text) { - if ( text === void 0 ) text = ''; - - var node = new VNode(); - node.text = text; - node.isComment = true; - return node - }; - - function createTextVNode (val) { - return new VNode(undefined, undefined, undefined, String(val)) - } - - // optimized shallow clone - // used for static nodes and slot nodes because they may be reused across - // multiple renders, cloning them avoids errors when DOM manipulations rely - // on their elm reference. - function cloneVNode (vnode) { - var cloned = new VNode( - vnode.tag, - vnode.data, - // #7975 - // clone children array to avoid mutating original in case of cloning - // a child. - vnode.children && vnode.children.slice(), - vnode.text, - vnode.elm, - vnode.context, - vnode.componentOptions, - vnode.asyncFactory - ); - cloned.ns = vnode.ns; - cloned.isStatic = vnode.isStatic; - cloned.key = vnode.key; - cloned.isComment = vnode.isComment; - cloned.fnContext = vnode.fnContext; - cloned.fnOptions = vnode.fnOptions; - cloned.fnScopeId = vnode.fnScopeId; - cloned.asyncMeta = vnode.asyncMeta; - cloned.isCloned = true; - return cloned - } - - /* - * not type checking this file because flow doesn't play well with - * dynamically accessing methods on Array prototype - */ - - var arrayProto = Array.prototype; - var arrayMethods = Object.create(arrayProto); - - var methodsToPatch = [ - 'push', - 'pop', - 'shift', - 'unshift', - 'splice', - 'sort', - 'reverse' - ]; - - /** - * Intercept mutating methods and emit events - */ - methodsToPatch.forEach(function (method) { - // cache original method - var original = arrayProto[method]; - def(arrayMethods, method, function mutator () { - var args = [], len = arguments.length; - while ( len-- ) args[ len ] = arguments[ len ]; - - var result = original.apply(this, args); - var ob = this.__ob__; - var inserted; - switch (method) { - case 'push': - case 'unshift': - inserted = args; - break - case 'splice': - inserted = args.slice(2); - break - } - if (inserted) { ob.observeArray(inserted); } - // notify change - ob.dep.notify(); - return result - }); - }); - - /* */ - - var arrayKeys = Object.getOwnPropertyNames(arrayMethods); - - /** - * In some cases we may want to disable observation inside a component's - * update computation. - */ - var shouldObserve = true; - - function toggleObserving (value) { - shouldObserve = value; - } - - /** - * Observer class that is attached to each observed - * object. Once attached, the observer converts the target - * object's property keys into getter/setters that - * collect dependencies and dispatch updates. - */ - var Observer = function Observer (value) { - this.value = value; - this.dep = new Dep(); - this.vmCount = 0; - def(value, '__ob__', this); - if (Array.isArray(value)) { - if (hasProto) { - protoAugment(value, arrayMethods); - } else { - copyAugment(value, arrayMethods, arrayKeys); - } - this.observeArray(value); - } else { - this.walk(value); - } - }; - - /** - * Walk through all properties and convert them into - * getter/setters. This method should only be called when - * value type is Object. - */ - Observer.prototype.walk = function walk (obj) { - var keys = Object.keys(obj); - for (var i = 0; i < keys.length; i++) { - defineReactive$$1(obj, keys[i]); - } - }; - - /** - * Observe a list of Array items. - */ - Observer.prototype.observeArray = function observeArray (items) { - for (var i = 0, l = items.length; i < l; i++) { - observe(items[i]); - } - }; - - // helpers - - /** - * Augment a target Object or Array by intercepting - * the prototype chain using __proto__ - */ - function protoAugment (target, src) { - /* eslint-disable no-proto */ - target.__proto__ = src; - /* eslint-enable no-proto */ - } - - /** - * Augment a target Object or Array by defining - * hidden properties. - */ - /* istanbul ignore next */ - function copyAugment (target, src, keys) { - for (var i = 0, l = keys.length; i < l; i++) { - var key = keys[i]; - def(target, key, src[key]); - } - } - - /** - * Attempt to create an observer instance for a value, - * returns the new observer if successfully observed, - * or the existing observer if the value already has one. - */ - function observe (value, asRootData) { - if (!isObject(value) || value instanceof VNode) { - return - } - var ob; - if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { - ob = value.__ob__; - } else if ( - shouldObserve && - !isServerRendering() && - (Array.isArray(value) || isPlainObject(value)) && - Object.isExtensible(value) && - !value._isVue - ) { - ob = new Observer(value); - } - if (asRootData && ob) { - ob.vmCount++; - } - return ob - } - - /** - * Define a reactive property on an Object. - */ - function defineReactive$$1 ( - obj, - key, - val, - customSetter, - shallow - ) { - var dep = new Dep(); - - var property = Object.getOwnPropertyDescriptor(obj, key); - if (property && property.configurable === false) { - return - } - - // cater for pre-defined getter/setters - var getter = property && property.get; - var setter = property && property.set; - if ((!getter || setter) && arguments.length === 2) { - val = obj[key]; - } - - var childOb = !shallow && observe(val); - Object.defineProperty(obj, key, { - enumerable: true, - configurable: true, - get: function reactiveGetter () { - var value = getter ? getter.call(obj) : val; - if (Dep.target) { - dep.depend(); - if (childOb) { - childOb.dep.depend(); - if (Array.isArray(value)) { - dependArray(value); - } - } - } - return value - }, - set: function reactiveSetter (newVal) { - var value = getter ? getter.call(obj) : val; - /* eslint-disable no-self-compare */ - if (newVal === value || (newVal !== newVal && value !== value)) { - return - } - /* eslint-enable no-self-compare */ - if (customSetter) { - customSetter(); - } - // #7981: for accessor properties without setter - if (getter && !setter) { return } - if (setter) { - setter.call(obj, newVal); - } else { - val = newVal; - } - childOb = !shallow && observe(newVal); - dep.notify(); - } - }); - } - - /** - * Set a property on an object. Adds the new property and - * triggers change notification if the property doesn't - * already exist. - */ - function set (target, key, val) { - if (isUndef(target) || isPrimitive(target) - ) { - warn(("Cannot set reactive property on undefined, null, or primitive value: " + ((target)))); - } - if (Array.isArray(target) && isValidArrayIndex(key)) { - target.length = Math.max(target.length, key); - target.splice(key, 1, val); - return val - } - if (key in target && !(key in Object.prototype)) { - target[key] = val; - return val - } - var ob = (target).__ob__; - if (target._isVue || (ob && ob.vmCount)) { - warn( - 'Avoid adding reactive properties to a Vue instance or its root $data ' + - 'at runtime - declare it upfront in the data option.' - ); - return val - } - if (!ob) { - target[key] = val; - return val - } - defineReactive$$1(ob.value, key, val); - ob.dep.notify(); - return val - } - - /** - * Delete a property and trigger change if necessary. - */ - function del (target, key) { - if (isUndef(target) || isPrimitive(target) - ) { - warn(("Cannot delete reactive property on undefined, null, or primitive value: " + ((target)))); - } - if (Array.isArray(target) && isValidArrayIndex(key)) { - target.splice(key, 1); - return - } - var ob = (target).__ob__; - if (target._isVue || (ob && ob.vmCount)) { - warn( - 'Avoid deleting properties on a Vue instance or its root $data ' + - '- just set it to null.' - ); - return - } - if (!hasOwn(target, key)) { - return - } - delete target[key]; - if (!ob) { - return - } - ob.dep.notify(); - } - - /** - * Collect dependencies on array elements when the array is touched, since - * we cannot intercept array element access like property getters. - */ - function dependArray (value) { - for (var e = (void 0), i = 0, l = value.length; i < l; i++) { - e = value[i]; - e && e.__ob__ && e.__ob__.dep.depend(); - if (Array.isArray(e)) { - dependArray(e); - } - } - } - - /* */ - - /** - * Option overwriting strategies are functions that handle - * how to merge a parent option value and a child option - * value into the final value. - */ - var strats = config.optionMergeStrategies; - - /** - * Options with restrictions - */ - { - strats.el = strats.propsData = function (parent, child, vm, key) { - if (!vm) { - warn( - "option \"" + key + "\" can only be used during instance " + - 'creation with the `new` keyword.' - ); - } - return defaultStrat(parent, child) - }; - } - - /** - * Helper that recursively merges two data objects together. - */ - function mergeData (to, from) { - if (!from) { return to } - var key, toVal, fromVal; - - var keys = hasSymbol - ? Reflect.ownKeys(from) - : Object.keys(from); - - for (var i = 0; i < keys.length; i++) { - key = keys[i]; - // in case the object is already observed... - if (key === '__ob__') { continue } - toVal = to[key]; - fromVal = from[key]; - if (!hasOwn(to, key)) { - set(to, key, fromVal); - } else if ( - toVal !== fromVal && - isPlainObject(toVal) && - isPlainObject(fromVal) - ) { - mergeData(toVal, fromVal); - } - } - return to - } - - /** - * Data - */ - function mergeDataOrFn ( - parentVal, - childVal, - vm - ) { - if (!vm) { - // in a Vue.extend merge, both should be functions - if (!childVal) { - return parentVal - } - if (!parentVal) { - return childVal - } - // when parentVal & childVal are both present, - // we need to return a function that returns the - // merged result of both functions... no need to - // check if parentVal is a function here because - // it has to be a function to pass previous merges. - return function mergedDataFn () { - return mergeData( - typeof childVal === 'function' ? childVal.call(this, this) : childVal, - typeof parentVal === 'function' ? parentVal.call(this, this) : parentVal - ) - } - } else { - return function mergedInstanceDataFn () { - // instance merge - var instanceData = typeof childVal === 'function' - ? childVal.call(vm, vm) - : childVal; - var defaultData = typeof parentVal === 'function' - ? parentVal.call(vm, vm) - : parentVal; - if (instanceData) { - return mergeData(instanceData, defaultData) - } else { - return defaultData - } - } - } - } - - strats.data = function ( - parentVal, - childVal, - vm - ) { - if (!vm) { - if (childVal && typeof childVal !== 'function') { - warn( - 'The "data" option should be a function ' + - 'that returns a per-instance value in component ' + - 'definitions.', - vm - ); - - return parentVal - } - return mergeDataOrFn(parentVal, childVal) - } - - return mergeDataOrFn(parentVal, childVal, vm) - }; - - /** - * Hooks and props are merged as arrays. - */ - function mergeHook ( - parentVal, - childVal - ) { - var res = childVal - ? parentVal - ? parentVal.concat(childVal) - : Array.isArray(childVal) - ? childVal - : [childVal] - : parentVal; - return res - ? dedupeHooks(res) - : res - } - - function dedupeHooks (hooks) { - var res = []; - for (var i = 0; i < hooks.length; i++) { - if (res.indexOf(hooks[i]) === -1) { - res.push(hooks[i]); - } - } - return res - } - - LIFECYCLE_HOOKS.forEach(function (hook) { - strats[hook] = mergeHook; - }); - - /** - * Assets - * - * When a vm is present (instance creation), we need to do - * a three-way merge between constructor options, instance - * options and parent options. - */ - function mergeAssets ( - parentVal, - childVal, - vm, - key - ) { - var res = Object.create(parentVal || null); - if (childVal) { - assertObjectType(key, childVal, vm); - return extend(res, childVal) - } else { - return res - } - } - - ASSET_TYPES.forEach(function (type) { - strats[type + 's'] = mergeAssets; - }); - - /** - * Watchers. - * - * Watchers hashes should not overwrite one - * another, so we merge them as arrays. - */ - strats.watch = function ( - parentVal, - childVal, - vm, - key - ) { - // work around Firefox's Object.prototype.watch... - if (parentVal === nativeWatch) { parentVal = undefined; } - if (childVal === nativeWatch) { childVal = undefined; } - /* istanbul ignore if */ - if (!childVal) { return Object.create(parentVal || null) } - { - assertObjectType(key, childVal, vm); - } - if (!parentVal) { return childVal } - var ret = {}; - extend(ret, parentVal); - for (var key$1 in childVal) { - var parent = ret[key$1]; - var child = childVal[key$1]; - if (parent && !Array.isArray(parent)) { - parent = [parent]; - } - ret[key$1] = parent - ? parent.concat(child) - : Array.isArray(child) ? child : [child]; - } - return ret - }; - - /** - * Other object hashes. - */ - strats.props = - strats.methods = - strats.inject = - strats.computed = function ( - parentVal, - childVal, - vm, - key - ) { - if (childVal && "development" !== 'production') { - assertObjectType(key, childVal, vm); - } - if (!parentVal) { return childVal } - var ret = Object.create(null); - extend(ret, parentVal); - if (childVal) { extend(ret, childVal); } - return ret - }; - strats.provide = mergeDataOrFn; - - /** - * Default strategy. - */ - var defaultStrat = function (parentVal, childVal) { - return childVal === undefined - ? parentVal - : childVal - }; - - /** - * Validate component names - */ - function checkComponents (options) { - for (var key in options.components) { - validateComponentName(key); - } - } - - function validateComponentName (name) { - if (!new RegExp(("^[a-zA-Z][\\-\\.0-9_" + (unicodeRegExp.source) + "]*$")).test(name)) { - warn( - 'Invalid component name: "' + name + '". Component names ' + - 'should conform to valid custom element name in html5 specification.' - ); - } - if (isBuiltInTag(name) || config.isReservedTag(name)) { - warn( - 'Do not use built-in or reserved HTML elements as component ' + - 'id: ' + name - ); - } - } - - /** - * Ensure all props option syntax are normalized into the - * Object-based format. - */ - function normalizeProps (options, vm) { - var props = options.props; - if (!props) { return } - var res = {}; - var i, val, name; - if (Array.isArray(props)) { - i = props.length; - while (i--) { - val = props[i]; - if (typeof val === 'string') { - name = camelize(val); - res[name] = { type: null }; - } else { - warn('props must be strings when using array syntax.'); - } - } - } else if (isPlainObject(props)) { - for (var key in props) { - val = props[key]; - name = camelize(key); - res[name] = isPlainObject(val) - ? val - : { type: val }; - } - } else { - warn( - "Invalid value for option \"props\": expected an Array or an Object, " + - "but got " + (toRawType(props)) + ".", - vm - ); - } - options.props = res; - } - - /** - * Normalize all injections into Object-based format - */ - function normalizeInject (options, vm) { - var inject = options.inject; - if (!inject) { return } - var normalized = options.inject = {}; - if (Array.isArray(inject)) { - for (var i = 0; i < inject.length; i++) { - normalized[inject[i]] = { from: inject[i] }; - } - } else if (isPlainObject(inject)) { - for (var key in inject) { - var val = inject[key]; - normalized[key] = isPlainObject(val) - ? extend({ from: key }, val) - : { from: val }; - } - } else { - warn( - "Invalid value for option \"inject\": expected an Array or an Object, " + - "but got " + (toRawType(inject)) + ".", - vm - ); - } - } - - /** - * Normalize raw function directives into object format. - */ - function normalizeDirectives (options) { - var dirs = options.directives; - if (dirs) { - for (var key in dirs) { - var def$$1 = dirs[key]; - if (typeof def$$1 === 'function') { - dirs[key] = { bind: def$$1, update: def$$1 }; - } - } - } - } - - function assertObjectType (name, value, vm) { - if (!isPlainObject(value)) { - warn( - "Invalid value for option \"" + name + "\": expected an Object, " + - "but got " + (toRawType(value)) + ".", - vm - ); - } - } - - /** - * Merge two option objects into a new one. - * Core utility used in both instantiation and inheritance. - */ - function mergeOptions ( - parent, - child, - vm - ) { - { - checkComponents(child); - } - - if (typeof child === 'function') { - child = child.options; - } - - normalizeProps(child, vm); - normalizeInject(child, vm); - normalizeDirectives(child); - - // Apply extends and mixins on the child options, - // but only if it is a raw options object that isn't - // the result of another mergeOptions call. - // Only merged options has the _base property. - if (!child._base) { - if (child.extends) { - parent = mergeOptions(parent, child.extends, vm); - } - if (child.mixins) { - for (var i = 0, l = child.mixins.length; i < l; i++) { - parent = mergeOptions(parent, child.mixins[i], vm); - } - } - } - - var options = {}; - var key; - for (key in parent) { - mergeField(key); - } - for (key in child) { - if (!hasOwn(parent, key)) { - mergeField(key); - } - } - function mergeField (key) { - var strat = strats[key] || defaultStrat; - options[key] = strat(parent[key], child[key], vm, key); - } - return options - } - - /** - * Resolve an asset. - * This function is used because child instances need access - * to assets defined in its ancestor chain. - */ - function resolveAsset ( - options, - type, - id, - warnMissing - ) { - /* istanbul ignore if */ - if (typeof id !== 'string') { - return - } - var assets = options[type]; - // check local registration variations first - if (hasOwn(assets, id)) { return assets[id] } - var camelizedId = camelize(id); - if (hasOwn(assets, camelizedId)) { return assets[camelizedId] } - var PascalCaseId = capitalize(camelizedId); - if (hasOwn(assets, PascalCaseId)) { return assets[PascalCaseId] } - // fallback to prototype chain - var res = assets[id] || assets[camelizedId] || assets[PascalCaseId]; - if (warnMissing && !res) { - warn( - 'Failed to resolve ' + type.slice(0, -1) + ': ' + id, - options - ); - } - return res - } - - /* */ - - - - function validateProp ( - key, - propOptions, - propsData, - vm - ) { - var prop = propOptions[key]; - var absent = !hasOwn(propsData, key); - var value = propsData[key]; - // boolean casting - var booleanIndex = getTypeIndex(Boolean, prop.type); - if (booleanIndex > -1) { - if (absent && !hasOwn(prop, 'default')) { - value = false; - } else if (value === '' || value === hyphenate(key)) { - // only cast empty string / same name to boolean if - // boolean has higher priority - var stringIndex = getTypeIndex(String, prop.type); - if (stringIndex < 0 || booleanIndex < stringIndex) { - value = true; - } - } - } - // check default value - if (value === undefined) { - value = getPropDefaultValue(vm, prop, key); - // since the default value is a fresh copy, - // make sure to observe it. - var prevShouldObserve = shouldObserve; - toggleObserving(true); - observe(value); - toggleObserving(prevShouldObserve); - } - { - assertProp(prop, key, value, vm, absent); - } - return value - } - - /** - * Get the default value of a prop. - */ - function getPropDefaultValue (vm, prop, key) { - // no default, return undefined - if (!hasOwn(prop, 'default')) { - return undefined - } - var def = prop.default; - // warn against non-factory defaults for Object & Array - if (isObject(def)) { - warn( - 'Invalid default value for prop "' + key + '": ' + - 'Props with type Object/Array must use a factory function ' + - 'to return the default value.', - vm - ); - } - // the raw prop value was also undefined from previous render, - // return previous default value to avoid unnecessary watcher trigger - if (vm && vm.$options.propsData && - vm.$options.propsData[key] === undefined && - vm._props[key] !== undefined - ) { - return vm._props[key] - } - // call factory function for non-Function types - // a value is Function if its prototype is function even across different execution context - return typeof def === 'function' && getType(prop.type) !== 'Function' - ? def.call(vm) - : def - } - - /** - * Assert whether a prop is valid. - */ - function assertProp ( - prop, - name, - value, - vm, - absent - ) { - if (prop.required && absent) { - warn( - 'Missing required prop: "' + name + '"', - vm - ); - return - } - if (value == null && !prop.required) { - return - } - var type = prop.type; - var valid = !type || type === true; - var expectedTypes = []; - if (type) { - if (!Array.isArray(type)) { - type = [type]; - } - for (var i = 0; i < type.length && !valid; i++) { - var assertedType = assertType(value, type[i], vm); - expectedTypes.push(assertedType.expectedType || ''); - valid = assertedType.valid; - } - } - - var haveExpectedTypes = expectedTypes.some(function (t) { return t; }); - if (!valid && haveExpectedTypes) { - warn( - getInvalidTypeMessage(name, value, expectedTypes), - vm - ); - return - } - var validator = prop.validator; - if (validator) { - if (!validator(value)) { - warn( - 'Invalid prop: custom validator check failed for prop "' + name + '".', - vm - ); - } - } - } - - var simpleCheckRE = /^(String|Number|Boolean|Function|Symbol|BigInt)$/; - - function assertType (value, type, vm) { - var valid; - var expectedType = getType(type); - if (simpleCheckRE.test(expectedType)) { - var t = typeof value; - valid = t === expectedType.toLowerCase(); - // for primitive wrapper objects - if (!valid && t === 'object') { - valid = value instanceof type; - } - } else if (expectedType === 'Object') { - valid = isPlainObject(value); - } else if (expectedType === 'Array') { - valid = Array.isArray(value); - } else { - try { - valid = value instanceof type; - } catch (e) { - warn('Invalid prop type: "' + String(type) + '" is not a constructor', vm); - valid = false; - } - } - return { - valid: valid, - expectedType: expectedType - } - } - - var functionTypeCheckRE = /^\s*function (\w+)/; - - /** - * Use function string name to check built-in types, - * because a simple equality check will fail when running - * across different vms / iframes. - */ - function getType (fn) { - var match = fn && fn.toString().match(functionTypeCheckRE); - return match ? match[1] : '' - } - - function isSameType (a, b) { - return getType(a) === getType(b) - } - - function getTypeIndex (type, expectedTypes) { - if (!Array.isArray(expectedTypes)) { - return isSameType(expectedTypes, type) ? 0 : -1 - } - for (var i = 0, len = expectedTypes.length; i < len; i++) { - if (isSameType(expectedTypes[i], type)) { - return i - } - } - return -1 - } - - function getInvalidTypeMessage (name, value, expectedTypes) { - var message = "Invalid prop: type check failed for prop \"" + name + "\"." + - " Expected " + (expectedTypes.map(capitalize).join(', ')); - var expectedType = expectedTypes[0]; - var receivedType = toRawType(value); - // check if we need to specify expected value - if ( - expectedTypes.length === 1 && - isExplicable(expectedType) && - isExplicable(typeof value) && - !isBoolean(expectedType, receivedType) - ) { - message += " with value " + (styleValue(value, expectedType)); - } - message += ", got " + receivedType + " "; - // check if we need to specify received value - if (isExplicable(receivedType)) { - message += "with value " + (styleValue(value, receivedType)) + "."; - } - return message - } - - function styleValue (value, type) { - if (type === 'String') { - return ("\"" + value + "\"") - } else if (type === 'Number') { - return ("" + (Number(value))) - } else { - return ("" + value) - } - } - - var EXPLICABLE_TYPES = ['string', 'number', 'boolean']; - function isExplicable (value) { - return EXPLICABLE_TYPES.some(function (elem) { return value.toLowerCase() === elem; }) - } - - function isBoolean () { - var args = [], len = arguments.length; - while ( len-- ) args[ len ] = arguments[ len ]; - - return args.some(function (elem) { return elem.toLowerCase() === 'boolean'; }) - } - - /* */ - - function handleError (err, vm, info) { - // Deactivate deps tracking while processing error handler to avoid possible infinite rendering. - // See: https://github.com/vuejs/vuex/issues/1505 - pushTarget(); - try { - if (vm) { - var cur = vm; - while ((cur = cur.$parent)) { - var hooks = cur.$options.errorCaptured; - if (hooks) { - for (var i = 0; i < hooks.length; i++) { - try { - var capture = hooks[i].call(cur, err, vm, info) === false; - if (capture) { return } - } catch (e) { - globalHandleError(e, cur, 'errorCaptured hook'); - } - } - } - } - } - globalHandleError(err, vm, info); - } finally { - popTarget(); - } - } - - function invokeWithErrorHandling ( - handler, - context, - args, - vm, - info - ) { - var res; - try { - res = args ? handler.apply(context, args) : handler.call(context); - if (res && !res._isVue && isPromise(res) && !res._handled) { - res.catch(function (e) { return handleError(e, vm, info + " (Promise/async)"); }); - // issue #9511 - // avoid catch triggering multiple times when nested calls - res._handled = true; - } - } catch (e) { - handleError(e, vm, info); - } - return res - } - - function globalHandleError (err, vm, info) { - if (config.errorHandler) { - try { - return config.errorHandler.call(null, err, vm, info) - } catch (e) { - // if the user intentionally throws the original error in the handler, - // do not log it twice - if (e !== err) { - logError(e, null, 'config.errorHandler'); - } - } - } - logError(err, vm, info); - } - - function logError (err, vm, info) { - { - warn(("Error in " + info + ": \"" + (err.toString()) + "\""), vm); - } - /* istanbul ignore else */ - if ((inBrowser || inWeex) && typeof console !== 'undefined') { - console.error(err); - } else { - throw err - } - } - - /* */ - - var isUsingMicroTask = false; - - var callbacks = []; - var pending = false; - - function flushCallbacks () { - pending = false; - var copies = callbacks.slice(0); - callbacks.length = 0; - for (var i = 0; i < copies.length; i++) { - copies[i](); - } - } - - // Here we have async deferring wrappers using microtasks. - // In 2.5 we used (macro) tasks (in combination with microtasks). - // However, it has subtle problems when state is changed right before repaint - // (e.g. #6813, out-in transitions). - // Also, using (macro) tasks in event handler would cause some weird behaviors - // that cannot be circumvented (e.g. #7109, #7153, #7546, #7834, #8109). - // So we now use microtasks everywhere, again. - // A major drawback of this tradeoff is that there are some scenarios - // where microtasks have too high a priority and fire in between supposedly - // sequential events (e.g. #4521, #6690, which have workarounds) - // or even between bubbling of the same event (#6566). - var timerFunc; - - // The nextTick behavior leverages the microtask queue, which can be accessed - // via either native Promise.then or MutationObserver. - // MutationObserver has wider support, however it is seriously bugged in - // UIWebView in iOS >= 9.3.3 when triggered in touch event handlers. It - // completely stops working after triggering a few times... so, if native - // Promise is available, we will use it: - /* istanbul ignore next, $flow-disable-line */ - if (typeof Promise !== 'undefined' && isNative(Promise)) { - var p = Promise.resolve(); - timerFunc = function () { - p.then(flushCallbacks); - // In problematic UIWebViews, Promise.then doesn't completely break, but - // it can get stuck in a weird state where callbacks are pushed into the - // microtask queue but the queue isn't being flushed, until the browser - // needs to do some other work, e.g. handle a timer. Therefore we can - // "force" the microtask queue to be flushed by adding an empty timer. - if (isIOS) { setTimeout(noop); } - }; - isUsingMicroTask = true; - } else if (!isIE && typeof MutationObserver !== 'undefined' && ( - isNative(MutationObserver) || - // PhantomJS and iOS 7.x - MutationObserver.toString() === '[object MutationObserverConstructor]' - )) { - // Use MutationObserver where native Promise is not available, - // e.g. PhantomJS, iOS7, Android 4.4 - // (#6466 MutationObserver is unreliable in IE11) - var counter = 1; - var observer = new MutationObserver(flushCallbacks); - var textNode = document.createTextNode(String(counter)); - observer.observe(textNode, { - characterData: true - }); - timerFunc = function () { - counter = (counter + 1) % 2; - textNode.data = String(counter); - }; - isUsingMicroTask = true; - } else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) { - // Fallback to setImmediate. - // Technically it leverages the (macro) task queue, - // but it is still a better choice than setTimeout. - timerFunc = function () { - setImmediate(flushCallbacks); - }; - } else { - // Fallback to setTimeout. - timerFunc = function () { - setTimeout(flushCallbacks, 0); - }; - } - - function nextTick (cb, ctx) { - var _resolve; - callbacks.push(function () { - if (cb) { - try { - cb.call(ctx); - } catch (e) { - handleError(e, ctx, 'nextTick'); - } - } else if (_resolve) { - _resolve(ctx); - } - }); - if (!pending) { - pending = true; - timerFunc(); - } - // $flow-disable-line - if (!cb && typeof Promise !== 'undefined') { - return new Promise(function (resolve) { - _resolve = resolve; - }) - } - } - - /* */ - - var mark; - var measure; - - { - var perf = inBrowser && window.performance; - /* istanbul ignore if */ - if ( - perf && - perf.mark && - perf.measure && - perf.clearMarks && - perf.clearMeasures - ) { - mark = function (tag) { return perf.mark(tag); }; - measure = function (name, startTag, endTag) { - perf.measure(name, startTag, endTag); - perf.clearMarks(startTag); - perf.clearMarks(endTag); - // perf.clearMeasures(name) - }; - } - } - - /* not type checking this file because flow doesn't play well with Proxy */ - - var initProxy; - - { - var allowedGlobals = makeMap( - 'Infinity,undefined,NaN,isFinite,isNaN,' + - 'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' + - 'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt,' + - 'require' // for Webpack/Browserify - ); - - var warnNonPresent = function (target, key) { - warn( - "Property or method \"" + key + "\" is not defined on the instance but " + - 'referenced during render. Make sure that this property is reactive, ' + - 'either in the data option, or for class-based components, by ' + - 'initializing the property. ' + - 'See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.', - target - ); - }; - - var warnReservedPrefix = function (target, key) { - warn( - "Property \"" + key + "\" must be accessed with \"$data." + key + "\" because " + - 'properties starting with "$" or "_" are not proxied in the Vue instance to ' + - 'prevent conflicts with Vue internals. ' + - 'See: https://vuejs.org/v2/api/#data', - target - ); - }; - - var hasProxy = - typeof Proxy !== 'undefined' && isNative(Proxy); - - if (hasProxy) { - var isBuiltInModifier = makeMap('stop,prevent,self,ctrl,shift,alt,meta,exact'); - config.keyCodes = new Proxy(config.keyCodes, { - set: function set (target, key, value) { - if (isBuiltInModifier(key)) { - warn(("Avoid overwriting built-in modifier in config.keyCodes: ." + key)); - return false - } else { - target[key] = value; - return true - } - } - }); - } - - var hasHandler = { - has: function has (target, key) { - var has = key in target; - var isAllowed = allowedGlobals(key) || - (typeof key === 'string' && key.charAt(0) === '_' && !(key in target.$data)); - if (!has && !isAllowed) { - if (key in target.$data) { warnReservedPrefix(target, key); } - else { warnNonPresent(target, key); } - } - return has || !isAllowed - } - }; - - var getHandler = { - get: function get (target, key) { - if (typeof key === 'string' && !(key in target)) { - if (key in target.$data) { warnReservedPrefix(target, key); } - else { warnNonPresent(target, key); } - } - return target[key] - } - }; - - initProxy = function initProxy (vm) { - if (hasProxy) { - // determine which proxy handler to use - var options = vm.$options; - var handlers = options.render && options.render._withStripped - ? getHandler - : hasHandler; - vm._renderProxy = new Proxy(vm, handlers); - } else { - vm._renderProxy = vm; - } - }; - } - - /* */ - - var seenObjects = new _Set(); - - /** - * Recursively traverse an object to evoke all converted - * getters, so that every nested property inside the object - * is collected as a "deep" dependency. - */ - function traverse (val) { - _traverse(val, seenObjects); - seenObjects.clear(); - } - - function _traverse (val, seen) { - var i, keys; - var isA = Array.isArray(val); - if ((!isA && !isObject(val)) || Object.isFrozen(val) || val instanceof VNode) { - return - } - if (val.__ob__) { - var depId = val.__ob__.dep.id; - if (seen.has(depId)) { - return - } - seen.add(depId); - } - if (isA) { - i = val.length; - while (i--) { _traverse(val[i], seen); } - } else { - keys = Object.keys(val); - i = keys.length; - while (i--) { _traverse(val[keys[i]], seen); } - } - } - - /* */ - - var normalizeEvent = cached(function (name) { - var passive = name.charAt(0) === '&'; - name = passive ? name.slice(1) : name; - var once$$1 = name.charAt(0) === '~'; // Prefixed last, checked first - name = once$$1 ? name.slice(1) : name; - var capture = name.charAt(0) === '!'; - name = capture ? name.slice(1) : name; - return { - name: name, - once: once$$1, - capture: capture, - passive: passive - } - }); - - function createFnInvoker (fns, vm) { - function invoker () { - var arguments$1 = arguments; - - var fns = invoker.fns; - if (Array.isArray(fns)) { - var cloned = fns.slice(); - for (var i = 0; i < cloned.length; i++) { - invokeWithErrorHandling(cloned[i], null, arguments$1, vm, "v-on handler"); - } - } else { - // return handler return value for single handlers - return invokeWithErrorHandling(fns, null, arguments, vm, "v-on handler") - } - } - invoker.fns = fns; - return invoker - } - - function updateListeners ( - on, - oldOn, - add, - remove$$1, - createOnceHandler, - vm - ) { - var name, def$$1, cur, old, event; - for (name in on) { - def$$1 = cur = on[name]; - old = oldOn[name]; - event = normalizeEvent(name); - if (isUndef(cur)) { - warn( - "Invalid handler for event \"" + (event.name) + "\": got " + String(cur), - vm - ); - } else if (isUndef(old)) { - if (isUndef(cur.fns)) { - cur = on[name] = createFnInvoker(cur, vm); - } - if (isTrue(event.once)) { - cur = on[name] = createOnceHandler(event.name, cur, event.capture); - } - add(event.name, cur, event.capture, event.passive, event.params); - } else if (cur !== old) { - old.fns = cur; - on[name] = old; - } - } - for (name in oldOn) { - if (isUndef(on[name])) { - event = normalizeEvent(name); - remove$$1(event.name, oldOn[name], event.capture); - } - } - } - - /* */ - - function mergeVNodeHook (def, hookKey, hook) { - if (def instanceof VNode) { - def = def.data.hook || (def.data.hook = {}); - } - var invoker; - var oldHook = def[hookKey]; - - function wrappedHook () { - hook.apply(this, arguments); - // important: remove merged hook to ensure it's called only once - // and prevent memory leak - remove(invoker.fns, wrappedHook); - } - - if (isUndef(oldHook)) { - // no existing hook - invoker = createFnInvoker([wrappedHook]); - } else { - /* istanbul ignore if */ - if (isDef(oldHook.fns) && isTrue(oldHook.merged)) { - // already a merged invoker - invoker = oldHook; - invoker.fns.push(wrappedHook); - } else { - // existing plain hook - invoker = createFnInvoker([oldHook, wrappedHook]); - } - } - - invoker.merged = true; - def[hookKey] = invoker; - } - - /* */ - - function extractPropsFromVNodeData ( - data, - Ctor, - tag - ) { - // we are only extracting raw values here. - // validation and default values are handled in the child - // component itself. - var propOptions = Ctor.options.props; - if (isUndef(propOptions)) { - return - } - var res = {}; - var attrs = data.attrs; - var props = data.props; - if (isDef(attrs) || isDef(props)) { - for (var key in propOptions) { - var altKey = hyphenate(key); - { - var keyInLowerCase = key.toLowerCase(); - if ( - key !== keyInLowerCase && - attrs && hasOwn(attrs, keyInLowerCase) - ) { - tip( - "Prop \"" + keyInLowerCase + "\" is passed to component " + - (formatComponentName(tag || Ctor)) + ", but the declared prop name is" + - " \"" + key + "\". " + - "Note that HTML attributes are case-insensitive and camelCased " + - "props need to use their kebab-case equivalents when using in-DOM " + - "templates. You should probably use \"" + altKey + "\" instead of \"" + key + "\"." - ); - } - } - checkProp(res, props, key, altKey, true) || - checkProp(res, attrs, key, altKey, false); - } - } - return res - } - - function checkProp ( - res, - hash, - key, - altKey, - preserve - ) { - if (isDef(hash)) { - if (hasOwn(hash, key)) { - res[key] = hash[key]; - if (!preserve) { - delete hash[key]; - } - return true - } else if (hasOwn(hash, altKey)) { - res[key] = hash[altKey]; - if (!preserve) { - delete hash[altKey]; - } - return true - } - } - return false - } - - /* */ - - // The template compiler attempts to minimize the need for normalization by - // statically analyzing the template at compile time. - // - // For plain HTML markup, normalization can be completely skipped because the - // generated render function is guaranteed to return Array. There are - // two cases where extra normalization is needed: - - // 1. When the children contains components - because a functional component - // may return an Array instead of a single root. In this case, just a simple - // normalization is needed - if any child is an Array, we flatten the whole - // thing with Array.prototype.concat. It is guaranteed to be only 1-level deep - // because functional components already normalize their own children. - function simpleNormalizeChildren (children) { - for (var i = 0; i < children.length; i++) { - if (Array.isArray(children[i])) { - return Array.prototype.concat.apply([], children) - } - } - return children - } - - // 2. When the children contains constructs that always generated nested Arrays, - // e.g.