Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

patches for thai tonal mark support #897

Open
raychunghk opened this issue Jan 5, 2025 · 1 comment
Open

patches for thai tonal mark support #897

raychunghk opened this issue Jan 5, 2025 · 1 comment

Comments

@raychunghk
Copy link

raychunghk commented Jan 5, 2025

泰國文字需要在字母上端加一個以上tonal mark如果逐個字用span的話會變樣。
chrome_s0VgGQejA7
現在ั記錄一下我的修正方法。


     {wordState.displayWord.split('').map((t, index, arr) => {
              return (
                <Letter
                  key={`${index}-${t}`}
                  letter={t}
                  visible={getLetterVisible(index)}
                  state={wordState.letterStates[index]}
                  previousLetter={arr[index - 1] || ''} // Pass the previous letter
                  secondPreviousLetter={arr[index - 2] || ''} // Pass the second previous letter
                />
              );
            })}

letter.tsx


import { EXPLICIT_SPACE } from '@/constants';
import { fontSizeConfigAtom } from '@/store';
import { useAtomValue } from 'jotai';
import React from 'react';

export type LetterState = 'normal' | 'correct' | 'wrong';

const stateClassNameMap: Record<string, Record<LetterState, string>> = {
  true: {
    normal: 'text-gray-400',
    correct: 'text-green-400 dark:text-green-700',
    wrong: 'text-red-400 dark:text-red-600',
  },
  false: {
    normal: 'text-gray-600 dark:text-gray-50',
    correct: 'text-green-600 dark:text-green-400',
    wrong: 'text-red-600 dark:text-red-400',
  },
};

export type LetterProps = {
  letter: string;
  state?: LetterState;
  visible?: boolean;
  previousLetter?: string; // Previous letter prop
  secondPreviousLetter?: string; // Second previous letter prop
};
//['ั', 'ี', 'ึ', 'ื', 'ุ', 'ู', '่', '๋', '้', 'ิ'];
const TOP_VOWELS = ['ั', 'ี', 'ึ', 'ื', '่', '๋', '้', 'ิ'];
const TONAL_MARKS = ['้', '่', '๊', '๋', '์'];

const Letter: React.FC<LetterProps> = ({ letter, state = 'normal', visible = true, previousLetter, secondPreviousLetter }) => {
  const fontSizeConfig = useAtomValue(fontSizeConfigAtom);

  // Check if the letter is a top vowel or tonal mark
  const isTopVowel = TOP_VOWELS.includes(letter);
  const isPreviousVowel = TOP_VOWELS.includes(previousLetter);
  const isSecondPreviousVowel = TOP_VOWELS.includes(secondPreviousLetter);
  const isPreviousTonalMark = TONAL_MARKS.includes(previousLetter);
  const isCurrentTonalMark = TONAL_MARKS.includes(letter);

  // Determine shifting
  const shouldShiftUp = isTopVowel && previousLetter && !isPreviousTonalMark;
  const shouldShiftFurther = (isTopVowel || isCurrentTonalMark) && (isPreviousVowel || (isPreviousTonalMark && isSecondPreviousVowel));

  // Log previous and second previous letters for debugging

  console.log(`is top vowel: ${isTopVowel}, Current Letter: ${letter}, Previous: ${previousLetter}, Second Previous: ${secondPreviousLetter}, Shift Further: ${shouldShiftFurther}, Shift Up: ${shouldShiftUp}`);

  // Log detailed condition checks
  console.log(`Detailed Conditions:
      isTopVowel: ${isTopVowel},
      isPreviousVowel: ${isPreviousVowel},
      isSecondPreviousVowel: ${isSecondPreviousVowel},
      isPreviousTonalMark: ${isPreviousTonalMark},
      isCurrentTonalMark: ${isCurrentTonalMark}
    `);


  // Additional log for current letter and previous letter being top tonal marks
  if (isCurrentTonalMark && isPreviousTonalMark) {
    console.log(`Current Tonal Mark: ${letter}, Previous Tonal Mark: ${previousLetter}`);
  }

  return (
    <span
      className={`m-0 p-0 font-mono font-normal ${stateClassNameMap[(letter === EXPLICIT_SPACE) as unknown as string][state]
        } ${shouldShiftUp ? 'shift-up' : ''} ${shouldShiftFurther ? 'shift-further' : ''} pr-0.8 duration-0 dark:text-opacity-80`}
      style={{ fontSize: fontSizeConfig.foreignFont.toString() + 'px' }}
    >
      {visible ? letter : '_'}
    </span>
  );
};

export default React.memo(Letter);
@raychunghk
Copy link
Author

index.css


@tailwind base;
@tailwind components;
@tailwind utilities;

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans',
    'Helvetica Neue', sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  background-color: #faf9ff;
  @apply transition-colors duration-300;
  user-select: none;
}

html.dark body {
  @apply bg-gray-900;
}

code {
  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
}

html,
body,
:global(#root) {
  height: 100%;
}

.my-card {
  box-shadow: 0px 100px 80px rgba(50, 46, 129, 0.07), 0px 41.7776px 33.4221px rgba(50, 46, 129, 0.0503198),
    0px 22.3363px 17.869px rgba(50, 46, 129, 0.0417275), 0px 12.5216px 10.0172px rgba(50, 46, 129, 0.035),
    0px 6.6501px 5.32008px rgba(50, 46, 129, 0.0282725), 0px 2.76726px 2.21381px rgba(50, 46, 129, 0.0196802);
}

/* Well, TailwindCSS does’t have `text-shadow` classes. */
.text-shadow {
  text-shadow: 0 4px 8px rgba(0, 0, 0, 0.16), 0 2px 4px rgba(0, 0, 0, 0.12), 0 4px 8px rgba(0, 0, 0, 0.08), 0 2px 4px rgba(0, 0, 0, 0.04);
}

