mirror of
				https://github.com/blakeblackshear/frigate.git
				synced 2025-10-27 10:52:11 +01:00 
			
		
		
		
	Timeline UI optimizations (#6367)
* Fix centering of bottom_center * Make bottom_center overlap vertically * Fix timeline icon behavior * Make disclaimer hidden under aria label * Don't literally say disclaimer
This commit is contained in:
		
							parent
							
								
									ede1dedbbd
								
							
						
					
					
						commit
						aded314f3c
					
				@ -7,48 +7,49 @@ const ButtonColors = {
 | 
				
			|||||||
    contained: 'bg-blue-500 focus:bg-blue-400 active:bg-blue-600 ring-blue-300',
 | 
					    contained: 'bg-blue-500 focus:bg-blue-400 active:bg-blue-600 ring-blue-300',
 | 
				
			||||||
    outlined:
 | 
					    outlined:
 | 
				
			||||||
      'text-blue-500 border-2 border-blue-500 hover:bg-blue-500 hover:bg-opacity-20 focus:bg-blue-500 focus:bg-opacity-40 active:bg-blue-500 active:bg-opacity-40',
 | 
					      'text-blue-500 border-2 border-blue-500 hover:bg-blue-500 hover:bg-opacity-20 focus:bg-blue-500 focus:bg-opacity-40 active:bg-blue-500 active:bg-opacity-40',
 | 
				
			||||||
    text:
 | 
					    text: 'text-blue-500 hover:bg-blue-500 hover:bg-opacity-20 focus:bg-blue-500 focus:bg-opacity-40 active:bg-blue-500 active:bg-opacity-40',
 | 
				
			||||||
      'text-blue-500 hover:bg-blue-500 hover:bg-opacity-20 focus:bg-blue-500 focus:bg-opacity-40 active:bg-blue-500 active:bg-opacity-40',
 | 
					    iconOnly: 'text-blue-500 hover:text-blue-200',
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  red: {
 | 
					  red: {
 | 
				
			||||||
    contained: 'bg-red-500 focus:bg-red-400 active:bg-red-600 ring-red-300',
 | 
					    contained: 'bg-red-500 focus:bg-red-400 active:bg-red-600 ring-red-300',
 | 
				
			||||||
    outlined:
 | 
					    outlined:
 | 
				
			||||||
      'text-red-500 border-2 border-red-500 hover:bg-red-500 hover:bg-opacity-20 focus:bg-red-500 focus:bg-opacity-40 active:bg-red-500 active:bg-opacity-40',
 | 
					      'text-red-500 border-2 border-red-500 hover:bg-red-500 hover:bg-opacity-20 focus:bg-red-500 focus:bg-opacity-40 active:bg-red-500 active:bg-opacity-40',
 | 
				
			||||||
    text:
 | 
					    text: 'text-red-500 hover:bg-red-500 hover:bg-opacity-20 focus:bg-red-500 focus:bg-opacity-40 active:bg-red-500 active:bg-opacity-40',
 | 
				
			||||||
      'text-red-500 hover:bg-red-500 hover:bg-opacity-20 focus:bg-red-500 focus:bg-opacity-40 active:bg-red-500 active:bg-opacity-40',
 | 
					    iconOnly: 'text-red-500 hover:text-red-200',
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  yellow: {
 | 
					  yellow: {
 | 
				
			||||||
    contained: 'bg-yellow-500 focus:bg-yellow-400 active:bg-yellow-600 ring-yellow-300',
 | 
					    contained: 'bg-yellow-500 focus:bg-yellow-400 active:bg-yellow-600 ring-yellow-300',
 | 
				
			||||||
    outlined:
 | 
					    outlined:
 | 
				
			||||||
      'text-yellow-500 border-2 border-yellow-500 hover:bg-yellow-500 hover:bg-opacity-20 focus:bg-yellow-500 focus:bg-opacity-40 active:bg-yellow-500 active:bg-opacity-40',
 | 
					      'text-yellow-500 border-2 border-yellow-500 hover:bg-yellow-500 hover:bg-opacity-20 focus:bg-yellow-500 focus:bg-opacity-40 active:bg-yellow-500 active:bg-opacity-40',
 | 
				
			||||||
    text:
 | 
					    text: 'text-yellow-500 hover:bg-yellow-500 hover:bg-opacity-20 focus:bg-yellow-500 focus:bg-opacity-40 active:bg-yellow-500 active:bg-opacity-40',
 | 
				
			||||||
      'text-yellow-500 hover:bg-yellow-500 hover:bg-opacity-20 focus:bg-yellow-500 focus:bg-opacity-40 active:bg-yellow-500 active:bg-opacity-40',
 | 
					    iconOnly: 'text-yellow-500 hover:text-yellow-200',
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  green: {
 | 
					  green: {
 | 
				
			||||||
    contained: 'bg-green-500 focus:bg-green-400 active:bg-green-600 ring-green-300',
 | 
					    contained: 'bg-green-500 focus:bg-green-400 active:bg-green-600 ring-green-300',
 | 
				
			||||||
    outlined:
 | 
					    outlined:
 | 
				
			||||||
      'text-green-500 border-2 border-green-500 hover:bg-green-500 hover:bg-opacity-20 focus:bg-green-500 focus:bg-opacity-40 active:bg-green-500 active:bg-opacity-40',
 | 
					      'text-green-500 border-2 border-green-500 hover:bg-green-500 hover:bg-opacity-20 focus:bg-green-500 focus:bg-opacity-40 active:bg-green-500 active:bg-opacity-40',
 | 
				
			||||||
    text:
 | 
					    text: 'text-green-500 hover:bg-green-500 hover:bg-opacity-20 focus:bg-green-500 focus:bg-opacity-40 active:bg-green-500 active:bg-opacity-40',
 | 
				
			||||||
      'text-green-500 hover:bg-green-500 hover:bg-opacity-20 focus:bg-green-500 focus:bg-opacity-40 active:bg-green-500 active:bg-opacity-40',
 | 
					    iconOnly: 'text-green-500 hover:text-green-200',
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  gray: {
 | 
					  gray: {
 | 
				
			||||||
    contained: 'bg-gray-500 focus:bg-gray-400 active:bg-gray-600 ring-gray-300',
 | 
					    contained: 'bg-gray-500 focus:bg-gray-400 active:bg-gray-600 ring-gray-300',
 | 
				
			||||||
    outlined:
 | 
					    outlined:
 | 
				
			||||||
      'text-gray-500 border-2 border-gray-500 hover:bg-gray-500 hover:bg-opacity-20 focus:bg-gray-500 focus:bg-opacity-40 active:bg-gray-500 active:bg-opacity-40',
 | 
					      'text-gray-500 border-2 border-gray-500 hover:bg-gray-500 hover:bg-opacity-20 focus:bg-gray-500 focus:bg-opacity-40 active:bg-gray-500 active:bg-opacity-40',
 | 
				
			||||||
    text:
 | 
					    text: 'text-gray-500 hover:bg-gray-500 hover:bg-opacity-20 focus:bg-gray-500 focus:bg-opacity-40 active:bg-gray-500 active:bg-opacity-40',
 | 
				
			||||||
      'text-gray-500 hover:bg-gray-500 hover:bg-opacity-20 focus:bg-gray-500 focus:bg-opacity-40 active:bg-gray-500 active:bg-opacity-40',
 | 
					    iconOnly: 'text-gray-500 hover:text-gray-200',
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  disabled: {
 | 
					  disabled: {
 | 
				
			||||||
    contained: 'bg-gray-400',
 | 
					    contained: 'bg-gray-400',
 | 
				
			||||||
    outlined:
 | 
					    outlined:
 | 
				
			||||||
      'text-gray-500 border-2 border-gray-500 hover:bg-gray-500 hover:bg-opacity-20 focus:bg-gray-500 focus:bg-opacity-40 active:bg-gray-500 active:bg-opacity-40',
 | 
					      'text-gray-500 border-2 border-gray-500 hover:bg-gray-500 hover:bg-opacity-20 focus:bg-gray-500 focus:bg-opacity-40 active:bg-gray-500 active:bg-opacity-40',
 | 
				
			||||||
    text:
 | 
					    text: 'text-gray-500 hover:bg-gray-500 hover:bg-opacity-20 focus:bg-gray-500 focus:bg-opacity-40 active:bg-gray-500 active:bg-opacity-40',
 | 
				
			||||||
      'text-gray-500 hover:bg-gray-500 hover:bg-opacity-20 focus:bg-gray-500 focus:bg-opacity-40 active:bg-gray-500 active:bg-opacity-40',
 | 
					    iconOnly: 'text-gray-500 hover:text-gray-200',
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  black: {
 | 
					  black: {
 | 
				
			||||||
    contained: '',
 | 
					    contained: '',
 | 
				
			||||||
    outlined: '',
 | 
					    outlined: '',
 | 
				
			||||||
    text: 'text-black dark:text-white',
 | 
					    text: 'text-black dark:text-white',
 | 
				
			||||||
 | 
					    iconOnly: '',
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -56,6 +57,7 @@ const ButtonTypes = {
 | 
				
			|||||||
  contained: 'text-white shadow focus:shadow-xl hover:shadow-md',
 | 
					  contained: 'text-white shadow focus:shadow-xl hover:shadow-md',
 | 
				
			||||||
  outlined: '',
 | 
					  outlined: '',
 | 
				
			||||||
  text: 'transition-opacity',
 | 
					  text: 'transition-opacity',
 | 
				
			||||||
 | 
					  iconOnly: 'transition-opacity',
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function Button({
 | 
					export default function Button({
 | 
				
			||||||
@ -73,7 +75,7 @@ export default function Button({
 | 
				
			|||||||
  let classes = `whitespace-nowrap flex items-center space-x-1 ${className} ${ButtonTypes[type]} ${
 | 
					  let classes = `whitespace-nowrap flex items-center space-x-1 ${className} ${ButtonTypes[type]} ${
 | 
				
			||||||
    ButtonColors[disabled ? 'disabled' : color][type]
 | 
					    ButtonColors[disabled ? 'disabled' : color][type]
 | 
				
			||||||
  } font-sans inline-flex font-bold uppercase text-xs px-1.5 md:px-2 py-2 rounded outline-none focus:outline-none ring-opacity-50 transition-shadow transition-colors ${
 | 
					  } font-sans inline-flex font-bold uppercase text-xs px-1.5 md:px-2 py-2 rounded outline-none focus:outline-none ring-opacity-50 transition-shadow transition-colors ${
 | 
				
			||||||
    disabled ? 'cursor-not-allowed' : 'focus:ring-2 cursor-pointer'
 | 
					    disabled ? 'cursor-not-allowed' : `${type == 'iconOnly' ? '' : 'focus:ring-2'} cursor-pointer`
 | 
				
			||||||
  }`;
 | 
					  }`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (disabled) {
 | 
					  if (disabled) {
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,7 @@ import { h } from 'preact';
 | 
				
			|||||||
import useSWR from 'swr';
 | 
					import useSWR from 'swr';
 | 
				
			||||||
import ActivityIndicator from './ActivityIndicator';
 | 
					import ActivityIndicator from './ActivityIndicator';
 | 
				
			||||||
import { formatUnixTimestampToDateTime } from '../utils/dateUtil';
 | 
					import { formatUnixTimestampToDateTime } from '../utils/dateUtil';
 | 
				
			||||||
 | 
					import About from '../icons/About';
 | 
				
			||||||
import PlayIcon from '../icons/Play';
 | 
					import PlayIcon from '../icons/Play';
 | 
				
			||||||
import ExitIcon from '../icons/Exit';
 | 
					import ExitIcon from '../icons/Exit';
 | 
				
			||||||
import { Zone } from '../icons/Zone';
 | 
					import { Zone } from '../icons/Zone';
 | 
				
			||||||
@ -81,7 +82,7 @@ export default function TimelineSummary({ event, onFrameSelected }) {
 | 
				
			|||||||
              <Button
 | 
					              <Button
 | 
				
			||||||
                key={index}
 | 
					                key={index}
 | 
				
			||||||
                className="rounded-full"
 | 
					                className="rounded-full"
 | 
				
			||||||
                type="text"
 | 
					                type="iconOnly"
 | 
				
			||||||
                color={index == timeIndex ? 'blue' : 'gray'}
 | 
					                color={index == timeIndex ? 'blue' : 'gray'}
 | 
				
			||||||
                aria-label={window.innerWidth > 640 ? getTimelineItemDescription(config, item, event) : ''}
 | 
					                aria-label={window.innerWidth > 640 ? getTimelineItemDescription(config, item, event) : ''}
 | 
				
			||||||
                onClick={() => onSelectMoment(index)}
 | 
					                onClick={() => onSelectMoment(index)}
 | 
				
			||||||
@ -92,7 +93,7 @@ export default function TimelineSummary({ event, onFrameSelected }) {
 | 
				
			|||||||
              <Button
 | 
					              <Button
 | 
				
			||||||
                key={index}
 | 
					                key={index}
 | 
				
			||||||
                className="rounded-full"
 | 
					                className="rounded-full"
 | 
				
			||||||
                type="text"
 | 
					                type="iconOnly"
 | 
				
			||||||
                color={index == timeIndex ? 'blue' : 'gray'}
 | 
					                color={index == timeIndex ? 'blue' : 'gray'}
 | 
				
			||||||
                aria-label={window.innerWidth > 640 ? getTimelineItemDescription(config, item, event) : ''}
 | 
					                aria-label={window.innerWidth > 640 ? getTimelineItemDescription(config, item, event) : ''}
 | 
				
			||||||
                onClick={() => onSelectMoment(index)}
 | 
					                onClick={() => onSelectMoment(index)}
 | 
				
			||||||
@ -104,9 +105,19 @@ export default function TimelineSummary({ event, onFrameSelected }) {
 | 
				
			|||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      {timeIndex >= 0 ? (
 | 
					      {timeIndex >= 0 ? (
 | 
				
			||||||
        <div className="bg-gray-500 p-4 m-2 max-w-md self-center">
 | 
					        <div className="m-2 max-w-md self-center">
 | 
				
			||||||
          Disclaimer: This data comes from the detect feed but is shown on the recordings, it is unlikely that the
 | 
					          <div className="flex justify-start">
 | 
				
			||||||
          streams are perfectly in sync so the bounding box and the footage will not line up perfectly.
 | 
					            <div className="text-lg flex justify-between py-4">Bounding boxes may not align</div>
 | 
				
			||||||
 | 
					            <Button
 | 
				
			||||||
 | 
					              className="rounded-full"
 | 
				
			||||||
 | 
					              type="text"
 | 
				
			||||||
 | 
					              color="gray"
 | 
				
			||||||
 | 
					              aria-label=" Disclaimer: This data comes from the detect feed but is shown on the recordings, it is unlikely that the
 | 
				
			||||||
 | 
					                      streams are perfectly in sync so the bounding box and the footage will not line up perfectly. The annotation_offset field can be used to adjust this."
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              <About className="w-4" />
 | 
				
			||||||
 | 
					            </Button>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      ) : null}
 | 
					      ) : null}
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
				
			|||||||
@ -17,4 +17,3 @@ export function About({ className = '' }) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default memo(About);
 | 
					export default memo(About);
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -724,7 +724,7 @@ export default function Events({ path, ...props }) {
 | 
				
			|||||||
                                      }}
 | 
					                                      }}
 | 
				
			||||||
                                    >
 | 
					                                    >
 | 
				
			||||||
                                      {eventOverlay.class_type == 'entered_zone' ? (
 | 
					                                      {eventOverlay.class_type == 'entered_zone' ? (
 | 
				
			||||||
                                        <div className="absolute w-2 h-2 bg-yellow-500 left-[50%] bottom-0" />
 | 
					                                        <div className="absolute w-2 h-2 bg-yellow-500 left-[50%] -translate-x-1/2 translate-y-3/4 bottom-0" />
 | 
				
			||||||
                                      ) : null}
 | 
					                                      ) : null}
 | 
				
			||||||
                                    </div>
 | 
					                                    </div>
 | 
				
			||||||
                                  ) : null}
 | 
					                                  ) : null}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user