Notifications: Extracted watch options, updated UI further
This commit is contained in:
		
							parent
							
								
									730f539029
								
							
						
					
					
						commit
						6100b99828
					
				| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace BookStack\Users;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class UserWatchOptions
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    protected static array $levelByOption = [
 | 
				
			||||||
 | 
					        'default' => -1,
 | 
				
			||||||
 | 
					        'ignore' => 0,
 | 
				
			||||||
 | 
					        'new' => 1,
 | 
				
			||||||
 | 
					        'updates' => 2,
 | 
				
			||||||
 | 
					        'comments' => 3,
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @return string[]
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static function getAvailableOptionNames(): array
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return array_keys(static::$levelByOption);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -403,4 +403,18 @@ return [
 | 
				
			||||||
    'references' => 'References',
 | 
					    'references' => 'References',
 | 
				
			||||||
    'references_none' => 'There are no tracked references to this item.',
 | 
					    'references_none' => 'There are no tracked references to this item.',
 | 
				
			||||||
    'references_to_desc' => 'Shown below are all the known pages in the system that link to this item.',
 | 
					    'references_to_desc' => 'Shown below are all the known pages in the system that link to this item.',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Watch Options
 | 
				
			||||||
 | 
					    'watch' => 'Watch',
 | 
				
			||||||
 | 
					    'watch_title_default' => 'Default Preferences',
 | 
				
			||||||
 | 
					    'watch_desc_default' => 'Revert watching to just your default notification preferences.',
 | 
				
			||||||
 | 
					    'watch_title_ignore' => 'Ignore',
 | 
				
			||||||
 | 
					    'watch_desc_ignore' => 'Ignore all notifications, including those from user-level preferences.',
 | 
				
			||||||
 | 
					    'watch_title_new' => 'New Pages',
 | 
				
			||||||
 | 
					    'watch_desc_new' => 'Notify when any new page is created within this item.',
 | 
				
			||||||
 | 
					    'watch_title_updates' => 'All Page Updates',
 | 
				
			||||||
 | 
					    'watch_desc_updates' => 'Notify upon all new pages and page changes.',
 | 
				
			||||||
 | 
					    'watch_title_comments' => 'All Page Updates & Comments',
 | 
				
			||||||
 | 
					    'watch_desc_comments' => 'Notify upon all new pages, page changes and new comments.',
 | 
				
			||||||
 | 
					    'watch_change_default' => 'Change default notification preferences',
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -132,6 +132,7 @@ export class Dropdown extends Component {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        onSelect(this.toggle, event => {
 | 
					        onSelect(this.toggle, event => {
 | 
				
			||||||
            event.stopPropagation();
 | 
					            event.stopPropagation();
 | 
				
			||||||
 | 
					            event.preventDefault();
 | 
				
			||||||
            this.show(event);
 | 
					            this.show(event);
 | 
				
			||||||
            if (event instanceof KeyboardEvent) {
 | 
					            if (event instanceof KeyboardEvent) {
 | 
				
			||||||
                keyboardNavHandler.focusNext();
 | 
					                keyboardNavHandler.focusNext();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -353,7 +353,7 @@ body.flexbox {
 | 
				
			||||||
  margin-inline-end: $-xl;
 | 
					  margin-inline-end: $-xl;
 | 
				
			||||||
  grid-template-columns: 1fr 4fr 1fr;
 | 
					  grid-template-columns: 1fr 4fr 1fr;
 | 
				
			||||||
  grid-template-areas: "a b c";
 | 
					  grid-template-areas: "a b c";
 | 
				
			||||||
  grid-column-gap: $-xxl;
 | 
					  grid-column-gap: $-xl;
 | 
				
			||||||
  .tri-layout-right {
 | 
					  .tri-layout-right {
 | 
				
			||||||
    grid-area: c;
 | 
					    grid-area: c;
 | 
				
			||||||
    min-width: 0;
 | 
					    min-width: 0;
 | 
				
			||||||
| 
						 | 
					@ -378,6 +378,14 @@ body.flexbox {
 | 
				
			||||||
    padding-inline-end: $-l;
 | 
					    padding-inline-end: $-l;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					@include between($xxl, $xxxl) {
 | 
				
			||||||
 | 
					  .tri-layout-container {
 | 
				
			||||||
 | 
					    grid-template-columns: 1fr calc(940px + (2 * $-m)) 1fr;
 | 
				
			||||||
 | 
					    grid-column-gap: $-s;
 | 
				
			||||||
 | 
					    margin-inline-start: $-m;
 | 
				
			||||||
 | 
					    margin-inline-end: $-m;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@include between($l, $xxl) {
 | 
					@include between($l, $xxl) {
 | 
				
			||||||
  .tri-layout-left {
 | 
					  .tri-layout-left {
 | 
				
			||||||
    position: sticky;
 | 
					    position: sticky;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -672,7 +672,7 @@ ul.pagination {
 | 
				
			||||||
  @include lightDark(color, #555, #eee);
 | 
					  @include lightDark(color, #555, #eee);
 | 
				
			||||||
  fill: currentColor;
 | 
					  fill: currentColor;
 | 
				
			||||||
  text-align: start !important;
 | 
					  text-align: start !important;
 | 
				
			||||||
  max-height: 500px;
 | 
					  max-height: 80vh;
 | 
				
			||||||
  overflow-y: auto;
 | 
					  overflow-y: auto;
 | 
				
			||||||
  &.anchor-left {
 | 
					  &.anchor-left {
 | 
				
			||||||
    inset-inline-end: auto;
 | 
					    inset-inline-end: auto;
 | 
				
			||||||
| 
						 | 
					@ -683,6 +683,7 @@ ul.pagination {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  &.xl-limited {
 | 
					  &.xl-limited {
 | 
				
			||||||
    width: 280px;
 | 
					    width: 280px;
 | 
				
			||||||
 | 
					    max-width: 100%;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  .text-muted {
 | 
					  .text-muted {
 | 
				
			||||||
    color: #999;
 | 
					    color: #999;
 | 
				
			||||||
| 
						 | 
					@ -708,6 +709,11 @@ ul.pagination {
 | 
				
			||||||
    white-space: nowrap;
 | 
					    white-space: nowrap;
 | 
				
			||||||
    line-height: 1.4;
 | 
					    line-height: 1.4;
 | 
				
			||||||
    cursor: pointer;
 | 
					    cursor: pointer;
 | 
				
			||||||
 | 
					    &.break-text {
 | 
				
			||||||
 | 
					      white-space: normal;
 | 
				
			||||||
 | 
					      word-wrap: break-word;
 | 
				
			||||||
 | 
					      overflow-wrap: break-word;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    &:hover, &:focus {
 | 
					    &:hover, &:focus {
 | 
				
			||||||
      text-decoration: none;
 | 
					      text-decoration: none;
 | 
				
			||||||
      background-color: var(--color-primary-light);
 | 
					      background-color: var(--color-primary-light);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
///////////////
 | 
					///////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Screen breakpoints
 | 
					// Screen breakpoints
 | 
				
			||||||
 | 
					$xxxl: 1700px;
 | 
				
			||||||
$xxl: 1400px;
 | 
					$xxl: 1400px;
 | 
				
			||||||
$xl: 1100px;
 | 
					$xl: 1100px;
 | 
				
			||||||
$l: 1000px;
 | 
					$l: 1000px;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -67,7 +67,7 @@
 | 
				
			||||||
@stop
 | 
					@stop
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@section('right')
 | 
					@section('right')
 | 
				
			||||||
    <div class="mb-xl" style="z-index: 1000; opacity: 1;">
 | 
					    <div class="mb-xl">
 | 
				
			||||||
        <h5>{{ trans('common.details') }}</h5>
 | 
					        <h5>{{ trans('common.details') }}</h5>
 | 
				
			||||||
        <div class="blended-links">
 | 
					        <div class="blended-links">
 | 
				
			||||||
            @include('entities.meta', ['entity' => $book])
 | 
					            @include('entities.meta', ['entity' => $book])
 | 
				
			||||||
| 
						 | 
					@ -142,6 +142,7 @@
 | 
				
			||||||
            @if(signedInUser())
 | 
					            @if(signedInUser())
 | 
				
			||||||
                @include('entities.favourite-action', ['entity' => $book])
 | 
					                @include('entities.favourite-action', ['entity' => $book])
 | 
				
			||||||
            @endif
 | 
					            @endif
 | 
				
			||||||
 | 
					            @include('entities.watch-action', ['entity' => $book])
 | 
				
			||||||
            @if(userCan('content-export'))
 | 
					            @if(userCan('content-export'))
 | 
				
			||||||
                @include('entities.export-menu', ['entity' => $book])
 | 
					                @include('entities.export-menu', ['entity' => $book])
 | 
				
			||||||
            @endif
 | 
					            @endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -69,11 +69,12 @@
 | 
				
			||||||
        </a>
 | 
					        </a>
 | 
				
			||||||
    @endif
 | 
					    @endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div class="dropdown-container">
 | 
					    <div component="dropdown"
 | 
				
			||||||
        <div class="entity-meta-item">
 | 
					         class="dropdown-container my-xxs">
 | 
				
			||||||
 | 
					        <a refs="dropdown@toggle" href="#" class="entity-meta-item my-none">
 | 
				
			||||||
            @icon('watch')
 | 
					            @icon('watch')
 | 
				
			||||||
            <span>Watching with default preferences</span>
 | 
					            <span>Watching with default preferences</span>
 | 
				
			||||||
        </div>
 | 
					        </a>
 | 
				
			||||||
        @include('entities.watch-controls', ['entity' => $entity])
 | 
					        @include('entities.watch-controls', ['entity' => $entity])
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,9 @@
 | 
				
			||||||
 | 
					<form action="{{ $entity->getUrl('/') }}" method="GET">
 | 
				
			||||||
 | 
					    {{ csrf_field() }}
 | 
				
			||||||
 | 
					    <input type="hidden" name="type" value="{{ get_class($entity) }}">
 | 
				
			||||||
 | 
					    <input type="hidden" name="id" value="{{ $entity->id }}">
 | 
				
			||||||
 | 
					    <button type="submit" data-shortcut="favourite" class="icon-list-item text-link">
 | 
				
			||||||
 | 
					        <span>@icon('watch')</span>
 | 
				
			||||||
 | 
					        <span>{{ trans('entities.watch') }}</span>
 | 
				
			||||||
 | 
					    </button>
 | 
				
			||||||
 | 
					</form>
 | 
				
			||||||
| 
						 | 
					@ -1,71 +1,32 @@
 | 
				
			||||||
<form action="{{ $entity->getUrl('/') }}" method="GET">
 | 
					<form action="{{ $entity->getUrl('/') }}" method="GET">
 | 
				
			||||||
{{--    {{ method_field('PUT') }}--}}
 | 
					{{--    {{ method_field('PUT') }}--}}
 | 
				
			||||||
 | 
					    {{ csrf_field() }}
 | 
				
			||||||
 | 
					    <input type="hidden" name="type" value="{{ get_class($entity) }}">
 | 
				
			||||||
 | 
					    <input type="hidden" name="id" value="{{ $entity->id }}">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <ul class="dropdown-menu xl-limited anchor-left" style="display: block;">
 | 
					    <ul refs="dropdown@menu" class="dropdown-menu xl-limited anchor-left pb-none">
 | 
				
			||||||
 | 
					        @foreach(\BookStack\Users\UserWatchOptions::getAvailableOptionNames() as $option)
 | 
				
			||||||
        <li>
 | 
					        <li>
 | 
				
			||||||
            <button name="level" value="default" class="icon-item">
 | 
					            <button name="level" value="{{ $option }}" class="icon-item">
 | 
				
			||||||
                <span class="text-pos pt-m">{!!  request()->query('level') === 'default' ? icon('check-circle') : '' !!}</span>
 | 
					                @if(request()->query('level') === $option)
 | 
				
			||||||
 | 
					                    <span class="text-pos pt-m" title="{{ trans('common.status_active') }}">@icon('check-circle')</span>
 | 
				
			||||||
 | 
					                @else
 | 
				
			||||||
 | 
					                    <span title="{{ trans('common.status_inactive') }}"></span>
 | 
				
			||||||
 | 
					                @endif
 | 
				
			||||||
                <div class="break-text">
 | 
					                <div class="break-text">
 | 
				
			||||||
                    <div class="mb-xxs"><strong>Default Preferences</strong></div>
 | 
					                    <div class="mb-xxs"><strong>{{ trans('entities.watch_title_' . $option) }}</strong></div>
 | 
				
			||||||
                    <div class="text-muted text-small">
 | 
					                    <div class="text-muted text-small">
 | 
				
			||||||
                        Revert watching to just your default notification preferences.
 | 
					                        {{ trans('entities.watch_desc_' . $option) }}
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
            </button>
 | 
					            </button>
 | 
				
			||||||
        </li>
 | 
					        </li>
 | 
				
			||||||
        <li><hr class="my-none"></li>
 | 
					        <li><hr class="my-none"></li>
 | 
				
			||||||
 | 
					        @endforeach
 | 
				
			||||||
        <li>
 | 
					        <li>
 | 
				
			||||||
            <button name="level" value="ignore" class="icon-item">
 | 
					            <a href="{{ url('/preferences/notifications') }}"
 | 
				
			||||||
                <span class="text-pos pt-m">{!!  request()->query('level') === 'ignore' ? icon('check-circle') : '' !!}</span>
 | 
					               target="_blank"
 | 
				
			||||||
                <div class="break-text">
 | 
					               class="text-item text-muted text-small break-text">{{ trans('entities.watch_change_default') }}</a>
 | 
				
			||||||
                    <div class="mb-xxs"><strong>Ignore</strong></div>
 | 
					 | 
				
			||||||
                    <div class="text-muted text-small">
 | 
					 | 
				
			||||||
                        Ignore all notifications, including those from user-level preferences.
 | 
					 | 
				
			||||||
                    </div>
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
            </button>
 | 
					 | 
				
			||||||
        </li>
 | 
					 | 
				
			||||||
        <li><hr class="my-none"></li>
 | 
					 | 
				
			||||||
        <li>
 | 
					 | 
				
			||||||
            <button name="level" value="new" class="icon-item">
 | 
					 | 
				
			||||||
                <span class="text-pos pt-m">{!!  request()->query('level') === 'new' ? icon('check-circle') : '' !!}</span>
 | 
					 | 
				
			||||||
                <div class="break-text">
 | 
					 | 
				
			||||||
                    <div class="mb-xxs"><strong>New Pages</strong></div>
 | 
					 | 
				
			||||||
                    <div class="text-muted text-small">
 | 
					 | 
				
			||||||
                        Notify when any new page is created within this item.
 | 
					 | 
				
			||||||
                    </div>
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
            </button>
 | 
					 | 
				
			||||||
        </li>
 | 
					 | 
				
			||||||
        <li><hr class="my-none"></li>
 | 
					 | 
				
			||||||
        <li>
 | 
					 | 
				
			||||||
            <button name="level" value="updates" class="icon-item">
 | 
					 | 
				
			||||||
                <span class="text-pos pt-m">{!!  request()->query('level') === 'updates' ? icon('check-circle') : '' !!}</span>
 | 
					 | 
				
			||||||
                <div class="break-text">
 | 
					 | 
				
			||||||
                    <div class="mb-xxs"><strong>All Page Updates</strong></div>
 | 
					 | 
				
			||||||
                    <div class="text-muted text-small">
 | 
					 | 
				
			||||||
                        Notify upon all new pages and page changes.
 | 
					 | 
				
			||||||
                    </div>
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
            </button>
 | 
					 | 
				
			||||||
        </li>
 | 
					 | 
				
			||||||
        <li><hr class="my-none"></li>
 | 
					 | 
				
			||||||
        <li>
 | 
					 | 
				
			||||||
            <button name="level" value="comments" class="icon-item">
 | 
					 | 
				
			||||||
                <span class="text-pos pt-m">{!!  request()->query('level') === 'comments' ? icon('check-circle') : '' !!}</span>
 | 
					 | 
				
			||||||
                <div class="break-text">
 | 
					 | 
				
			||||||
                    <div class="mb-xxs"><strong>All Page Updates & Comments</strong></div>
 | 
					 | 
				
			||||||
                    <div class="text-muted text-small">
 | 
					 | 
				
			||||||
                        Notify upon all new pages, page changes and new comments.
 | 
					 | 
				
			||||||
                    </div>
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
            </button>
 | 
					 | 
				
			||||||
        </li>
 | 
					 | 
				
			||||||
        <li><hr class="my-none"></li>
 | 
					 | 
				
			||||||
        <li>
 | 
					 | 
				
			||||||
            <div class="text-small text-muted px-l pb-xxs pt-xs">
 | 
					 | 
				
			||||||
                <a href="{{ url('/preferences/notifications') }}" target="_blank">Change default notification preferences</a>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
        </li>
 | 
					        </li>
 | 
				
			||||||
    </ul>
 | 
					    </ul>
 | 
				
			||||||
</form>
 | 
					</form>
 | 
				
			||||||
		Loading…
	
		Reference in New Issue