Compare commits
	
		
			10 Commits
		
	
	
		
			32d6e0c875
			...
			d2a854490f
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					d2a854490f | ||
| 
						 | 
					d465951f31 | ||
| 
						 | 
					55b10f5a5c | ||
| 
						 | 
					edf4163e38 | ||
| 
						 | 
					09cba205a4 | ||
| 
						 | 
					eea7446346 | ||
| 
						 | 
					429d6451c4 | ||
| 
						 | 
					128a45ad77 | ||
| 
						 | 
					66a85f29f9 | ||
| 
						 | 
					d1d8def602 | 
@@ -143,3 +143,17 @@ pub async fn list_patterns(
 | 
				
			|||||||
        .map_err(|e| errors::AppError::StorageFailure(e.to_string()))?;
 | 
					        .map_err(|e| errors::AppError::StorageFailure(e.to_string()))?;
 | 
				
			||||||
    Ok(patterns)
 | 
					    Ok(patterns)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tauri::command]
 | 
				
			||||||
 | 
					pub async fn save_pattern(
 | 
				
			||||||
 | 
					    app_state: State<'_, Arc<RwLock<AppState>>>,
 | 
				
			||||||
 | 
					    pattern: Pattern,
 | 
				
			||||||
 | 
					) -> Result<(), errors::AppError> {
 | 
				
			||||||
 | 
					    let state = app_state.read().await;
 | 
				
			||||||
 | 
					    state
 | 
				
			||||||
 | 
					        .db
 | 
				
			||||||
 | 
					        .store_pattern(&pattern)
 | 
				
			||||||
 | 
					        .await
 | 
				
			||||||
 | 
					        .map_err(|e| errors::AppError::StorageFailure(e.to_string()))?;
 | 
				
			||||||
 | 
					    Ok(())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -65,7 +65,8 @@ pub fn run() {
 | 
				
			|||||||
            cmd::activate_central_adapter,
 | 
					            cmd::activate_central_adapter,
 | 
				
			||||||
            cmd::start_scan_devices,
 | 
					            cmd::start_scan_devices,
 | 
				
			||||||
            cmd::stop_scan_devices,
 | 
					            cmd::stop_scan_devices,
 | 
				
			||||||
            cmd::list_patterns
 | 
					            cmd::list_patterns,
 | 
				
			||||||
 | 
					            cmd::save_pattern
 | 
				
			||||||
        ])
 | 
					        ])
 | 
				
			||||||
        .run(tauri::generate_context!())
 | 
					        .run(tauri::generate_context!())
 | 
				
			||||||
        .expect("error while running tauri application");
 | 
					        .expect("error while running tauri application");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -227,10 +227,12 @@
 | 
				
			|||||||
        --button-text: var(--color-info);
 | 
					        --button-text: var(--color-info);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      &:hover {
 | 
					      &:hover {
 | 
				
			||||||
 | 
					        color: var(--button-text);
 | 
				
			||||||
        background-color: color-mix(in oklch, var(--button-text) 8%, transparent);
 | 
					        background-color: color-mix(in oklch, var(--button-text) 8%, transparent);
 | 
				
			||||||
        box-shadow: var(--elevation-0);
 | 
					        box-shadow: var(--elevation-0);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      &:active {
 | 
					      &:active {
 | 
				
			||||||
 | 
					        color: var(--button-text);
 | 
				
			||||||
        background-color: color-mix(in oklch, var(--button-text) 18%, transparent);
 | 
					        background-color: color-mix(in oklch, var(--button-text) 18%, transparent);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -260,11 +262,13 @@
 | 
				
			|||||||
        --button-text: var(--color-info);
 | 
					        --button-text: var(--color-info);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      &:hover {
 | 
					      &:hover {
 | 
				
			||||||
        --button-surface: color-mix(in oklch, var(--button-text) 8%, transparent);
 | 
					        color: var(--button-text);
 | 
				
			||||||
 | 
					        background-color: color-mix(in oklch, var(--button-text) 8%, transparent);
 | 
				
			||||||
        box-shadow: var(--elevation-0);
 | 
					        box-shadow: var(--elevation-0);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      &:active {
 | 
					      &:active {
 | 
				
			||||||
        --button-surface: color-mix(in oklch, var(--button-text) 18%, transparent);
 | 
					        color: var(--button-text);
 | 
				
			||||||
 | 
					        background-color: color-mix(in oklch, var(--button-text) 18%, transparent);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    &.text:disabled {
 | 
					    &.text:disabled {
 | 
				
			||||||
@@ -274,6 +278,7 @@
 | 
				
			|||||||
    &.icon:not(:disabled) {
 | 
					    &.icon:not(:disabled) {
 | 
				
			||||||
      --button-text: var(--color-on-surface-variant);
 | 
					      --button-text: var(--color-on-surface-variant);
 | 
				
			||||||
      --button-surface: transparent;
 | 
					      --button-surface: transparent;
 | 
				
			||||||
 | 
					      padding: calc(var(--spacing) * 1);
 | 
				
			||||||
      &.selected {
 | 
					      &.selected {
 | 
				
			||||||
        --button-text: var(--color-primary);
 | 
					        --button-text: var(--color-primary);
 | 
				
			||||||
        &.secondary {
 | 
					        &.secondary {
 | 
				
			||||||
@@ -296,20 +301,24 @@
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      &:hover {
 | 
					      &:hover {
 | 
				
			||||||
        --button-surface: color-mix(in oklch, var(--button-text) 8%, transparent);
 | 
					        color: var(--button-text);
 | 
				
			||||||
 | 
					        background-color: color-mix(in oklch, var(--button-text) 8%, transparent);
 | 
				
			||||||
        box-shadow: var(--elevation-0);
 | 
					        box-shadow: var(--elevation-0);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      &:active {
 | 
					      &:active {
 | 
				
			||||||
        --button-surface: color-mix(in oklch, var(--button-text) 18%, transparent);
 | 
					        color: var(--button-text);
 | 
				
			||||||
 | 
					        background-color: color-mix(in oklch, var(--button-text) 18%, transparent);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    &.icon:disabled {
 | 
					    &.icon:disabled {
 | 
				
			||||||
      --button-text: color-mix(in oklch, var(--color-on-surface) 38%, transparent);
 | 
					      --button-text: color-mix(in oklch, var(--color-on-surface) 38%, transparent);
 | 
				
			||||||
      --button-surface: transparent;
 | 
					      --button-surface: transparent;
 | 
				
			||||||
 | 
					      padding: calc(var(--spacing) * 1);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    &.filled_icon:not(:disabled) {
 | 
					    &.filled_icon:not(:disabled) {
 | 
				
			||||||
      --button-text: var(--color-on-primary);
 | 
					      --button-text: var(--color-on-primary);
 | 
				
			||||||
      --button-surface: var(--color-primary);
 | 
					      --button-surface: var(--color-primary);
 | 
				
			||||||
 | 
					      padding: calc(var(--spacing) * 1);
 | 
				
			||||||
      &.secondary {
 | 
					      &.secondary {
 | 
				
			||||||
        --button-text: var(--color-on-secondary);
 | 
					        --button-text: var(--color-on-secondary);
 | 
				
			||||||
        --button-surface: var(--color-secondary);
 | 
					        --button-surface: var(--color-secondary);
 | 
				
			||||||
@@ -342,10 +351,12 @@
 | 
				
			|||||||
    &.filled_icon:disabled {
 | 
					    &.filled_icon:disabled {
 | 
				
			||||||
      --button-text: color-mix(in oklch, var(--color-on-surface) 38%, transparent);
 | 
					      --button-text: color-mix(in oklch, var(--color-on-surface) 38%, transparent);
 | 
				
			||||||
      --button-surface: color-mix(in oklch, var(--color-on-surface) 12%, transparent);
 | 
					      --button-surface: color-mix(in oklch, var(--color-on-surface) 12%, transparent);
 | 
				
			||||||
 | 
					      padding: calc(var(--spacing) * 1);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    &.tonal_icon:not(:disabled) {
 | 
					    &.tonal_icon:not(:disabled) {
 | 
				
			||||||
      --button-text: var(--color-on-primary-container);
 | 
					      --button-text: var(--color-on-primary-container);
 | 
				
			||||||
      --button-surface: var(--color-primary-container);
 | 
					      --button-surface: var(--color-primary-container);
 | 
				
			||||||
 | 
					      padding: calc(var(--spacing) * 1);
 | 
				
			||||||
      &.secondary {
 | 
					      &.secondary {
 | 
				
			||||||
        --button-text: var(--color-on-secondary-container);
 | 
					        --button-text: var(--color-on-secondary-container);
 | 
				
			||||||
        --button-surface: var(--color-secondary-container);
 | 
					        --button-surface: var(--color-secondary-container);
 | 
				
			||||||
@@ -360,52 +371,59 @@
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
      &.warn {
 | 
					      &.warn {
 | 
				
			||||||
        --button-text: var(--color-on-warning-container);
 | 
					        --button-text: var(--color-on-warning-container);
 | 
				
			||||||
        --button-surface: var(--color-warning);
 | 
					        --button-surface: var(--color-warning-container);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      &.success {
 | 
					      &.success {
 | 
				
			||||||
        --button-text: var(--color-on-success-container);
 | 
					        --button-text: var(--color-on-success-container);
 | 
				
			||||||
        --button-surface: var(--color-success-container);
 | 
					        --button-surface: var(--color-success-container);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      &.info {
 | 
					      &.info {
 | 
				
			||||||
        --button-text: var(--color-on-info);
 | 
					        --button-text: var(--color-on-info-container);
 | 
				
			||||||
        --button-surface: var(--color-info);
 | 
					        --button-surface: var(--color-info-container);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      &.unselected {
 | 
					      &.unselected {
 | 
				
			||||||
        --button-text: var(--color-on-surface-variant);
 | 
					        --button-text: var(--color-on-surface-variant);
 | 
				
			||||||
        --button-surface: var(--color-surface-container-highest);
 | 
					        --button-surface: var(--color-surface-container-highest);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      &:hover {
 | 
					      &:hover {
 | 
				
			||||||
        --button-surface: color-mix(in oklch, var(--button-text) 8%, transparent);
 | 
					        color: var(--button-surface);
 | 
				
			||||||
 | 
					        background-color: color-mix(in oklch, var(--button-surface) 8%, transparent);
 | 
				
			||||||
        box-shadow: var(--elevation-0);
 | 
					        box-shadow: var(--elevation-0);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      &:active {
 | 
					      &:active {
 | 
				
			||||||
        --button-surface: color-mix(in oklch, var(--button-text) 18%, transparent);
 | 
					        color: var(--button-surface);
 | 
				
			||||||
 | 
					        background-color: color-mix(in oklch, var(--button-surface) 18%, transparent);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    &.tonal_icon:disabled {
 | 
					    &.tonal_icon:disabled {
 | 
				
			||||||
      --button-text: color-mix(in oklch, var(--color-on-surface) 38%, transparent);
 | 
					      --button-text: color-mix(in oklch, var(--color-on-surface) 38%, transparent);
 | 
				
			||||||
      --button-surface: color-mix(in oklch, var(--color-on-surface) 12%, transparent);
 | 
					      --button-surface: color-mix(in oklch, var(--color-on-surface) 12%, transparent);
 | 
				
			||||||
 | 
					      padding: calc(var(--spacing) * 1);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    &.outlined_icon:not(:disabled) {
 | 
					    &.outlined_icon:not(:disabled) {
 | 
				
			||||||
      --button-text: var(--color-on-surface-variant);
 | 
					      --button-text: var(--color-on-surface-variant);
 | 
				
			||||||
      --button-surface: transparent;
 | 
					      --button-surface: transparent;
 | 
				
			||||||
      border: 1px solid var(--button-outline);
 | 
					      border: 1px solid var(--button-outline);
 | 
				
			||||||
 | 
					      padding: calc(var(--spacing) * 1);
 | 
				
			||||||
      &.selected {
 | 
					      &.selected {
 | 
				
			||||||
        --button-text: var(--color-inverse-on-surface);
 | 
					        --button-text: var(--color-inverse-on-surface);
 | 
				
			||||||
        --button-surface: var(--color-inverse-surface);
 | 
					        --button-surface: var(--color-inverse-surface);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      &:hover {
 | 
					      &:hover {
 | 
				
			||||||
        --button-surface: color-mix(in oklch, var(--button-text) 8%, transparent);
 | 
					        color: var(--button-text);
 | 
				
			||||||
 | 
					        background-color: color-mix(in oklch, var(--button-text) 8%, transparent);
 | 
				
			||||||
        box-shadow: var(--elevation-0);
 | 
					        box-shadow: var(--elevation-0);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      &:active {
 | 
					      &:active {
 | 
				
			||||||
        --button-surface: color-mix(in oklch, var(--button-text) 18%, transparent);
 | 
					        color: var(--button-text);
 | 
				
			||||||
 | 
					        background-color: color-mix(in oklch, var(--button-text) 18%, transparent);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    &.outlined_icon:disabled {
 | 
					    &.outlined_icon:disabled {
 | 
				
			||||||
      --button-text: color-mix(in oklch, var(--color-on-surface) 38%, transparent);
 | 
					      --button-text: color-mix(in oklch, var(--color-on-surface) 38%, transparent);
 | 
				
			||||||
      --button-surface: color-mix(in oklch, var(--color-on-surface) 12%, transparent);
 | 
					      --button-surface: color-mix(in oklch, var(--color-on-surface) 12%, transparent);
 | 
				
			||||||
      border: 1px solid color-mix(in oklch, var(--color-on-surface) 12%, transparent);
 | 
					      border: 1px solid color-mix(in oklch, var(--color-on-surface) 12%, transparent);
 | 
				
			||||||
 | 
					      padding: calc(var(--spacing) * 1);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										47
									
								
								src/components/Switch.module.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/components/Switch.module.css
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					@layer components {
 | 
				
			||||||
 | 
					  .switch {
 | 
				
			||||||
 | 
					    display: inline-flex;
 | 
				
			||||||
 | 
					    align-items: center;
 | 
				
			||||||
 | 
					    gap: 1em;
 | 
				
			||||||
 | 
					    cursor: pointer;
 | 
				
			||||||
 | 
					    &[aria-disabled='true'] {
 | 
				
			||||||
 | 
					      cursor: not-allowed;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .switch_handle {
 | 
				
			||||||
 | 
					    position: relative;
 | 
				
			||||||
 | 
					    width: calc(var(--spacing) * 9);
 | 
				
			||||||
 | 
					    height: calc(var(--spacing) * 5);
 | 
				
			||||||
 | 
					    border: 1px solid var(--color-primary);
 | 
				
			||||||
 | 
					    border-radius: calc(var(--border-radius) * 2);
 | 
				
			||||||
 | 
					    background-color: color-mix(in oklch, var(--color-surface-container-high) 38%, transparent);
 | 
				
			||||||
 | 
					    &::before {
 | 
				
			||||||
 | 
					      content: '';
 | 
				
			||||||
 | 
					      position: absolute;
 | 
				
			||||||
 | 
					      transform: translate(2px, 3px);
 | 
				
			||||||
 | 
					      width: calc(var(--spacing) * 3);
 | 
				
			||||||
 | 
					      height: calc(var(--spacing) * 3);
 | 
				
			||||||
 | 
					      border-radius: calc(var(--border-radius) * 2);
 | 
				
			||||||
 | 
					      background-color: var(--color-primary);
 | 
				
			||||||
 | 
					      transition: transform 0.2s ease-in-out;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    &.checked {
 | 
				
			||||||
 | 
					      background-color: color-mix(in oklch, var(--color-primary) 38%, transparent);
 | 
				
			||||||
 | 
					      &::before {
 | 
				
			||||||
 | 
					        background-color: var(--color-primary);
 | 
				
			||||||
 | 
					        transform: translate(calc(var(--spacing) * 5 - 2px), 3px);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    [aria-disabled='true'] & {
 | 
				
			||||||
 | 
					      --disabled-color: var(--color-on-surface);
 | 
				
			||||||
 | 
					      background-color: color-mix(in oklch, var(--disabled-color) 8%, transparent);
 | 
				
			||||||
 | 
					      border-color: var(--disabled-color);
 | 
				
			||||||
 | 
					      &.checked {
 | 
				
			||||||
 | 
					        background-color: color-mix(in oklch, var(--disabled-color) 20%, transparent);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      &::before {
 | 
				
			||||||
 | 
					        background-color: color-mix(in oklch, var(--disabled-color) 38%, transparent);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										40
									
								
								src/components/Switch.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/components/Switch.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
				
			|||||||
 | 
					import cx from 'clsx';
 | 
				
			||||||
 | 
					import { FC, useCallback, useEffect, useState } from 'react';
 | 
				
			||||||
 | 
					import styles from './Switch.module.css';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type SwitchProps = {
 | 
				
			||||||
 | 
					  name?: string;
 | 
				
			||||||
 | 
					  checked?: boolean;
 | 
				
			||||||
 | 
					  disabled?: boolean;
 | 
				
			||||||
 | 
					  onChange?: (checked: boolean) => void;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Switch: FC<SwitchProps> = ({ name, checked = false, disabled = false, onChange }) => {
 | 
				
			||||||
 | 
					  const [isChecked, setChecked] = useState(checked);
 | 
				
			||||||
 | 
					  const handleChange = useCallback(() => {
 | 
				
			||||||
 | 
					    if (!disabled) {
 | 
				
			||||||
 | 
					      setChecked((prev) => !prev);
 | 
				
			||||||
 | 
					      onChange?.(!isChecked);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }, [disabled, onChange, isChecked]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    if (checked !== isChecked) {
 | 
				
			||||||
 | 
					      setChecked(checked);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }, [checked]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div aria-disabled={disabled} className={styles.switch}>
 | 
				
			||||||
 | 
					      <div
 | 
				
			||||||
 | 
					        className={cx(styles.switch_handle, isChecked && styles.checked)}
 | 
				
			||||||
 | 
					        onClick={handleChange}
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					      {name !== undefined && (
 | 
				
			||||||
 | 
					        <input type="hidden" name={name} value={isChecked ? 'true' : 'false'} />
 | 
				
			||||||
 | 
					      )}
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default Switch;
 | 
				
			||||||
@@ -9,5 +9,8 @@
 | 
				
			|||||||
    border-radius: calc(var(--border-radius) * 2);
 | 
					    border-radius: calc(var(--border-radius) * 2);
 | 
				
			||||||
    color: var(--color-light-on-surface);
 | 
					    color: var(--color-light-on-surface);
 | 
				
			||||||
    background-color: var(--color-surface-container);
 | 
					    background-color: var(--color-surface-container);
 | 
				
			||||||
 | 
					    .content {
 | 
				
			||||||
 | 
					      max-width: 300px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										19
									
								
								src/page-components/pattern-editor/PatternHeader.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/page-components/pattern-editor/PatternHeader.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					import { Icon } from '@iconify/react/dist/iconify.js';
 | 
				
			||||||
 | 
					import { FC } from 'react';
 | 
				
			||||||
 | 
					import EditableContent from '../../components/EditableContent';
 | 
				
			||||||
 | 
					import styles from './PatternHeader.module.css';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const PatternHeader: FC = () => {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div className={styles.pattern_header}>
 | 
				
			||||||
 | 
					      <EditableContent as="h3" placeholder="Pattern Name" additionalClassName={styles.content} />
 | 
				
			||||||
 | 
					      <div className="spacer" />
 | 
				
			||||||
 | 
					      <button className="tonal">
 | 
				
			||||||
 | 
					        <Icon icon="material-symbols-light:close" />
 | 
				
			||||||
 | 
					        Close Edit
 | 
				
			||||||
 | 
					      </button>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default PatternHeader;
 | 
				
			||||||
@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					@layer pages {
 | 
				
			||||||
 | 
					  .pattern_overview {
 | 
				
			||||||
 | 
					    flex: 1;
 | 
				
			||||||
 | 
					    display: flex;
 | 
				
			||||||
 | 
					    flex-direction: column;
 | 
				
			||||||
 | 
					    align-items: stretch;
 | 
				
			||||||
 | 
					    gap: calc(var(--spacing));
 | 
				
			||||||
 | 
					    padding: calc(var(--spacing) * 2) calc(var(--spacing));
 | 
				
			||||||
 | 
					    border-radius: calc(var(--border-radius) * 2);
 | 
				
			||||||
 | 
					    color: var(--color-on-surface);
 | 
				
			||||||
 | 
					    background-color: var(--color-surface-container);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .attribute_row {
 | 
				
			||||||
 | 
					    display: flex;
 | 
				
			||||||
 | 
					    flex-direction: row;
 | 
				
			||||||
 | 
					    align-items: center;
 | 
				
			||||||
 | 
					    gap: calc(var(--spacing) * 2);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										18
									
								
								src/page-components/pattern-editor/PatternOverview.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/page-components/pattern-editor/PatternOverview.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					import { FC } from 'react';
 | 
				
			||||||
 | 
					import Switch from '../../components/Switch';
 | 
				
			||||||
 | 
					import styles from './PatternOverview.module.css';
 | 
				
			||||||
 | 
					import PulseList from './PulseList';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const PatternOverview: FC = () => {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div className={styles.pattern_overview}>
 | 
				
			||||||
 | 
					      <div className={styles.attribute_row}>
 | 
				
			||||||
 | 
					        <label>Smooth Repeat</label>
 | 
				
			||||||
 | 
					        <Switch />
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <PulseList />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default PatternOverview;
 | 
				
			||||||
@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					@layer pages {
 | 
				
			||||||
 | 
					  .pulse_attributes {
 | 
				
			||||||
 | 
					    flex: 2;
 | 
				
			||||||
 | 
					    display: flex;
 | 
				
			||||||
 | 
					    flex-direction: column;
 | 
				
			||||||
 | 
					    align-items: stretch;
 | 
				
			||||||
 | 
					    gap: calc(var(--spacing) * 2);
 | 
				
			||||||
 | 
					    padding: calc(var(--spacing) * 2) calc(var(--spacing));
 | 
				
			||||||
 | 
					    border-radius: calc(var(--border-radius) * 2);
 | 
				
			||||||
 | 
					    color: var(--color-on-surface);
 | 
				
			||||||
 | 
					    background-color: var(--color-surface-container);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										8
									
								
								src/page-components/pattern-editor/PulseAttributes.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/page-components/pattern-editor/PulseAttributes.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					import { FC } from 'react';
 | 
				
			||||||
 | 
					import styles from './PulseAttributes.module.css';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const PulseAttributes: FC = () => {
 | 
				
			||||||
 | 
					  return <div className={styles.pulse_attributes}></div>;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default PulseAttributes;
 | 
				
			||||||
							
								
								
									
										20
									
								
								src/page-components/pattern-editor/PulseList.module.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/page-components/pattern-editor/PulseList.module.css
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					@layer page {
 | 
				
			||||||
 | 
					  .pulse_tools {
 | 
				
			||||||
 | 
					    display: flex;
 | 
				
			||||||
 | 
					    flex-direction: row;
 | 
				
			||||||
 | 
					    justify-content: flex-end;
 | 
				
			||||||
 | 
					    align-items: center;
 | 
				
			||||||
 | 
					    gap: calc(var(--spacing) * 2);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .pulses {
 | 
				
			||||||
 | 
					    min-width: 0;
 | 
				
			||||||
 | 
					    min-height: 0;
 | 
				
			||||||
 | 
					    overflow: hidden;
 | 
				
			||||||
 | 
					    flex: 1;
 | 
				
			||||||
 | 
					    padding-inline: calc(var(--spacing) * 2);
 | 
				
			||||||
 | 
					    padding-block-end: calc(var(--spacing));
 | 
				
			||||||
 | 
					    display: flex;
 | 
				
			||||||
 | 
					    flex-direction: column;
 | 
				
			||||||
 | 
					    align-items: stretch;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										22
									
								
								src/page-components/pattern-editor/PulseList.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/page-components/pattern-editor/PulseList.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					import { Icon } from '@iconify/react/dist/iconify.js';
 | 
				
			||||||
 | 
					import { FC } from 'react';
 | 
				
			||||||
 | 
					import { ScrollArea } from '../../components/ScrollArea';
 | 
				
			||||||
 | 
					import styles from './PulseList.module.css';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const PulseList: FC = () => {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <>
 | 
				
			||||||
 | 
					      <div className={styles.pulse_tools}>
 | 
				
			||||||
 | 
					        <button className="text">
 | 
				
			||||||
 | 
					          <Icon icon="material-symbols-light:add" />
 | 
				
			||||||
 | 
					          <span>Add Pulse</span>
 | 
				
			||||||
 | 
					        </button>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div className={styles.pulses}>
 | 
				
			||||||
 | 
					        <ScrollArea enableY></ScrollArea>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default PulseList;
 | 
				
			||||||
		Reference in New Issue
	
	Block a user