.shadow-upper {
  box-shadow: 0 -1px 4px rgba(0, 0, 0, 0.1);
}

.customized-scrollbar::-webkit-scrollbar {
  width: 6px;
  background: inherit;
}

.customized-scrollbar::-webkit-scrollbar-thumb {
  background: rgba(0, 0, 0, 0.25);
}

.customized-scrollbar::-webkit-scrollbar-track {
  background: transparent;
}

@layer components {
  .icon {
    @apply h-5.5 w-5.5 focus:outline-none;
  }

  .word-chip {
    @apply flex h-10 w-auto cursor-pointer
      flex-row items-center
    justify-center rounded-md border-2
      border-solid border-indigo-400 bg-white px-2 py-0.5 transition-colors duration-100 hover:bg-indigo-100 dark:border-slate-800
      dark:bg-slate-700 dark:hover:bg-slate-600 md:h-12
      md:px-5 md:py-1;
  }

  .word-chip > span {
    @apply font-mono text-2xl font-light text-gray-600 dark:text-gray-300 md:text-3xl;
  }

  .word-chip-tooltip {
    @apply pointer-events-none flex items-center justify-center whitespace-nowrap rounded-lg
      bg-white px-2 py-1 text-xs text-gray-500
      shadow-md dark:bg-gray-800 dark:text-gray-300;
  }

  .my-btn-primary {
    @apply flex items-center justify-center rounded-lg bg-indigo-400 px-6 py-1 text-lg text-white hover:opacity-90 focus:outline-none dark:text-opacity-80;
  }

  .my-btn-info-panel {
    @apply mt-3 inline-flex w-full justify-center rounded-md px-3 py-2 text-sm
      font-semibold text-white shadow-sm transition-colors focus:outline-none
      dark:bg-opacity-70 dark:text-opacity-80 sm:ml-3 sm:mt-0 sm:w-auto
      sm:text-sm;
  }

  .tooltip {
    @apply whitespace-nowrap rounded-lg bg-white px-2 py-1 text-xs text-gray-500 shadow-md dark:bg-gray-700 dark:text-gray-300;
  }

  .switch-root {
    @apply relative inline-flex h-6 w-12 shrink-0 cursor-pointer items-center rounded-full border-3 border-transparent bg-gray-300 transition-colors duration-200 ease-in-out focus:outline-none;
  }
  .switch-root[data-headlessui-state='checked'] {
    @apply bg-indigo-400;
  }
  .switch-thumb {
    @apply pointer-events-none inline-block h-4 w-4 translate-x-0 transform rounded-full bg-white shadow-lg ring-0 transition duration-200 ease-in-out;
  }
  [data-headlessui-state='checked'] .switch-thumb {
    @apply translate-x-[25px];
  }

  .listbox-button {
    @apply relative w-40 cursor-pointer rounded-lg bg-white py-2 pl-3 pr-10 text-left shadow-md focus:outline-none dark:bg-gray-600;
  }
  .listbox-button span:nth-of-type(1) {
    @apply block truncate text-gray-900 dark:text-white dark:text-opacity-60;
  }
  .listbox-button span:nth-of-type(2) {
    @apply pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2 focus:outline-none;
  }
  .listbox-options {
    @apply absolute mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg  focus:outline-none dark:bg-gray-600;
  }
  .listbox-options > li {
    @apply relative cursor-pointer select-none py-2 pl-10 pr-4 text-gray-900 ui-active:bg-indigo-100 ui-active:text-indigo-900 dark:text-white dark:text-opacity-60 dark:ui-active:bg-gray-500 dark:ui-active:text-indigo-300;
  }
  .listbox-options > li > span:first-child {
    @apply block truncate font-normal  ui-selected:font-medium;
  }
  .listbox-options-icon {
    @apply absolute inset-y-0 left-0 flex items-center pl-3 text-indigo-600 dark:text-indigo-400;
  }

  .slider {
    @apply relative flex h-10 w-full cursor-pointer select-none items-center;
  }
  .slider [data-disabled] {
    @apply pointer-events-none opacity-50;
  }
  .slider > span:nth-child(1) {
    @apply relative h-[5px] flex-grow rounded-full bg-gray-200;
  }
  .slider > span:nth-child(1) > span:nth-child(1) {
    @apply absolute h-full rounded-full bg-indigo-400;
  }
  .slider > span:nth-child(2) {
    @apply block h-4 w-4 cursor-pointer rounded-full border border-gray-200 bg-white drop-shadow-md;
  }
}

.gradient-text {
  background-image: linear-gradient(90deg, #f66, #f90);
  background-clip: text;

  color: transparent;
  animation: gradient-text-hue 5s linear infinite;
}

@keyframes gradient-text-hue {
  from {
    filter: hue-rotate(0);
  }
  to {
    filter: hue-rotate(-1turn);
  }
}

@keyframes typing {
  from {
    width: 0;
  }
  to {
    width: 30em;
  } /* 调整为字符总数的一半 */
}

@keyframes blink-caret {
  from,
  to {
    border-color: transparent;
  }
  50% {
    border-color: #f0f0f0;
  }
}

.typewriter {
  width: 30em;
  margin: 0 auto;
}
@keyframes hideCaret {
  to {
    border-right-color: transparent;
  }
}

@keyframes gradientBG {
  0% {
    background-position: 0% 50%;
  }

  50% {
    background-position: 100% 50%;
  }

  100% {
    background-position: 0% 50%;
  }
}
.shift-up {
  transform: translateY(-0.1em); /* Adjust the value as needed */
  display: inline-block; /* Ensure it behaves like inline text */
}
.shift-further {
  transform: translateY(-0.4em); /* Further shift for vowels following another vowel */
  display: inline-block;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant